@aws/nx-plugin 1.0.0-rc.84 → 1.0.0-rc.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/generators.json +7 -0
  2. package/migrations.json +6 -1
  3. package/package.json +1 -1
  4. package/src/internal/test-matrix/generator.js +16 -0
  5. package/src/internal/test-matrix/generator.js.map +1 -1
  6. package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/metadata.json +3 -0
  7. package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.d.ts +6 -0
  8. package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.js +146 -0
  9. package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.js.map +1 -0
  10. package/src/open-api/json-metadata/generator.d.ts +24 -0
  11. package/src/open-api/json-metadata/generator.js +37 -0
  12. package/src/open-api/json-metadata/generator.js.map +1 -0
  13. package/src/open-api/json-metadata/schema.d.js +6 -0
  14. package/src/open-api/json-metadata/schema.d.js.map +1 -0
  15. package/src/open-api/json-metadata/schema.d.ts +9 -0
  16. package/src/open-api/json-metadata/schema.json +20 -0
  17. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +1604 -559
  18. package/src/py/fast-api/generator.js +2 -1
  19. package/src/py/fast-api/generator.js.map +1 -1
  20. package/src/sdk/open-api.d.ts +2 -0
  21. package/src/sdk/open-api.js +2 -1
  22. package/src/sdk/open-api.js.map +1 -1
  23. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1548 -440
  24. package/src/smithy/ts/api/generator.js +2 -1
  25. package/src/smithy/ts/api/generator.js.map +1 -1
  26. package/src/terraform/project/files/application/bootstrap/providers.tf.template +2 -0
  27. package/src/terraform/project/files/application/scripts/bootstrap-destroy.ts.template +111 -0
  28. package/src/terraform/project/files/application/src/providers.tf.template +2 -0
  29. package/src/terraform/project/files/checkov/checkov.yml.template +8 -0
  30. package/src/terraform/project/generator.js +47 -4
  31. package/src/terraform/project/generator.js.map +1 -1
  32. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +1552 -525
  33. package/src/trpc/backend/files-operations/scripts/generate-operations.ts.template +40 -0
  34. package/src/trpc/backend/generator.js +10 -0
  35. package/src/trpc/backend/generator.js.map +1 -1
  36. package/src/utils/api-constructs/api-constructs.js +11 -0
  37. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  38. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +243 -3
  39. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +428 -1
  40. package/src/utils/api-constructs/open-api-metadata.d.ts +20 -3
  41. package/src/utils/api-constructs/open-api-metadata.js +64 -8
  42. package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
  43. package/src/utils/api-constructs/trpc-operations-metadata.d.ts +21 -0
  44. package/src/utils/api-constructs/trpc-operations-metadata.js +55 -0
  45. package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -0
@@ -168,7 +168,8 @@ export const tsSmithyApiGenerator = async (tree, options)=>{
168
168
  iac,
169
169
  apiNameKebabCase,
170
170
  specPath: joinPathFragments('dist', modelProjectConfig.root, 'build', 'openapi', 'openapi.json'),
171
- specBuildTargetName: `${modelProjectConfig.name}:build`
171
+ specBuildTargetName: `${modelProjectConfig.name}:build`,
172
+ integrationPattern
172
173
  });
173
174
  // Add bundle target using rolldown
174
175
  await addTypeScriptBundleTarget(tree, backendProjectConfig, {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/smithy/ts/api/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport tsProjectGenerator, {\n getTsLibDetails,\n} from '../../../ts/lib/generator.js';\nimport { addTsDependencies } from '../../../utils/add-dependencies.js';\nimport {\n API_CONSTRUCTS_DEPENDENCIES,\n API_CONSTRUCTS_PY_DEPENDENCIES,\n addApiGatewayInfra,\n} from '../../../utils/api-constructs/api-constructs.js';\nimport { addSharedConstructsOpenApiMetadataGenerateTarget } from '../../../utils/api-constructs/open-api-metadata.js';\nimport {\n addTypeScriptBundleTarget,\n BUNDLE_DEPENDENCIES,\n} from '../../../utils/bundle/bundle.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../../utils/fs.js';\nimport { updateGitIgnore } from '../../../utils/git.js';\nimport { resolveIac } from '../../../utils/iac.js';\nimport { installDependencies } from '../../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars } from '../../../utils/module-format.js';\nimport { toClassName, toKebabCase } from '../../../utils/names.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { assignPort } from '../../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../../utils/shared-constructs-constants.js';\nimport smithyProjectGenerator from '../../project/generator.js';\nimport type { TsSmithyApiGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface TsSmithyApiMetadata extends IacMetadata {\n readonly apiName: string;\n readonly auth: TsSmithyApiGeneratorSchema['auth'];\n readonly modelProject: string;\n}\n\n// Each entry names the branch it belongs to, so the same declaration drives both\n// adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<TsSmithyApiMetadata>()({\n ts: [\n { name: '@smithy/server-apigateway' },\n { name: '@smithy/server-node' },\n { name: '@middy/core' },\n { name: '@aws-lambda-powertools/logger' },\n { name: '@aws-lambda-powertools/parameters' },\n { name: '@aws-lambda-powertools/tracer' },\n { name: '@aws-lambda-powertools/metrics' },\n { name: '@aws-sdk/client-appconfigdata' },\n // The custom authorizer handler parses its event.\n { name: '@aws-lambda-powertools/parser', when: (m) => m.auth === 'custom' },\n { name: '@types/aws-lambda', dev: true },\n // tsx runs the local server from the workspace root.\n { name: 'tsx', dev: true, root: true },\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(API_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(BUNDLE_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: ownedElsewhere(API_CONSTRUCTS_PY_DEPENDENCIES),\n});\n\nexport const TS_SMITHY_API_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const tsSmithyApiGenerator = async (\n tree: Tree,\n options: TsSmithyApiGeneratorSchema,\n): Promise<GeneratorCallback> => {\n if (\n (options.infra as string) !== 'rest-lambda' &&\n (options.infra as string) !== 'none'\n ) {\n throw new Error(\n `Unsupported infra '${options.infra}' for Smithy TypeScript API. ` +\n `Only 'rest-lambda' (API Gateway REST API) is supported.`,\n );\n }\n\n const integrationPattern = getIntegrationPattern(options);\n const apiNameClassName = toClassName(options.name);\n const apiNameKebabCase = toKebabCase(options.name);\n const { fullyQualifiedName: backendFullyQualifiedName, dir } =\n getTsLibDetails(tree, options);\n const modelProjectName = `${apiNameKebabCase}-model`;\n\n let projectExists: boolean;\n try {\n readProjectConfigurationUnqualified(tree, backendFullyQualifiedName);\n projectExists = true;\n } catch {\n projectExists = false;\n }\n\n if (!projectExists) {\n // Generate the model project\n await smithyProjectGenerator(tree, {\n name: modelProjectName,\n serviceName: apiNameClassName,\n namespace: options.namespace,\n directory: dir,\n subDirectory: 'model',\n preferInstallDependencies: false,\n });\n\n // Generate the backend project\n await tsProjectGenerator(tree, {\n name: options.name,\n directory: dir,\n subDirectory: 'backend',\n preferInstallDependencies: false,\n });\n }\n\n // Add metadata to associate backend project with model project\n const modelProjectConfig = readProjectConfigurationUnqualified(\n tree,\n modelProjectName,\n );\n updateProjectConfiguration(tree, modelProjectConfig.name, {\n ...modelProjectConfig,\n metadata: {\n ...modelProjectConfig.metadata,\n backendProject: backendFullyQualifiedName,\n } as any,\n });\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded here and read by the declaration's predicates, so the packages\n // added below are exactly the ones the version sync will own.\n const metadata: TsSmithyApiMetadata = {\n apiName: options.name,\n auth: options.auth,\n modelProject: modelProjectConfig.name,\n ...(iac ? { iac } : {}),\n };\n\n addGeneratorMetadata(\n tree,\n backendFullyQualifiedName,\n TS_SMITHY_API_GENERATOR_INFO,\n metadata,\n );\n\n const backendProjectConfig = readProjectConfigurationUnqualified(\n tree,\n backendFullyQualifiedName,\n );\n const port = assignPort(tree, backendProjectConfig, 3001);\n\n // Delete default index.ts with \"hello\" function\n tree.delete(joinPathFragments(backendProjectConfig.sourceRoot, 'index.ts'));\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n backendProjectConfig.sourceRoot,\n {\n apiNameClassName,\n port,\n ...esmVars(tree),\n },\n );\n\n if (options.infra !== 'none') {\n if (options.auth === 'custom') {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n '..',\n '..',\n '..',\n 'utils',\n 'api-constructs',\n 'files',\n 'cdk',\n 'authorizer',\n 'rest',\n ),\n backendProjectConfig.sourceRoot,\n {},\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n }\n\n // Add infrastructure\n await sharedConstructsGenerator(\n tree,\n {\n iac,\n },\n DEPENDENCIES,\n );\n await addApiGatewayInfra(\n tree,\n {\n iac,\n apiProjectName: backendFullyQualifiedName,\n apiNameClassName,\n apiNameKebabCase,\n auth: options.auth,\n constructType: 'rest',\n backend: {\n type: 'smithy',\n bundleOutputDir: joinPathFragments(\n 'dist',\n backendProjectConfig.root,\n 'bundle',\n ),\n integrationPattern,\n ...(options.auth === 'custom' && {\n authorizerBundleOutputDir: joinPathFragments(\n 'dist',\n backendProjectConfig.root,\n 'bundle',\n 'authorizer',\n ),\n }),\n },\n },\n DEPENDENCIES,\n );\n addSharedConstructsOpenApiMetadataGenerateTarget(tree, {\n iac,\n apiNameKebabCase,\n specPath: joinPathFragments(\n 'dist',\n modelProjectConfig.root,\n 'build',\n 'openapi',\n 'openapi.json',\n ),\n specBuildTargetName: `${modelProjectConfig.name}:build`,\n });\n\n // Add bundle target using rolldown\n await addTypeScriptBundleTarget(\n tree,\n backendProjectConfig,\n {\n targetFilePath: 'src/handler.ts',\n external: [/@aws-sdk\\/.*/], // lambda runtime provides aws sdk\n },\n DEPENDENCIES,\n );\n\n if (options.auth === 'custom') {\n await addTypeScriptBundleTarget(\n tree,\n backendProjectConfig,\n {\n targetFilePath: 'src/authorizer.ts',\n bundleOutputDir: 'authorizer',\n external: [/@aws-sdk\\/.*/],\n },\n DEPENDENCIES,\n );\n }\n }\n\n const cmd = new FsCommands(tree, DEPENDENCIES);\n const generatedSrcDirFromRoot = '{projectRoot}/src/generated';\n\n // Target for copying the ssdk built by the model\n backendProjectConfig.targets['copy-ssdk'] = {\n cache: true,\n inputs: [\n {\n dependentTasksOutputFiles: '**/*',\n },\n ],\n executor: 'nx:run-commands',\n options: {\n commands: [\n cmd.rm(generatedSrcDirFromRoot),\n cmd.mkdir(generatedSrcDirFromRoot),\n cmd.cp(\n joinPathFragments('dist', modelProjectConfig.root, 'build', 'ssdk'),\n joinPathFragments(generatedSrcDirFromRoot, 'ssdk'),\n ),\n ],\n parallel: false,\n },\n outputs: ['{projectRoot}/src/generated'],\n dependsOn: [`${modelProjectConfig.name}:build`],\n };\n addDependencyToTargetIfNotPresent(\n backendProjectConfig,\n 'compile',\n 'copy-ssdk',\n );\n\n // Add a project which continuously copies based on changes to the model project\n // This allows the \"serve\" target to hot reload when the smithy model is changed\n backendProjectConfig.targets['watch-copy-ssdk'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `nx watch --projects=${modelProjectConfig.name} --includeDependencies -- nx run ${backendFullyQualifiedName}:copy-ssdk`,\n },\n };\n\n // Add serve target for running the server locally\n backendProjectConfig.targets.serve = normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n continuous: true,\n dependsOn: ['copy-ssdk', 'watch-copy-ssdk'],\n options: {\n command: 'tsx --watch src/local-server.ts',\n cwd: '{projectRoot}',\n },\n });\n\n const existingDevDependsOn =\n backendProjectConfig.targets['dev']?.dependsOn ?? [];\n\n backendProjectConfig.targets['dev'] = normalizeTargetKeyOrder({\n ...backendProjectConfig.targets.serve,\n // Own copy of dependsOn so adding dev dependencies below doesn't\n // mutate the shared array referenced by the serve target.\n dependsOn: [...(backendProjectConfig.targets.serve.dependsOn ?? [])],\n options: {\n ...backendProjectConfig.targets.serve.options,\n env: {\n LOCAL_DEV: 'true',\n },\n },\n });\n\n // Preserve any dependencies added to dev by connection generators\n for (const dependency of existingDevDependsOn) {\n addDependencyToTargetIfNotPresent(backendProjectConfig, 'dev', dependency);\n }\n\n // Ignore generated code\n updateGitIgnore(tree, backendProjectConfig.root, (patterns) => [\n ...patterns,\n 'src/generated',\n ]);\n\n updateProjectConfiguration(\n tree,\n backendFullyQualifiedName,\n backendProjectConfig,\n );\n\n addTsDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: backendProjectConfig.root,\n });\n\n await addGeneratorMetricsIfApplicable(tree, [TS_SMITHY_API_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nconst getIntegrationPattern = (\n options: TsSmithyApiGeneratorSchema,\n): 'isolated' | 'shared' => options.integrationPattern ?? 'isolated';\n\nexport default tsSmithyApiGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","tsProjectGenerator","getTsLibDetails","addTsDependencies","API_CONSTRUCTS_DEPENDENCIES","API_CONSTRUCTS_PY_DEPENDENCIES","addApiGatewayInfra","addSharedConstructsOpenApiMetadataGenerateTarget","addTypeScriptBundleTarget","BUNDLE_DEPENDENCIES","declareDependencies","ownedElsewhere","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","esmVars","toClassName","toKebabCase","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","smithyProjectGenerator","DEPENDENCIES","ts","name","when","m","auth","dev","root","py","TS_SMITHY_API_GENERATOR_INFO","filename","tsSmithyApiGenerator","tree","options","infra","Error","integrationPattern","getIntegrationPattern","apiNameClassName","apiNameKebabCase","fullyQualifiedName","backendFullyQualifiedName","dir","modelProjectName","projectExists","serviceName","namespace","directory","subDirectory","preferInstallDependencies","modelProjectConfig","metadata","backendProject","iac","undefined","apiName","modelProject","backendProjectConfig","port","delete","sourceRoot","dirname","overwriteStrategy","KeepExisting","apiProjectName","constructType","backend","type","bundleOutputDir","authorizerBundleOutputDir","specPath","specBuildTargetName","targetFilePath","external","cmd","generatedSrcDirFromRoot","targets","cache","inputs","dependentTasksOutputFiles","executor","commands","rm","mkdir","cp","parallel","outputs","dependsOn","continuous","command","serve","cwd","existingDevDependsOn","env","LOCAL_DEV","dependency","patterns","projectRoot","languages"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../packages/nx-plugin/src/smithy/ts/api/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport tsProjectGenerator, {\n getTsLibDetails,\n} from '../../../ts/lib/generator.js';\nimport { addTsDependencies } from '../../../utils/add-dependencies.js';\nimport {\n API_CONSTRUCTS_DEPENDENCIES,\n API_CONSTRUCTS_PY_DEPENDENCIES,\n addApiGatewayInfra,\n} from '../../../utils/api-constructs/api-constructs.js';\nimport { addSharedConstructsOpenApiMetadataGenerateTarget } from '../../../utils/api-constructs/open-api-metadata.js';\nimport {\n addTypeScriptBundleTarget,\n BUNDLE_DEPENDENCIES,\n} from '../../../utils/bundle/bundle.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../../utils/fs.js';\nimport { updateGitIgnore } from '../../../utils/git.js';\nimport { resolveIac } from '../../../utils/iac.js';\nimport { installDependencies } from '../../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../../utils/metrics.js';\nimport { esmVars } from '../../../utils/module-format.js';\nimport { toClassName, toKebabCase } from '../../../utils/names.js';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n normalizeTargetKeyOrder,\n readProjectConfigurationUnqualified,\n} from '../../../utils/nx.js';\nimport { assignPort } from '../../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../../utils/shared-constructs-constants.js';\nimport smithyProjectGenerator from '../../project/generator.js';\nimport type { TsSmithyApiGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface TsSmithyApiMetadata extends IacMetadata {\n readonly apiName: string;\n readonly auth: TsSmithyApiGeneratorSchema['auth'];\n readonly modelProject: string;\n}\n\n// Each entry names the branch it belongs to, so the same declaration drives both\n// adding and the version sync.\nexport const DEPENDENCIES = declareDependencies<TsSmithyApiMetadata>()({\n ts: [\n { name: '@smithy/server-apigateway' },\n { name: '@smithy/server-node' },\n { name: '@middy/core' },\n { name: '@aws-lambda-powertools/logger' },\n { name: '@aws-lambda-powertools/parameters' },\n { name: '@aws-lambda-powertools/tracer' },\n { name: '@aws-lambda-powertools/metrics' },\n { name: '@aws-sdk/client-appconfigdata' },\n // The custom authorizer handler parses its event.\n { name: '@aws-lambda-powertools/parser', when: (m) => m.auth === 'custom' },\n { name: '@types/aws-lambda', dev: true },\n // tsx runs the local server from the workspace root.\n { name: 'tsx', dev: true, root: true },\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(API_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(BUNDLE_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: ownedElsewhere(API_CONSTRUCTS_PY_DEPENDENCIES),\n});\n\nexport const TS_SMITHY_API_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const tsSmithyApiGenerator = async (\n tree: Tree,\n options: TsSmithyApiGeneratorSchema,\n): Promise<GeneratorCallback> => {\n if (\n (options.infra as string) !== 'rest-lambda' &&\n (options.infra as string) !== 'none'\n ) {\n throw new Error(\n `Unsupported infra '${options.infra}' for Smithy TypeScript API. ` +\n `Only 'rest-lambda' (API Gateway REST API) is supported.`,\n );\n }\n\n const integrationPattern = getIntegrationPattern(options);\n const apiNameClassName = toClassName(options.name);\n const apiNameKebabCase = toKebabCase(options.name);\n const { fullyQualifiedName: backendFullyQualifiedName, dir } =\n getTsLibDetails(tree, options);\n const modelProjectName = `${apiNameKebabCase}-model`;\n\n let projectExists: boolean;\n try {\n readProjectConfigurationUnqualified(tree, backendFullyQualifiedName);\n projectExists = true;\n } catch {\n projectExists = false;\n }\n\n if (!projectExists) {\n // Generate the model project\n await smithyProjectGenerator(tree, {\n name: modelProjectName,\n serviceName: apiNameClassName,\n namespace: options.namespace,\n directory: dir,\n subDirectory: 'model',\n preferInstallDependencies: false,\n });\n\n // Generate the backend project\n await tsProjectGenerator(tree, {\n name: options.name,\n directory: dir,\n subDirectory: 'backend',\n preferInstallDependencies: false,\n });\n }\n\n // Add metadata to associate backend project with model project\n const modelProjectConfig = readProjectConfigurationUnqualified(\n tree,\n modelProjectName,\n );\n updateProjectConfiguration(tree, modelProjectConfig.name, {\n ...modelProjectConfig,\n metadata: {\n ...modelProjectConfig.metadata,\n backendProject: backendFullyQualifiedName,\n } as any,\n });\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n options.infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n // Recorded here and read by the declaration's predicates, so the packages\n // added below are exactly the ones the version sync will own.\n const metadata: TsSmithyApiMetadata = {\n apiName: options.name,\n auth: options.auth,\n modelProject: modelProjectConfig.name,\n ...(iac ? { iac } : {}),\n };\n\n addGeneratorMetadata(\n tree,\n backendFullyQualifiedName,\n TS_SMITHY_API_GENERATOR_INFO,\n metadata,\n );\n\n const backendProjectConfig = readProjectConfigurationUnqualified(\n tree,\n backendFullyQualifiedName,\n );\n const port = assignPort(tree, backendProjectConfig, 3001);\n\n // Delete default index.ts with \"hello\" function\n tree.delete(joinPathFragments(backendProjectConfig.sourceRoot, 'index.ts'));\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n backendProjectConfig.sourceRoot,\n {\n apiNameClassName,\n port,\n ...esmVars(tree),\n },\n );\n\n if (options.infra !== 'none') {\n if (options.auth === 'custom') {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n '..',\n '..',\n '..',\n 'utils',\n 'api-constructs',\n 'files',\n 'cdk',\n 'authorizer',\n 'rest',\n ),\n backendProjectConfig.sourceRoot,\n {},\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n }\n\n // Add infrastructure\n await sharedConstructsGenerator(\n tree,\n {\n iac,\n },\n DEPENDENCIES,\n );\n await addApiGatewayInfra(\n tree,\n {\n iac,\n apiProjectName: backendFullyQualifiedName,\n apiNameClassName,\n apiNameKebabCase,\n auth: options.auth,\n constructType: 'rest',\n backend: {\n type: 'smithy',\n bundleOutputDir: joinPathFragments(\n 'dist',\n backendProjectConfig.root,\n 'bundle',\n ),\n integrationPattern,\n ...(options.auth === 'custom' && {\n authorizerBundleOutputDir: joinPathFragments(\n 'dist',\n backendProjectConfig.root,\n 'bundle',\n 'authorizer',\n ),\n }),\n },\n },\n DEPENDENCIES,\n );\n addSharedConstructsOpenApiMetadataGenerateTarget(tree, {\n iac,\n apiNameKebabCase,\n specPath: joinPathFragments(\n 'dist',\n modelProjectConfig.root,\n 'build',\n 'openapi',\n 'openapi.json',\n ),\n specBuildTargetName: `${modelProjectConfig.name}:build`,\n integrationPattern,\n });\n\n // Add bundle target using rolldown\n await addTypeScriptBundleTarget(\n tree,\n backendProjectConfig,\n {\n targetFilePath: 'src/handler.ts',\n external: [/@aws-sdk\\/.*/], // lambda runtime provides aws sdk\n },\n DEPENDENCIES,\n );\n\n if (options.auth === 'custom') {\n await addTypeScriptBundleTarget(\n tree,\n backendProjectConfig,\n {\n targetFilePath: 'src/authorizer.ts',\n bundleOutputDir: 'authorizer',\n external: [/@aws-sdk\\/.*/],\n },\n DEPENDENCIES,\n );\n }\n }\n\n const cmd = new FsCommands(tree, DEPENDENCIES);\n const generatedSrcDirFromRoot = '{projectRoot}/src/generated';\n\n // Target for copying the ssdk built by the model\n backendProjectConfig.targets['copy-ssdk'] = {\n cache: true,\n inputs: [\n {\n dependentTasksOutputFiles: '**/*',\n },\n ],\n executor: 'nx:run-commands',\n options: {\n commands: [\n cmd.rm(generatedSrcDirFromRoot),\n cmd.mkdir(generatedSrcDirFromRoot),\n cmd.cp(\n joinPathFragments('dist', modelProjectConfig.root, 'build', 'ssdk'),\n joinPathFragments(generatedSrcDirFromRoot, 'ssdk'),\n ),\n ],\n parallel: false,\n },\n outputs: ['{projectRoot}/src/generated'],\n dependsOn: [`${modelProjectConfig.name}:build`],\n };\n addDependencyToTargetIfNotPresent(\n backendProjectConfig,\n 'compile',\n 'copy-ssdk',\n );\n\n // Add a project which continuously copies based on changes to the model project\n // This allows the \"serve\" target to hot reload when the smithy model is changed\n backendProjectConfig.targets['watch-copy-ssdk'] = {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n command: `nx watch --projects=${modelProjectConfig.name} --includeDependencies -- nx run ${backendFullyQualifiedName}:copy-ssdk`,\n },\n };\n\n // Add serve target for running the server locally\n backendProjectConfig.targets.serve = normalizeTargetKeyOrder({\n executor: 'nx:run-commands',\n continuous: true,\n dependsOn: ['copy-ssdk', 'watch-copy-ssdk'],\n options: {\n command: 'tsx --watch src/local-server.ts',\n cwd: '{projectRoot}',\n },\n });\n\n const existingDevDependsOn =\n backendProjectConfig.targets['dev']?.dependsOn ?? [];\n\n backendProjectConfig.targets['dev'] = normalizeTargetKeyOrder({\n ...backendProjectConfig.targets.serve,\n // Own copy of dependsOn so adding dev dependencies below doesn't\n // mutate the shared array referenced by the serve target.\n dependsOn: [...(backendProjectConfig.targets.serve.dependsOn ?? [])],\n options: {\n ...backendProjectConfig.targets.serve.options,\n env: {\n LOCAL_DEV: 'true',\n },\n },\n });\n\n // Preserve any dependencies added to dev by connection generators\n for (const dependency of existingDevDependsOn) {\n addDependencyToTargetIfNotPresent(backendProjectConfig, 'dev', dependency);\n }\n\n // Ignore generated code\n updateGitIgnore(tree, backendProjectConfig.root, (patterns) => [\n ...patterns,\n 'src/generated',\n ]);\n\n updateProjectConfiguration(\n tree,\n backendFullyQualifiedName,\n backendProjectConfig,\n );\n\n addTsDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: backendProjectConfig.root,\n });\n\n await addGeneratorMetricsIfApplicable(tree, [TS_SMITHY_API_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nconst getIntegrationPattern = (\n options: TsSmithyApiGeneratorSchema,\n): 'isolated' | 'shared' => options.integrationPattern ?? 'isolated';\n\nexport default tsSmithyApiGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","tsProjectGenerator","getTsLibDetails","addTsDependencies","API_CONSTRUCTS_DEPENDENCIES","API_CONSTRUCTS_PY_DEPENDENCIES","addApiGatewayInfra","addSharedConstructsOpenApiMetadataGenerateTarget","addTypeScriptBundleTarget","BUNDLE_DEPENDENCIES","declareDependencies","ownedElsewhere","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","esmVars","toClassName","toKebabCase","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","normalizeTargetKeyOrder","readProjectConfigurationUnqualified","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","smithyProjectGenerator","DEPENDENCIES","ts","name","when","m","auth","dev","root","py","TS_SMITHY_API_GENERATOR_INFO","filename","tsSmithyApiGenerator","tree","options","infra","Error","integrationPattern","getIntegrationPattern","apiNameClassName","apiNameKebabCase","fullyQualifiedName","backendFullyQualifiedName","dir","modelProjectName","projectExists","serviceName","namespace","directory","subDirectory","preferInstallDependencies","modelProjectConfig","metadata","backendProject","iac","undefined","apiName","modelProject","backendProjectConfig","port","delete","sourceRoot","dirname","overwriteStrategy","KeepExisting","apiProjectName","constructType","backend","type","bundleOutputDir","authorizerBundleOutputDir","specPath","specBuildTargetName","targetFilePath","external","cmd","generatedSrcDirFromRoot","targets","cache","inputs","dependentTasksOutputFiles","executor","commands","rm","mkdir","cp","parallel","outputs","dependsOn","continuous","command","serve","cwd","existingDevDependsOn","env","LOCAL_DEV","dependency","patterns","projectRoot","languages"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  terraform {
2
+ required_version = ">= 1.0"
3
+
2
4
  required_providers {
3
5
  aws = {
4
6
  source = "hashicorp/aws"
@@ -0,0 +1,111 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import {
5
+ S3Client,
6
+ DeleteObjectsCommand,
7
+ GetObjectCommand,
8
+ ListObjectVersionsCommand,
9
+ } from '@aws-sdk/client-s3';
10
+ import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
11
+ import { resolveAwsConfig } from './aws-config';
12
+
13
+ const projectRootRel = process.argv[2];
14
+ if (!projectRootRel) {
15
+ throw new Error(
16
+ 'Expected the project root as argv[2] — this script is wired up by the generated `bootstrap-destroy` nx target and should be invoked through it.',
17
+ );
18
+ }
19
+ const workspaceRoot = process.cwd();
20
+ const projectRoot = resolve(workspaceRoot, projectRootRel);
21
+ const bootstrapDir = join(projectRoot, 'bootstrap');
22
+ const tfStatePath = join(
23
+ workspaceRoot,
24
+ 'dist',
25
+ projectRootRel,
26
+ 'terraform',
27
+ 'bootstrap.tfstate',
28
+ );
29
+
30
+ /** Removes every object version and delete marker so the bucket can be destroyed. */
31
+ const emptyBucket = async (s3: S3Client, bucket: string) => {
32
+ for (;;) {
33
+ const listed = await s3.send(
34
+ new ListObjectVersionsCommand({ Bucket: bucket }),
35
+ );
36
+ const objects = [
37
+ ...(listed.Versions ?? []),
38
+ ...(listed.DeleteMarkers ?? []),
39
+ ].map(({ Key, VersionId }) => ({ Key, VersionId }));
40
+
41
+ if (objects.length === 0) return;
42
+
43
+ await s3.send(
44
+ new DeleteObjectsCommand({
45
+ Bucket: bucket,
46
+ Delete: { Objects: objects, Quiet: true },
47
+ }),
48
+ );
49
+
50
+ if (!listed.IsTruncated) return;
51
+ }
52
+ };
53
+
54
+ /**
55
+ * Destroys the remote Terraform state bucket created by `bootstrap`.
56
+ *
57
+ * The bucket holds its own state object, so the state is pulled from S3 first
58
+ * (this works from a fresh checkout) and the bucket emptied before the destroy
59
+ * — it is not `force_destroy`, so a non-empty bucket fails to delete.
60
+ */
61
+ const main = async () => {
62
+ const { accountId, region } = await resolveAwsConfig();
63
+ const bucket = `${accountId}-tf-state-${region}`;
64
+
65
+ const s3 = new S3Client({ region, credentials: fromNodeProviderChain() });
66
+
67
+ mkdirSync(dirname(tfStatePath), { recursive: true });
68
+
69
+ // Prefer the remote state, so this works from a fresh checkout.
70
+ try {
71
+ const out = await s3.send(
72
+ new GetObjectCommand({ Bucket: bucket, Key: 'bootstrap.tfstate' }),
73
+ );
74
+ if (out.Body) {
75
+ writeFileSync(tfStatePath, await out.Body.transformToByteArray());
76
+ }
77
+ } catch (err: any) {
78
+ const status = err?.$metadata?.httpStatusCode;
79
+ const name = err?.name ?? '';
80
+ const missing =
81
+ name === 'NoSuchBucket' || name === 'NoSuchKey' || status === 404;
82
+ if (!missing) throw err;
83
+ }
84
+
85
+ if (!existsSync(tfStatePath)) {
86
+ console.log(
87
+ `No bootstrap state found for ${bucket} — nothing to destroy. It may already have been destroyed.`,
88
+ );
89
+ return;
90
+ }
91
+
92
+ execFileSync('terraform', ['init'], { cwd: bootstrapDir, stdio: 'inherit' });
93
+
94
+ await emptyBucket(s3, bucket);
95
+
96
+ execFileSync(
97
+ 'terraform',
98
+ [
99
+ 'destroy',
100
+ '-auto-approve',
101
+ `-state=${tfStatePath}`,
102
+ `-var=aws_region=${region}`,
103
+ ],
104
+ { cwd: bootstrapDir, stdio: 'inherit' },
105
+ );
106
+ };
107
+
108
+ main().catch((err) => {
109
+ console.error(err);
110
+ process.exit(1);
111
+ });
@@ -1,4 +1,6 @@
1
1
  terraform {
2
+ required_version = ">= 1.0"
3
+
2
4
  required_providers {
3
5
  aws = {
4
6
  source = "hashicorp/aws"
@@ -0,0 +1,8 @@
1
+ # Defines the checks to skip entirely. Remove if your requirements differ.
2
+ skip-check:
3
+ # Lambda function suppressions
4
+ - CKV_AWS_115 # Concurrent execution limit
5
+ - CKV_AWS_116 # Dead Letter Queue
6
+ - CKV_AWS_117 # Lambda functions in VPC
7
+ - CKV_AWS_173 # Encrypt Lambda environment variables
8
+ - CKV_AWS_272 # Code signing
@@ -81,6 +81,9 @@ export async function terraformProjectGenerator(tree, schema) {
81
81
  const distDir = joinPathFragments(outDirToRootRelativePath, 'dist', '{projectRoot}');
82
82
  const tfDistDir = joinPathFragments(distDir, 'terraform');
83
83
  const checkovReportJsonPath = joinPathFragments(distDir, 'checkov', 'checkov_report.json');
84
+ // `test` keeps its `.terraform` here rather than in `src`, so initialising it
85
+ // never races the backend-configured targets over the shared one.
86
+ const testDataDir = joinPathFragments(distDir, 'terraform-test');
84
87
  // Calculate relative path from current project to common/terraform/metrics
85
88
  // Use forward slashes for terraform module source paths (even on Windows)
86
89
  const metricsModulePath = relative(join(tree.root, lib.dir, 'src'), join(tree.root, 'packages', SHARED_TERRAFORM_DIR, 'src', 'metrics')).replace(/\\/g, '/');
@@ -119,13 +122,16 @@ export async function terraformProjectGenerator(tree, schema) {
119
122
  executor: 'nx:run-commands',
120
123
  options: {
121
124
  forwardAllArgs: true,
122
- command: `terraform destroy -state=${tfDistDir}/bootstrap.tfstate`,
123
- cwd: '{projectRoot}/bootstrap'
125
+ commands: [
126
+ 'tsx {projectRoot}/scripts/bootstrap-destroy.ts {projectRoot}'
127
+ ],
128
+ cwd: '{workspaceRoot}'
124
129
  }
125
130
  },
126
131
  build: {
127
132
  dependsOn: [
128
133
  'fmt',
134
+ 'checkov',
129
135
  'test',
130
136
  `${sharedTfProjectName}:build`
131
137
  ]
@@ -212,6 +218,7 @@ export async function terraformProjectGenerator(tree, schema) {
212
218
  build: {
213
219
  dependsOn: [
214
220
  'fmt',
221
+ 'checkov',
215
222
  'test'
216
223
  ]
217
224
  },
@@ -240,18 +247,50 @@ export async function terraformProjectGenerator(tree, schema) {
240
247
  cwd: '{projectRoot}/src'
241
248
  }
242
249
  },
243
- test: {
250
+ checkov: {
244
251
  executor: 'nx:run-commands',
245
252
  cache: true,
246
253
  outputs: [
247
254
  '{workspaceRoot}/dist/{projectRoot}/checkov'
248
255
  ],
249
256
  options: {
250
- command: uvxCommand('checkov', `--directory . -o cli -o json --output-file-path console,${checkovReportJsonPath}`),
257
+ command: uvxCommand('checkov', `--config-file ../checkov.yml --directory . -o cli -o json --output-file-path console,${checkovReportJsonPath}`),
251
258
  forwardAllArgs: true,
252
259
  cwd: '{projectRoot}/src'
253
260
  }
254
261
  },
262
+ // Terraform's native test framework, which runs any `.tftest.hcl` files.
263
+ // A project with none is a no-op success.
264
+ //
265
+ // `-backend=false` installs the modules and providers the tests need
266
+ // without configuring the S3 backend, so this runs before `bootstrap` and
267
+ // needs no credentials. `TF_DATA_DIR` keeps that `.terraform` out of `src`,
268
+ // so it never races the backend-configured targets over the shared one.
269
+ // `^production` is what invalidates the cache when a consumed module
270
+ // changes; `{projectRoot}/**/*` alone would serve a stale pass.
271
+ test: {
272
+ executor: 'nx:run-commands',
273
+ cache: true,
274
+ inputs: [
275
+ 'default',
276
+ '^production'
277
+ ],
278
+ outputs: [
279
+ `{workspaceRoot}/dist/{projectRoot}/terraform-test`
280
+ ],
281
+ options: {
282
+ commands: [
283
+ 'terraform init -backend=false',
284
+ 'terraform test'
285
+ ],
286
+ forwardAllArgs: true,
287
+ cwd: '{projectRoot}/src',
288
+ parallel: false,
289
+ env: {
290
+ TF_DATA_DIR: testDataDir
291
+ }
292
+ }
293
+ },
255
294
  validate: {
256
295
  executor: 'nx:run-commands',
257
296
  cache: true,
@@ -293,6 +332,10 @@ export async function terraformProjectGenerator(tree, schema) {
293
332
  }, {
294
333
  overwriteStrategy: OverwriteStrategy.Overwrite
295
334
  });
335
+ // Checkov skips are the user's to curate, so preserve any they have added.
336
+ generateFiles(tree, joinPathFragments(import.meta.dirname, './files/checkov'), lib.dir, {}, {
337
+ overwriteStrategy: OverwriteStrategy.KeepExisting
338
+ });
296
339
  const nxJson = readNxJson(tree);
297
340
  if (!nxJson.plugins?.find((p)=>typeof p === 'string' ? p === NX_EXTEND_PLUGIN : p.plugin === NX_EXTEND_PLUGIN)) {
298
341
  nxJson.plugins = [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/terraform/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addProjectConfiguration,\n detectPackageManager,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type TargetConfiguration,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { join, relative } from 'path';\nimport { getTsLibDetails } from '../../ts/lib/generator.js';\nimport { addTsDependencies } from '../../utils/add-dependencies.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase } from '../../utils/names.js';\nimport {\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { uvxCommand } from '../../utils/py.js';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n SHARED_TERRAFORM_DIR,\n SHARED_TERRAFORM_NAME,\n} from '../../utils/shared-constructs-constants.js';\nimport {\n terraformProviderVersions,\n withVersions,\n} from '../../utils/versions.js';\nimport type { TerraformProjectGeneratorSchema } from './schema';\n\n// Terraform projects carry no package.json, so their build tooling and the AWS\n// SDK the vended deploy scripts import are declared at the workspace root. This\n// generator records no metadata, so nothing a predicate could read.\nexport const DEPENDENCIES = declareDependencies()({\n ts: [\n { name: '@nx-extend/terraform', dev: true, root: true },\n { name: 'make-dir-cli', dev: true, root: true },\n { name: 'tsx', dev: true, root: true },\n { name: '@aws-sdk/client-s3', dev: true, root: true },\n { name: '@aws-sdk/client-sts', dev: true, root: true },\n { name: '@aws-sdk/credential-providers', dev: true, root: true },\n { name: '@smithy/config-resolver', dev: true, root: true },\n { name: '@smithy/node-config-provider', dev: true, root: true },\n // Declared for its pinned version, which goes into npm's `overrides` below.\n { name: '@nx/devkit', versionOnly: true },\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n});\n\nconst NX_EXTEND_PLUGIN = '@nx-extend/terraform';\nexport const TERRAFORM_PROJECT_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport async function terraformProjectGenerator(\n tree: Tree,\n schema: TerraformProjectGeneratorSchema,\n): Promise<GeneratorCallback> {\n // Just use getTsLibDetails as it isn't specific to TS\n const lib = getTsLibDetails(tree, schema);\n const { fullyQualifiedName: sharedTfProjectName } = getTsLibDetails(tree, {\n name: SHARED_TERRAFORM_NAME,\n });\n\n const outDirToRootRelativePath = relative(\n join(tree.root, lib.dir, 'src'),\n tree.root,\n ).replace(/\\\\/g, '/');\n const distDir = joinPathFragments(\n outDirToRootRelativePath,\n 'dist',\n '{projectRoot}',\n );\n const tfDistDir = joinPathFragments(distDir, 'terraform');\n const checkovReportJsonPath = joinPathFragments(\n distDir,\n 'checkov',\n 'checkov_report.json',\n );\n\n // Calculate relative path from current project to common/terraform/metrics\n // Use forward slashes for terraform module source paths (even on Windows)\n const metricsModulePath = relative(\n join(tree.root, lib.dir, 'src'),\n join(tree.root, 'packages', SHARED_TERRAFORM_DIR, 'src', 'metrics'),\n ).replace(/\\\\/g, '/');\n\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '.terraform']);\n\n const applicationTargets: {\n [targetName: string]: TargetConfiguration;\n } = {\n apply: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: `terraform apply ${tfDistDir}/dev.tfplan`,\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['plan'],\n },\n bootstrap: {\n executor: 'nx:run-commands',\n options: {\n forwardAllArgs: true,\n commands: ['tsx {projectRoot}/scripts/bootstrap.ts {projectRoot}'],\n cwd: '{workspaceRoot}',\n },\n },\n 'bootstrap-destroy': {\n executor: 'nx:run-commands',\n options: {\n forwardAllArgs: true,\n command: `terraform destroy -state=${tfDistDir}/bootstrap.tfstate`,\n cwd: '{projectRoot}/bootstrap',\n },\n },\n build: {\n dependsOn: ['fmt', 'test', `${sharedTfProjectName}:build`],\n },\n deploy: {\n dependsOn: ['apply'],\n },\n destroy: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: 'terraform destroy -var-file=env/dev.tfvars',\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['init'],\n },\n init: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n env: { TF_ENV: 'dev' },\n },\n },\n options: {\n forwardAllArgs: true,\n commands: ['tsx {projectRoot}/scripts/init.ts {projectRoot}'],\n cwd: '{workspaceRoot}',\n },\n dependsOn: ['^init'],\n },\n output: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform output -json',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n plan: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n commands: [\n `make-dir ${tfDistDir}`,\n `terraform plan -var-file=env/dev.tfvars -out=${tfDistDir}/dev.tfplan`,\n ],\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n parallel: false,\n },\n dependsOn: ['init', 'validate', '^validate', 'build'],\n },\n };\n\n const libTargets: {\n [targetName: string]: TargetConfiguration;\n } = {\n build: {\n dependsOn: ['fmt', 'test'],\n },\n fmt: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform fmt',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n init: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: 'terraform init',\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n test: {\n executor: 'nx:run-commands',\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/checkov'],\n options: {\n command: uvxCommand(\n 'checkov',\n `--directory . -o cli -o json --output-file-path console,${checkovReportJsonPath}`,\n ),\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n validate: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform validate',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['init'],\n },\n };\n\n const projectConfiguration = {\n root: lib.dir,\n projectType: schema.type,\n sourceRoot: joinPathFragments(lib.dir, 'src'),\n targets: sortObjectKeys({\n ...libTargets,\n ...(schema.type === 'application' ? applicationTargets : {}),\n }),\n };\n\n // Only create the project configuration on first run; skip it on re-run so\n // existing project.json customisations are preserved.\n if (!projectExists(tree, lib.fullyQualifiedName)) {\n addProjectConfiguration(tree, lib.fullyQualifiedName, projectConfiguration);\n }\n // This generator IS the Terraform project, so the provider is fixed.\n addGeneratorMetadata(\n tree,\n lib.fullyQualifiedName,\n TERRAFORM_PROJECT_GENERATOR_INFO,\n { iac: 'terraform' },\n );\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, `./files/${schema.type}`), // path to the file templates\n lib.dir, // destination path of the files\n {\n metricsModulePath,\n stateKeyPrefix: kebabCase(lib.fullyQualifiedName),\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n\n const nxJson = readNxJson(tree);\n\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === NX_EXTEND_PLUGIN\n : p.plugin === NX_EXTEND_PLUGIN,\n )\n ) {\n nxJson.plugins = [...(nxJson.plugins ?? []), NX_EXTEND_PLUGIN];\n updateNxJson(tree, nxJson);\n }\n\n // Ensure shared constructs for Terraform are created\n await sharedConstructsGenerator(tree, { iac: 'terraform' }, DEPENDENCIES);\n\n // Add Terraform metrics\n await addGeneratorMetricsIfApplicable(tree, [\n TERRAFORM_PROJECT_GENERATOR_INFO,\n ]);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n // @nx-extend/terraform has a peer dependency on @nx/devkit ^21.0.0 which causes\n // npm install to fail, so for NPM we add a resolution\n // Can remove when https://github.com/TriPSs/nx-extend/issues/407 is addressed\n if (detectPackageManager() === 'npm') {\n updateJson(tree, 'package.json', (packageJson) => {\n packageJson.overrides = {\n ...packageJson.overrides,\n ...withVersions(DEPENDENCIES, ['@nx/devkit']),\n };\n return packageJson;\n });\n }\n\n // `@nx-extend/terraform` is registered as an Nx plugin in nx.json, so Nx\n // loads it when computing the project graph — it must resolve even if the\n // caller would otherwise prefer to defer installing.\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript'],\n ensureResolvable: [NX_EXTEND_PLUGIN],\n });\n}\nexport default terraformProjectGenerator;\n"],"names":["addProjectConfiguration","detectPackageManager","generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","join","relative","getTsLibDetails","addTsDependencies","declareDependencies","ownedElsewhere","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","addGeneratorMetadata","getGeneratorInfo","projectExists","sortObjectKeys","uvxCommand","sharedConstructsGenerator","SHARED_CONSTRUCTS_DEPENDENCIES","SHARED_TERRAFORM_DIR","SHARED_TERRAFORM_NAME","terraformProviderVersions","withVersions","DEPENDENCIES","ts","name","dev","root","versionOnly","NX_EXTEND_PLUGIN","TERRAFORM_PROJECT_GENERATOR_INFO","filename","terraformProjectGenerator","tree","schema","lib","fullyQualifiedName","sharedTfProjectName","outDirToRootRelativePath","dir","replace","distDir","tfDistDir","checkovReportJsonPath","metricsModulePath","patterns","applicationTargets","apply","executor","defaultConfiguration","configurations","command","options","forwardAllArgs","cwd","dependsOn","bootstrap","commands","build","deploy","destroy","init","env","TF_ENV","output","cache","inputs","plan","parallel","libTargets","fmt","test","outputs","validate","projectConfiguration","projectType","type","sourceRoot","targets","iac","dirname","stateKeyPrefix","overwriteStrategy","Overwrite","nxJson","plugins","find","p","plugin","packageJson","overrides","preferInstallDependencies","languages","ensureResolvable"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/terraform/project/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addProjectConfiguration,\n detectPackageManager,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type TargetConfiguration,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { join, relative } from 'path';\nimport { getTsLibDetails } from '../../ts/lib/generator.js';\nimport { addTsDependencies } from '../../utils/add-dependencies.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport { updateGitIgnore } from '../../utils/git.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase } from '../../utils/names.js';\nimport {\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n} from '../../utils/nx.js';\nimport { sortObjectKeys } from '../../utils/object.js';\nimport { uvxCommand } from '../../utils/py.js';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n SHARED_TERRAFORM_DIR,\n SHARED_TERRAFORM_NAME,\n} from '../../utils/shared-constructs-constants.js';\nimport {\n terraformProviderVersions,\n withVersions,\n} from '../../utils/versions.js';\nimport type { TerraformProjectGeneratorSchema } from './schema';\n\n// Terraform projects carry no package.json, so their build tooling and the AWS\n// SDK the vended deploy scripts import are declared at the workspace root. This\n// generator records no metadata, so nothing a predicate could read.\nexport const DEPENDENCIES = declareDependencies()({\n ts: [\n { name: '@nx-extend/terraform', dev: true, root: true },\n { name: 'make-dir-cli', dev: true, root: true },\n { name: 'tsx', dev: true, root: true },\n { name: '@aws-sdk/client-s3', dev: true, root: true },\n { name: '@aws-sdk/client-sts', dev: true, root: true },\n { name: '@aws-sdk/credential-providers', dev: true, root: true },\n { name: '@smithy/config-resolver', dev: true, root: true },\n { name: '@smithy/node-config-provider', dev: true, root: true },\n // Declared for its pinned version, which goes into npm's `overrides` below.\n { name: '@nx/devkit', versionOnly: true },\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n});\n\nconst NX_EXTEND_PLUGIN = '@nx-extend/terraform';\nexport const TERRAFORM_PROJECT_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport async function terraformProjectGenerator(\n tree: Tree,\n schema: TerraformProjectGeneratorSchema,\n): Promise<GeneratorCallback> {\n // Just use getTsLibDetails as it isn't specific to TS\n const lib = getTsLibDetails(tree, schema);\n const { fullyQualifiedName: sharedTfProjectName } = getTsLibDetails(tree, {\n name: SHARED_TERRAFORM_NAME,\n });\n\n const outDirToRootRelativePath = relative(\n join(tree.root, lib.dir, 'src'),\n tree.root,\n ).replace(/\\\\/g, '/');\n const distDir = joinPathFragments(\n outDirToRootRelativePath,\n 'dist',\n '{projectRoot}',\n );\n const tfDistDir = joinPathFragments(distDir, 'terraform');\n const checkovReportJsonPath = joinPathFragments(\n distDir,\n 'checkov',\n 'checkov_report.json',\n );\n // `test` keeps its `.terraform` here rather than in `src`, so initialising it\n // never races the backend-configured targets over the shared one.\n const testDataDir = joinPathFragments(distDir, 'terraform-test');\n\n // Calculate relative path from current project to common/terraform/metrics\n // Use forward slashes for terraform module source paths (even on Windows)\n const metricsModulePath = relative(\n join(tree.root, lib.dir, 'src'),\n join(tree.root, 'packages', SHARED_TERRAFORM_DIR, 'src', 'metrics'),\n ).replace(/\\\\/g, '/');\n\n updateGitIgnore(tree, '.', (patterns) => [...patterns, '.terraform']);\n\n const applicationTargets: {\n [targetName: string]: TargetConfiguration;\n } = {\n apply: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: `terraform apply ${tfDistDir}/dev.tfplan`,\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['plan'],\n },\n bootstrap: {\n executor: 'nx:run-commands',\n options: {\n forwardAllArgs: true,\n commands: ['tsx {projectRoot}/scripts/bootstrap.ts {projectRoot}'],\n cwd: '{workspaceRoot}',\n },\n },\n 'bootstrap-destroy': {\n executor: 'nx:run-commands',\n options: {\n forwardAllArgs: true,\n commands: [\n 'tsx {projectRoot}/scripts/bootstrap-destroy.ts {projectRoot}',\n ],\n cwd: '{workspaceRoot}',\n },\n },\n build: {\n dependsOn: ['fmt', 'checkov', 'test', `${sharedTfProjectName}:build`],\n },\n deploy: {\n dependsOn: ['apply'],\n },\n destroy: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: 'terraform destroy -var-file=env/dev.tfvars',\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['init'],\n },\n init: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n env: { TF_ENV: 'dev' },\n },\n },\n options: {\n forwardAllArgs: true,\n commands: ['tsx {projectRoot}/scripts/init.ts {projectRoot}'],\n cwd: '{workspaceRoot}',\n },\n dependsOn: ['^init'],\n },\n output: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform output -json',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n plan: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n commands: [\n `make-dir ${tfDistDir}`,\n `terraform plan -var-file=env/dev.tfvars -out=${tfDistDir}/dev.tfplan`,\n ],\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n parallel: false,\n },\n dependsOn: ['init', 'validate', '^validate', 'build'],\n },\n };\n\n const libTargets: {\n [targetName: string]: TargetConfiguration;\n } = {\n build: {\n dependsOn: ['fmt', 'checkov', 'test'],\n },\n fmt: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform fmt',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n init: {\n executor: 'nx:run-commands',\n defaultConfiguration: 'dev',\n configurations: {\n dev: {\n command: 'terraform init',\n },\n },\n options: {\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n checkov: {\n executor: 'nx:run-commands',\n cache: true,\n outputs: ['{workspaceRoot}/dist/{projectRoot}/checkov'],\n options: {\n command: uvxCommand(\n 'checkov',\n `--config-file ../checkov.yml --directory . -o cli -o json --output-file-path console,${checkovReportJsonPath}`,\n ),\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n },\n // Terraform's native test framework, which runs any `.tftest.hcl` files.\n // A project with none is a no-op success.\n //\n // `-backend=false` installs the modules and providers the tests need\n // without configuring the S3 backend, so this runs before `bootstrap` and\n // needs no credentials. `TF_DATA_DIR` keeps that `.terraform` out of `src`,\n // so it never races the backend-configured targets over the shared one.\n // `^production` is what invalidates the cache when a consumed module\n // changes; `{projectRoot}/**/*` alone would serve a stale pass.\n test: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/dist/{projectRoot}/terraform-test`],\n options: {\n commands: ['terraform init -backend=false', 'terraform test'],\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n parallel: false,\n env: { TF_DATA_DIR: testDataDir },\n },\n },\n validate: {\n executor: 'nx:run-commands',\n cache: true,\n inputs: ['default'],\n options: {\n command: 'terraform validate',\n forwardAllArgs: true,\n cwd: '{projectRoot}/src',\n },\n dependsOn: ['init'],\n },\n };\n\n const projectConfiguration = {\n root: lib.dir,\n projectType: schema.type,\n sourceRoot: joinPathFragments(lib.dir, 'src'),\n targets: sortObjectKeys({\n ...libTargets,\n ...(schema.type === 'application' ? applicationTargets : {}),\n }),\n };\n\n // Only create the project configuration on first run; skip it on re-run so\n // existing project.json customisations are preserved.\n if (!projectExists(tree, lib.fullyQualifiedName)) {\n addProjectConfiguration(tree, lib.fullyQualifiedName, projectConfiguration);\n }\n // This generator IS the Terraform project, so the provider is fixed.\n addGeneratorMetadata(\n tree,\n lib.fullyQualifiedName,\n TERRAFORM_PROJECT_GENERATOR_INFO,\n { iac: 'terraform' },\n );\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, `./files/${schema.type}`), // path to the file templates\n lib.dir, // destination path of the files\n {\n metricsModulePath,\n stateKeyPrefix: kebabCase(lib.fullyQualifiedName),\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n\n // Checkov skips are the user's to curate, so preserve any they have added.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, './files/checkov'),\n lib.dir,\n {},\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n const nxJson = readNxJson(tree);\n\n if (\n !nxJson.plugins?.find((p) =>\n typeof p === 'string'\n ? p === NX_EXTEND_PLUGIN\n : p.plugin === NX_EXTEND_PLUGIN,\n )\n ) {\n nxJson.plugins = [...(nxJson.plugins ?? []), NX_EXTEND_PLUGIN];\n updateNxJson(tree, nxJson);\n }\n\n // Ensure shared constructs for Terraform are created\n await sharedConstructsGenerator(tree, { iac: 'terraform' }, DEPENDENCIES);\n\n // Add Terraform metrics\n await addGeneratorMetricsIfApplicable(tree, [\n TERRAFORM_PROJECT_GENERATOR_INFO,\n ]);\n\n addTsDependencies(tree, DEPENDENCIES);\n\n // @nx-extend/terraform has a peer dependency on @nx/devkit ^21.0.0 which causes\n // npm install to fail, so for NPM we add a resolution\n // Can remove when https://github.com/TriPSs/nx-extend/issues/407 is addressed\n if (detectPackageManager() === 'npm') {\n updateJson(tree, 'package.json', (packageJson) => {\n packageJson.overrides = {\n ...packageJson.overrides,\n ...withVersions(DEPENDENCIES, ['@nx/devkit']),\n };\n return packageJson;\n });\n }\n\n // `@nx-extend/terraform` is registered as an Nx plugin in nx.json, so Nx\n // loads it when computing the project graph — it must resolve even if the\n // caller would otherwise prefer to defer installing.\n return () =>\n installDependencies(tree, schema.preferInstallDependencies, {\n languages: ['typescript'],\n ensureResolvable: [NX_EXTEND_PLUGIN],\n });\n}\nexport default terraformProjectGenerator;\n"],"names":["addProjectConfiguration","detectPackageManager","generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","join","relative","getTsLibDetails","addTsDependencies","declareDependencies","ownedElsewhere","updateGitIgnore","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","addGeneratorMetadata","getGeneratorInfo","projectExists","sortObjectKeys","uvxCommand","sharedConstructsGenerator","SHARED_CONSTRUCTS_DEPENDENCIES","SHARED_TERRAFORM_DIR","SHARED_TERRAFORM_NAME","terraformProviderVersions","withVersions","DEPENDENCIES","ts","name","dev","root","versionOnly","NX_EXTEND_PLUGIN","TERRAFORM_PROJECT_GENERATOR_INFO","filename","terraformProjectGenerator","tree","schema","lib","fullyQualifiedName","sharedTfProjectName","outDirToRootRelativePath","dir","replace","distDir","tfDistDir","checkovReportJsonPath","testDataDir","metricsModulePath","patterns","applicationTargets","apply","executor","defaultConfiguration","configurations","command","options","forwardAllArgs","cwd","dependsOn","bootstrap","commands","build","deploy","destroy","init","env","TF_ENV","output","cache","inputs","plan","parallel","libTargets","fmt","checkov","outputs","test","TF_DATA_DIR","validate","projectConfiguration","projectType","type","sourceRoot","targets","iac","dirname","stateKeyPrefix","overwriteStrategy","Overwrite","KeepExisting","nxJson","plugins","find","p","plugin","packageJson","overrides","preferInstallDependencies","languages","ensureResolvable"],"mappings":"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"}