@aws-cdk/toolkit-lib 0.2.0 → 0.3.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.
Files changed (45) hide show
  1. package/build-info.json +2 -2
  2. package/lib/actions/bootstrap/index.js +69 -5
  3. package/lib/actions/diff/index.d.ts +8 -0
  4. package/lib/actions/diff/index.js +1 -1
  5. package/lib/actions/diff/private/helpers.d.ts +16 -0
  6. package/lib/actions/diff/private/helpers.js +31 -6
  7. package/lib/actions/index.d.ts +1 -0
  8. package/lib/actions/index.js +2 -1
  9. package/lib/actions/refactor/index.d.ts +15 -0
  10. package/lib/actions/refactor/index.js +3 -0
  11. package/lib/api/cloud-assembly/cached-source.d.ts +36 -0
  12. package/lib/api/cloud-assembly/cached-source.js +52 -0
  13. package/lib/api/cloud-assembly/index.d.ts +1 -0
  14. package/lib/api/cloud-assembly/index.js +2 -1
  15. package/lib/api/cloud-assembly/private/borrowed-assembly.d.ts +14 -0
  16. package/lib/api/cloud-assembly/private/borrowed-assembly.js +22 -0
  17. package/lib/api/cloud-assembly/private/context-aware-source.d.ts +18 -5
  18. package/lib/api/cloud-assembly/private/context-aware-source.js +25 -8
  19. package/lib/api/cloud-assembly/private/index.d.ts +0 -2
  20. package/lib/api/cloud-assembly/private/index.js +1 -3
  21. package/lib/api/cloud-assembly/private/prepare-source.d.ts +37 -8
  22. package/lib/api/cloud-assembly/private/prepare-source.js +76 -17
  23. package/lib/api/cloud-assembly/private/readable-assembly.d.ts +26 -0
  24. package/lib/api/cloud-assembly/private/readable-assembly.js +34 -0
  25. package/lib/api/cloud-assembly/private/source-builder.d.ts +27 -0
  26. package/lib/api/cloud-assembly/private/source-builder.js +139 -30
  27. package/lib/api/cloud-assembly/private/stack-assembly.d.ts +9 -4
  28. package/lib/api/cloud-assembly/private/stack-assembly.js +21 -3
  29. package/lib/api/cloud-assembly/source-builder.d.ts +6 -0
  30. package/lib/api/cloud-assembly/source-builder.js +1 -1
  31. package/lib/api/cloud-assembly/types.d.ts +32 -1
  32. package/lib/api/cloud-assembly/types.js +1 -1
  33. package/lib/api/shared-private.js +373 -20
  34. package/lib/api/shared-private.js.map +4 -4
  35. package/lib/api/shared-public.d.ts +82 -61
  36. package/lib/index_bg.wasm +0 -0
  37. package/lib/toolkit/private/index.d.ts +4 -0
  38. package/lib/toolkit/private/index.js +7 -2
  39. package/lib/toolkit/toolkit.d.ts +15 -2
  40. package/lib/toolkit/toolkit.js +326 -162
  41. package/package.json +11 -11
  42. package/lib/api/cloud-assembly/private/cached-source.d.ts +0 -15
  43. package/lib/api/cloud-assembly/private/cached-source.js +0 -25
  44. package/lib/api/cloud-assembly/private/identity-source.d.ts +0 -10
  45. package/lib/api/cloud-assembly/private/identity-source.js +0 -17
@@ -41,6 +41,7 @@ __export(shared_private_exports, {
41
41
  AccountAccessKeyCache: () => AccountAccessKeyCache,
42
42
  ActiveAssetCache: () => ActiveAssetCache,
43
43
  ActivityPrinterBase: () => ActivityPrinterBase,
44
+ AmbiguityError: () => AmbiguityError,
44
45
  AssemblyError: () => AssemblyError,
45
46
  AssetManifestBuilder: () => AssetManifestBuilder,
46
47
  AuthenticationError: () => AuthenticationError,
@@ -100,6 +101,8 @@ __export(shared_private_exports, {
100
101
  RWLock: () => RWLock,
101
102
  RequireApproval: () => RequireApproval,
102
103
  ResourceImporter: () => ResourceImporter,
104
+ ResourceLocation: () => ResourceLocation,
105
+ ResourceMapping: () => ResourceMapping,
103
106
  ResourceMigrator: () => ResourceMigrator,
104
107
  RollbackChoice: () => RollbackChoice,
105
108
  S3_ISOLATED_TAG: () => S3_ISOLATED_TAG,
@@ -123,6 +126,7 @@ __export(shared_private_exports, {
123
126
  WorkGraph: () => WorkGraph,
124
127
  WorkGraphBuilder: () => WorkGraphBuilder,
125
128
  addMetadataAssetsToManifest: () => addMetadataAssetsToManifest,
129
+ ambiguousMovements: () => ambiguousMovements,
126
130
  asIoHelper: () => asIoHelper,
127
131
  assertIsSuccessfulDeployStackResult: () => assertIsSuccessfulDeployStackResult,
128
132
  cached: () => cached,
@@ -136,7 +140,10 @@ __export(shared_private_exports, {
136
140
  determineAllowCrossAccountAssetPublishing: () => determineAllowCrossAccountAssetPublishing,
137
141
  error: () => error,
138
142
  findCloudWatchLogGroups: () => findCloudWatchLogGroups,
143
+ findResourceMovements: () => findResourceMovements,
144
+ formatAmbiguousMappings: () => formatAmbiguousMappings,
139
145
  formatSdkLoggerContent: () => formatSdkLoggerContent,
146
+ formatTypedMappings: () => formatTypedMappings,
140
147
  getBootstrapStackInfo: () => getBootstrapStackInfo,
141
148
  guessExecutable: () => guessExecutable,
142
149
  info: () => info,
@@ -157,6 +164,8 @@ __export(shared_private_exports, {
157
164
  refreshStacks: () => refreshStacks,
158
165
  removeNonImportResources: () => removeNonImportResources,
159
166
  replaceEnvPlaceholders: () => replaceEnvPlaceholders,
167
+ resourceMappings: () => resourceMappings,
168
+ resourceMovements: () => resourceMovements,
160
169
  result: () => result,
161
170
  setSdkTracing: () => setSdkTracing,
162
171
  some: () => some,
@@ -1186,6 +1195,16 @@ var IO = {
1186
1195
  description: "Stack deletion failed",
1187
1196
  interface: "ErrorPayload"
1188
1197
  }),
1198
+ // 8. Refactor (8xxx)
1199
+ CDK_TOOLKIT_I8900: result({
1200
+ code: "CDK_TOOLKIT_I8900",
1201
+ description: "Refactor result",
1202
+ interface: "RefactorResult"
1203
+ }),
1204
+ CDK_TOOLKIT_W8010: warn({
1205
+ code: "CDK_TOOLKIT_W8010",
1206
+ description: "Refactor execution not yet supported"
1207
+ }),
1189
1208
  // 9: Bootstrap (9xxx)
1190
1209
  CDK_TOOLKIT_I9000: info({
1191
1210
  code: "CDK_TOOLKIT_I9000",
@@ -2180,6 +2199,14 @@ var SDK = class {
2180
2199
  stackResources.push(...page?.StackResourceSummaries || []);
2181
2200
  }
2182
2201
  return stackResources;
2202
+ },
2203
+ paginatedListStacks: async (input) => {
2204
+ const stackResources = Array();
2205
+ const paginator = (0, import_client_cloudformation.paginateListStacks)({ client }, input);
2206
+ for await (const page of paginator) {
2207
+ stackResources.push(...page?.StackSummaries || []);
2208
+ }
2209
+ return stackResources;
2183
2210
  }
2184
2211
  };
2185
2212
  }
@@ -4650,11 +4677,14 @@ async function uploadBodyParameterAndCreateChangeSet(ioHelper, options) {
4650
4677
  role: executionRoleArn
4651
4678
  });
4652
4679
  } catch (e) {
4653
- await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(String(e)));
4654
- await ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg(
4655
- "Could not create a change set, will base the diff on template differences (run again with -v to see the reason)\n"
4656
- ));
4657
- return void 0;
4680
+ if (!options.failOnError) {
4681
+ await ioHelper.notify(IO.DEFAULT_TOOLKIT_DEBUG.msg(String(e)));
4682
+ await ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg(
4683
+ "Could not create a change set, will base the diff on template differences (run again with -v to see the reason)\n"
4684
+ ));
4685
+ return void 0;
4686
+ }
4687
+ throw new ToolkitError("Could not create a change set and failOnError is set. (run again with failOnError off to base the diff on template differences)\n", e);
4658
4688
  }
4659
4689
  }
4660
4690
  async function uploadStackTemplateAssets(stack, deployments) {
@@ -8901,7 +8931,6 @@ var Context = class {
8901
8931
 
8902
8932
  // ../tmp-toolkit-helpers/src/api/diff/diff-formatter.ts
8903
8933
  var import_node_util2 = require("node:util");
8904
- var import_stream2 = require("stream");
8905
8934
  var cxschema3 = __toESM(require("@aws-cdk/cloud-assembly-schema"));
8906
8935
  var import_cloudformation_diff = require("@aws-cdk/cloudformation-diff");
8907
8936
  var chalk10 = __toESM(require("chalk"));
@@ -8914,8 +8943,9 @@ var RequireApproval = /* @__PURE__ */ ((RequireApproval2) => {
8914
8943
  return RequireApproval2;
8915
8944
  })(RequireApproval || {});
8916
8945
 
8917
- // ../tmp-toolkit-helpers/src/api/diff/diff-formatter.ts
8918
- var StringWriteStream = class extends import_stream2.Writable {
8946
+ // ../tmp-toolkit-helpers/src/api/streams.ts
8947
+ var import_node_stream = require("node:stream");
8948
+ var StringWriteStream = class extends import_node_stream.Writable {
8919
8949
  buffer = [];
8920
8950
  constructor() {
8921
8951
  super();
@@ -8928,6 +8958,8 @@ var StringWriteStream = class extends import_stream2.Writable {
8928
8958
  return this.buffer.join("");
8929
8959
  }
8930
8960
  };
8961
+
8962
+ // ../tmp-toolkit-helpers/src/api/diff/diff-formatter.ts
8931
8963
  var DiffFormatter = class {
8932
8964
  ioHelper;
8933
8965
  oldTemplate;
@@ -8936,15 +8968,23 @@ var DiffFormatter = class {
8936
8968
  changeSet;
8937
8969
  nestedStacks;
8938
8970
  isImport;
8971
+ /**
8972
+ * Stores the TemplateDiffs that get calculated in this DiffFormatter,
8973
+ * indexed by the stack name.
8974
+ */
8975
+ _diffs = {};
8939
8976
  constructor(props) {
8940
8977
  this.ioHelper = props.ioHelper;
8941
8978
  this.oldTemplate = props.templateInfo.oldTemplate;
8942
8979
  this.newTemplate = props.templateInfo.newTemplate;
8943
- this.stackName = props.templateInfo.stackName;
8980
+ this.stackName = props.templateInfo.newTemplate.stackName;
8944
8981
  this.changeSet = props.templateInfo.changeSet;
8945
8982
  this.nestedStacks = props.templateInfo.nestedStacks;
8946
8983
  this.isImport = props.templateInfo.isImport ?? false;
8947
8984
  }
8985
+ get diffs() {
8986
+ return this._diffs;
8987
+ }
8948
8988
  /**
8949
8989
  * Format the stack diff
8950
8990
  */
@@ -8962,6 +9002,7 @@ var DiffFormatter = class {
8962
9002
  }
8963
9003
  formatStackDiffHelper(oldTemplate, stackName, nestedStackTemplates, options) {
8964
9004
  let diff = (0, import_cloudformation_diff.fullDiff)(oldTemplate, this.newTemplate.template, this.changeSet, this.isImport);
9005
+ this._diffs[stackName] = diff;
8965
9006
  const stream = new StringWriteStream();
8966
9007
  let numStacksWithChanges = 0;
8967
9008
  let formattedDiff = "";
@@ -9028,6 +9069,7 @@ var DiffFormatter = class {
9028
9069
  formatSecurityDiff(options) {
9029
9070
  const ioDefaultHelper = new IoDefaultMessages(this.ioHelper);
9030
9071
  const diff = (0, import_cloudformation_diff.fullDiff)(this.oldTemplate, this.newTemplate.template, this.changeSet);
9072
+ this._diffs[this.stackName] = diff;
9031
9073
  if (diffRequiresApproval(diff, options.requireApproval)) {
9032
9074
  const stream = new StringWriteStream();
9033
9075
  stream.write((0, import_node_util2.format)(`Stack ${chalk10.bold(this.stackName)}
@@ -10098,8 +10140,294 @@ function findAllLogGroupNames(stackResources, evaluateCfnTemplate) {
10098
10140
  return logGroupNames;
10099
10141
  }
10100
10142
 
10143
+ // ../tmp-toolkit-helpers/src/api/refactoring/index.ts
10144
+ var import_cloudformation_diff2 = require("@aws-cdk/cloudformation-diff");
10145
+
10146
+ // ../tmp-toolkit-helpers/src/api/refactoring/digest.ts
10147
+ var crypto2 = __toESM(require("node:crypto"));
10148
+ var import_util40 = require("@aws-cdk/cloudformation-diff/lib/diff/util");
10149
+ function computeResourceDigests(template) {
10150
+ const resources = template.Resources || {};
10151
+ const graph = {};
10152
+ const reverseGraph = {};
10153
+ for (const id of Object.keys(resources)) {
10154
+ graph[id] = /* @__PURE__ */ new Set();
10155
+ reverseGraph[id] = /* @__PURE__ */ new Set();
10156
+ }
10157
+ const findDependencies = (value) => {
10158
+ if (!value || typeof value !== "object") return [];
10159
+ if (Array.isArray(value)) {
10160
+ return value.flatMap(findDependencies);
10161
+ }
10162
+ if ("Ref" in value) {
10163
+ return [value.Ref];
10164
+ }
10165
+ if ("Fn::GetAtt" in value) {
10166
+ const refTarget = Array.isArray(value["Fn::GetAtt"]) ? value["Fn::GetAtt"][0] : value["Fn::GetAtt"].split(".")[0];
10167
+ return [refTarget];
10168
+ }
10169
+ if ("DependsOn" in value) {
10170
+ return [value.DependsOn];
10171
+ }
10172
+ return Object.values(value).flatMap(findDependencies);
10173
+ };
10174
+ for (const [id, res] of Object.entries(resources)) {
10175
+ const deps = findDependencies(res || {});
10176
+ for (const dep of deps) {
10177
+ if (dep in resources && dep !== id) {
10178
+ graph[id].add(dep);
10179
+ reverseGraph[dep].add(id);
10180
+ }
10181
+ }
10182
+ }
10183
+ const outDegree = Object.keys(graph).reduce((acc, k) => {
10184
+ acc[k] = graph[k].size;
10185
+ return acc;
10186
+ }, {});
10187
+ const queue = Object.keys(outDegree).filter((k) => outDegree[k] === 0);
10188
+ const order = [];
10189
+ while (queue.length > 0) {
10190
+ const node = queue.shift();
10191
+ order.push(node);
10192
+ for (const nxt of reverseGraph[node]) {
10193
+ outDegree[nxt]--;
10194
+ if (outDegree[nxt] === 0) {
10195
+ queue.push(nxt);
10196
+ }
10197
+ }
10198
+ }
10199
+ const result2 = {};
10200
+ for (const id of order) {
10201
+ const resource = resources[id];
10202
+ const resourceProperties = resource.Properties ?? {};
10203
+ const model = (0, import_util40.loadResourceModel)(resource.Type);
10204
+ const identifier = intersection2(Object.keys(resourceProperties), model?.primaryIdentifier ?? []);
10205
+ let toHash;
10206
+ if (identifier.length === model?.primaryIdentifier?.length) {
10207
+ toHash = resource.Type + identifier.sort().map((attr) => JSON.stringify(resourceProperties[attr])).join("");
10208
+ } else {
10209
+ const depDigests = Array.from(graph[id]).map((d) => result2[d]);
10210
+ const propertiesHash = hashObject(stripReferences(stripConstructPath(resource)));
10211
+ toHash = resource.Type + propertiesHash + depDigests.join("");
10212
+ }
10213
+ result2[id] = crypto2.createHash("sha256").update(toHash).digest("hex");
10214
+ }
10215
+ return result2;
10216
+ }
10217
+ function hashObject(obj) {
10218
+ const hash = crypto2.createHash("sha256");
10219
+ function addToHash(value) {
10220
+ if (value == null) {
10221
+ addToHash("null");
10222
+ } else if (typeof value === "object") {
10223
+ if (Array.isArray(value)) {
10224
+ value.forEach(addToHash);
10225
+ } else {
10226
+ Object.keys(value).sort().forEach((key) => {
10227
+ hash.update(key);
10228
+ addToHash(value[key]);
10229
+ });
10230
+ }
10231
+ } else {
10232
+ hash.update(typeof value + value.toString());
10233
+ }
10234
+ }
10235
+ addToHash(obj);
10236
+ return hash.digest("hex");
10237
+ }
10238
+ function stripReferences(value) {
10239
+ if (!value || typeof value !== "object") return value;
10240
+ if (Array.isArray(value)) {
10241
+ return value.map(stripReferences);
10242
+ }
10243
+ if ("Ref" in value) {
10244
+ return { __cloud_ref__: "Ref" };
10245
+ }
10246
+ if ("Fn::GetAtt" in value) {
10247
+ return { __cloud_ref__: "Fn::GetAtt" };
10248
+ }
10249
+ if ("DependsOn" in value) {
10250
+ return { __cloud_ref__: "DependsOn" };
10251
+ }
10252
+ const result2 = {};
10253
+ for (const [k, v] of Object.entries(value)) {
10254
+ result2[k] = stripReferences(v);
10255
+ }
10256
+ return result2;
10257
+ }
10258
+ function stripConstructPath(resource) {
10259
+ if (resource?.Metadata?.["aws:cdk:path"] == null) {
10260
+ return resource;
10261
+ }
10262
+ const copy = JSON.parse(JSON.stringify(resource));
10263
+ delete copy.Metadata["aws:cdk:path"];
10264
+ return copy;
10265
+ }
10266
+ function intersection2(a, b) {
10267
+ return a.filter((value) => b.includes(value));
10268
+ }
10269
+
10270
+ // ../tmp-toolkit-helpers/src/api/refactoring/index.ts
10271
+ var AmbiguityError = class extends Error {
10272
+ constructor(movements) {
10273
+ super("Ambiguous resource mappings");
10274
+ this.movements = movements;
10275
+ }
10276
+ paths() {
10277
+ return this.movements.map(([a, b]) => [convert(a), convert(b)]);
10278
+ function convert(locations) {
10279
+ return locations.map((l) => l.toPath());
10280
+ }
10281
+ }
10282
+ };
10283
+ var ResourceLocation = class {
10284
+ constructor(stack, logicalResourceId) {
10285
+ this.stack = stack;
10286
+ this.logicalResourceId = logicalResourceId;
10287
+ }
10288
+ toPath() {
10289
+ const stack = this.stack;
10290
+ const resource = stack.template.Resources?.[this.logicalResourceId];
10291
+ const result2 = resource?.Metadata?.["aws:cdk:path"];
10292
+ if (result2 != null) {
10293
+ return result2;
10294
+ }
10295
+ return `${stack.stackName}.${this.logicalResourceId}`;
10296
+ }
10297
+ getType() {
10298
+ const resource = this.stack.template.Resources?.[this.logicalResourceId ?? ""];
10299
+ return resource?.Type ?? "Unknown";
10300
+ }
10301
+ equalTo(other) {
10302
+ return this.logicalResourceId === other.logicalResourceId && this.stack.stackName === other.stack.stackName;
10303
+ }
10304
+ };
10305
+ var ResourceMapping = class {
10306
+ constructor(source, destination) {
10307
+ this.source = source;
10308
+ this.destination = destination;
10309
+ }
10310
+ toTypedMapping() {
10311
+ return {
10312
+ // the type is the same in both source and destination,
10313
+ // so we can use either one
10314
+ type: this.source.getType(),
10315
+ sourcePath: this.source.toPath(),
10316
+ destinationPath: this.destination.toPath()
10317
+ };
10318
+ }
10319
+ };
10320
+ function groupByKey(entries) {
10321
+ const result2 = {};
10322
+ for (const [hash, location] of entries) {
10323
+ if (hash in result2) {
10324
+ result2[hash].push(location);
10325
+ } else {
10326
+ result2[hash] = [location];
10327
+ }
10328
+ }
10329
+ return result2;
10330
+ }
10331
+ function resourceMovements(before, after) {
10332
+ return Object.values(
10333
+ removeUnmovedResources(
10334
+ zip(groupByKey(before.flatMap(resourceDigests)), groupByKey(after.flatMap(resourceDigests)))
10335
+ )
10336
+ );
10337
+ }
10338
+ function ambiguousMovements(movements) {
10339
+ return movements.filter(([pre, post]) => pre.length > 0 && post.length > 0).filter(([pre, post]) => pre.length > 1 || post.length > 1);
10340
+ }
10341
+ function resourceMappings(movements) {
10342
+ return movements.filter(([pre, post]) => pre.length === 1 && post.length === 1 && !pre[0].equalTo(post[0])).map(([pre, post]) => new ResourceMapping(pre[0], post[0]));
10343
+ }
10344
+ function removeUnmovedResources(m) {
10345
+ const result2 = {};
10346
+ for (const [hash, [before, after]] of Object.entries(m)) {
10347
+ const common = before.filter((b) => after.some((a) => a.equalTo(b)));
10348
+ result2[hash] = [
10349
+ before.filter((b) => !common.some((c) => b.equalTo(c))),
10350
+ after.filter((a) => !common.some((c) => a.equalTo(c)))
10351
+ ];
10352
+ }
10353
+ return result2;
10354
+ }
10355
+ function zip(m1, m2) {
10356
+ const result2 = {};
10357
+ for (const [hash, locations] of Object.entries(m1)) {
10358
+ if (hash in m2) {
10359
+ result2[hash] = [locations, m2[hash]];
10360
+ } else {
10361
+ result2[hash] = [locations, []];
10362
+ }
10363
+ }
10364
+ for (const [hash, locations] of Object.entries(m2)) {
10365
+ if (!(hash in m1)) {
10366
+ result2[hash] = [[], locations];
10367
+ }
10368
+ }
10369
+ return result2;
10370
+ }
10371
+ function resourceDigests(stack) {
10372
+ const digests = computeResourceDigests(stack.template);
10373
+ return Object.entries(digests).map(([logicalId, digest]) => {
10374
+ const location = new ResourceLocation(stack, logicalId);
10375
+ return [digest, location];
10376
+ });
10377
+ }
10378
+ async function findResourceMovements(stacks, sdkProvider) {
10379
+ const stackGroups = /* @__PURE__ */ new Map();
10380
+ for (const stack of stacks) {
10381
+ const environment = stack.environment;
10382
+ const key = hashObject(environment);
10383
+ if (stackGroups.has(key)) {
10384
+ stackGroups.get(key)[1].push(stack);
10385
+ } else {
10386
+ const before = await getDeployedStacks(sdkProvider, environment);
10387
+ stackGroups.set(key, [before, [stack]]);
10388
+ }
10389
+ }
10390
+ const result2 = [];
10391
+ for (const [_, [before, after]] of stackGroups) {
10392
+ result2.push(...resourceMovements(before, after));
10393
+ }
10394
+ return result2;
10395
+ }
10396
+ async function getDeployedStacks(sdkProvider, environment) {
10397
+ const cfn = (await sdkProvider.forEnvironment(environment, 0 /* ForReading */)).sdk.cloudFormation();
10398
+ const summaries = await cfn.paginatedListStacks({
10399
+ StackStatusFilter: [
10400
+ "CREATE_COMPLETE",
10401
+ "UPDATE_COMPLETE",
10402
+ "UPDATE_ROLLBACK_COMPLETE",
10403
+ "IMPORT_COMPLETE",
10404
+ "ROLLBACK_COMPLETE"
10405
+ ]
10406
+ });
10407
+ const normalize = async (summary) => {
10408
+ const templateCommandOutput = await cfn.getTemplate({ StackName: summary.StackName });
10409
+ const template = deserializeStructure(templateCommandOutput.TemplateBody ?? "{}");
10410
+ return {
10411
+ environment,
10412
+ stackName: summary.StackName,
10413
+ template
10414
+ };
10415
+ };
10416
+ return Promise.all(summaries.map(normalize));
10417
+ }
10418
+ function formatTypedMappings(mappings) {
10419
+ const stream = new StringWriteStream();
10420
+ (0, import_cloudformation_diff2.formatTypedMappings)(stream, mappings);
10421
+ return stream.toString();
10422
+ }
10423
+ function formatAmbiguousMappings(paths) {
10424
+ const stream = new StringWriteStream();
10425
+ (0, import_cloudformation_diff2.formatAmbiguousMappings)(stream, paths);
10426
+ return stream.toString();
10427
+ }
10428
+
10101
10429
  // ../tmp-toolkit-helpers/src/api/resource-import/importer.ts
10102
- var import_util40 = require("util");
10430
+ var import_util42 = require("util");
10103
10431
  var cfnDiff = __toESM(require("@aws-cdk/cloudformation-diff"));
10104
10432
  var chalk14 = __toESM(require("chalk"));
10105
10433
  var fs13 = __toESM(require("fs-extra"));
@@ -10140,12 +10468,12 @@ var ResourceImporter = class {
10140
10468
  const descr = this.describeResource(resource.logicalId);
10141
10469
  const idProps = contents[resource.logicalId];
10142
10470
  if (idProps) {
10143
- await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg((0, import_util40.format)("%s: importing using %s", chalk14.blue(descr), chalk14.blue(fmtdict(idProps)))));
10471
+ await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg((0, import_util42.format)("%s: importing using %s", chalk14.blue(descr), chalk14.blue(fmtdict(idProps)))));
10144
10472
  ret.importResources.push(resource);
10145
10473
  ret.resourceMap[resource.logicalId] = idProps;
10146
10474
  delete contents[resource.logicalId];
10147
10475
  } else {
10148
- await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg((0, import_util40.format)("%s: skipping", chalk14.blue(descr))));
10476
+ await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg((0, import_util42.format)("%s: skipping", chalk14.blue(descr))));
10149
10477
  }
10150
10478
  }
10151
10479
  const unknown = Object.keys(contents);
@@ -10189,9 +10517,9 @@ var ResourceImporter = class {
10189
10517
  });
10190
10518
  assertIsSuccessfulDeployStackResult(result2);
10191
10519
  const message2 = result2.noOp ? " \u2705 %s (no changes)" : " \u2705 %s";
10192
- await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg("\n" + chalk14.green((0, import_util40.format)(message2, this.stack.displayName))));
10520
+ await this.ioHelper.notify(IO.DEFAULT_TOOLKIT_INFO.msg("\n" + chalk14.green((0, import_util42.format)(message2, this.stack.displayName))));
10193
10521
  } catch (e) {
10194
- await this.ioHelper.notify(IO.CDK_TOOLKIT_E3900.msg((0, import_util40.format)("\n \u274C %s failed: %s", chalk14.bold(this.stack.displayName), e), { error: e }));
10522
+ await this.ioHelper.notify(IO.CDK_TOOLKIT_E3900.msg((0, import_util42.format)("\n \u274C %s failed: %s", chalk14.bold(this.stack.displayName), e), { error: e }));
10195
10523
  throw e;
10196
10524
  }
10197
10525
  }
@@ -10470,14 +10798,18 @@ var RWLock = class {
10470
10798
  */
10471
10799
  async acquireWrite() {
10472
10800
  await this.assertNoOtherWriters();
10473
- const readers = await this.currentReaders();
10801
+ const readers = await this._currentReaders();
10474
10802
  if (readers.length > 0) {
10475
10803
  throw new ToolkitError(`Other CLIs (PID=${readers}) are currently reading from ${this.directory}. Invoke the CLI in sequence, or use '--output' to synth into different directories.`);
10476
10804
  }
10477
10805
  await writeFileAtomic(this.writerFile, this.pidString);
10806
+ let released = false;
10478
10807
  return {
10479
10808
  release: async () => {
10480
- await deleteFile(this.writerFile);
10809
+ if (!released) {
10810
+ await deleteFile(this.writerFile);
10811
+ released = true;
10812
+ }
10481
10813
  },
10482
10814
  convertToReaderLock: async () => {
10483
10815
  const ret = await this.doAcquireRead();
@@ -10511,22 +10843,30 @@ var RWLock = class {
10511
10843
  async doAcquireRead() {
10512
10844
  const readerFile = this.readerFile();
10513
10845
  await writeFileAtomic(readerFile, this.pidString);
10846
+ let released = false;
10514
10847
  return {
10515
10848
  release: async () => {
10516
- await deleteFile(readerFile);
10849
+ if (!released) {
10850
+ await deleteFile(readerFile);
10851
+ released = true;
10852
+ }
10517
10853
  }
10518
10854
  };
10519
10855
  }
10520
10856
  async assertNoOtherWriters() {
10521
- const writer = await this.currentWriter();
10857
+ const writer = await this._currentWriter();
10522
10858
  if (writer) {
10523
10859
  throw new ToolkitError(`Another CLI (PID=${writer}) is currently synthing to ${this.directory}. Invoke the CLI in sequence, or use '--output' to synth into different directories.`);
10524
10860
  }
10525
10861
  }
10526
10862
  /**
10527
10863
  * Check the current writer (if any)
10864
+ *
10865
+ * Publicly accessible for testing purposes. Do not use.
10866
+ *
10867
+ * @internal
10528
10868
  */
10529
- async currentWriter() {
10869
+ async _currentWriter() {
10530
10870
  const contents = await readFileIfExists(this.writerFile);
10531
10871
  if (!contents) {
10532
10872
  return void 0;
@@ -10540,8 +10880,12 @@ var RWLock = class {
10540
10880
  }
10541
10881
  /**
10542
10882
  * Check the current readers (if any)
10883
+ *
10884
+ * Publicly accessible for testing purposes. Do not use.
10885
+ *
10886
+ * @internal
10543
10887
  */
10544
- async currentReaders() {
10888
+ async _currentReaders() {
10545
10889
  const re = /^read\.([^.]+)\.[^.]+\.lock$/;
10546
10890
  const ret = new Array();
10547
10891
  let children;
@@ -12031,6 +12375,7 @@ var availableContextProviders = {
12031
12375
  AccountAccessKeyCache,
12032
12376
  ActiveAssetCache,
12033
12377
  ActivityPrinterBase,
12378
+ AmbiguityError,
12034
12379
  AssemblyError,
12035
12380
  AssetManifestBuilder,
12036
12381
  AuthenticationError,
@@ -12090,6 +12435,8 @@ var availableContextProviders = {
12090
12435
  RWLock,
12091
12436
  RequireApproval,
12092
12437
  ResourceImporter,
12438
+ ResourceLocation,
12439
+ ResourceMapping,
12093
12440
  ResourceMigrator,
12094
12441
  RollbackChoice,
12095
12442
  S3_ISOLATED_TAG,
@@ -12113,6 +12460,7 @@ var availableContextProviders = {
12113
12460
  WorkGraph,
12114
12461
  WorkGraphBuilder,
12115
12462
  addMetadataAssetsToManifest,
12463
+ ambiguousMovements,
12116
12464
  asIoHelper,
12117
12465
  assertIsSuccessfulDeployStackResult,
12118
12466
  cached,
@@ -12126,7 +12474,10 @@ var availableContextProviders = {
12126
12474
  determineAllowCrossAccountAssetPublishing,
12127
12475
  error,
12128
12476
  findCloudWatchLogGroups,
12477
+ findResourceMovements,
12478
+ formatAmbiguousMappings,
12129
12479
  formatSdkLoggerContent,
12480
+ formatTypedMappings,
12130
12481
  getBootstrapStackInfo,
12131
12482
  guessExecutable,
12132
12483
  info,
@@ -12147,6 +12498,8 @@ var availableContextProviders = {
12147
12498
  refreshStacks,
12148
12499
  removeNonImportResources,
12149
12500
  replaceEnvPlaceholders,
12501
+ resourceMappings,
12502
+ resourceMovements,
12150
12503
  result,
12151
12504
  setSdkTracing,
12152
12505
  some,