@aws/nx-plugin 1.0.2 → 1.0.4

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 (59) hide show
  1. package/LICENSE-THIRD-PARTY +30 -14
  2. package/migrations.json +22 -17
  3. package/package.json +7 -7
  4. package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +3 -3
  5. package/src/infra/app/__snapshots__/generator.spec.ts.snap +3 -3
  6. package/src/license/dependency-check/collectors/npm-collector.d.ts +14 -0
  7. package/src/license/dependency-check/collectors/npm-collector.js +35 -1
  8. package/src/license/dependency-check/collectors/npm-collector.js.map +1 -1
  9. package/src/migrations/v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks/migration.js.map +1 -0
  10. package/src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration.js.map +1 -0
  11. package/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.js.map +1 -0
  12. package/src/migrations/v1.0.3/0001-terraform-init-target/metadata.json +3 -0
  13. package/src/migrations/v1.0.3/0001-terraform-init-target/migration.d.ts +6 -0
  14. package/src/migrations/v1.0.3/0001-terraform-init-target/migration.js +153 -0
  15. package/src/migrations/v1.0.3/0001-terraform-init-target/migration.js.map +1 -0
  16. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  17. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +7 -7
  18. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +9 -9
  19. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +8 -8
  20. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +3 -3
  21. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +27 -27
  22. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +6 -6
  23. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +8 -8
  24. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +10 -10
  25. package/src/sdk/open-api.d.ts +2 -2
  26. package/src/sdk/open-api.js +1 -1
  27. package/src/sdk/open-api.js.map +1 -1
  28. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +16 -16
  29. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +19 -19
  30. package/src/terraform/project/generator.js +52 -44
  31. package/src/terraform/project/generator.js.map +1 -1
  32. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +27 -27
  33. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +8 -8
  34. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +3 -3
  35. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +3 -3
  36. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +6 -6
  37. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +4 -4
  38. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +18 -18
  39. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +28 -28
  40. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +3 -3
  41. package/src/utils/docker.d.ts +1 -1
  42. package/src/utils/test-migration.d.ts +20 -0
  43. package/src/utils/test-migration.js +32 -0
  44. package/src/utils/test-migration.js.map +1 -0
  45. package/src/utils/versions.d.ts +99 -99
  46. package/src/utils/versions.js +92 -92
  47. package/src/utils/versions.js.map +1 -1
  48. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js.map +0 -1
  49. package/src/migrations/latest/shadcn-cn-package/migration.js.map +0 -1
  50. package/src/migrations/latest/terraform-harness-environment-variables/migration.js.map +0 -1
  51. /package/src/migrations/{latest/sandbox-pattern-nested-stacks → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/metadata.json +0 -0
  52. /package/src/migrations/{latest/sandbox-pattern-nested-stacks → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/migration.d.ts +0 -0
  53. /package/src/migrations/{latest/sandbox-pattern-nested-stacks → v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks}/migration.js +0 -0
  54. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0002-shadcn-cn-package}/metadata.json +0 -0
  55. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0002-shadcn-cn-package}/migration.d.ts +0 -0
  56. /package/src/migrations/{latest/shadcn-cn-package → v1.0.0-rc.98/0002-shadcn-cn-package}/migration.js +0 -0
  57. /package/src/migrations/{latest/terraform-harness-environment-variables → v1.0.2/0001-terraform-harness-environment-variables}/metadata.json +0 -0
  58. /package/src/migrations/{latest/terraform-harness-environment-variables → v1.0.2/0001-terraform-harness-environment-variables}/migration.d.ts +0 -0
  59. /package/src/migrations/{latest/terraform-harness-environment-variables → v1.0.2/0001-terraform-harness-environment-variables}/migration.js +0 -0
@@ -108,7 +108,7 @@ THE SOFTWARE.
108
108
 
109
109
  ---
110
110
 
111
- The following software may be included in this product: @astral-sh/ruff-wasm-nodejs (0.16.6)
111
+ The following software may be included in this product: @astral-sh/ruff-wasm-nodejs (0.16.9)
112
112
  This software contains the following license and notice below:
113
113
 
114
114
  MIT License
@@ -3898,7 +3898,7 @@ SOFTWARE.
3898
3898
 
3899
3899
  ---
3900
3900
 
3901
- The following software may be included in this product: @modelcontextprotocol/sdk (1.30.0)
3901
+ The following software may be included in this product: @modelcontextprotocol/sdk (1.30.1)
3902
3902
  This software contains the following license and notice below:
3903
3903
 
3904
3904
  MIT License
@@ -4247,7 +4247,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
4247
4247
 
4248
4248
  ---
4249
4249
 
4250
- The following software may be included in this product: @nxlv/python (23.0.0)
4250
+ The following software may be included in this product: @nxlv/python (23.1.1)
4251
4251
  This software contains the following license and notice below:
4252
4252
 
4253
4253
  MIT License
@@ -4274,7 +4274,7 @@ SOFTWARE.
4274
4274
 
4275
4275
  ---
4276
4276
 
4277
- The following software may be included in this product: @oxc-project/types (0.148.0)
4277
+ The following software may be included in this product: @oxc-project/types (0.150.0)
4278
4278
  This software contains the following license and notice below:
4279
4279
 
4280
4280
  MIT License
@@ -6352,6 +6352,22 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
6352
6352
 
6353
6353
  ---
6354
6354
 
6355
+ The following software may be included in this product: chalk-template (1.1.2)
6356
+ This software contains the following license and notice below:
6357
+
6358
+ MIT License
6359
+
6360
+ Copyright (c) Josh Junon
6361
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
6362
+
6363
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6364
+
6365
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6366
+
6367
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6368
+
6369
+ ---
6370
+
6355
6371
  The following software may be included in this product: character-entities (2.0.2)
6356
6372
  This software contains the following license and notice below:
6357
6373
 
@@ -8741,7 +8757,7 @@ THE SOFTWARE.
8741
8757
 
8742
8758
  ---
8743
8759
 
8744
- The following software may be included in this product: fs-extra (11.4.0)
8760
+ The following software may be included in this product: fs-extra (11.4.1)
8745
8761
  This software contains the following license and notice below:
8746
8762
 
8747
8763
  (The MIT License)
@@ -9018,7 +9034,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9018
9034
 
9019
9035
  ---
9020
9036
 
9021
- The following software may be included in this product: hono (4.13.3)
9037
+ The following software may be included in this product: hono (4.13.8)
9022
9038
  This software contains the following license and notice below:
9023
9039
 
9024
9040
  MIT License
@@ -12387,7 +12403,7 @@ SOFTWARE.
12387
12403
 
12388
12404
  ---
12389
12405
 
12390
- The following software may be included in this product: nanoid (3.3.17)
12406
+ The following software may be included in this product: nanoid (3.3.19)
12391
12407
  This software contains the following license and notice below:
12392
12408
 
12393
12409
  The MIT License (MIT)
@@ -13258,7 +13274,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13258
13274
 
13259
13275
  ---
13260
13276
 
13261
- The following software may be included in this product: postcss (8.5.26)
13277
+ The following software may be included in this product: postcss (8.5.28)
13262
13278
  This software contains the following license and notice below:
13263
13279
 
13264
13280
  The MIT License (MIT)
@@ -13528,7 +13544,7 @@ THE SOFTWARE.
13528
13544
 
13529
13545
  ---
13530
13546
 
13531
- The following software may be included in this product: react (19.2.8)
13547
+ The following software may be included in this product: react (19.3.0)
13532
13548
  This software contains the following license and notice below:
13533
13549
 
13534
13550
  MIT License
@@ -13555,7 +13571,7 @@ SOFTWARE.
13555
13571
 
13556
13572
  ---
13557
13573
 
13558
- The following software may be included in this product: react-dom (19.2.8)
13574
+ The following software may be included in this product: react-dom (19.3.0)
13559
13575
  This software contains the following license and notice below:
13560
13576
 
13561
13577
  MIT License
@@ -14149,7 +14165,7 @@ SOFTWARE.
14149
14165
 
14150
14166
  ---
14151
14167
 
14152
- The following software may be included in this product: rolldown (1.2.7)
14168
+ The following software may be included in this product: rolldown (1.2.9)
14153
14169
  This software contains the following license and notice below:
14154
14170
 
14155
14171
  MIT License
@@ -14346,7 +14362,7 @@ SOFTWARE.
14346
14362
 
14347
14363
  ---
14348
14364
 
14349
- The following software may be included in this product: scheduler (0.27.0)
14365
+ The following software may be included in this product: scheduler (0.28.0)
14350
14366
  This software contains the following license and notice below:
14351
14367
 
14352
14368
  MIT License
@@ -16072,7 +16088,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16072
16088
 
16073
16089
  ---
16074
16090
 
16075
- The following software may be included in this product: vite (8.2.2)
16091
+ The following software may be included in this product: vite (8.3.1)
16076
16092
  This software contains the following license and notice below:
16077
16093
 
16078
16094
  # Vite core license
@@ -19446,7 +19462,7 @@ OTHER DEALINGS IN THE SOFTWARE.
19446
19462
 
19447
19463
  ---
19448
19464
 
19449
- The following software may be included in this product: zod (4.5.4)
19465
+ The following software may be included in this product: zod (4.6.5)
19450
19466
  This software contains the following license and notice below:
19451
19467
 
19452
19468
  MIT License
package/migrations.json CHANGED
@@ -2,21 +2,6 @@
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "name": "@aws/nx-plugin",
4
4
  "generators": {
5
- "latest-sandbox-pattern-nested-stacks": {
6
- "version": "1.0.0-rc.98",
7
- "description": "Update the deploy-sandbox and destroy-sandbox stage patterns to match stacks nested below the stage's stacks, so cdk destroy removes the website WebACL stack",
8
- "implementation": "./src/migrations/latest/sandbox-pattern-nested-stacks/migration"
9
- },
10
- "latest-shadcn-cn-package": {
11
- "version": "1.0.0-rc.98",
12
- "description": "Move the shared shadcn package's components onto the cn package the shadcn registry now depends on",
13
- "implementation": "./src/migrations/latest/shadcn-cn-package/migration"
14
- },
15
- "latest-terraform-harness-environment-variables": {
16
- "version": "1.0.2",
17
- "description": "Send an empty map rather than null for a vended Terraform AgentCore Harness module's environment_variables, so the first apply does not fail after creating the Harness",
18
- "implementation": "./src/migrations/latest/terraform-harness-environment-variables/migration"
19
- },
20
5
  "v1.0.0-rc.50-0001-modernize-function-props-cast": {
21
6
  "version": "1.0.0-rc.50",
22
7
  "description": "Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs",
@@ -372,8 +357,28 @@
372
357
  "description": "Add build, lint, format and typecheck targets plus a tsconfig.json to AgentCore Gateway and Harness projects",
373
358
  "implementation": "./src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration"
374
359
  },
375
- "sync-vended-versions": {
360
+ "v1.0.0-rc.98-0001-sandbox-pattern-nested-stacks": {
361
+ "version": "1.0.0-rc.98",
362
+ "description": "Update the deploy-sandbox and destroy-sandbox stage patterns to match stacks nested below the stage's stacks, so cdk destroy removes the website WebACL stack",
363
+ "implementation": "./src/migrations/v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks/migration"
364
+ },
365
+ "v1.0.0-rc.98-0002-shadcn-cn-package": {
366
+ "version": "1.0.0-rc.98",
367
+ "description": "Move the shared shadcn package's components onto the cn package the shadcn registry now depends on",
368
+ "implementation": "./src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration"
369
+ },
370
+ "v1.0.2-0001-terraform-harness-environment-variables": {
376
371
  "version": "1.0.2",
372
+ "description": "Send an empty map rather than null for a vended Terraform AgentCore Harness module's environment_variables, so the first apply does not fail after creating the Harness",
373
+ "implementation": "./src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration"
374
+ },
375
+ "v1.0.3-0001-terraform-init-target": {
376
+ "version": "1.0.3",
377
+ "description": "Add the terraform-init target to Terraform projects so the shared provider plugin cache has a single writer",
378
+ "implementation": "./src/migrations/v1.0.3/0001-terraform-init-target/migration"
379
+ },
380
+ "sync-vended-versions": {
381
+ "version": "1.0.4",
377
382
  "description": "Sync vended dependency versions and the tracked plugin version to those vended by this release",
378
383
  "implementation": "./src/utils/version-upgrade-migration/migration"
379
384
  }
@@ -479,7 +484,7 @@
479
484
  }
480
485
  },
481
486
  "nx-23.2.1-nx-packages": {
482
- "version": "1.0.2",
487
+ "version": "1.0.1",
483
488
  "packages": {
484
489
  "nx": {
485
490
  "version": "23.2.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws/nx-plugin",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/awslabs/nx-plugin-for-aws.git",
@@ -40,17 +40,17 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@apidevtools/swagger-parser": "12.1.0",
43
- "@astral-sh/ruff-wasm-nodejs": "0.16.6",
43
+ "@astral-sh/ruff-wasm-nodejs": "0.16.9",
44
44
  "@biomejs/js-api": "6.0.0",
45
- "@biomejs/wasm-nodejs": "2.5.12",
45
+ "@biomejs/wasm-nodejs": "2.5.14",
46
46
  "@getgrit/gritql": "0.0.3",
47
47
  "@iarna/toml": "2.2.5",
48
- "@modelcontextprotocol/sdk": "1.30.0",
48
+ "@modelcontextprotocol/sdk": "1.30.1",
49
49
  "@nx/devkit": "23.2.1",
50
50
  "@nx/js": "23.2.1",
51
51
  "@nx/react": "23.2.1",
52
52
  "@nx/vite": "23.2.1",
53
- "@nxlv/python": "23.0.0",
53
+ "@nxlv/python": "23.1.1",
54
54
  "@phenomnomnominal/tsquery": "6.2.0",
55
55
  "@types/estree": "1.0.9",
56
56
  "@types/js-yaml": "4.0.9",
@@ -79,9 +79,9 @@
79
79
  "typescript": "6.0.3",
80
80
  "unified": "11.0.5",
81
81
  "unist-util-visit": "5.1.0",
82
- "vite": "8.2.2",
82
+ "vite": "8.3.1",
83
83
  "vitest": "4.1.11",
84
- "zod": "4.5.4"
84
+ "zod": "4.6.5"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@types/semver": "7.8.0"
@@ -7,15 +7,15 @@ exports[`agentcore-gateway generator > protocol: http > omits protocol_type from
7
7
  required_providers {
8
8
  aws = {
9
9
  source = "hashicorp/aws"
10
- version = "6.63.0"
10
+ version = "6.66.0"
11
11
  }
12
12
  time = {
13
13
  source = "hashicorp/time"
14
- version = "0.14.1"
14
+ version = "0.14.2"
15
15
  }
16
16
  random = {
17
17
  source = "hashicorp/random"
18
- version = "3.9.0"
18
+ version = "3.9.1"
19
19
  }
20
20
  }
21
21
  }
@@ -50,7 +50,7 @@ exports[`infra generator > should configure Checkov target correctly > checkov-t
50
50
  "default",
51
51
  ],
52
52
  "options": {
53
- "command": "uvx --from checkov==3.3.16 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
53
+ "command": "uvx --from checkov==3.3.20 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
54
54
  },
55
55
  "outputs": [
56
56
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -150,7 +150,7 @@ exports[`infra generator > should configure project.json with correct targets >
150
150
  "default",
151
151
  ],
152
152
  "options": {
153
- "command": "uvx --from checkov==3.3.16 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
153
+ "command": "uvx --from checkov==3.3.20 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
154
154
  },
155
155
  "outputs": [
156
156
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -762,7 +762,7 @@ exports[`infra generator > should handle custom project names correctly > custom
762
762
  "default",
763
763
  ],
764
764
  "options": {
765
- "command": "uvx --from checkov==3.3.16 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
765
+ "command": "uvx --from checkov==3.3.20 checkov --config-file {projectRoot}/checkov.yml --directory dist/{projectRoot}/cdk.out --framework cloudformation",
766
766
  },
767
767
  "outputs": [
768
768
  "{workspaceRoot}/dist/{projectRoot}/checkov",
@@ -7,4 +7,18 @@ export interface NpmDependency {
7
7
  export interface NpmCollectorOptions {
8
8
  start: string;
9
9
  }
10
+ /**
11
+ * Resolve a license that only names a file into the license that file grants.
12
+ *
13
+ * license-checker reads a package's license file only when the package declares
14
+ * no license, so a package declaring `SEE LICENSE IN LICENSE` is reported as
15
+ * `Custom: LICENSE` and evaluates to UNKNOWN even when the file grants a
16
+ * pre-approved license. Read the file license-checker already located and run
17
+ * its text detection over it, which returns an SPDX id with the trailing `*`
18
+ * marking a license guessed from text.
19
+ *
20
+ * The reference is kept when the file can't be read, or when detection can't
21
+ * name a license, so the dependency is still reported as UNKNOWN.
22
+ */
23
+ export declare const resolveFileReferencedLicense: (rawLicense: string, licenseFile: string | undefined) => string;
10
24
  export declare const collectNpmDependencies: (options: NpmCollectorOptions) => Promise<NpmDependency[]>;
@@ -3,6 +3,10 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ import { existsSync, readFileSync } from "fs";
5
5
  import * as licenseChecker from "license-checker-rseidelsohn";
6
+ // license-checker's own license-from-text detection, which it applies to
7
+ // packages that declare no license. Reused here so a `SEE LICENSE IN <file>`
8
+ // package resolves the same way, rather than through a second implementation.
9
+ import { getLicenseTitle } from "license-checker-rseidelsohn/lib/getLicenseTitle.js";
6
10
  import { join } from "path";
7
11
  const NAME_VERSION_RE = /^(@?[^@]+)@(.+)$/;
8
12
  const splitNameVersion = (identifier)=>{
@@ -27,6 +31,36 @@ const flattenLicense = (raw)=>{
27
31
  }
28
32
  return raw;
29
33
  };
34
+ /**
35
+ * A license that names a file instead of a license: the SPDX form
36
+ * `SEE LICENSE IN <file>`, or the `Custom: <file>` license-checker reports it
37
+ * as.
38
+ */ const FILE_REFERENCE_RE = /^(?:custom:|see\s+license\s+in)\s+(.+)$/i;
39
+ /**
40
+ * Resolve a license that only names a file into the license that file grants.
41
+ *
42
+ * license-checker reads a package's license file only when the package declares
43
+ * no license, so a package declaring `SEE LICENSE IN LICENSE` is reported as
44
+ * `Custom: LICENSE` and evaluates to UNKNOWN even when the file grants a
45
+ * pre-approved license. Read the file license-checker already located and run
46
+ * its text detection over it, which returns an SPDX id with the trailing `*`
47
+ * marking a license guessed from text.
48
+ *
49
+ * The reference is kept when the file can't be read, or when detection can't
50
+ * name a license, so the dependency is still reported as UNKNOWN.
51
+ */ export const resolveFileReferencedLicense = (rawLicense, licenseFile)=>{
52
+ if (!licenseFile || !FILE_REFERENCE_RE.test(rawLicense.trim())) {
53
+ return rawLicense;
54
+ }
55
+ let detected = null;
56
+ try {
57
+ detected = getLicenseTitle(readFileSync(licenseFile, 'utf-8'));
58
+ } catch {
59
+ return rawLicense;
60
+ }
61
+ if (!detected || detected === 'Undefined' || FILE_REFERENCE_RE.test(detected)) return rawLicense;
62
+ return detected;
63
+ };
30
64
  export const collectNpmDependencies = async (options)=>{
31
65
  const nodeModules = join(options.start, 'node_modules');
32
66
  if (!existsSync(nodeModules)) {
@@ -58,7 +92,7 @@ export const collectNpmDependencies = async (options)=>{
58
92
  out.push({
59
93
  name,
60
94
  version,
61
- rawLicense: flattenLicense(info.licenses),
95
+ rawLicense: resolveFileReferencedLicense(flattenLicense(info.licenses), info.licenseFile),
62
96
  path: info.path
63
97
  });
64
98
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/license/dependency-check/collectors/npm-collector.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { existsSync, readFileSync } from 'fs';\nimport * as licenseChecker from 'license-checker-rseidelsohn';\nimport { join } from 'path';\n\nexport interface NpmDependency {\n name: string;\n version: string;\n rawLicense: string;\n path?: string;\n}\n\nexport interface NpmCollectorOptions {\n start: string;\n}\n\nconst NAME_VERSION_RE = /^(@?[^@]+)@(.+)$/;\n\nconst splitNameVersion = (\n identifier: string,\n): { name: string; version: string } => {\n const match = identifier.match(NAME_VERSION_RE);\n if (!match) {\n return { name: identifier, version: '0.0.0' };\n }\n return { name: match[1], version: match[2] };\n};\n\nconst flattenLicense = (raw: string | string[] | undefined | null): string => {\n if (!raw) return '';\n if (Array.isArray(raw)) {\n if (raw.length === 0) return '';\n if (raw.length === 1) return raw[0];\n return `(${raw.join(' OR ')})`;\n }\n return raw;\n};\n\nexport const collectNpmDependencies = async (\n options: NpmCollectorOptions,\n): Promise<NpmDependency[]> => {\n const nodeModules = join(options.start, 'node_modules');\n if (!existsSync(nodeModules)) {\n return [];\n }\n\n const exclude = new Set<string>();\n\n const projectPackageJson = join(options.start, 'package.json');\n if (existsSync(projectPackageJson)) {\n try {\n const pkg = JSON.parse(readFileSync(projectPackageJson, 'utf-8')) as {\n name?: string;\n };\n if (pkg.name) exclude.add(pkg.name);\n } catch {\n // ignore\n }\n }\n\n const packages = await new Promise<licenseChecker.ModuleInfos>(\n (resolve, reject) => {\n licenseChecker.init(\n {\n start: options.start,\n excludePrivatePackages: true,\n },\n (err, results) => {\n if (err) reject(err);\n else resolve(results);\n },\n );\n },\n );\n\n const out: NpmDependency[] = [];\n for (const [identifier, info] of Object.entries(packages)) {\n const { name, version } = splitNameVersion(identifier);\n if (exclude.has(name)) continue;\n out.push({\n name,\n version,\n rawLicense: flattenLicense(info.licenses),\n path: info.path,\n });\n }\n return out;\n};\n"],"names":["existsSync","readFileSync","licenseChecker","join","NAME_VERSION_RE","splitNameVersion","identifier","match","name","version","flattenLicense","raw","Array","isArray","length","collectNpmDependencies","options","nodeModules","start","exclude","Set","projectPackageJson","pkg","JSON","parse","add","packages","Promise","resolve","reject","init","excludePrivatePackages","err","results","out","info","Object","entries","has","push","rawLicense","licenses","path"],"mappings":"AAAA;;;CAGC,GACD,SAASA,UAAU,EAAEC,YAAY,QAAQ,KAAK;AAC9C,YAAYC,oBAAoB,8BAA8B;AAC9D,SAASC,IAAI,QAAQ,OAAO;AAa5B,MAAMC,kBAAkB;AAExB,MAAMC,mBAAmB,CACvBC;IAEA,MAAMC,QAAQD,WAAWC,KAAK,CAACH;IAC/B,IAAI,CAACG,OAAO;QACV,OAAO;YAAEC,MAAMF;YAAYG,SAAS;QAAQ;IAC9C;IACA,OAAO;QAAED,MAAMD,KAAK,CAAC,EAAE;QAAEE,SAASF,KAAK,CAAC,EAAE;IAAC;AAC7C;AAEA,MAAMG,iBAAiB,CAACC;IACtB,IAAI,CAACA,KAAK,OAAO;IACjB,IAAIC,MAAMC,OAAO,CAACF,MAAM;QACtB,IAAIA,IAAIG,MAAM,KAAK,GAAG,OAAO;QAC7B,IAAIH,IAAIG,MAAM,KAAK,GAAG,OAAOH,GAAG,CAAC,EAAE;QACnC,OAAO,CAAC,CAAC,EAAEA,IAAIR,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC;IACA,OAAOQ;AACT;AAEA,OAAO,MAAMI,yBAAyB,OACpCC;IAEA,MAAMC,cAAcd,KAAKa,QAAQE,KAAK,EAAE;IACxC,IAAI,CAAClB,WAAWiB,cAAc;QAC5B,OAAO,EAAE;IACX;IAEA,MAAME,UAAU,IAAIC;IAEpB,MAAMC,qBAAqBlB,KAAKa,QAAQE,KAAK,EAAE;IAC/C,IAAIlB,WAAWqB,qBAAqB;QAClC,IAAI;YACF,MAAMC,MAAMC,KAAKC,KAAK,CAACvB,aAAaoB,oBAAoB;YAGxD,IAAIC,IAAId,IAAI,EAAEW,QAAQM,GAAG,CAACH,IAAId,IAAI;QACpC,EAAE,OAAM;QACN,SAAS;QACX;IACF;IAEA,MAAMkB,WAAW,MAAM,IAAIC,QACzB,CAACC,SAASC;QACR3B,eAAe4B,IAAI,CACjB;YACEZ,OAAOF,QAAQE,KAAK;YACpBa,wBAAwB;QAC1B,GACA,CAACC,KAAKC;YACJ,IAAID,KAAKH,OAAOG;iBACXJ,QAAQK;QACf;IAEJ;IAGF,MAAMC,MAAuB,EAAE;IAC/B,KAAK,MAAM,CAAC5B,YAAY6B,KAAK,IAAIC,OAAOC,OAAO,CAACX,UAAW;QACzD,MAAM,EAAElB,IAAI,EAAEC,OAAO,EAAE,GAAGJ,iBAAiBC;QAC3C,IAAIa,QAAQmB,GAAG,CAAC9B,OAAO;QACvB0B,IAAIK,IAAI,CAAC;YACP/B;YACAC;YACA+B,YAAY9B,eAAeyB,KAAKM,QAAQ;YACxCC,MAAMP,KAAKO,IAAI;QACjB;IACF;IACA,OAAOR;AACT,EAAE"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/license/dependency-check/collectors/npm-collector.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { existsSync, readFileSync } from 'fs';\nimport * as licenseChecker from 'license-checker-rseidelsohn';\n// license-checker's own license-from-text detection, which it applies to\n// packages that declare no license. Reused here so a `SEE LICENSE IN <file>`\n// package resolves the same way, rather than through a second implementation.\nimport { getLicenseTitle } from 'license-checker-rseidelsohn/lib/getLicenseTitle.js';\nimport { join } from 'path';\n\nexport interface NpmDependency {\n name: string;\n version: string;\n rawLicense: string;\n path?: string;\n}\n\nexport interface NpmCollectorOptions {\n start: string;\n}\n\nconst NAME_VERSION_RE = /^(@?[^@]+)@(.+)$/;\n\nconst splitNameVersion = (\n identifier: string,\n): { name: string; version: string } => {\n const match = identifier.match(NAME_VERSION_RE);\n if (!match) {\n return { name: identifier, version: '0.0.0' };\n }\n return { name: match[1], version: match[2] };\n};\n\nconst flattenLicense = (raw: string | string[] | undefined | null): string => {\n if (!raw) return '';\n if (Array.isArray(raw)) {\n if (raw.length === 0) return '';\n if (raw.length === 1) return raw[0];\n return `(${raw.join(' OR ')})`;\n }\n return raw;\n};\n\n/**\n * A license that names a file instead of a license: the SPDX form\n * `SEE LICENSE IN <file>`, or the `Custom: <file>` license-checker reports it\n * as.\n */\nconst FILE_REFERENCE_RE = /^(?:custom:|see\\s+license\\s+in)\\s+(.+)$/i;\n\n/**\n * Resolve a license that only names a file into the license that file grants.\n *\n * license-checker reads a package's license file only when the package declares\n * no license, so a package declaring `SEE LICENSE IN LICENSE` is reported as\n * `Custom: LICENSE` and evaluates to UNKNOWN even when the file grants a\n * pre-approved license. Read the file license-checker already located and run\n * its text detection over it, which returns an SPDX id with the trailing `*`\n * marking a license guessed from text.\n *\n * The reference is kept when the file can't be read, or when detection can't\n * name a license, so the dependency is still reported as UNKNOWN.\n */\nexport const resolveFileReferencedLicense = (\n rawLicense: string,\n licenseFile: string | undefined,\n): string => {\n if (!licenseFile || !FILE_REFERENCE_RE.test(rawLicense.trim())) {\n return rawLicense;\n }\n let detected: string | null = null;\n try {\n detected = getLicenseTitle(readFileSync(licenseFile, 'utf-8'));\n } catch {\n return rawLicense;\n }\n if (!detected || detected === 'Undefined' || FILE_REFERENCE_RE.test(detected))\n return rawLicense;\n return detected;\n};\n\nexport const collectNpmDependencies = async (\n options: NpmCollectorOptions,\n): Promise<NpmDependency[]> => {\n const nodeModules = join(options.start, 'node_modules');\n if (!existsSync(nodeModules)) {\n return [];\n }\n\n const exclude = new Set<string>();\n\n const projectPackageJson = join(options.start, 'package.json');\n if (existsSync(projectPackageJson)) {\n try {\n const pkg = JSON.parse(readFileSync(projectPackageJson, 'utf-8')) as {\n name?: string;\n };\n if (pkg.name) exclude.add(pkg.name);\n } catch {\n // ignore\n }\n }\n\n const packages = await new Promise<licenseChecker.ModuleInfos>(\n (resolve, reject) => {\n licenseChecker.init(\n {\n start: options.start,\n excludePrivatePackages: true,\n },\n (err, results) => {\n if (err) reject(err);\n else resolve(results);\n },\n );\n },\n );\n\n const out: NpmDependency[] = [];\n for (const [identifier, info] of Object.entries(packages)) {\n const { name, version } = splitNameVersion(identifier);\n if (exclude.has(name)) continue;\n out.push({\n name,\n version,\n rawLicense: resolveFileReferencedLicense(\n flattenLicense(info.licenses),\n info.licenseFile,\n ),\n path: info.path,\n });\n }\n return out;\n};\n"],"names":["existsSync","readFileSync","licenseChecker","getLicenseTitle","join","NAME_VERSION_RE","splitNameVersion","identifier","match","name","version","flattenLicense","raw","Array","isArray","length","FILE_REFERENCE_RE","resolveFileReferencedLicense","rawLicense","licenseFile","test","trim","detected","collectNpmDependencies","options","nodeModules","start","exclude","Set","projectPackageJson","pkg","JSON","parse","add","packages","Promise","resolve","reject","init","excludePrivatePackages","err","results","out","info","Object","entries","has","push","licenses","path"],"mappings":"AAAA;;;CAGC,GACD,SAASA,UAAU,EAAEC,YAAY,QAAQ,KAAK;AAC9C,YAAYC,oBAAoB,8BAA8B;AAC9D,yEAAyE;AACzE,6EAA6E;AAC7E,8EAA8E;AAC9E,SAASC,eAAe,QAAQ,qDAAqD;AACrF,SAASC,IAAI,QAAQ,OAAO;AAa5B,MAAMC,kBAAkB;AAExB,MAAMC,mBAAmB,CACvBC;IAEA,MAAMC,QAAQD,WAAWC,KAAK,CAACH;IAC/B,IAAI,CAACG,OAAO;QACV,OAAO;YAAEC,MAAMF;YAAYG,SAAS;QAAQ;IAC9C;IACA,OAAO;QAAED,MAAMD,KAAK,CAAC,EAAE;QAAEE,SAASF,KAAK,CAAC,EAAE;IAAC;AAC7C;AAEA,MAAMG,iBAAiB,CAACC;IACtB,IAAI,CAACA,KAAK,OAAO;IACjB,IAAIC,MAAMC,OAAO,CAACF,MAAM;QACtB,IAAIA,IAAIG,MAAM,KAAK,GAAG,OAAO;QAC7B,IAAIH,IAAIG,MAAM,KAAK,GAAG,OAAOH,GAAG,CAAC,EAAE;QACnC,OAAO,CAAC,CAAC,EAAEA,IAAIR,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC;IACA,OAAOQ;AACT;AAEA;;;;CAIC,GACD,MAAMI,oBAAoB;AAE1B;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,YACAC;IAEA,IAAI,CAACA,eAAe,CAACH,kBAAkBI,IAAI,CAACF,WAAWG,IAAI,KAAK;QAC9D,OAAOH;IACT;IACA,IAAII,WAA0B;IAC9B,IAAI;QACFA,WAAWnB,gBAAgBF,aAAakB,aAAa;IACvD,EAAE,OAAM;QACN,OAAOD;IACT;IACA,IAAI,CAACI,YAAYA,aAAa,eAAeN,kBAAkBI,IAAI,CAACE,WAClE,OAAOJ;IACT,OAAOI;AACT,EAAE;AAEF,OAAO,MAAMC,yBAAyB,OACpCC;IAEA,MAAMC,cAAcrB,KAAKoB,QAAQE,KAAK,EAAE;IACxC,IAAI,CAAC1B,WAAWyB,cAAc;QAC5B,OAAO,EAAE;IACX;IAEA,MAAME,UAAU,IAAIC;IAEpB,MAAMC,qBAAqBzB,KAAKoB,QAAQE,KAAK,EAAE;IAC/C,IAAI1B,WAAW6B,qBAAqB;QAClC,IAAI;YACF,MAAMC,MAAMC,KAAKC,KAAK,CAAC/B,aAAa4B,oBAAoB;YAGxD,IAAIC,IAAIrB,IAAI,EAAEkB,QAAQM,GAAG,CAACH,IAAIrB,IAAI;QACpC,EAAE,OAAM;QACN,SAAS;QACX;IACF;IAEA,MAAMyB,WAAW,MAAM,IAAIC,QACzB,CAACC,SAASC;QACRnC,eAAeoC,IAAI,CACjB;YACEZ,OAAOF,QAAQE,KAAK;YACpBa,wBAAwB;QAC1B,GACA,CAACC,KAAKC;YACJ,IAAID,KAAKH,OAAOG;iBACXJ,QAAQK;QACf;IAEJ;IAGF,MAAMC,MAAuB,EAAE;IAC/B,KAAK,MAAM,CAACnC,YAAYoC,KAAK,IAAIC,OAAOC,OAAO,CAACX,UAAW;QACzD,MAAM,EAAEzB,IAAI,EAAEC,OAAO,EAAE,GAAGJ,iBAAiBC;QAC3C,IAAIoB,QAAQmB,GAAG,CAACrC,OAAO;QACvBiC,IAAIK,IAAI,CAAC;YACPtC;YACAC;YACAQ,YAAYD,6BACVN,eAAegC,KAAKK,QAAQ,GAC5BL,KAAKxB,WAAW;YAElB8B,MAAMN,KAAKM,IAAI;QACjB;IACF;IACA,OAAOP;AACT,EAAE"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.98/0001-sandbox-pattern-nested-stacks/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Widen the stage pattern of the sandbox targets of ts#infra projects from\n * `<stage>/*` to `<stage>/**`.\n *\n * A single `*` matches the stage's own stacks but nothing below them, so it\n * misses stacks a construct creates inside a stack - such as the `us-east-1`\n * WebACL stack a website creates for its CloudFront distribution.\n * `cdk destroy` only deletes the stacks its pattern selects, so\n * `destroy-sandbox` left that stack, and the WebACL it bills for, deployed.\n */\n\nconst SANDBOX_TARGETS = ['deploy-sandbox', 'destroy-sandbox'];\n\n/** A quoted or bare stage pattern ending in a single `*`, ie `\"my-sandbox/*\"`. */\nconst SINGLE_STAR_PATTERN = /^(\"?)\\S+\\/\\*\\1$/;\n\nconst widen = (token: string): string => token.replace(/\\/\\*(\"?)$/, '/**$1');\n\n/**\n * Whether the command is one of the deploy/destroy commands this generator\n * vends - either a direct `cdk deploy`/`cdk destroy`, or the stage-config\n * script that wraps it. Anything else has been hand-written and is reported\n * rather than rewritten.\n */\nconst isGeneratedCommand = (command: string): boolean =>\n /(^|\\s)cdk\\s+(deploy|destroy)(\\s|$)/.test(command) ||\n command.includes('infra-deploy.ts') ||\n command.includes('infra-destroy.ts');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n for (const [name, project] of getProjects(tree)) {\n if (\n (project.metadata as { generator?: string } | undefined)?.generator !==\n INFRA_APP_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n let projectChanged = false;\n\n for (const targetName of SANDBOX_TARGETS) {\n const target: TargetConfiguration | undefined =\n project.targets?.[targetName];\n const command = target?.options?.command;\n if (!target || typeof command !== 'string') {\n continue;\n }\n\n const args = command.split(/\\s+/);\n // Nothing to widen: already `/**`, or the pattern has been removed. Keeps\n // re-runs - and a project generated after this change - a no-op.\n if (!args.some((arg) => SINGLE_STAR_PATTERN.test(arg))) {\n continue;\n }\n\n if (!isGeneratedCommand(command)) {\n nextSteps.push(\n `${name}: its ${targetName} target has been customised, so it was left as it is. Widen its stage pattern from \"<stage>/*\" to \"<stage>/**\" so it also matches stacks nested below the stage's stacks, such as a website's WebACL stack.`,\n );\n continue;\n }\n\n target.options.command = args\n .map((arg) => (SINGLE_STAR_PATTERN.test(arg) ? widen(arg) : arg))\n .join(' ');\n projectChanged = true;\n }\n\n if (projectChanged) {\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","SANDBOX_TARGETS","SINGLE_STAR_PATTERN","widen","token","replace","isGeneratedCommand","command","test","includes","migration","tree","nextSteps","migrated","name","project","metadata","generator","id","projectChanged","targetName","target","targets","options","args","split","some","arg","push","map","join"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;CASC,GAED,MAAMC,kBAAkB;IAAC;IAAkB;CAAkB;AAE7D,gFAAgF,GAChF,MAAMC,sBAAsB;AAE5B,MAAMC,QAAQ,CAACC,QAA0BA,MAAMC,OAAO,CAAC,aAAa;AAEpE;;;;;CAKC,GACD,MAAMC,qBAAqB,CAACC,UAC1B,qCAAqCC,IAAI,CAACD,YAC1CA,QAAQE,QAAQ,CAAC,sBACjBF,QAAQE,QAAQ,CAAC;AAEnB,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAIlB,YAAYc,MAAO;QAC/C,IACE,AAACI,QAAQC,QAAQ,EAAyCC,cAC1DlB,yBAAyBmB,EAAE,EAC3B;YACA;QACF;QAEA,IAAIC,iBAAiB;QAErB,KAAK,MAAMC,cAAcnB,gBAAiB;YACxC,MAAMoB,SACJN,QAAQO,OAAO,EAAE,CAACF,WAAW;YAC/B,MAAMb,UAAUc,QAAQE,SAAShB;YACjC,IAAI,CAACc,UAAU,OAAOd,YAAY,UAAU;gBAC1C;YACF;YAEA,MAAMiB,OAAOjB,QAAQkB,KAAK,CAAC;YAC3B,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,CAACD,KAAKE,IAAI,CAAC,CAACC,MAAQzB,oBAAoBM,IAAI,CAACmB,OAAO;gBACtD;YACF;YAEA,IAAI,CAACrB,mBAAmBC,UAAU;gBAChCK,UAAUgB,IAAI,CACZ,GAAGd,KAAK,MAAM,EAAEM,WAAW,2MAA2M,CAAC;gBAEzO;YACF;YAEAC,OAAOE,OAAO,CAAChB,OAAO,GAAGiB,KACtBK,GAAG,CAAC,CAACF,MAASzB,oBAAoBM,IAAI,CAACmB,OAAOxB,MAAMwB,OAAOA,KAC3DG,IAAI,CAAC;YACRX,iBAAiB;QACnB;QAEA,IAAIA,gBAAgB;YAClBrB,2BAA2Ba,MAAMG,MAAMC;YACvCF,WAAW;QACb;IACF;IAEA,IAAIA,UAAU;QACZ,MAAMb,qBAAqBW;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.98/0002-shadcn-cn-package/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n readJson,\n type Tree,\n} from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport {\n addDependenciesToPackageJson,\n removeDependenciesFromPackageJson,\n} from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_SHADCN_DIR,\n} from '../../../utils/shared-constructs-constants.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * Move the shared shadcn package onto the `cn` package.\n *\n * The shadcn registry now serves components importing `cn` from the `cn`\n * package and declares it as a registry dependency, so a component added by\n * `shadcn add` no longer resolves the package's own `#lib/utils` helper. This\n * carries an existing workspace onto that shape: the components import `cn`,\n * `src/lib/utils.ts` becomes the single-line re-export shadcn's own install\n * guide prescribes, which keeps every consumer importing `cn` through\n * `<scope>common-shadcn/lib/utils` working, and clsx / tailwind-merge are\n * dropped now that nothing imports them.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Only touches a `packages/common/shadcn` this plugin's generators produced,\n * guarded by `components.json`'s aliases still matching the generated shape.\n * - An import is only rewritten when `cn` is its sole binding, so a file also\n * pulling a user's own helper out of `#lib/utils` keeps resolving through the\n * re-export.\n * - `src/lib/utils.ts` is only rewritten while it still holds the generated\n * `twMerge(clsx(...))` helper; a customised one is reported instead.\n * - clsx / tailwind-merge are only dropped once nothing under `src` imports\n * them.\n * - Idempotent: every write is guarded by the old shape still being present.\n */\n\nconst libraryRoot = joinPathFragments(PACKAGES_DIR, SHARED_SHADCN_DIR);\nconst componentsJsonPath = joinPathFragments(libraryRoot, 'components.json');\nconst packageJsonPath = joinPathFragments(libraryRoot, 'package.json');\nconst srcRoot = joinPathFragments(libraryRoot, 'src');\nconst utilsPath = joinPathFragments(srcRoot, 'lib', 'utils.ts');\n\n/** The aliases today's generators write, which this migration leaves in place. */\nconst generatedAliases: Record<string, string> = {\n components: '#components',\n utils: '#lib/utils',\n hooks: '#hooks',\n lib: '#lib',\n ui: '#components/ui',\n};\n\nconst CN_IMPORT_REWRITE = `\\`import { cn } from '#lib/utils'\\` => \\`import { cn } from 'cn'\\``;\n\n/** The generated helper, whichever way the user's formatter has laid it out. */\nconst GENERATED_CN_HELPER = `\\`twMerge(clsx($_))\\``;\n\nconst importsPackage = (name: string): string => `\\`import $_ from '${name}'\\``;\n\nconst REEXPORT_UTILS = `export { cn } from 'cn';\\n`;\n\nconst DROPPED_PACKAGES = ['clsx', 'tailwind-merge'] as const;\n\n/** Every `.ts`/`.tsx` file in the package's source tree. */\nconst sourceFiles = (tree: Tree, dir: string): string[] => {\n if (!tree.exists(dir)) {\n return [];\n }\n return tree.children(dir).flatMap((entry) => {\n const path = joinPathFragments(dir, entry);\n if (!tree.isFile(path)) {\n return sourceFiles(tree, path);\n }\n return path.endsWith('.ts') || path.endsWith('.tsx') ? [path] : [];\n });\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(componentsJsonPath) || !tree.exists(packageJsonPath)) {\n return { nextSteps };\n }\n\n const aliases =\n readJson<{ aliases?: Record<string, string> }>(tree, componentsJsonPath)\n .aliases ?? {};\n if (Object.entries(generatedAliases).some(([k, v]) => aliases[k] !== v)) {\n return { nextSteps };\n }\n\n const files = sourceFiles(tree, srcRoot);\n\n for (const file of files) {\n await applyGritQL(tree, file, CN_IMPORT_REWRITE);\n }\n\n if (tree.exists(utilsPath)) {\n if (await matchGritQL(tree, utilsPath, GENERATED_CN_HELPER)) {\n tree.write(utilsPath, REEXPORT_UTILS);\n } else if (tree.read(utilsPath, 'utf-8') !== REEXPORT_UTILS) {\n nextSteps.push(\n `${utilsPath}: no longer holds the generated cn helper - left untouched. Re-export cn from the 'cn' package by hand so consumers importing it from here keep working.`,\n );\n }\n }\n\n addDependenciesToPackageJson(\n tree,\n { cn: TS_VERSIONS.cn },\n {},\n packageJsonPath,\n );\n\n const stillImported = new Set<string>();\n for (const file of sourceFiles(tree, srcRoot)) {\n for (const name of DROPPED_PACKAGES) {\n if (await matchGritQL(tree, file, importsPackage(name))) {\n stillImported.add(name);\n }\n }\n }\n\n const dropped = DROPPED_PACKAGES.filter((name) => !stillImported.has(name));\n removeDependenciesFromPackageJson(tree, dropped, dropped, packageJsonPath);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","readJson","applyGritQL","matchGritQL","addDependenciesToPackageJson","removeDependenciesFromPackageJson","formatFilesInSubtree","PACKAGES_DIR","SHARED_SHADCN_DIR","TS_VERSIONS","libraryRoot","componentsJsonPath","packageJsonPath","srcRoot","utilsPath","generatedAliases","components","utils","hooks","lib","ui","CN_IMPORT_REWRITE","GENERATED_CN_HELPER","importsPackage","name","REEXPORT_UTILS","DROPPED_PACKAGES","sourceFiles","tree","dir","exists","children","flatMap","entry","path","isFile","endsWith","migration","nextSteps","aliases","Object","entries","some","k","v","files","file","write","read","push","cn","stillImported","Set","add","dropped","filter","has"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,EAEjBC,QAAQ,QAEH,aAAa;AACpB,SAASC,WAAW,EAAEC,WAAW,QAAQ,wBAAwB;AACjE,SACEC,4BAA4B,EAC5BC,iCAAiC,QAC5B,iCAAiC;AACxC,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,iBAAiB,QACZ,gDAAgD;AACvD,SAASC,WAAW,QAAQ,6BAA6B;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GAED,MAAMC,cAAcV,kBAAkBO,cAAcC;AACpD,MAAMG,qBAAqBX,kBAAkBU,aAAa;AAC1D,MAAME,kBAAkBZ,kBAAkBU,aAAa;AACvD,MAAMG,UAAUb,kBAAkBU,aAAa;AAC/C,MAAMI,YAAYd,kBAAkBa,SAAS,OAAO;AAEpD,gFAAgF,GAChF,MAAME,mBAA2C;IAC/CC,YAAY;IACZC,OAAO;IACPC,OAAO;IACPC,KAAK;IACLC,IAAI;AACN;AAEA,MAAMC,oBAAoB,CAAC,kEAAkE,CAAC;AAE9F,8EAA8E,GAC9E,MAAMC,sBAAsB,CAAC,qBAAqB,CAAC;AAEnD,MAAMC,iBAAiB,CAACC,OAAyB,CAAC,kBAAkB,EAAEA,KAAK,GAAG,CAAC;AAE/E,MAAMC,iBAAiB,CAAC,0BAA0B,CAAC;AAEnD,MAAMC,mBAAmB;IAAC;IAAQ;CAAiB;AAEnD,0DAA0D,GAC1D,MAAMC,cAAc,CAACC,MAAYC;IAC/B,IAAI,CAACD,KAAKE,MAAM,CAACD,MAAM;QACrB,OAAO,EAAE;IACX;IACA,OAAOD,KAAKG,QAAQ,CAACF,KAAKG,OAAO,CAAC,CAACC;QACjC,MAAMC,OAAOlC,kBAAkB6B,KAAKI;QACpC,IAAI,CAACL,KAAKO,MAAM,CAACD,OAAO;YACtB,OAAOP,YAAYC,MAAMM;QAC3B;QACA,OAAOA,KAAKE,QAAQ,CAAC,UAAUF,KAAKE,QAAQ,CAAC,UAAU;YAACF;SAAK,GAAG,EAAE;IACpE;AACF;AAEA,eAAe,eAAeG,UAC5BT,IAAU;IAEV,MAAMU,YAAsB,EAAE;IAE9B,IAAI,CAACV,KAAKE,MAAM,CAACnB,uBAAuB,CAACiB,KAAKE,MAAM,CAAClB,kBAAkB;QACrE,OAAO;YAAE0B;QAAU;IACrB;IAEA,MAAMC,UACJtC,SAA+C2B,MAAMjB,oBAClD4B,OAAO,IAAI,CAAC;IACjB,IAAIC,OAAOC,OAAO,CAAC1B,kBAAkB2B,IAAI,CAAC,CAAC,CAACC,GAAGC,EAAE,GAAKL,OAAO,CAACI,EAAE,KAAKC,IAAI;QACvE,OAAO;YAAEN;QAAU;IACrB;IAEA,MAAMO,QAAQlB,YAAYC,MAAMf;IAEhC,KAAK,MAAMiC,QAAQD,MAAO;QACxB,MAAM3C,YAAY0B,MAAMkB,MAAMzB;IAChC;IAEA,IAAIO,KAAKE,MAAM,CAAChB,YAAY;QAC1B,IAAI,MAAMX,YAAYyB,MAAMd,WAAWQ,sBAAsB;YAC3DM,KAAKmB,KAAK,CAACjC,WAAWW;QACxB,OAAO,IAAIG,KAAKoB,IAAI,CAAClC,WAAW,aAAaW,gBAAgB;YAC3Da,UAAUW,IAAI,CACZ,GAAGnC,UAAU,wJAAwJ,CAAC;QAE1K;IACF;IAEAV,6BACEwB,MACA;QAAEsB,IAAIzC,YAAYyC,EAAE;IAAC,GACrB,CAAC,GACDtC;IAGF,MAAMuC,gBAAgB,IAAIC;IAC1B,KAAK,MAAMN,QAAQnB,YAAYC,MAAMf,SAAU;QAC7C,KAAK,MAAMW,QAAQE,iBAAkB;YACnC,IAAI,MAAMvB,YAAYyB,MAAMkB,MAAMvB,eAAeC,QAAQ;gBACvD2B,cAAcE,GAAG,CAAC7B;YACpB;QACF;IACF;IAEA,MAAM8B,UAAU5B,iBAAiB6B,MAAM,CAAC,CAAC/B,OAAS,CAAC2B,cAAcK,GAAG,CAAChC;IACrEnB,kCAAkCuB,MAAM0B,SAASA,SAAS1C;IAE1D,MAAMN,qBAAqBsB;IAE3B,OAAO;QAAEU;IAAU;AACrB"}
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.2/0001-terraform-harness-environment-variables/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Stop each vended Terraform AgentCore Harness app module\n * (`app/harnesses/<name>/<name>.tf`) sending a null `environment_variables`.\n *\n * The service stores no environment variables as an empty map and returns one,\n * so a null fails the apply with \"inconsistent values for sensitive attribute\"\n * once the Harness has already been created, leaving it tainted. Every\n * subsequent apply fails the same way.\n *\n * Modules whose assignment has been edited are left untouched and reported via\n * `nextSteps`.\n */\n\nconst TERRAFORM_HARNESS_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/harnesses`;\n\n/** The assignment the generator used to write. */\nconst NULLABLE_ASSIGNMENT = 'environment_variables = var.environment_variables';\n\n/** What it becomes, so the value sent matches what the service returns. */\nconst COALESCED_ASSIGNMENT =\n 'environment_variables = coalesce(var.environment_variables, {})';\n\nconst divergedMessage = (filePath: string) =>\n `${filePath}: its environment_variables assignment has been edited, so it was left as it is. Change it to \\`${COALESCED_ASSIGNMENT}\\` — the AgentCore service returns an empty map when a Harness has no environment variables, and sending null fails the apply after the Harness has been created.`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n if (!tree.exists(TERRAFORM_HARNESS_APP_DIR)) {\n return { nextSteps }; // This workspace has no Terraform harness modules.\n }\n\n for (const dirName of tree.children(TERRAFORM_HARNESS_APP_DIR)) {\n const filePath = joinPathFragments(\n TERRAFORM_HARNESS_APP_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a harness app module directory.\n }\n\n const contents = tree.read(filePath, 'utf-8') ?? '';\n\n if (contents.includes(COALESCED_ASSIGNMENT)) {\n continue; // Already migrated, so a re-run is a no-op.\n }\n\n if (!contents.includes(NULLABLE_ASSIGNMENT)) {\n nextSteps.push(divergedMessage(filePath));\n continue;\n }\n\n tree.write(\n filePath,\n contents.replace(NULLABLE_ASSIGNMENT, COALESCED_ASSIGNMENT),\n );\n migrated = true;\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree, TERRAFORM_HARNESS_APP_DIR);\n }\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_HARNESS_APP_DIR","NULLABLE_ASSIGNMENT","COALESCED_ASSIGNMENT","divergedMessage","filePath","migration","tree","nextSteps","migrated","exists","dirName","children","contents","read","includes","push","write","replace"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;CAWC,GAED,MAAMC,4BAA4B,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,kBAAkB,CAAC;AAE7F,gDAAgD,GAChD,MAAME,sBAAsB;AAE5B,yEAAyE,GACzE,MAAMC,uBACJ;AAEF,MAAMC,kBAAkB,CAACC,WACvB,GAAGA,SAAS,gGAAgG,EAAEF,qBAAqB,iKAAiK,CAAC;AAEvS,eAAe,eAAeG,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,IAAI,CAACF,KAAKG,MAAM,CAACT,4BAA4B;QAC3C,OAAO;YAAEO;QAAU,GAAG,mDAAmD;IAC3E;IAEA,KAAK,MAAMG,WAAWJ,KAAKK,QAAQ,CAACX,2BAA4B;QAC9D,MAAMI,WAAWR,kBACfI,2BACAU,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACJ,KAAKG,MAAM,CAACL,WAAW;YAC1B,UAAU,sCAAsC;QAClD;QAEA,MAAMQ,WAAWN,KAAKO,IAAI,CAACT,UAAU,YAAY;QAEjD,IAAIQ,SAASE,QAAQ,CAACZ,uBAAuB;YAC3C,UAAU,4CAA4C;QACxD;QAEA,IAAI,CAACU,SAASE,QAAQ,CAACb,sBAAsB;YAC3CM,UAAUQ,IAAI,CAACZ,gBAAgBC;YAC/B;QACF;QAEAE,KAAKU,KAAK,CACRZ,UACAQ,SAASK,OAAO,CAAChB,qBAAqBC;QAExCM,WAAW;IACb;IAEA,IAAIA,UAAU;QACZ,MAAMX,qBAAqBS,MAAMN;IACnC;IAEA,OAAO;QAAEO;IAAU;AACrB"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "description": "Add the terraform-init target to Terraform projects so the shared provider plugin cache has a single writer"
3
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type MigrationReturnObject, type Tree } from '@nx/devkit';
6
+ export default function migration(tree: Tree): Promise<MigrationReturnObject>;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { getProjects, joinPathFragments, updateProjectConfiguration } from "@nx/devkit";
5
+ import { relative } from "path";
6
+ import { TERRAFORM_PROJECT_GENERATOR_INFO } from "../../../terraform/project/generator.js";
7
+ import { formatFilesInSubtree } from "../../../utils/format.js";
8
+ import { sortObjectKeys } from "../../../utils/object.js";
9
+ /**
10
+ * Give the shared Terraform provider plugin cache a single writer.
11
+ *
12
+ * `init`, `test` and `validate` each ran their own `terraform init` against one
13
+ * per-project cache, and Nx schedules them concurrently — `plan` depends on both
14
+ * `init` and `validate`. Two `terraform init` runs filling the cache at once each
15
+ * compute a different hash for the same provider, because the hash covers a
16
+ * directory the other is still writing, and terraform then rejects the mismatch
17
+ * against the lock file: "the cached package ... does not match any of the
18
+ * checksums recorded in the dependency lock file".
19
+ *
20
+ * The new `terraform-init` target runs that init once, and `test`, `validate` and
21
+ * `init` depend on it — `test` and `validate` now run against the `TF_DATA_DIR`
22
+ * it prepared rather than initialising their own.
23
+ */ const TERRAFORM_INIT = 'terraform-init';
24
+ /** `terraform init` as the pre-fix `test` and `validate` targets ran it. */ const BACKENDLESS_INIT = 'terraform init -backend=false';
25
+ const divergedStep = (projectName, targetName)=>`${projectName}: its '${targetName}' target no longer matches the shape the generator produced - left untouched. Point it at the \`TF_DATA_DIR\` of the new \`${TERRAFORM_INIT}\` target and add \`"dependsOn": ["${TERRAFORM_INIT}"]\`, so its \`terraform init\` no longer races the other targets over the provider cache.`;
26
+ /** Path from a target running in `{projectRoot}/src` back to the workspace root. */ const rootRelativePath = (projectRoot)=>relative(joinPathFragments(projectRoot, 'src'), '.').replace(/\\/g, '/');
27
+ const pluginCacheDirFor = (toRoot)=>joinPathFragments(toRoot, '.terraform', 'plugin-cache', '{projectRoot}');
28
+ const dataDirFor = (toRoot, name)=>joinPathFragments(toRoot, 'dist', '{projectRoot}', name);
29
+ /**
30
+ * The target as the generator vends it: `-backend=false` needs no credentials,
31
+ * so this runs on a fresh workspace before `bootstrap`, and its `TF_DATA_DIR`
32
+ * keeps the `.terraform` it initialises out of `src`.
33
+ */ const terraformInitTarget = (projectRoot)=>{
34
+ const toRoot = rootRelativePath(projectRoot);
35
+ const pluginCacheDir = pluginCacheDirFor(toRoot);
36
+ return {
37
+ executor: 'nx:run-commands',
38
+ options: {
39
+ commands: [
40
+ {
41
+ command: `shx mkdir -p ${pluginCacheDir}`,
42
+ forwardAllArgs: false
43
+ },
44
+ BACKENDLESS_INIT
45
+ ],
46
+ forwardAllArgs: true,
47
+ cwd: '{projectRoot}/src',
48
+ parallel: false,
49
+ env: {
50
+ TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT),
51
+ TF_PLUGIN_CACHE_DIR: pluginCacheDir
52
+ }
53
+ }
54
+ };
55
+ };
56
+ /** Every command a target runs, across its options and its configurations. */ const commandsOf = (target)=>[
57
+ target.options,
58
+ ...Object.values(target.configurations ?? {})
59
+ ].flatMap((holder)=>[
60
+ holder?.command,
61
+ ...Array.isArray(holder?.commands) ? holder.commands : []
62
+ ]).map((command)=>typeof command === 'string' ? command : command?.command).filter((command)=>typeof command === 'string');
63
+ /**
64
+ * Whether the target still runs the `terraform init` this migration orders. A
65
+ * library's `init` runs it directly and an application's delegates to the vended
66
+ * script.
67
+ */ const runsTerraformInit = (target)=>commandsOf(target).some((command)=>command.includes('terraform init') || command.includes('scripts/init.ts'));
68
+ /** Creating the plugin cache directory, which `terraform-init` now does. */ const isMakeCacheDir = (command)=>/^(shx mkdir -p|make-dir)\s/.test(command) && command.includes('plugin-cache');
69
+ /**
70
+ * Rewrites `test` or `validate` to run against the `TF_DATA_DIR` `terraform-init`
71
+ * prepared. Only the exact shape the generator produced is rewritten: its own
72
+ * `terraform init` (with the cache directory the plugin-cache fix added ahead of
73
+ * it), then the one terraform command the target exists to run. Anything else is
74
+ * the user's, and is reported instead.
75
+ */ const migrateInitlessTarget = (target, verb, toRoot)=>{
76
+ const commands = commandsOf(target).filter((command)=>!isMakeCacheDir(command));
77
+ if (commands.length !== 2 || commands[0] !== BACKENDLESS_INIT || commands[1] !== `terraform ${verb}`) {
78
+ return false;
79
+ }
80
+ const options = target.options ?? {};
81
+ const env = options.env ?? {};
82
+ if (env.TF_DATA_DIR !== dataDirFor(toRoot, `terraform-${verb}`)) {
83
+ return false;
84
+ }
85
+ const { TF_DATA_DIR: _dataDir, TF_PLUGIN_CACHE_DIR: _cacheDir, ...rest } = env;
86
+ delete options.commands;
87
+ // `parallel: false` sequenced the init ahead of the command; one command left.
88
+ delete options.parallel;
89
+ target.options = {
90
+ ...options,
91
+ command: `terraform ${verb}`,
92
+ env: {
93
+ ...rest,
94
+ TF_DATA_DIR: dataDirFor(toRoot, TERRAFORM_INIT)
95
+ }
96
+ };
97
+ return true;
98
+ };
99
+ export default async function migration(tree) {
100
+ const nextSteps = [];
101
+ for (const [projectName, project] of getProjects(tree)){
102
+ const generator = project.metadata?.generator;
103
+ if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;
104
+ let targets = project.targets ?? {};
105
+ const toRoot = rootRelativePath(project.root);
106
+ let changed = false;
107
+ // Guarded on the target being absent, so a re-run — and a project generated
108
+ // with it — is a no-op.
109
+ if (!targets[TERRAFORM_INIT]) {
110
+ targets = sortObjectKeys({
111
+ ...targets,
112
+ [TERRAFORM_INIT]: terraformInitTarget(project.root)
113
+ });
114
+ changed = true;
115
+ }
116
+ for (const targetName of [
117
+ 'init',
118
+ 'test',
119
+ 'validate'
120
+ ]){
121
+ const target = targets[targetName];
122
+ if (!target) continue;
123
+ if (target.dependsOn?.includes(TERRAFORM_INIT)) continue;
124
+ // `init` keeps its own backend-configured `terraform init`; `test` and
125
+ // `validate` hand theirs over to `terraform-init`, so nothing is ordered
126
+ // after a target whose shape is no longer recognised.
127
+ const migrated = targetName === 'init' ? runsTerraformInit(target) : migrateInitlessTarget(target, targetName, toRoot);
128
+ if (!migrated) {
129
+ nextSteps.push(divergedStep(projectName, targetName));
130
+ continue;
131
+ }
132
+ // Prepended rather than appended, so a migrated workspace matches a
133
+ // freshly generated one.
134
+ target.dependsOn = [
135
+ TERRAFORM_INIT,
136
+ ...target.dependsOn ?? []
137
+ ];
138
+ changed = true;
139
+ }
140
+ if (changed) {
141
+ updateProjectConfiguration(tree, projectName, {
142
+ ...project,
143
+ targets
144
+ });
145
+ }
146
+ }
147
+ await formatFilesInSubtree(tree);
148
+ return {
149
+ nextSteps
150
+ };
151
+ }
152
+
153
+ //# sourceMappingURL=migration.js.map