@aws/nx-plugin 1.0.10 → 1.0.12

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.
Files changed (35) hide show
  1. package/LICENSE-THIRD-PARTY +14 -41
  2. package/migrations.json +11 -11
  3. package/package.json +4 -4
  4. package/src/migrations/v1.0.10/0001-pin-strands-mcp-client-peer/migration.js.map +1 -0
  5. package/src/migrations/v1.0.9/0001-py-dynamodb-bind-base-model-meta/migration.js.map +1 -0
  6. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +6 -6
  7. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +7 -7
  8. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +1 -1
  9. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
  10. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +2 -2
  11. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +14 -14
  12. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1 -1
  13. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +2 -2
  14. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +1 -1
  15. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +2 -2
  16. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +12 -12
  17. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +1 -1
  18. package/src/utils/docker.d.ts +1 -1
  19. package/src/utils/version-lockstep/exact-dependency.d.ts +65 -0
  20. package/src/utils/version-lockstep/exact-dependency.js +213 -0
  21. package/src/utils/version-lockstep/exact-dependency.js.map +1 -0
  22. package/src/utils/version-lockstep/report.d.ts +44 -0
  23. package/src/utils/version-lockstep/report.js +108 -0
  24. package/src/utils/version-lockstep/report.js.map +1 -0
  25. package/src/utils/versions.d.ts +75 -60
  26. package/src/utils/versions.js +82 -60
  27. package/src/utils/versions.js.map +1 -1
  28. package/src/migrations/latest/pin-strands-mcp-client-peer/migration.js.map +0 -1
  29. package/src/migrations/latest/py-dynamodb-bind-base-model-meta/migration.js.map +0 -1
  30. /package/src/migrations/{latest/pin-strands-mcp-client-peer → v1.0.10/0001-pin-strands-mcp-client-peer}/metadata.json +0 -0
  31. /package/src/migrations/{latest/pin-strands-mcp-client-peer → v1.0.10/0001-pin-strands-mcp-client-peer}/migration.d.ts +0 -0
  32. /package/src/migrations/{latest/pin-strands-mcp-client-peer → v1.0.10/0001-pin-strands-mcp-client-peer}/migration.js +0 -0
  33. /package/src/migrations/{latest/py-dynamodb-bind-base-model-meta → v1.0.9/0001-py-dynamodb-bind-base-model-meta}/metadata.json +0 -0
  34. /package/src/migrations/{latest/py-dynamodb-bind-base-model-meta → v1.0.9/0001-py-dynamodb-bind-base-model-meta}/migration.d.ts +0 -0
  35. /package/src/migrations/{latest/py-dynamodb-bind-base-model-meta → v1.0.9/0001-py-dynamodb-bind-base-model-meta}/migration.js +0 -0
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { readJson, writeJson } from "@nx/devkit";
5
+ import { coerce, satisfies, valid } from "semver";
6
+ /** The bare version in a pin, whatever range syntax it was written with. */ const bare = (version)=>coerce(version, {
7
+ includePrerelease: true
8
+ })?.version;
9
+ const message = (error)=>error instanceof Error ? error.message : String(error);
10
+ /**
11
+ * The versions the source's `dependencies` give its followers, and the version
12
+ * of the follower each group mate is grouped with, so the group stays in step.
13
+ */ const targetsFrom = ({ source, followers }, sourceVersion, dependencies, groups, current)=>{
14
+ const missing = followers.filter((name)=>!dependencies[name]);
15
+ if (missing.length > 0) {
16
+ return {
17
+ held: `${source} ${sourceVersion} does not depend on ${missing.join(', ')}`
18
+ };
19
+ }
20
+ // Releases so far declare exact versions. If one declares a range, take its
21
+ // bare version: our pins are exact, and a single copy needs that version.
22
+ const targets = new Map(followers.map((name)=>{
23
+ const declared = dependencies[name];
24
+ return [
25
+ name,
26
+ valid(declared) ?? bare(declared) ?? declared
27
+ ];
28
+ }));
29
+ for (const group of groups){
30
+ const inGroup = followers.filter((name)=>group.includes(name));
31
+ if (inGroup.length === 0) continue;
32
+ const version = targets.get(inGroup[0]);
33
+ const disagreeing = inGroup.find((name)=>targets.get(name) !== version);
34
+ if (disagreeing) {
35
+ return {
36
+ held: `${source} ${sourceVersion} depends on ${inGroup[0]} ${version} but ${disagreeing} ${targets.get(disagreeing)}, which must move in step`
37
+ };
38
+ }
39
+ for (const name of group){
40
+ if (!targets.has(name) && current[name] !== undefined) {
41
+ targets.set(name, version);
42
+ }
43
+ }
44
+ }
45
+ return targets;
46
+ };
47
+ /** Why the peers being written would reject the targets, if they would. */ const unmetPeers = async ({ source, peers }, sourceVersion, targets, written, lookup)=>{
48
+ const unmet = [];
49
+ for (const peer of peers){
50
+ const peerVersion = written(peer);
51
+ if (peerVersion === undefined) continue;
52
+ let ranges;
53
+ try {
54
+ ranges = await lookup(peer, peerVersion, 'peerDependencies');
55
+ } catch (error) {
56
+ return `could not read the peerDependencies of ${peer} ${peerVersion} (${message(error)})`;
57
+ }
58
+ for (const [name, version] of targets){
59
+ const range = ranges[name];
60
+ if (range && !satisfies(version, range, {
61
+ includePrerelease: true
62
+ })) {
63
+ unmet.push(`${peer} ${peerVersion} requires ${name} ${range}, but ${source} ${sourceVersion} needs ${version}`);
64
+ }
65
+ }
66
+ }
67
+ return unmet.length > 0 ? unmet.join('; ') : undefined;
68
+ };
69
+ /**
70
+ * Set each rule's followers, and their lockstep group mates, to the exact
71
+ * versions the source being written depends on. Runs after the lockstep, which
72
+ * can only hold a group back and so can't move one up to what the source needs.
73
+ *
74
+ * Mutates `proposed`, which holds versions not yet written anywhere. When a peer
75
+ * would reject the result, or a manifest can't be read, every pin the rule covers
76
+ * is put back to `current` for this run instead. Returns a note for each pin set
77
+ * and each rule held, so the reason reaches the update's PR.
78
+ */ export const pinToExactDependencies = async (rules, groups, current, proposed, lookup)=>{
79
+ const notes = [];
80
+ const written = (name)=>{
81
+ const version = proposed[name] ?? current[name];
82
+ return version === undefined ? undefined : bare(version);
83
+ };
84
+ for (const rule of rules){
85
+ const { source, followers, peers, reason } = rule;
86
+ const mates = groups.filter((group)=>followers.some((name)=>group.includes(name))).flat();
87
+ const covered = [
88
+ ...new Set([
89
+ source,
90
+ ...followers,
91
+ ...mates,
92
+ ...peers
93
+ ])
94
+ ].filter((name)=>current[name] !== undefined);
95
+ // Every pin the rule covers goes back to its current version, so nothing
96
+ // the rule could not check is written.
97
+ const hold = (why)=>{
98
+ const notTaken = covered.filter((name)=>proposed[name] !== undefined && proposed[name] !== current[name]);
99
+ notes.push({
100
+ name: source,
101
+ note: `${source} held at ${current[source]}, with ${covered.filter((name)=>name !== source).join(', ')} at their current versions` + (notTaken.length > 0 ? ` (not taken: ${notTaken.map((name)=>`${name} ${proposed[name]}`).join(', ')})` : '') + `: ${why}`
102
+ });
103
+ for (const name of covered)proposed[name] = current[name];
104
+ };
105
+ const sourceVersion = written(source);
106
+ if (sourceVersion === undefined) continue;
107
+ let dependencies;
108
+ try {
109
+ dependencies = await lookup(source, sourceVersion, 'dependencies');
110
+ } catch (error) {
111
+ hold(`could not read the dependencies of ${source} ${sourceVersion} (${message(error)})`);
112
+ continue;
113
+ }
114
+ const targets = targetsFrom(rule, sourceVersion, dependencies, groups, current);
115
+ if (!(targets instanceof Map)) {
116
+ hold(targets.held);
117
+ continue;
118
+ }
119
+ const unmet = await unmetPeers(rule, sourceVersion, targets, written, lookup);
120
+ if (unmet) {
121
+ hold(unmet);
122
+ continue;
123
+ }
124
+ for (const [name, version] of targets){
125
+ const before = proposed[name] ?? current[name];
126
+ if (before === version) continue;
127
+ proposed[name] = version;
128
+ notes.push({
129
+ name,
130
+ note: `${name} set to ${version} (${before} proposed) to match the exact dependencies of ${source} ${sourceVersion}: ${reason}`
131
+ });
132
+ }
133
+ }
134
+ return notes;
135
+ };
136
+ /** Reads each release's field once; a failed read fails the same way when repeated. */ export const memoizeLookup = (lookup)=>{
137
+ const cache = new Map();
138
+ return async (name, version, field)=>{
139
+ const key = `${name}@${version} ${field}`;
140
+ let cached = cache.get(key);
141
+ if (!cached) {
142
+ cached = lookup(name, version, field);
143
+ cache.set(key, cached);
144
+ }
145
+ return {
146
+ ...await cached
147
+ };
148
+ };
149
+ };
150
+ /** Where the update records what each rule's source release depends on. */ export const EXACT_DEPENDENCY_SOURCES_PATH = 'packages/nx-plugin/exact-dependency-sources.json';
151
+ /**
152
+ * What each rule's source, at the version being written, depends on for its
153
+ * followers. Reuses `recorded` for a source that did not move and reads the
154
+ * registry otherwise. Throws when a follower being written is not that version,
155
+ * or when the source's dependencies can't be read or omit a follower.
156
+ */ export const verifyExactDependencies = async (rules, versions, recorded, lookup)=>{
157
+ const sources = {};
158
+ const written = (name)=>{
159
+ const version = versions[name];
160
+ return version === undefined ? undefined : bare(version);
161
+ };
162
+ for (const { source, followers, reason } of rules){
163
+ const sourceVersion = written(source);
164
+ if (sourceVersion === undefined) continue;
165
+ let dependencies;
166
+ if (recorded[source]?.version === sourceVersion) {
167
+ dependencies = recorded[source].dependencies;
168
+ } else {
169
+ try {
170
+ dependencies = await lookup(source, sourceVersion, 'dependencies');
171
+ } catch (error) {
172
+ throw new Error(`could not read the dependencies of ${source} ${sourceVersion} (${message(error)})`);
173
+ }
174
+ }
175
+ const missing = followers.filter((name)=>!dependencies[name]);
176
+ if (missing.length > 0) {
177
+ throw new Error(`${source} ${sourceVersion} does not depend on ${missing.join(', ')}`);
178
+ }
179
+ const expected = Object.fromEntries(followers.map((name)=>{
180
+ const declared = dependencies[name];
181
+ return [
182
+ name,
183
+ valid(declared) ?? bare(declared) ?? declared
184
+ ];
185
+ }));
186
+ const differing = followers.filter((name)=>written(name) !== expected[name]);
187
+ if (differing.length > 0) {
188
+ throw new Error(`${differing.map((name)=>`${name} ${written(name)}`).join(', ')} but ${source} ${sourceVersion} depends on ${differing.map((name)=>`${name} ${expected[name]}`).join(', ')}: ${reason}`);
189
+ }
190
+ sources[source] = {
191
+ version: sourceVersion,
192
+ dependencies: expected
193
+ };
194
+ }
195
+ return sources;
196
+ };
197
+ /**
198
+ * Record in `EXACT_DEPENDENCY_SOURCES_PATH` what the sources being written depend
199
+ * on, which `versions.spec.ts` checks the pins against. Throws as
200
+ * `verifyExactDependencies` does, before anything is written.
201
+ * @returns paths written, for the update report
202
+ */ export const writeExactDependencySources = async (tree, rules, versions, lookup)=>{
203
+ const path = EXACT_DEPENDENCY_SOURCES_PATH;
204
+ const recorded = tree.exists(path) ? readJson(tree, path) : {};
205
+ const sources = await verifyExactDependencies(rules, versions, recorded, lookup);
206
+ if (JSON.stringify(sources) === JSON.stringify(recorded)) return [];
207
+ writeJson(tree, path, sources);
208
+ return [
209
+ path
210
+ ];
211
+ };
212
+
213
+ //# sourceMappingURL=exact-dependency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-lockstep/exact-dependency.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { readJson, type Tree, writeJson } from '@nx/devkit';\nimport { coerce, satisfies, valid } from 'semver';\nimport type {\n IVersionedDep,\n LockstepNote,\n ProposedVersions,\n} from './lockstep.js';\n\n/**\n * Pins that must equal the exact `dependencies` a published release of another\n * pin declares, for packages that don't share a version line.\n */\nexport interface ExactDependencyPin {\n /** The pin whose published `dependencies` the followers take. */\n source: IVersionedDep;\n /** Pins set to exactly the version `source` depends on. */\n followers: readonly [IVersionedDep, ...IVersionedDep[]];\n /** Pins whose published `peerDependencies` must accept the followers. */\n peers: readonly IVersionedDep[];\n /** Why the followers must match, for the update's PR. */\n reason: string;\n}\n\n/** The manifest fields the rule reads. */\nexport type ManifestField = 'dependencies' | 'peerDependencies';\n\n/**\n * Reads one field of a published release's manifest, for example from\n * `https://registry.npmjs.org/<name>/<version>`. Resolves to `{}` when the\n * release has no such field, and rejects when the release can't be read.\n */\nexport type DependencyLookup = (\n name: string,\n version: string,\n field: ManifestField,\n) => Promise<Record<string, string>>;\n\n/** Groups of pins held at one version, as in `LOCKSTEP_GROUPS`. */\ntype Groups = readonly (readonly string[])[];\n\n/** The version each pin must take, or why there isn't one. */\ntype Targets = Map<IVersionedDep, string> | { held: string };\n\n/** The bare version in a pin, whatever range syntax it was written with. */\nconst bare = (version: string): string | undefined =>\n coerce(version, { includePrerelease: true })?.version;\n\nconst message = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * The versions the source's `dependencies` give its followers, and the version\n * of the follower each group mate is grouped with, so the group stays in step.\n */\nconst targetsFrom = (\n { source, followers }: ExactDependencyPin,\n sourceVersion: string,\n dependencies: Record<string, string>,\n groups: Groups,\n current: Readonly<ProposedVersions>,\n): Targets => {\n const missing = followers.filter((name) => !dependencies[name]);\n if (missing.length > 0) {\n return {\n held: `${source} ${sourceVersion} does not depend on ${missing.join(', ')}`,\n };\n }\n\n // Releases so far declare exact versions. If one declares a range, take its\n // bare version: our pins are exact, and a single copy needs that version.\n const targets = new Map<IVersionedDep, string>(\n followers.map((name) => {\n const declared = dependencies[name];\n return [name, valid(declared) ?? bare(declared) ?? declared];\n }),\n );\n\n for (const group of groups) {\n const inGroup = followers.filter((name) => group.includes(name));\n if (inGroup.length === 0) continue;\n const version = targets.get(inGroup[0]) as string;\n const disagreeing = inGroup.find((name) => targets.get(name) !== version);\n if (disagreeing) {\n return {\n held: `${source} ${sourceVersion} depends on ${inGroup[0]} ${version} but ${disagreeing} ${targets.get(disagreeing)}, which must move in step`,\n };\n }\n for (const name of group as readonly IVersionedDep[]) {\n if (!targets.has(name) && current[name] !== undefined) {\n targets.set(name, version);\n }\n }\n }\n\n return targets;\n};\n\n/** Why the peers being written would reject the targets, if they would. */\nconst unmetPeers = async (\n { source, peers }: ExactDependencyPin,\n sourceVersion: string,\n targets: Map<IVersionedDep, string>,\n written: (name: IVersionedDep) => string | undefined,\n lookup: DependencyLookup,\n): Promise<string | undefined> => {\n const unmet: string[] = [];\n for (const peer of peers) {\n const peerVersion = written(peer);\n if (peerVersion === undefined) continue;\n let ranges: Record<string, string>;\n try {\n ranges = await lookup(peer, peerVersion, 'peerDependencies');\n } catch (error) {\n return `could not read the peerDependencies of ${peer} ${peerVersion} (${message(error)})`;\n }\n for (const [name, version] of targets) {\n const range = ranges[name];\n if (range && !satisfies(version, range, { includePrerelease: true })) {\n unmet.push(\n `${peer} ${peerVersion} requires ${name} ${range}, but ${source} ${sourceVersion} needs ${version}`,\n );\n }\n }\n }\n return unmet.length > 0 ? unmet.join('; ') : undefined;\n};\n\n/**\n * Set each rule's followers, and their lockstep group mates, to the exact\n * versions the source being written depends on. Runs after the lockstep, which\n * can only hold a group back and so can't move one up to what the source needs.\n *\n * Mutates `proposed`, which holds versions not yet written anywhere. When a peer\n * would reject the result, or a manifest can't be read, every pin the rule covers\n * is put back to `current` for this run instead. Returns a note for each pin set\n * and each rule held, so the reason reaches the update's PR.\n */\nexport const pinToExactDependencies = async (\n rules: readonly ExactDependencyPin[],\n groups: Groups,\n current: Readonly<ProposedVersions>,\n proposed: ProposedVersions,\n lookup: DependencyLookup,\n): Promise<LockstepNote[]> => {\n const notes: LockstepNote[] = [];\n const written = (name: IVersionedDep): string | undefined => {\n const version = proposed[name] ?? current[name];\n return version === undefined ? undefined : bare(version);\n };\n\n for (const rule of rules) {\n const { source, followers, peers, reason } = rule;\n const mates = groups\n .filter((group) => followers.some((name) => group.includes(name)))\n .flat() as IVersionedDep[];\n const covered = [\n ...new Set([source, ...followers, ...mates, ...peers]),\n ].filter((name) => current[name] !== undefined);\n\n // Every pin the rule covers goes back to its current version, so nothing\n // the rule could not check is written.\n const hold = (why: string) => {\n const notTaken = covered.filter(\n (name) =>\n proposed[name] !== undefined && proposed[name] !== current[name],\n );\n notes.push({\n name: source,\n note:\n `${source} held at ${current[source]}, with ${covered\n .filter((name) => name !== source)\n .join(', ')} at their current versions` +\n (notTaken.length > 0\n ? ` (not taken: ${notTaken\n .map((name) => `${name} ${proposed[name]}`)\n .join(', ')})`\n : '') +\n `: ${why}`,\n });\n for (const name of covered) proposed[name] = current[name];\n };\n\n const sourceVersion = written(source);\n if (sourceVersion === undefined) continue;\n\n let dependencies: Record<string, string>;\n try {\n dependencies = await lookup(source, sourceVersion, 'dependencies');\n } catch (error) {\n hold(\n `could not read the dependencies of ${source} ${sourceVersion} (${message(error)})`,\n );\n continue;\n }\n\n const targets = targetsFrom(\n rule,\n sourceVersion,\n dependencies,\n groups,\n current,\n );\n if (!(targets instanceof Map)) {\n hold(targets.held);\n continue;\n }\n\n const unmet = await unmetPeers(\n rule,\n sourceVersion,\n targets,\n written,\n lookup,\n );\n if (unmet) {\n hold(unmet);\n continue;\n }\n\n for (const [name, version] of targets) {\n const before = proposed[name] ?? current[name];\n if (before === version) continue;\n proposed[name] = version;\n notes.push({\n name,\n note: `${name} set to ${version} (${before} proposed) to match the exact dependencies of ${source} ${sourceVersion}: ${reason}`,\n });\n }\n }\n\n return notes;\n};\n\n/** Reads each release's field once; a failed read fails the same way when repeated. */\nexport const memoizeLookup = (lookup: DependencyLookup): DependencyLookup => {\n const cache = new Map<string, Promise<Record<string, string>>>();\n return async (name, version, field) => {\n const key = `${name}@${version} ${field}`;\n let cached = cache.get(key);\n if (!cached) {\n cached = lookup(name, version, field);\n cache.set(key, cached);\n }\n return { ...(await cached) };\n };\n};\n\n/** Where the update records what each rule's source release depends on. */\nexport const EXACT_DEPENDENCY_SOURCES_PATH =\n 'packages/nx-plugin/exact-dependency-sources.json';\n\n/** Per rule source: the version pinned and the exact versions it depends on for its followers. */\nexport type ExactDependencySources = Record<\n string,\n { version: string; dependencies: Record<string, string> }\n>;\n\n/**\n * What each rule's source, at the version being written, depends on for its\n * followers. Reuses `recorded` for a source that did not move and reads the\n * registry otherwise. Throws when a follower being written is not that version,\n * or when the source's dependencies can't be read or omit a follower.\n */\nexport const verifyExactDependencies = async (\n rules: readonly ExactDependencyPin[],\n versions: Readonly<ProposedVersions>,\n recorded: Readonly<ExactDependencySources>,\n lookup: DependencyLookup,\n): Promise<ExactDependencySources> => {\n const sources: ExactDependencySources = {};\n const written = (name: IVersionedDep): string | undefined => {\n const version = versions[name];\n return version === undefined ? undefined : bare(version);\n };\n\n for (const { source, followers, reason } of rules) {\n const sourceVersion = written(source);\n if (sourceVersion === undefined) continue;\n\n let dependencies: Record<string, string>;\n if (recorded[source]?.version === sourceVersion) {\n dependencies = recorded[source].dependencies;\n } else {\n try {\n dependencies = await lookup(source, sourceVersion, 'dependencies');\n } catch (error) {\n throw new Error(\n `could not read the dependencies of ${source} ${sourceVersion} (${message(error)})`,\n );\n }\n }\n\n const missing = followers.filter((name) => !dependencies[name]);\n if (missing.length > 0) {\n throw new Error(\n `${source} ${sourceVersion} does not depend on ${missing.join(', ')}`,\n );\n }\n\n const expected = Object.fromEntries(\n followers.map((name) => {\n const declared = dependencies[name];\n return [name, valid(declared) ?? bare(declared) ?? declared];\n }),\n );\n const differing = followers.filter(\n (name) => written(name) !== expected[name],\n );\n if (differing.length > 0) {\n throw new Error(\n `${differing.map((name) => `${name} ${written(name)}`).join(', ')} but ${source} ${sourceVersion} depends on ${differing.map((name) => `${name} ${expected[name]}`).join(', ')}: ${reason}`,\n );\n }\n\n sources[source] = { version: sourceVersion, dependencies: expected };\n }\n\n return sources;\n};\n\n/**\n * Record in `EXACT_DEPENDENCY_SOURCES_PATH` what the sources being written depend\n * on, which `versions.spec.ts` checks the pins against. Throws as\n * `verifyExactDependencies` does, before anything is written.\n * @returns paths written, for the update report\n */\nexport const writeExactDependencySources = async (\n tree: Tree,\n rules: readonly ExactDependencyPin[],\n versions: Readonly<ProposedVersions>,\n lookup: DependencyLookup,\n): Promise<string[]> => {\n const path = EXACT_DEPENDENCY_SOURCES_PATH;\n const recorded: ExactDependencySources = tree.exists(path)\n ? readJson(tree, path)\n : {};\n const sources = await verifyExactDependencies(\n rules,\n versions,\n recorded,\n lookup,\n );\n if (JSON.stringify(sources) === JSON.stringify(recorded)) return [];\n writeJson(tree, path, sources);\n return [path];\n};\n"],"names":["readJson","writeJson","coerce","satisfies","valid","bare","version","includePrerelease","message","error","Error","String","targetsFrom","source","followers","sourceVersion","dependencies","groups","current","missing","filter","name","length","held","join","targets","Map","map","declared","group","inGroup","includes","get","disagreeing","find","has","undefined","set","unmetPeers","peers","written","lookup","unmet","peer","peerVersion","ranges","range","push","pinToExactDependencies","rules","proposed","notes","rule","reason","mates","some","flat","covered","Set","hold","why","notTaken","note","before","memoizeLookup","cache","field","key","cached","EXACT_DEPENDENCY_SOURCES_PATH","verifyExactDependencies","versions","recorded","sources","expected","Object","fromEntries","differing","writeExactDependencySources","tree","path","exists","JSON","stringify"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /** A pin the run moves from one version to another. */
6
+ export interface VersionChange {
7
+ name: string;
8
+ oldVersion: string;
9
+ newVersion: string;
10
+ }
11
+ /** A file the run rewrites. */
12
+ export interface TemplateChange {
13
+ path: string;
14
+ }
15
+ /** Something the run could not do, reported so it reaches the PR body. */
16
+ export interface ReportNote {
17
+ note: string;
18
+ }
19
+ export type ReportChange = VersionChange | TemplateChange | ReportNote;
20
+ /** A titled section of the report. */
21
+ export interface ChangeGroup {
22
+ title: string;
23
+ changes: ReportChange[];
24
+ }
25
+ /**
26
+ * The longest line commitlint accepts in a commit body or footer, from rule sets
27
+ * such as `@commitlint/config-conventional`'s rules followed by the repo's
28
+ * overrides. Later rule sets override earlier ones.
29
+ */
30
+ export declare const commitMessageLineLimit: (...ruleSets: readonly Readonly<Record<string, unknown>>[]) => number;
31
+ /**
32
+ * Splits a line longer than `limit` at spaces into lines of at most `limit`.
33
+ * A list item continues indented under its text, so Markdown keeps it one item,
34
+ * and no continuation starts with a word that would start a Markdown block. A
35
+ * word longer than `limit`, such as a URL, stays whole on its own line.
36
+ */
37
+ export declare const wrapReportLine: (line: string, limit: number) => string[];
38
+ /** Wraps each line of `text` with {@link wrapReportLine}. */
39
+ export declare const wrapReport: (text: string, limit: number) => string;
40
+ /**
41
+ * The version update report: each group with changes as a titled list, with
42
+ * lines wrapped to `limit`.
43
+ */
44
+ export declare const formatReport: (changeGroups: readonly ChangeGroup[], limit: number) => string;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ /** A pin the run moves from one version to another. */ /**
5
+ * The longest line commitlint accepts in a commit body or footer, from rule sets
6
+ * such as `@commitlint/config-conventional`'s rules followed by the repo's
7
+ * overrides. Later rule sets override earlier ones.
8
+ */ export const commitMessageLineLimit = (...ruleSets)=>{
9
+ const limitOf = (rule)=>{
10
+ const value = ruleSets.map((rules)=>rules[rule]).filter((setting)=>setting !== undefined).at(-1);
11
+ const limit = Array.isArray(value) ? value[2] : undefined;
12
+ if (typeof limit !== 'number') {
13
+ throw new Error(`commitlint rule ${rule} sets no line limit`);
14
+ }
15
+ return limit;
16
+ };
17
+ // commitlint can parse a wrapped line as the start of the footer.
18
+ return Math.min(limitOf('body-max-line-length'), limitOf('footer-max-line-length'));
19
+ };
20
+ /** A list item marker and the spaces after it. */ const LIST_MARKER = /^(\s*)([-+*]|\d{1,9}[.)])( +)/;
21
+ /** A word that would start a Markdown block at the start of a continuation. */ const BLOCK_START = /^(?:[-+*]|\d{1,9}[.)]|#{1,6}|[<>`~].*|[-=*_]{3,})$/;
22
+ /**
23
+ * Splits a line longer than `limit` at spaces into lines of at most `limit`.
24
+ * A list item continues indented under its text, so Markdown keeps it one item,
25
+ * and no continuation starts with a word that would start a Markdown block. A
26
+ * word longer than `limit`, such as a URL, stays whole on its own line.
27
+ */ export const wrapReportLine = (line, limit)=>{
28
+ if (line.length <= limit) return [
29
+ line
30
+ ];
31
+ const marker = LIST_MARKER.exec(line)?.[0];
32
+ const first = marker ?? /^\s*/.exec(line)?.[0] ?? '';
33
+ const indent = marker ? ' '.repeat(marker.length) : first;
34
+ const fits = (prefix, words)=>prefix.length + words.join(' ').length <= limit;
35
+ const lines = [
36
+ {
37
+ prefix: first,
38
+ words: []
39
+ }
40
+ ];
41
+ for (const word of line.slice(first.length).split(/\s+/).filter(Boolean)){
42
+ const current = lines[lines.length - 1];
43
+ if (current.words.length === 0 || fits(current.prefix, [
44
+ ...current.words,
45
+ word
46
+ ])) {
47
+ current.words.push(word);
48
+ continue;
49
+ }
50
+ const last = current.words[current.words.length - 1];
51
+ if (BLOCK_START.test(word) && current.words.length > 1 && !BLOCK_START.test(last) && fits(indent, [
52
+ last,
53
+ word
54
+ ])) {
55
+ current.words.pop();
56
+ lines.push({
57
+ prefix: indent,
58
+ words: [
59
+ last,
60
+ word
61
+ ]
62
+ });
63
+ } else {
64
+ lines.push({
65
+ prefix: indent,
66
+ words: [
67
+ word
68
+ ]
69
+ });
70
+ }
71
+ }
72
+ return lines.map(({ prefix, words })=>prefix + words.join(' '));
73
+ };
74
+ /** Wraps each line of `text` with {@link wrapReportLine}. */ export const wrapReport = (text, limit)=>text.split('\n').flatMap((line)=>wrapReportLine(line, limit)).join('\n');
75
+ /**
76
+ * The version update report: each group with changes as a titled list, with
77
+ * lines wrapped to `limit`.
78
+ */ export const formatReport = (changeGroups, limit)=>{
79
+ let reportContent = '';
80
+ // Process each change group
81
+ changeGroups.forEach((group, index)=>{
82
+ if (group.changes.length > 0) {
83
+ // Add separator between groups
84
+ if (index > 0) {
85
+ reportContent += '\n';
86
+ }
87
+ reportContent += `${group.title}\n`;
88
+ group.changes.forEach((change)=>{
89
+ if ('oldVersion' in change) {
90
+ reportContent += `- ${change.name} ${change.oldVersion} -> ${change.newVersion}\n`;
91
+ return;
92
+ }
93
+ if ('note' in change) {
94
+ reportContent += `- ${change.note}\n`;
95
+ return;
96
+ }
97
+ reportContent += `- ${change.path}\n`;
98
+ });
99
+ }
100
+ });
101
+ // If no changes at all
102
+ if (reportContent.length === 0) {
103
+ reportContent = 'No version updates required.\n';
104
+ }
105
+ return wrapReport(reportContent, limit);
106
+ };
107
+
108
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/version-lockstep/report.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/** A pin the run moves from one version to another. */\nexport interface VersionChange {\n name: string;\n oldVersion: string;\n newVersion: string;\n}\n\n/** A file the run rewrites. */\nexport interface TemplateChange {\n path: string;\n}\n\n/** Something the run could not do, reported so it reaches the PR body. */\nexport interface ReportNote {\n note: string;\n}\n\nexport type ReportChange = VersionChange | TemplateChange | ReportNote;\n\n/** A titled section of the report. */\nexport interface ChangeGroup {\n title: string;\n changes: ReportChange[];\n}\n\n/**\n * The longest line commitlint accepts in a commit body or footer, from rule sets\n * such as `@commitlint/config-conventional`'s rules followed by the repo's\n * overrides. Later rule sets override earlier ones.\n */\nexport const commitMessageLineLimit = (\n ...ruleSets: readonly Readonly<Record<string, unknown>>[]\n): number => {\n const limitOf = (rule: string): number => {\n const value = ruleSets\n .map((rules) => rules[rule])\n .filter((setting) => setting !== undefined)\n .at(-1);\n const limit = Array.isArray(value) ? value[2] : undefined;\n if (typeof limit !== 'number') {\n throw new Error(`commitlint rule ${rule} sets no line limit`);\n }\n return limit;\n };\n // commitlint can parse a wrapped line as the start of the footer.\n return Math.min(\n limitOf('body-max-line-length'),\n limitOf('footer-max-line-length'),\n );\n};\n\n/** A list item marker and the spaces after it. */\nconst LIST_MARKER = /^(\\s*)([-+*]|\\d{1,9}[.)])( +)/;\n\n/** A word that would start a Markdown block at the start of a continuation. */\nconst BLOCK_START = /^(?:[-+*]|\\d{1,9}[.)]|#{1,6}|[<>`~].*|[-=*_]{3,})$/;\n\n/**\n * Splits a line longer than `limit` at spaces into lines of at most `limit`.\n * A list item continues indented under its text, so Markdown keeps it one item,\n * and no continuation starts with a word that would start a Markdown block. A\n * word longer than `limit`, such as a URL, stays whole on its own line.\n */\nexport const wrapReportLine = (line: string, limit: number): string[] => {\n if (line.length <= limit) return [line];\n\n const marker = LIST_MARKER.exec(line)?.[0];\n const first = marker ?? /^\\s*/.exec(line)?.[0] ?? '';\n const indent = marker ? ' '.repeat(marker.length) : first;\n const fits = (prefix: string, words: string[]) =>\n prefix.length + words.join(' ').length <= limit;\n\n const lines: { prefix: string; words: string[] }[] = [\n { prefix: first, words: [] },\n ];\n for (const word of line.slice(first.length).split(/\\s+/).filter(Boolean)) {\n const current = lines[lines.length - 1];\n if (\n current.words.length === 0 ||\n fits(current.prefix, [...current.words, word])\n ) {\n current.words.push(word);\n continue;\n }\n const last = current.words[current.words.length - 1];\n if (\n BLOCK_START.test(word) &&\n current.words.length > 1 &&\n !BLOCK_START.test(last) &&\n fits(indent, [last, word])\n ) {\n current.words.pop();\n lines.push({ prefix: indent, words: [last, word] });\n } else {\n lines.push({ prefix: indent, words: [word] });\n }\n }\n\n return lines.map(({ prefix, words }) => prefix + words.join(' '));\n};\n\n/** Wraps each line of `text` with {@link wrapReportLine}. */\nexport const wrapReport = (text: string, limit: number): string =>\n text\n .split('\\n')\n .flatMap((line) => wrapReportLine(line, limit))\n .join('\\n');\n\n/**\n * The version update report: each group with changes as a titled list, with\n * lines wrapped to `limit`.\n */\nexport const formatReport = (\n changeGroups: readonly ChangeGroup[],\n limit: number,\n): string => {\n let reportContent = '';\n\n // Process each change group\n changeGroups.forEach((group, index) => {\n if (group.changes.length > 0) {\n // Add separator between groups\n if (index > 0) {\n reportContent += '\\n';\n }\n\n reportContent += `${group.title}\\n`;\n group.changes.forEach((change) => {\n if ('oldVersion' in change) {\n reportContent += `- ${change.name} ${change.oldVersion} -> ${change.newVersion}\\n`;\n return;\n }\n if ('note' in change) {\n reportContent += `- ${change.note}\\n`;\n return;\n }\n reportContent += `- ${change.path}\\n`;\n });\n }\n });\n\n // If no changes at all\n if (reportContent.length === 0) {\n reportContent = 'No version updates required.\\n';\n }\n\n return wrapReport(reportContent, limit);\n};\n"],"names":["commitMessageLineLimit","ruleSets","limitOf","rule","value","map","rules","filter","setting","undefined","at","limit","Array","isArray","Error","Math","min","LIST_MARKER","BLOCK_START","wrapReportLine","line","length","marker","exec","first","indent","repeat","fits","prefix","words","join","lines","word","slice","split","Boolean","current","push","last","test","pop","wrapReport","text","flatMap","formatReport","changeGroups","reportContent","forEach","group","index","changes","title","change","name","oldVersion","newVersion","note","path"],"mappings":"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"}