@aws/nx-plugin 1.1.1 → 1.2.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 (115) hide show
  1. package/README.md +30 -29
  2. package/generators.json +8 -0
  3. package/migrations.json +1 -1
  4. package/package.json +1 -1
  5. package/src/agentcore-harness/generator.d.ts +1 -1
  6. package/src/greengrass/component/common.d.ts +60 -0
  7. package/src/greengrass/component/common.js +191 -0
  8. package/src/greengrass/component/common.js.map +1 -0
  9. package/src/greengrass/component/dependencies.d.ts +101 -0
  10. package/src/greengrass/component/dependencies.js +37 -0
  11. package/src/greengrass/component/dependencies.js.map +1 -0
  12. package/src/greengrass/component/generator.d.ts +174 -0
  13. package/src/greengrass/component/generator.js +32 -0
  14. package/src/greengrass/component/generator.js.map +1 -0
  15. package/src/greengrass/component/metadata.d.ts +2 -0
  16. package/src/greengrass/component/metadata.js +14 -0
  17. package/src/greengrass/component/metadata.js.map +1 -0
  18. package/src/greengrass/component/python/__snapshots__/generator.spec.ts.snap +450 -0
  19. package/src/greengrass/component/python/files/component/main.py.template +60 -0
  20. package/src/greengrass/component/python/files/component/recipe.yaml.template +30 -0
  21. package/src/greengrass/component/python/files/gdk/gdk-config.json.template +13 -0
  22. package/src/greengrass/component/python/files/tests/test___componentSnakeCase__.py.template +37 -0
  23. package/src/greengrass/component/python/generator.d.ts +15 -0
  24. package/src/greengrass/component/python/generator.js +192 -0
  25. package/src/greengrass/component/python/generator.js.map +1 -0
  26. package/src/greengrass/component/schema.d.js +6 -0
  27. package/src/greengrass/component/schema.d.js.map +1 -0
  28. package/src/greengrass/component/schema.d.ts +18 -0
  29. package/src/greengrass/component/schema.json +82 -0
  30. package/src/greengrass/component/typescript/__snapshots__/generator.spec.ts.snap +275 -0
  31. package/src/greengrass/component/typescript/files/component/recipe.yaml.template +41 -0
  32. package/src/greengrass/component/typescript/files/entrypoint/main.ts.template +58 -0
  33. package/src/greengrass/component/typescript/files/gdk/gdk-config.json.template +13 -0
  34. package/src/greengrass/component/typescript/files/scripts/vendor-crt-addon.ts.template +115 -0
  35. package/src/greengrass/component/typescript/generator.d.ts +16 -0
  36. package/src/greengrass/component/typescript/generator.js +194 -0
  37. package/src/greengrass/component/typescript/generator.js.map +1 -0
  38. package/src/infra/app/generator.d.ts +1 -1
  39. package/src/init/generator.d.ts +1 -1
  40. package/src/internal/test-matrix/generator.js +42 -0
  41. package/src/internal/test-matrix/generator.js.map +1 -1
  42. package/src/license/dependency-check/pre-approved.js +2 -1
  43. package/src/license/dependency-check/pre-approved.js.map +1 -1
  44. package/src/open-api/py-client/generator.d.ts +1 -1
  45. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -0
  46. package/src/preset/generator.d.ts +1 -1
  47. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  48. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  49. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  50. package/src/py/agent/react-connection/generator.d.ts +1 -1
  51. package/src/py/fast-api/react/generator.d.ts +1 -1
  52. package/src/py/project/generator.js +2 -0
  53. package/src/py/project/generator.js.map +1 -1
  54. package/src/sdk/greengrass.d.ts +6 -0
  55. package/src/sdk/greengrass.js +6 -0
  56. package/src/sdk/greengrass.js.map +1 -0
  57. package/src/smithy/project/generator.d.ts +1 -1
  58. package/src/smithy/react-connection/generator.d.ts +1 -1
  59. package/src/terraform/project/generator.d.ts +1 -1
  60. package/src/trpc/react/generator.d.ts +1 -1
  61. package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
  62. package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
  63. package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
  64. package/src/ts/agent/react-connection/generator.d.ts +1 -1
  65. package/src/ts/astro-docs/generator.d.ts +1 -1
  66. package/src/ts/dcr-proxy/generator.d.ts +1 -1
  67. package/src/ts/dynamodb/generator.d.ts +1 -1
  68. package/src/ts/lambda-function/generator.d.ts +1 -1
  69. package/src/ts/lib/generator.d.ts +1 -1
  70. package/src/ts/nx-generator/generator.d.ts +1 -1
  71. package/src/ts/nx-migration/generator.d.ts +1 -1
  72. package/src/ts/nx-plugin/generator.d.ts +1 -1
  73. package/src/ts/rdb/generator.d.ts +1 -1
  74. package/src/ts/react-website/agui/generator.d.ts +1 -1
  75. package/src/utils/__snapshots__/shared-greengrass-scripts.spec.ts.snap +1279 -0
  76. package/src/utils/files/common/scripts/src/greengrass/build-artifact.ts.template +236 -0
  77. package/src/utils/files/common/scripts/src/greengrass/component-logs.ts.template +48 -0
  78. package/src/utils/files/common/scripts/src/greengrass/deploy-local.ts.template +497 -0
  79. package/src/utils/files/common/scripts/src/greengrass/recipe-utils.ts.template +356 -0
  80. package/src/utils/files/common/scripts/src/greengrass/zip-writer.ts.template +121 -0
  81. package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +3 -3
  82. package/src/utils/files/terraform/src/metrics/metrics.tf.template +1 -1
  83. package/src/utils/greengrass/constants.d.ts +58 -0
  84. package/src/utils/greengrass/constants.js +63 -0
  85. package/src/utils/greengrass/constants.js.map +1 -0
  86. package/src/utils/greengrass/naming.d.ts +46 -0
  87. package/src/utils/greengrass/naming.js +67 -0
  88. package/src/utils/greengrass/naming.js.map +1 -0
  89. package/src/utils/greengrass/recipe.d.ts +143 -0
  90. package/src/utils/greengrass/recipe.js +119 -0
  91. package/src/utils/greengrass/recipe.js.map +1 -0
  92. package/src/utils/greengrass-constructs/files/cdk/app/greengrass-component/__componentDirName__.ts.template +42 -0
  93. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/artifact-bucket.ts.template +82 -0
  94. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/component-version.ts.template +370 -0
  95. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/deployment.ts.template +276 -0
  96. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/index.ts.template +5 -0
  97. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/next-version.ts.template +119 -0
  98. package/src/utils/greengrass-constructs/files/cdk/core/greengrass/recipe.ts.template +90 -0
  99. package/src/utils/greengrass-constructs/files/next-version/__nextVersionFileName__.template +195 -0
  100. package/src/utils/greengrass-constructs/files/terraform/app/greengrass-component/__componentDirName__/__componentDirName__.tf.template +26 -0
  101. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/artifact-bucket/main.tf.template +204 -0
  102. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/component-version/main.tf.template +156 -0
  103. package/src/utils/greengrass-constructs/files/terraform/core/greengrass/deployment/main.tf.template +186 -0
  104. package/src/utils/greengrass-constructs/greengrass-constructs.d.ts +57 -0
  105. package/src/utils/greengrass-constructs/greengrass-constructs.js +154 -0
  106. package/src/utils/greengrass-constructs/greengrass-constructs.js.map +1 -0
  107. package/src/utils/nx.d.ts +15 -0
  108. package/src/utils/nx.js +32 -0
  109. package/src/utils/nx.js.map +1 -1
  110. package/src/utils/shared-greengrass-scripts.d.ts +21 -0
  111. package/src/utils/shared-greengrass-scripts.js +43 -0
  112. package/src/utils/shared-greengrass-scripts.js.map +1 -0
  113. package/src/utils/versions.d.ts +7 -0
  114. package/src/utils/versions.js +7 -0
  115. package/src/utils/versions.js.map +1 -1
@@ -0,0 +1,156 @@
1
+ terraform {
2
+ required_providers {
3
+ aws = {
4
+ source = "hashicorp/aws"
5
+ version = "<%- awsProviderVersion %>"
6
+ }
7
+ awscc = {
8
+ source = "hashicorp/awscc"
9
+ version = "<%- awsccProviderVersion %>"
10
+ }
11
+ }
12
+ }
13
+
14
+ variable "recipes_dir" {
15
+ description = "Directory holding the one resolved recipe YAML the <c>-artifact target writes (greengrass-build/recipes). Read at plan time."
16
+ type = string
17
+ }
18
+
19
+ variable "artifacts_dir" {
20
+ description = "Directory holding the <c>-artifact target's artifact tree (greengrass-build/artifacts), containing one file per manifest platform at <artifacts_dir>/<ComponentName>/<ComponentVersion>/."
21
+ type = string
22
+ }
23
+
24
+ variable "bucket_name" {
25
+ # Use the artifact-bucket module output to wait for bucket hardening.
26
+ description = "Name of the shared artifact bucket this version's artifact is uploaded to."
27
+ type = string
28
+ }
29
+
30
+ locals {
31
+ placeholder_prefix = "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/"
32
+
33
+ recipe_files = fileset(var.recipes_dir, "*.y*ml")
34
+ recipe_candidate = try(tolist(local.recipe_files)[0], null)
35
+ recipe_path = "${var.recipes_dir}/${coalesce(local.recipe_candidate, "__no_recipe_found__")}"
36
+ recipe = try(yamldecode(file(local.recipe_path)), {})
37
+ component_name = try(local.recipe.ComponentName, "")
38
+ component_version = try(local.recipe.ComponentVersion, "")
39
+
40
+ artifact_dir = "${var.artifacts_dir}/${local.component_name}/${local.component_version}"
41
+ artifact_files = try(fileset(local.artifact_dir, "*"), [])
42
+ artifact_basenames = sort(tolist(local.artifact_files))
43
+ artifact_hashes = { for f in local.artifact_basenames : f => filesha256("${local.artifact_dir}/${f}") }
44
+
45
+ # Hash the sorted artifact names and their content digests on both IaC paths.
46
+ sha256 = sha256(join("\n", [for f in local.artifact_basenames : "${f}:${local.artifact_hashes[f]}"]))
47
+
48
+ destination_key_prefix = "${local.component_name}/${substr(local.sha256, 0, 32)}/"
49
+ replacement_prefix = "s3://${var.bucket_name}/${local.destination_key_prefix}"
50
+
51
+ # Substitute only managed artifact URIs, preserving other recipe fields
52
+ # and manifests without artifacts.
53
+ substituted_manifests = [
54
+ for manifest in try(local.recipe.Manifests, []) : merge(manifest, [
55
+ for _ in range(can(manifest.Artifacts) ? 1 : 0) : {
56
+ Artifacts = [
57
+ for artifact in manifest.Artifacts : merge(artifact, {
58
+ Uri = (
59
+ startswith(artifact.Uri, local.placeholder_prefix)
60
+ ? "${local.replacement_prefix}${substr(artifact.Uri, length(local.placeholder_prefix), -1)}"
61
+ : artifact.Uri
62
+ )
63
+ })
64
+ ]
65
+ }
66
+ ]...)
67
+ ]
68
+ substituted_recipe = merge(local.recipe, [
69
+ for _ in range(can(local.recipe.Manifests) ? 1 : 0) : {
70
+ Manifests = local.substituted_manifests
71
+ }
72
+ ]...)
73
+
74
+ substituted_basenames = distinct(flatten([
75
+ for manifest in try(local.recipe.Manifests, []) : [
76
+ for artifact in try(manifest.Artifacts, []) : substr(artifact.Uri, length(local.placeholder_prefix), -1)
77
+ if startswith(artifact.Uri, local.placeholder_prefix)
78
+ ]
79
+ ]))
80
+ missing_basenames = setsubtract(toset(local.substituted_basenames), toset(local.artifact_basenames))
81
+ unreferenced_artifacts = setsubtract(toset(local.artifact_basenames), toset(local.substituted_basenames))
82
+ }
83
+
84
+ # Validate the recipe and artifact set before uploading or publishing.
85
+ resource "terraform_data" "guard" {
86
+ lifecycle {
87
+ precondition {
88
+ condition = length(local.recipe_files) == 1
89
+ error_message = "Expected exactly one resolved recipe in \"${var.recipes_dir}\" - run the component's \"-artifact\" target first. Found ${length(local.recipe_files)}."
90
+ }
91
+ precondition {
92
+ condition = length(local.artifact_files) >= 1
93
+ error_message = "Expected at least one artifact for ${local.component_name}@${local.component_version} in \"${local.artifact_dir}\" - run the component's \"-artifact\" target first. Found ${length(local.artifact_files)}."
94
+ }
95
+ precondition {
96
+ condition = length(local.missing_basenames) == 0
97
+ error_message = "\"${local.recipe_path}\" references artifact(s) ${join(", ", local.missing_basenames)}, but the files built for ${local.component_name}@${local.component_version} are ${join(", ", local.artifact_basenames)}. Make each recipe artifact Uri end in one of those names."
98
+ }
99
+ precondition {
100
+ condition = length(local.unreferenced_artifacts) == 0
101
+ error_message = "The build produced artifact(s) ${join(", ", local.unreferenced_artifacts)} for ${local.component_name}@${local.component_version} that no manifest references. Add a manifest whose artifact Uri ends in each name, then bump ComponentVersion before re-applying."
102
+ }
103
+ precondition {
104
+ condition = can(regex("^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$", local.component_version))
105
+ error_message = "Terraform requires an explicit ComponentVersion such as 1.0.0; NEXT_PATCH, NEXT_MINOR and NEXT_MAJOR are supported only by CDK. Set ComponentVersion in recipe.yaml, rebuild the artifact, and plan again."
106
+ }
107
+ }
108
+ }
109
+
110
+ # Changed artifact content replaces object keys and deletes the outgoing objects.
111
+ # Retain the publishing module before staged rollouts; see the generator guide.
112
+ resource "aws_s3_object" "artifact" {
113
+ for_each = local.artifact_hashes
114
+
115
+ bucket = var.bucket_name
116
+ key = "${local.destination_key_prefix}${each.key}"
117
+ source = "${local.artifact_dir}/${each.key}"
118
+ source_hash = each.value
119
+
120
+ depends_on = [terraform_data.guard]
121
+
122
+ # Upload the incoming object before deleting the outgoing key.
123
+ lifecycle {
124
+ create_before_destroy = true
125
+ }
126
+ }
127
+
128
+ # Recipe changes replace this immutable version; a reused version with changed
129
+ # content fails creation before the outgoing version is deleted.
130
+ resource "awscc_greengrassv2_component_version" "this" {
131
+ # JSON encoding keeps recipe field types intact.
132
+ inline_recipe = jsonencode(local.substituted_recipe)
133
+
134
+ # Publish only after all artifact uploads complete.
135
+ depends_on = [aws_s3_object.artifact]
136
+
137
+ # Create the new version before deleting the old one. Other fleets may still
138
+ # need the old version and objects; see the guide before a staged rollout.
139
+ lifecycle {
140
+ create_before_destroy = true
141
+ }
142
+ }
143
+
144
+ output "component_name" {
145
+ value = local.component_name
146
+ }
147
+
148
+ output "component_version" {
149
+ # Consumers wait for the published version before revising a deployment.
150
+ value = local.component_version
151
+ depends_on = [awscc_greengrassv2_component_version.this]
152
+ }
153
+
154
+ output "arn" {
155
+ value = awscc_greengrassv2_component_version.this.arn
156
+ }
@@ -0,0 +1,186 @@
1
+ terraform {
2
+ required_providers {
3
+ aws = {
4
+ source = "hashicorp/aws"
5
+ version = "<%- awsProviderVersion %>"
6
+ }
7
+ awscc = {
8
+ source = "hashicorp/awscc"
9
+ version = "<%- awsccProviderVersion %>"
10
+ }
11
+ }
12
+ }
13
+
14
+ variable "thing_group_name" {
15
+ description = "Creates a new aws_iot_thing_group and deploys to it. Mutually exclusive with thing_name and target_arn."
16
+ type = string
17
+ default = null
18
+ }
19
+
20
+ variable "thing_name" {
21
+ description = "Deploys to an existing thing, imported by name (not created). Mutually exclusive with thing_group_name and target_arn."
22
+ type = string
23
+ default = null
24
+ }
25
+
26
+ variable "target_arn" {
27
+ description = "Deploys to an existing thing or thing group, imported by ARN (not created). Mutually exclusive with thing_group_name and thing_name."
28
+ type = string
29
+ default = null
30
+ }
31
+
32
+ variable "parent_target_arn" {
33
+ description = "ARN of the parent deployment, for a subdeployment onto a nested thing group."
34
+ type = string
35
+ default = null
36
+ }
37
+
38
+ variable "deployment_name" {
39
+ type = string
40
+ default = null
41
+ }
42
+
43
+ variable "components" {
44
+ description = "Components to deploy, keyed by ComponentName. `configuration_update.merge`, if set, must already be a JSON-encoded string (matching the awscc schema) - use jsonencode() when building this map."
45
+ type = map(object({
46
+ component_version = optional(string)
47
+ configuration_update = optional(object({
48
+ merge = optional(string)
49
+ reset = optional(list(string))
50
+ }))
51
+ run_with = optional(object({
52
+ posix_user = optional(string)
53
+ windows_user = optional(string)
54
+ system_resource_limits = optional(object({
55
+ cpus = optional(number)
56
+ memory = optional(number)
57
+ }))
58
+ }))
59
+ }))
60
+ default = {}
61
+ }
62
+
63
+ variable "deployment_policies" {
64
+ type = object({
65
+ failure_handling_policy = optional(string)
66
+ component_update_policy = optional(object({
67
+ timeout_in_seconds = optional(number)
68
+ action = optional(string)
69
+ }))
70
+ configuration_validation_policy = optional(object({
71
+ timeout_in_seconds = optional(number)
72
+ }))
73
+ })
74
+ default = null
75
+ }
76
+
77
+ variable "iot_job_configuration" {
78
+ type = any
79
+ default = null
80
+ }
81
+
82
+ variable "tags" {
83
+ type = map(string)
84
+ default = {}
85
+ }
86
+
87
+ data "aws_partition" "current" {}
88
+ data "aws_region" "current" {}
89
+ data "aws_caller_identity" "current" {}
90
+
91
+ locals {
92
+ target_inputs_provided = compact([
93
+ var.thing_group_name != null ? "thing_group_name" : "",
94
+ var.thing_name != null ? "thing_name" : "",
95
+ var.target_arn != null ? "target_arn" : "",
96
+ ])
97
+
98
+ creating_thing_group = var.thing_group_name != null
99
+
100
+ target_arn = (
101
+ var.thing_group_name != null ? aws_iot_thing_group.this[0].arn :
102
+ var.thing_name != null ? "arn:${data.aws_partition.current.partition}:iot:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:thing/${var.thing_name}" :
103
+ var.target_arn
104
+ )
105
+
106
+ # Validate literal target ARNs against this configuration's partition,
107
+ # account and region.
108
+ target_arn_display = var.target_arn != null ? var.target_arn : ""
109
+ target_arn_fields = var.target_arn != null ? split(":", var.target_arn) : []
110
+ target_arn_parsed = length(local.target_arn_fields) > 5
111
+ target_arn_partition = local.target_arn_parsed ? local.target_arn_fields[1] : ""
112
+ target_arn_service = local.target_arn_parsed ? local.target_arn_fields[2] : ""
113
+ target_arn_region = local.target_arn_parsed ? local.target_arn_fields[3] : ""
114
+ target_arn_account = local.target_arn_parsed ? local.target_arn_fields[4] : ""
115
+
116
+ target_arn_mismatches = !local.target_arn_parsed ? [] : compact([
117
+ local.target_arn_service != "iot" ? "service \"${local.target_arn_service}\" is not \"iot\"" : "",
118
+ local.target_arn_partition != "" && local.target_arn_partition != data.aws_partition.current.partition ? "partition \"${local.target_arn_partition}\" does not match \"${data.aws_partition.current.partition}\"" : "",
119
+ local.target_arn_account != "" && local.target_arn_account != data.aws_caller_identity.current.account_id ? "account \"${local.target_arn_account}\" does not match \"${data.aws_caller_identity.current.account_id}\"" : "",
120
+ local.target_arn_region != "" && local.target_arn_region != data.aws_region.current.region ? "region \"${local.target_arn_region}\" does not match \"${data.aws_region.current.region}\"" : "",
121
+ ])
122
+
123
+ # Allow configuration-only entries without a component version.
124
+ next_version_sentinel_components = [
125
+ for component_name, component in var.components : component_name
126
+ if contains(["NEXT_PATCH", "NEXT_MINOR", "NEXT_MAJOR"], component.component_version == null ? "" : component.component_version)
127
+ ]
128
+ }
129
+
130
+ resource "terraform_data" "guard" {
131
+ lifecycle {
132
+ precondition {
133
+ condition = length(local.target_inputs_provided) == 1
134
+ error_message = "greengrass deployment requires exactly one of thing_group_name, thing_name or target_arn, got: ${length(local.target_inputs_provided) == 0 ? "(none)" : join(", ", local.target_inputs_provided)}."
135
+ }
136
+ # Validate before creating the deployment; a module dependency can defer
137
+ # identity reads and this check to apply.
138
+ precondition {
139
+ condition = length(local.target_arn_mismatches) == 0
140
+ error_message = "target_arn \"${local.target_arn_display}\" looks like it belongs to a different environment than this configuration: ${join(", ", local.target_arn_mismatches)}."
141
+ }
142
+ precondition {
143
+ condition = length(local.next_version_sentinel_components) == 0
144
+ error_message = "Component(s) ${join(", ", local.next_version_sentinel_components)} use NEXT_* version markers. Terraform requires explicit versions such as 1.0.0; automatic versioning is supported only by CDK."
145
+ }
146
+ }
147
+ }
148
+
149
+ resource "aws_iot_thing_group" "this" {
150
+ count = local.creating_thing_group ? 1 : 0
151
+ name = var.thing_group_name
152
+ tags = var.tags
153
+
154
+ depends_on = [terraform_data.guard]
155
+ }
156
+
157
+ # Deleting a deployment removes cloud management state; uninstall components
158
+ # through a deployment revision first.
159
+ resource "awscc_greengrassv2_deployment" "this" {
160
+ deployment_name = var.deployment_name
161
+ target_arn = local.target_arn
162
+ parent_target_arn = var.parent_target_arn
163
+ components = var.components
164
+ deployment_policies = var.deployment_policies
165
+ iot_job_configuration = var.iot_job_configuration
166
+ tags = var.tags
167
+
168
+ depends_on = [terraform_data.guard]
169
+
170
+ # Create the new deployment revision before deleting the superseded resource.
171
+ lifecycle {
172
+ create_before_destroy = true
173
+ }
174
+ }
175
+
176
+ output "target_arn" {
177
+ value = local.target_arn
178
+ }
179
+
180
+ output "deployment_id" {
181
+ value = awscc_greengrassv2_deployment.this.deployment_id
182
+ }
183
+
184
+ output "thing_group_arn" {
185
+ value = local.creating_thing_group ? aws_iot_thing_group.this[0].arn : null
186
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { type Tree } from '@nx/devkit';
6
+ import type { DependencyDeclaration, MustDeclare } from '../declared-dependencies.js';
7
+ import type { Iac } from '../iac.js';
8
+ import type { IacMetadata } from '../shared-constructs-constants.js';
9
+ /** CDK recipe parsing and the deploy-time version resolver dependencies. */
10
+ export declare const GREENGRASS_CONSTRUCTS_DEPENDENCIES: readonly [{
11
+ readonly name: "js-yaml";
12
+ readonly when: (m: IacMetadata) => boolean;
13
+ }, {
14
+ readonly name: "@types/js-yaml";
15
+ readonly dev: true;
16
+ readonly when: (m: IacMetadata) => boolean;
17
+ }, {
18
+ readonly name: "@aws-sdk/client-greengrassv2";
19
+ readonly when: (m: IacMetadata) => boolean;
20
+ }];
21
+ /**
22
+ * Vends the shared `GreengrassArtifactBucket` / `GreengrassComponentVersion` /
23
+ * `GreengrassDeployment` / recipe-reader constructs (CDK) or modules
24
+ * (Terraform, via the `hashicorp/awscc` provider - neither
25
+ * `AWS::GreengrassV2::ComponentVersion` nor `AWS::GreengrassV2::Deployment`
26
+ * exists in the pinned `hashicorp/aws` provider) into
27
+ * `common/constructs/src/core/greengrass/` or
28
+ * `common/terraform/src/core/greengrass/`. Existing core files are preserved
29
+ * on later component runs; missing files are added. Idempotent: called from
30
+ * every component generator run.
31
+ */
32
+ export declare const addGreengrassCoreConstructs: <const D extends DependencyDeclaration>(tree: Tree, { iac }: {
33
+ iac: Iac;
34
+ }, declaration: D & MustDeclare<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES, D>) => Promise<void>;
35
+ export interface AddGreengrassComponentAppConstructOptions {
36
+ readonly iac: Iac;
37
+ readonly componentNameClassName: string;
38
+ readonly componentDisplayName: string;
39
+ readonly componentDirName: string;
40
+ readonly project: string;
41
+ /** The host project whose `<c>-artifact` target this construct reads at synth time. */
42
+ readonly hostProjectName: string;
43
+ readonly recipesDirFromRoot: string;
44
+ readonly artifactsDirFromRoot: string;
45
+ }
46
+ /**
47
+ * Vends the per-component app construct/module: a thin
48
+ * `GreengrassComponentVersion` wrapper pinning this component's build output
49
+ * paths, at `common/constructs/src/app/greengrass/<componentDirName>.ts`
50
+ * (CDK) or `common/terraform/src/app/greengrass-component/<componentDirName>/`
51
+ * (Terraform, taking the artifact bucket's name as a plain input variable so
52
+ * user IaC can own or import the shared artifact repository).
53
+ * `OverwriteStrategy.KeepExisting` either way. Registers the host project on
54
+ * the shared iac project's `build`/`assemble` targets so `nx run
55
+ * <infra>:deploy` always deploys a freshly built artifact.
56
+ */
57
+ export declare const addGreengrassComponentAppConstruct: <const D extends DependencyDeclaration>(tree: Tree, options: AddGreengrassComponentAppConstructOptions, declaration: D & MustDeclare<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES, D>) => Promise<void>;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */ import { generateFiles, getProjects, joinPathFragments, logger, OverwriteStrategy, updateJson } from "@nx/devkit";
5
+ import { addStarExport, applyGritQL, matchGritQL } from "../ast.js";
6
+ import { forDependencies } from "../declared-dependencies.js";
7
+ import { addDependenciesToPackageJson } from "../dependencies.js";
8
+ import { buildDefaultComponentName } from "../greengrass/naming.js";
9
+ import { esmVars } from "../module-format.js";
10
+ import { addArtifactProjectToTargets } from "../nx.js";
11
+ import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
12
+ import { cdkLambdaRuntimeVars, terraformProviderVersions, withVersions } from "../versions.js";
13
+ /** CDK recipe parsing and the deploy-time version resolver dependencies. */ export const GREENGRASS_CONSTRUCTS_DEPENDENCIES = [
14
+ {
15
+ name: 'js-yaml',
16
+ when: (m)=>m.iac === 'cdk'
17
+ },
18
+ {
19
+ name: '@types/js-yaml',
20
+ dev: true,
21
+ when: (m)=>m.iac === 'cdk'
22
+ },
23
+ {
24
+ name: '@aws-sdk/client-greengrassv2',
25
+ when: (m)=>m.iac === 'cdk'
26
+ }
27
+ ];
28
+ const CORE_GREENGRASS_DIR = joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'core', 'greengrass');
29
+ const APP_GREENGRASS_DIR = joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'app', 'greengrass');
30
+ const CORE_GREENGRASS_TERRAFORM_DIR = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'core', 'greengrass');
31
+ const APP_GREENGRASS_COMPONENT_TERRAFORM_DIR = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'app', 'greengrass-component');
32
+ /** Add the awscc requirement and default configuration to existing root modules. */ const configureGreengrassTerraformProviders = async (tree)=>{
33
+ const roots = [
34
+ ...getProjects(tree).values()
35
+ ].filter((project)=>project.projectType === 'application').map((project)=>project.sourceRoot ?? joinPathFragments(project.root, 'src')).filter((root)=>tree.children(root).some((name)=>name.endsWith('.tf')));
36
+ if (roots.length === 0) {
37
+ logger.warn('Create a terraform#project application and re-run greengrass#component to configure awscc, ' + 'or declare hashicorp/awscc and provider "awscc" { region = var.aws_region } in your root module.');
38
+ }
39
+ for (const root of roots){
40
+ const paths = tree.children(root).filter((name)=>name.endsWith('.tf')).map((name)=>joinPathFragments(root, name));
41
+ const requirement = `awscc = {
42
+ source = "hashicorp/awscc"
43
+ version = "${terraformProviderVersions().awsccProviderVersion}"
44
+ }`;
45
+ let requirementPath;
46
+ let configured = false;
47
+ for (const path of paths){
48
+ if (await matchGritQL(tree, path, 'language hcl\n`required_providers { $_ }`')) {
49
+ requirementPath ??= path;
50
+ }
51
+ configured ||= await matchGritQL(tree, path, 'language hcl\n`provider "awscc" { $config }` where { $config <: not contains `alias = $_` }');
52
+ }
53
+ if (!requirementPath) {
54
+ requirementPath = joinPathFragments(root, 'greengrass-providers.tf');
55
+ if (tree.exists(requirementPath)) {
56
+ throw new Error(`Cannot add awscc required_providers: ${requirementPath} already exists without a terraform block. Configure awscc in the root module.`);
57
+ }
58
+ tree.write(requirementPath, `terraform {\n required_providers {\n ${requirement}\n }\n}\n`);
59
+ } else {
60
+ const filledEmptyBlock = await applyGritQL(tree, requirementPath, `language hcl\n\`required_providers {}\` => \`required_providers {\n ${requirement}\n }\``);
61
+ if (!filledEmptyBlock) {
62
+ await applyGritQL(tree, requirementPath, 'language hcl\n`required_providers { $providers }` where { ' + '$providers <: not contains `awscc = $_`, ' + `$providers += \`\n ${requirement}\` }`);
63
+ }
64
+ }
65
+ if (!configured) {
66
+ tree.write(requirementPath, `${tree.read(requirementPath, 'utf-8').trimEnd()}\n\nprovider "awscc" {\n region = var.aws_region\n}\n`);
67
+ }
68
+ }
69
+ };
70
+ /** Registers `projectName`'s artifact target on the shared iac project the caller vended into. */ const addArtifactProjectToSharedTargets = (tree, iac, projectName)=>{
71
+ updateJson(tree, joinPathFragments(PACKAGES_DIR, iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR, 'project.json'), (config)=>{
72
+ addArtifactProjectToTargets(config, projectName);
73
+ return config;
74
+ });
75
+ };
76
+ /**
77
+ * Vends the shared `GreengrassArtifactBucket` / `GreengrassComponentVersion` /
78
+ * `GreengrassDeployment` / recipe-reader constructs (CDK) or modules
79
+ * (Terraform, via the `hashicorp/awscc` provider - neither
80
+ * `AWS::GreengrassV2::ComponentVersion` nor `AWS::GreengrassV2::Deployment`
81
+ * exists in the pinned `hashicorp/aws` provider) into
82
+ * `common/constructs/src/core/greengrass/` or
83
+ * `common/terraform/src/core/greengrass/`. Existing core files are preserved
84
+ * on later component runs; missing files are added. Idempotent: called from
85
+ * every component generator run.
86
+ */ export const addGreengrassCoreConstructs = async (tree, { iac }, declaration)=>{
87
+ const componentName = buildDefaultComponentName(tree, 'Namespace');
88
+ const componentKeyPrefix = `${componentName.slice(0, componentName.lastIndexOf('.'))}.*`;
89
+ if (iac === 'terraform') {
90
+ await configureGreengrassTerraformProviders(tree);
91
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'terraform', 'core', 'greengrass'), CORE_GREENGRASS_TERRAFORM_DIR, {
92
+ ...terraformProviderVersions(),
93
+ componentKeyPrefix
94
+ }, {
95
+ overwriteStrategy: OverwriteStrategy.KeepExisting
96
+ });
97
+ return;
98
+ }
99
+ if (iac !== 'cdk') {
100
+ throw new Error(`Unsupported iac ${iac}`);
101
+ }
102
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'cdk', 'core', 'greengrass'), CORE_GREENGRASS_DIR, {
103
+ ...esmVars(tree),
104
+ ...cdkLambdaRuntimeVars(),
105
+ componentKeyPrefix
106
+ }, {
107
+ overwriteStrategy: OverwriteStrategy.KeepExisting
108
+ });
109
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'next-version'), joinPathFragments(CORE_GREENGRASS_DIR, 'next-version'), {
110
+ nextVersionFileName: 'index.js'
111
+ }, {
112
+ overwriteStrategy: OverwriteStrategy.KeepExisting
113
+ });
114
+ await addStarExport(tree, joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'core', 'index.ts'), './greengrass/index.js');
115
+ addDependenciesToPackageJson(tree, withVersions(forDependencies(declaration), [
116
+ 'js-yaml',
117
+ '@aws-sdk/client-greengrassv2'
118
+ ]), withVersions(forDependencies(declaration), [
119
+ '@types/js-yaml'
120
+ ]), joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'package.json'));
121
+ };
122
+ /**
123
+ * Vends the per-component app construct/module: a thin
124
+ * `GreengrassComponentVersion` wrapper pinning this component's build output
125
+ * paths, at `common/constructs/src/app/greengrass/<componentDirName>.ts`
126
+ * (CDK) or `common/terraform/src/app/greengrass-component/<componentDirName>/`
127
+ * (Terraform, taking the artifact bucket's name as a plain input variable so
128
+ * user IaC can own or import the shared artifact repository).
129
+ * `OverwriteStrategy.KeepExisting` either way. Registers the host project on
130
+ * the shared iac project's `build`/`assemble` targets so `nx run
131
+ * <infra>:deploy` always deploys a freshly built artifact.
132
+ */ export const addGreengrassComponentAppConstruct = async (tree, options, declaration)=>{
133
+ await addGreengrassCoreConstructs(tree, {
134
+ iac: options.iac
135
+ }, forDependencies(declaration));
136
+ if (options.iac === 'terraform') {
137
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'terraform', 'app', 'greengrass-component'), APP_GREENGRASS_COMPONENT_TERRAFORM_DIR, options, {
138
+ overwriteStrategy: OverwriteStrategy.KeepExisting
139
+ });
140
+ addArtifactProjectToSharedTargets(tree, 'terraform', options.hostProjectName);
141
+ return;
142
+ }
143
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'cdk', 'app', 'greengrass-component'), APP_GREENGRASS_DIR, {
144
+ ...options,
145
+ ...esmVars(tree)
146
+ }, {
147
+ overwriteStrategy: OverwriteStrategy.KeepExisting
148
+ });
149
+ await addStarExport(tree, joinPathFragments(APP_GREENGRASS_DIR, 'index.ts'), `./${options.componentDirName}.js`);
150
+ await addStarExport(tree, joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'app', 'index.ts'), './greengrass/index.js');
151
+ addArtifactProjectToSharedTargets(tree, 'cdk', options.hostProjectName);
152
+ };
153
+
154
+ //# sourceMappingURL=greengrass-constructs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/greengrass-constructs/greengrass-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n getProjects,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { addStarExport, applyGritQL, matchGritQL } from '../ast.js';\nimport type {\n DependencyDeclaration,\n MustDeclare,\n} from '../declared-dependencies.js';\nimport { forDependencies } from '../declared-dependencies.js';\nimport { addDependenciesToPackageJson } from '../dependencies.js';\nimport { buildDefaultComponentName } from '../greengrass/naming.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport { addArtifactProjectToTargets } from '../nx.js';\nimport type { IacMetadata } from '../shared-constructs-constants.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport {\n cdkLambdaRuntimeVars,\n type ITsDepVersion,\n terraformProviderVersions,\n withVersions,\n} from '../versions.js';\n\n/** CDK recipe parsing and the deploy-time version resolver dependencies. */\nexport const GREENGRASS_CONSTRUCTS_DEPENDENCIES = [\n { name: 'js-yaml', when: (m: IacMetadata) => m.iac === 'cdk' },\n {\n name: '@types/js-yaml',\n dev: true,\n when: (m: IacMetadata) => m.iac === 'cdk',\n },\n {\n name: '@aws-sdk/client-greengrassv2',\n when: (m: IacMetadata) => m.iac === 'cdk',\n },\n] as const satisfies readonly {\n name: ITsDepVersion;\n dev?: boolean;\n root?: boolean;\n when?: (m: IacMetadata) => boolean;\n}[];\n\nconst CORE_GREENGRASS_DIR = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'greengrass',\n);\nconst APP_GREENGRASS_DIR = joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'greengrass',\n);\nconst CORE_GREENGRASS_TERRAFORM_DIR = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'greengrass',\n);\nconst APP_GREENGRASS_COMPONENT_TERRAFORM_DIR = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'greengrass-component',\n);\n/** Add the awscc requirement and default configuration to existing root modules. */\nconst configureGreengrassTerraformProviders = async (\n tree: Tree,\n): Promise<void> => {\n const roots = [...getProjects(tree).values()]\n .filter((project) => project.projectType === 'application')\n .map(\n (project) => project.sourceRoot ?? joinPathFragments(project.root, 'src'),\n )\n .filter((root) => tree.children(root).some((name) => name.endsWith('.tf')));\n if (roots.length === 0) {\n logger.warn(\n 'Create a terraform#project application and re-run greengrass#component to configure awscc, ' +\n 'or declare hashicorp/awscc and provider \"awscc\" { region = var.aws_region } in your root module.',\n );\n }\n for (const root of roots) {\n const paths = tree\n .children(root)\n .filter((name) => name.endsWith('.tf'))\n .map((name) => joinPathFragments(root, name));\n const requirement = `awscc = {\n source = \"hashicorp/awscc\"\n version = \"${terraformProviderVersions().awsccProviderVersion}\"\n }`;\n let requirementPath: string | undefined;\n let configured = false;\n for (const path of paths) {\n if (\n await matchGritQL(\n tree,\n path,\n 'language hcl\\n`required_providers { $_ }`',\n )\n ) {\n requirementPath ??= path;\n }\n configured ||= await matchGritQL(\n tree,\n path,\n 'language hcl\\n`provider \"awscc\" { $config }` where { $config <: not contains `alias = $_` }',\n );\n }\n if (!requirementPath) {\n requirementPath = joinPathFragments(root, 'greengrass-providers.tf');\n if (tree.exists(requirementPath)) {\n throw new Error(\n `Cannot add awscc required_providers: ${requirementPath} already exists without a terraform block. Configure awscc in the root module.`,\n );\n }\n tree.write(\n requirementPath,\n `terraform {\\n required_providers {\\n ${requirement}\\n }\\n}\\n`,\n );\n } else {\n const filledEmptyBlock = await applyGritQL(\n tree,\n requirementPath,\n `language hcl\\n\\`required_providers {}\\` => \\`required_providers {\\n ${requirement}\\n }\\``,\n );\n if (!filledEmptyBlock) {\n await applyGritQL(\n tree,\n requirementPath,\n 'language hcl\\n`required_providers { $providers }` where { ' +\n '$providers <: not contains `awscc = $_`, ' +\n `$providers += \\`\\n ${requirement}\\` }`,\n );\n }\n }\n if (!configured) {\n tree.write(\n requirementPath,\n `${tree.read(requirementPath, 'utf-8')!.trimEnd()}\\n\\nprovider \"awscc\" {\\n region = var.aws_region\\n}\\n`,\n );\n }\n }\n};\n\n/** Registers `projectName`'s artifact target on the shared iac project the caller vended into. */\nconst addArtifactProjectToSharedTargets = (\n tree: Tree,\n iac: Iac,\n projectName: string,\n): void => {\n updateJson(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR,\n 'project.json',\n ),\n (config: ProjectConfiguration) => {\n addArtifactProjectToTargets(config, projectName);\n return config;\n },\n );\n};\n\n/**\n * Vends the shared `GreengrassArtifactBucket` / `GreengrassComponentVersion` /\n * `GreengrassDeployment` / recipe-reader constructs (CDK) or modules\n * (Terraform, via the `hashicorp/awscc` provider - neither\n * `AWS::GreengrassV2::ComponentVersion` nor `AWS::GreengrassV2::Deployment`\n * exists in the pinned `hashicorp/aws` provider) into\n * `common/constructs/src/core/greengrass/` or\n * `common/terraform/src/core/greengrass/`. Existing core files are preserved\n * on later component runs; missing files are added. Idempotent: called from\n * every component generator run.\n */\nexport const addGreengrassCoreConstructs = async <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n { iac }: { iac: Iac },\n declaration: D & MustDeclare<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES, D>,\n): Promise<void> => {\n const componentName = buildDefaultComponentName(tree, 'Namespace');\n const componentKeyPrefix = `${componentName.slice(0, componentName.lastIndexOf('.'))}.*`;\n if (iac === 'terraform') {\n await configureGreengrassTerraformProviders(tree);\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'core',\n 'greengrass',\n ),\n CORE_GREENGRASS_TERRAFORM_DIR,\n { ...terraformProviderVersions(), componentKeyPrefix },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n return;\n }\n if (iac !== 'cdk') {\n throw new Error(`Unsupported iac ${iac}`);\n }\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'core',\n 'greengrass',\n ),\n CORE_GREENGRASS_DIR,\n { ...esmVars(tree), ...cdkLambdaRuntimeVars(), componentKeyPrefix },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'next-version'),\n joinPathFragments(CORE_GREENGRASS_DIR, 'next-version'),\n { nextVersionFileName: 'index.js' },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'index.ts',\n ),\n './greengrass/index.js',\n );\n\n addDependenciesToPackageJson(\n tree,\n withVersions(\n forDependencies<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['js-yaml', '@aws-sdk/client-greengrassv2'],\n ),\n withVersions(\n forDependencies<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['@types/js-yaml'],\n ),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'package.json'),\n );\n};\n\nexport interface AddGreengrassComponentAppConstructOptions {\n readonly iac: Iac;\n readonly componentNameClassName: string;\n readonly componentDisplayName: string;\n readonly componentDirName: string;\n readonly project: string;\n /** The host project whose `<c>-artifact` target this construct reads at synth time. */\n readonly hostProjectName: string;\n readonly recipesDirFromRoot: string;\n readonly artifactsDirFromRoot: string;\n}\n\n/**\n * Vends the per-component app construct/module: a thin\n * `GreengrassComponentVersion` wrapper pinning this component's build output\n * paths, at `common/constructs/src/app/greengrass/<componentDirName>.ts`\n * (CDK) or `common/terraform/src/app/greengrass-component/<componentDirName>/`\n * (Terraform, taking the artifact bucket's name as a plain input variable so\n * user IaC can own or import the shared artifact repository).\n * `OverwriteStrategy.KeepExisting` either way. Registers the host project on\n * the shared iac project's `build`/`assemble` targets so `nx run\n * <infra>:deploy` always deploys a freshly built artifact.\n */\nexport const addGreengrassComponentAppConstruct = async <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n options: AddGreengrassComponentAppConstructOptions,\n declaration: D & MustDeclare<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES, D>,\n): Promise<void> => {\n await addGreengrassCoreConstructs(\n tree,\n { iac: options.iac },\n forDependencies<typeof GREENGRASS_CONSTRUCTS_DEPENDENCIES>(declaration),\n );\n\n if (options.iac === 'terraform') {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'greengrass-component',\n ),\n APP_GREENGRASS_COMPONENT_TERRAFORM_DIR,\n options,\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n addArtifactProjectToSharedTargets(\n tree,\n 'terraform',\n options.hostProjectName,\n );\n return;\n }\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'greengrass-component',\n ),\n APP_GREENGRASS_DIR,\n { ...options, ...esmVars(tree) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(APP_GREENGRASS_DIR, 'index.ts'),\n `./${options.componentDirName}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n './greengrass/index.js',\n );\n\n addArtifactProjectToSharedTargets(tree, 'cdk', options.hostProjectName);\n};\n"],"names":["generateFiles","getProjects","joinPathFragments","logger","OverwriteStrategy","updateJson","addStarExport","applyGritQL","matchGritQL","forDependencies","addDependenciesToPackageJson","buildDefaultComponentName","esmVars","addArtifactProjectToTargets","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","cdkLambdaRuntimeVars","terraformProviderVersions","withVersions","GREENGRASS_CONSTRUCTS_DEPENDENCIES","name","when","m","iac","dev","CORE_GREENGRASS_DIR","APP_GREENGRASS_DIR","CORE_GREENGRASS_TERRAFORM_DIR","APP_GREENGRASS_COMPONENT_TERRAFORM_DIR","configureGreengrassTerraformProviders","tree","roots","values","filter","project","projectType","map","sourceRoot","root","children","some","endsWith","length","warn","paths","requirement","awsccProviderVersion","requirementPath","configured","path","exists","Error","write","filledEmptyBlock","read","trimEnd","addArtifactProjectToSharedTargets","projectName","config","addGreengrassCoreConstructs","declaration","componentName","componentKeyPrefix","slice","lastIndexOf","dirname","overwriteStrategy","KeepExisting","nextVersionFileName","addGreengrassComponentAppConstruct","options","hostProjectName","componentDirName"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,WAAW,EACXC,iBAAiB,EACjBC,MAAM,EACNC,iBAAiB,EAGjBC,UAAU,QACL,aAAa;AACpB,SAASC,aAAa,EAAEC,WAAW,EAAEC,WAAW,QAAQ,YAAY;AAKpE,SAASC,eAAe,QAAQ,8BAA8B;AAC9D,SAASC,4BAA4B,QAAQ,qBAAqB;AAClE,SAASC,yBAAyB,QAAQ,0BAA0B;AAEpE,SAASC,OAAO,QAAQ,sBAAsB;AAC9C,SAASC,2BAA2B,QAAQ,WAAW;AAEvD,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAC3C,SACEC,oBAAoB,EAEpBC,yBAAyB,EACzBC,YAAY,QACP,iBAAiB;AAExB,0EAA0E,GAC1E,OAAO,MAAMC,qCAAqC;IAChD;QAAEC,MAAM;QAAWC,MAAM,CAACC,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IAC7D;QACEH,MAAM;QACNI,KAAK;QACLH,MAAM,CAACC,IAAmBA,EAAEC,GAAG,KAAK;IACtC;IACA;QACEH,MAAM;QACNC,MAAM,CAACC,IAAmBA,EAAEC,GAAG,KAAK;IACtC;CACD,CAKG;AAEJ,MAAME,sBAAsBxB,kBAC1BY,cACAC,uBACA,OACA,QACA;AAEF,MAAMY,qBAAqBzB,kBACzBY,cACAC,uBACA,OACA,OACA;AAEF,MAAMa,gCAAgC1B,kBACpCY,cACAE,sBACA,OACA,QACA;AAEF,MAAMa,yCAAyC3B,kBAC7CY,cACAE,sBACA,OACA,OACA;AAEF,kFAAkF,GAClF,MAAMc,wCAAwC,OAC5CC;IAEA,MAAMC,QAAQ;WAAI/B,YAAY8B,MAAME,MAAM;KAAG,CAC1CC,MAAM,CAAC,CAACC,UAAYA,QAAQC,WAAW,KAAK,eAC5CC,GAAG,CACF,CAACF,UAAYA,QAAQG,UAAU,IAAIpC,kBAAkBiC,QAAQI,IAAI,EAAE,QAEpEL,MAAM,CAAC,CAACK,OAASR,KAAKS,QAAQ,CAACD,MAAME,IAAI,CAAC,CAACpB,OAASA,KAAKqB,QAAQ,CAAC;IACrE,IAAIV,MAAMW,MAAM,KAAK,GAAG;QACtBxC,OAAOyC,IAAI,CACT,gGACE;IAEN;IACA,KAAK,MAAML,QAAQP,MAAO;QACxB,MAAMa,QAAQd,KACXS,QAAQ,CAACD,MACTL,MAAM,CAAC,CAACb,OAASA,KAAKqB,QAAQ,CAAC,QAC/BL,GAAG,CAAC,CAAChB,OAASnB,kBAAkBqC,MAAMlB;QACzC,MAAMyB,cAAc,CAAC;;iBAER,EAAE5B,4BAA4B6B,oBAAoB,CAAC;KAC/D,CAAC;QACF,IAAIC;QACJ,IAAIC,aAAa;QACjB,KAAK,MAAMC,QAAQL,MAAO;YACxB,IACE,MAAMrC,YACJuB,MACAmB,MACA,8CAEF;gBACAF,oBAAoBE;YACtB;YACAD,eAAe,MAAMzC,YACnBuB,MACAmB,MACA;QAEJ;QACA,IAAI,CAACF,iBAAiB;YACpBA,kBAAkB9C,kBAAkBqC,MAAM;YAC1C,IAAIR,KAAKoB,MAAM,CAACH,kBAAkB;gBAChC,MAAM,IAAII,MACR,CAAC,qCAAqC,EAAEJ,gBAAgB,8EAA8E,CAAC;YAE3I;YACAjB,KAAKsB,KAAK,CACRL,iBACA,CAAC,yCAAyC,EAAEF,YAAY,UAAU,CAAC;QAEvE,OAAO;YACL,MAAMQ,mBAAmB,MAAM/C,YAC7BwB,MACAiB,iBACA,CAAC,uEAAuE,EAAEF,YAAY,OAAO,CAAC;YAEhG,IAAI,CAACQ,kBAAkB;gBACrB,MAAM/C,YACJwB,MACAiB,iBACA,+DACE,8CACA,CAAC,sBAAsB,EAAEF,YAAY,IAAI,CAAC;YAEhD;QACF;QACA,IAAI,CAACG,YAAY;YACflB,KAAKsB,KAAK,CACRL,iBACA,GAAGjB,KAAKwB,IAAI,CAACP,iBAAiB,SAAUQ,OAAO,GAAG,sDAAsD,CAAC;QAE7G;IACF;AACF;AAEA,gGAAgG,GAChG,MAAMC,oCAAoC,CACxC1B,MACAP,KACAkC;IAEArD,WACE0B,MACA7B,kBACEY,cACAU,QAAQ,QAAQT,wBAAwBC,sBACxC,iBAEF,CAAC2C;QACC9C,4BAA4B8C,QAAQD;QACpC,OAAOC;IACT;AAEJ;AAEA;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,8BAA8B,OAGzC7B,MACA,EAAEP,GAAG,EAAgB,EACrBqC;IAEA,MAAMC,gBAAgBnD,0BAA0BoB,MAAM;IACtD,MAAMgC,qBAAqB,GAAGD,cAAcE,KAAK,CAAC,GAAGF,cAAcG,WAAW,CAAC,MAAM,EAAE,CAAC;IACxF,IAAIzC,QAAQ,aAAa;QACvB,MAAMM,sCAAsCC;QAC5C/B,cACE+B,MACA7B,kBACE,YAAYgE,OAAO,EACnB,SACA,aACA,QACA,eAEFtC,+BACA;YAAE,GAAGV,2BAA2B;YAAE6C;QAAmB,GACrD;YAAEI,mBAAmB/D,kBAAkBgE,YAAY;QAAC;QAEtD;IACF;IACA,IAAI5C,QAAQ,OAAO;QACjB,MAAM,IAAI4B,MAAM,CAAC,gBAAgB,EAAE5B,KAAK;IAC1C;IAEAxB,cACE+B,MACA7B,kBACE,YAAYgE,OAAO,EACnB,SACA,OACA,QACA,eAEFxC,qBACA;QAAE,GAAGd,QAAQmB,KAAK;QAAE,GAAGd,sBAAsB;QAAE8C;IAAmB,GAClE;QAAEI,mBAAmB/D,kBAAkBgE,YAAY;IAAC;IAEtDpE,cACE+B,MACA7B,kBAAkB,YAAYgE,OAAO,EAAE,SAAS,iBAChDhE,kBAAkBwB,qBAAqB,iBACvC;QAAE2C,qBAAqB;IAAW,GAClC;QAAEF,mBAAmB/D,kBAAkBgE,YAAY;IAAC;IAGtD,MAAM9D,cACJyB,MACA7B,kBACEY,cACAC,uBACA,OACA,QACA,aAEF;IAGFL,6BACEqB,MACAZ,aACEV,gBAA2DoD,cAC3D;QAAC;QAAW;KAA+B,GAE7C1C,aACEV,gBAA2DoD,cAC3D;QAAC;KAAiB,GAEpB3D,kBAAkBY,cAAcC,uBAAuB;AAE3D,EAAE;AAcF;;;;;;;;;;CAUC,GACD,OAAO,MAAMuD,qCAAqC,OAGhDvC,MACAwC,SACAV;IAEA,MAAMD,4BACJ7B,MACA;QAAEP,KAAK+C,QAAQ/C,GAAG;IAAC,GACnBf,gBAA2DoD;IAG7D,IAAIU,QAAQ/C,GAAG,KAAK,aAAa;QAC/BxB,cACE+B,MACA7B,kBACE,YAAYgE,OAAO,EACnB,SACA,aACA,OACA,yBAEFrC,wCACA0C,SACA;YAAEJ,mBAAmB/D,kBAAkBgE,YAAY;QAAC;QAEtDX,kCACE1B,MACA,aACAwC,QAAQC,eAAe;QAEzB;IACF;IAEAxE,cACE+B,MACA7B,kBACE,YAAYgE,OAAO,EACnB,SACA,OACA,OACA,yBAEFvC,oBACA;QAAE,GAAG4C,OAAO;QAAE,GAAG3D,QAAQmB,KAAK;IAAC,GAC/B;QAAEoC,mBAAmB/D,kBAAkBgE,YAAY;IAAC;IAGtD,MAAM9D,cACJyB,MACA7B,kBAAkByB,oBAAoB,aACtC,CAAC,EAAE,EAAE4C,QAAQE,gBAAgB,CAAC,GAAG,CAAC;IAEpC,MAAMnE,cACJyB,MACA7B,kBACEY,cACAC,uBACA,OACA,OACA,aAEF;IAGF0C,kCAAkC1B,MAAM,OAAOwC,QAAQC,eAAe;AACxE,EAAE"}
package/src/utils/nx.d.ts CHANGED
@@ -86,6 +86,21 @@ export declare const addComponentGeneratorMetadata: (tree: Tree, projectName: st
86
86
  }, componentPath: string, componentName?: string, additionalMetadata?: {
87
87
  [key: string]: any;
88
88
  }) => void;
89
+ /**
90
+ * Merge `patch` into the component metadata entry matched on generator id and
91
+ * name, leaving every other recorded value alone. A no-op when no entry matches
92
+ * or when the patch changes nothing.
93
+ *
94
+ * `addComponentGeneratorMetadata` leaves an existing entry untouched, so a
95
+ * generator whose options may legitimately change between runs pairs the two:
96
+ * the add records a first run, this converges the values a later run resolved
97
+ * differently.
98
+ */
99
+ export declare const updateComponentGeneratorMetadata: (tree: Tree, projectName: string, info: {
100
+ id: string;
101
+ }, componentName: string | undefined, patch: {
102
+ [key: string]: any;
103
+ }) => void;
89
104
  /**
90
105
  * Merge a generator's own config into an `nx.json` `targetDefaults` value,
91
106
  * preserving whatever the workspace already had. `apply` receives the config to
package/src/utils/nx.js CHANGED
@@ -139,6 +139,38 @@ export const getPackageVersion = ()=>{
139
139
  });
140
140
  }
141
141
  };
142
+ /**
143
+ * Merge `patch` into the component metadata entry matched on generator id and
144
+ * name, leaving every other recorded value alone. A no-op when no entry matches
145
+ * or when the patch changes nothing.
146
+ *
147
+ * `addComponentGeneratorMetadata` leaves an existing entry untouched, so a
148
+ * generator whose options may legitimately change between runs pairs the two:
149
+ * the add records a first run, this converges the values a later run resolved
150
+ * differently.
151
+ */ export const updateComponentGeneratorMetadata = (tree, projectName, info, componentName, patch)=>{
152
+ const config = readProjectConfigurationUnqualified(tree, projectName);
153
+ const existingComponents = config?.metadata?.components ?? [];
154
+ const updated = existingComponents.map((component)=>component.generator === info.id && component.name === componentName ? {
155
+ ...component,
156
+ ...patch
157
+ } : component);
158
+ if (JSON.stringify(updated) === JSON.stringify(existingComponents)) {
159
+ return;
160
+ }
161
+ // Place metadata before targets for a stable serialized key order.
162
+ const { targets, ...rest } = config;
163
+ updateProjectConfiguration(tree, config.name, {
164
+ ...rest,
165
+ metadata: {
166
+ ...config?.metadata,
167
+ components: updated
168
+ },
169
+ ...targets ? {
170
+ targets
171
+ } : {}
172
+ });
173
+ };
142
174
  /**
143
175
  * Merge a generator's own config into an `nx.json` `targetDefaults` value,
144
176
  * preserving whatever the workspace already had. `apply` receives the config to