@aws/nx-plugin 1.0.0-rc.97 → 1.0.0-rc.98
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.
- package/LICENSE-THIRD-PARTY +9 -9
- package/migrations.json +125 -115
- package/package.json +3 -3
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +4 -4
- package/src/infra/app/generator.js +5 -2
- package/src/infra/app/generator.js.map +1 -1
- package/src/internal/test-matrix/generator.js +2 -2
- package/src/internal/test-matrix/generator.js.map +1 -1
- package/src/license/sync/generator.d.ts +10 -0
- package/src/license/sync/generator.js +1 -1
- package/src/license/sync/generator.js.map +1 -1
- package/src/migrations/latest/sandbox-pattern-nested-stacks/metadata.json +3 -0
- package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js +68 -0
- package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js.map +1 -0
- package/src/migrations/latest/shadcn-cn-package/metadata.json +3 -0
- package/src/migrations/latest/shadcn-cn-package/migration.js +114 -0
- package/src/migrations/latest/shadcn-cn-package/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0001-dev-target-depends-on-pull-image/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0002-open-api-codegen-executor/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0003-terraform-provider-plugin-cache/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0004-python-test-input-scoping/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0005-vitest-coverage-output-dir/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0006-add-assemble-target/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0007-docker-target-cache-soundness/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0008-declare-cacheable-target-inputs/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.90/0009-terraform-fmt-check/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.92/0001-react-website-unique-dev-ports/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.94/0001-infra-deploy-express-mode/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.94/0002-shx-fs-commands/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.94/0003-agent-core-vendor-target/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.95/0001-rolldown-config-bundle-transient/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.95/0002-agent-connection-pin-strands-peers/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.95/0003-ignore-package-manager-temp-files/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.95/0004-shadcn-package-imports-exports/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.js.map +1 -0
- package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +2 -2
- package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +4 -4
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +4 -4
- package/src/py/agent/a2a-connection/generator.d.ts +1 -1
- package/src/py/agent/gateway-connection/generator.d.ts +1 -1
- package/src/py/agent/mcp-connection/generator.d.ts +1 -1
- package/src/py/agent/react-connection/generator.d.ts +1 -7
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/smithy/project/__snapshots__/generator.spec.ts.snap +5 -5
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
- package/src/terraform/project/schema.d.js +0 -3
- package/src/terraform/project/schema.d.js.map +1 -1
- package/src/terraform/project/schema.d.ts +0 -4
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +12 -12
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +4 -4
- package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/agent/react-connection/generator.d.ts +1 -9
- package/src/ts/astro-docs/files/translation/scripts/translate.ts.template +47 -2
- package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +6 -6
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/ts/mcp-server/files/app/http.ts.template +1 -1
- package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/nx-generator/files/local/generator.spec.ts.template +2 -2
- package/src/ts/nx-migration/generator.js +3 -1
- package/src/ts/nx-migration/generator.js.map +1 -1
- package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +1 -25
- package/src/ts/nx-plugin/generator.js +19 -17
- package/src/ts/nx-plugin/generator.js.map +1 -1
- package/src/ts/nx-plugin/utils.d.ts +21 -0
- package/src/ts/nx-plugin/utils.js +41 -1
- package/src/ts/nx-plugin/utils.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +10 -10
- package/src/ts/react-website/agui/generator.d.ts +1 -5
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +26 -26
- package/src/ts/react-website/app/generator.d.ts +1 -5
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
- package/src/utils/ast.js +55 -16
- package/src/utils/ast.js.map +1 -1
- package/src/utils/dependencies.d.ts +10 -0
- package/src/utils/dependencies.js +93 -1
- package/src/utils/dependencies.js.map +1 -1
- package/src/utils/files/common/shadcn/src/components/ui/alert.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/avatar.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/breadcrumb.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/button.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/card.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/input.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/separator.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/sheet.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/sidebar.tsx.template +1 -1
- package/src/utils/files/common/shadcn/src/components/ui/skeleton.tsx.template +1 -1
- package/src/utils/files/common/shadcn/src/components/ui/spinner.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/textarea.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/components/ui/tooltip.tsx.template +1 -2
- package/src/utils/files/common/shadcn/src/lib/utils.ts.template +1 -6
- package/src/utils/shared-shadcn.d.ts +1 -3
- package/src/utils/shared-shadcn.js +1 -4
- package/src/utils/shared-shadcn.js.map +1 -1
- package/src/utils/versions.d.ts +52 -53
- package/src/utils/versions.js +51 -52
- package/src/utils/versions.js.map +1 -1
- package/src/migrations/latest/add-assemble-target/migration.js.map +0 -1
- package/src/migrations/latest/agent-connection-pin-strands-peers/migration.js.map +0 -1
- package/src/migrations/latest/agent-core-vendor-target/migration.js.map +0 -1
- package/src/migrations/latest/checkov-scan-cache-inputs/migration.js.map +0 -1
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +0 -1
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +0 -1
- package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +0 -1
- package/src/migrations/latest/gateway-url-accessor/migration.js.map +0 -1
- package/src/migrations/latest/ignore-package-manager-temp-files/migration.js.map +0 -1
- package/src/migrations/latest/infra-deploy-express-mode/migration.js.map +0 -1
- package/src/migrations/latest/open-api-codegen-executor/migration.js.map +0 -1
- package/src/migrations/latest/py-lambda-powertools-context/migration.js.map +0 -1
- package/src/migrations/latest/python-test-input-scoping/migration.js.map +0 -1
- package/src/migrations/latest/react-website-unique-dev-ports/migration.js.map +0 -1
- package/src/migrations/latest/rolldown-config-bundle-transient/migration.js.map +0 -1
- package/src/migrations/latest/script-project-quality-gates/migration.js.map +0 -1
- package/src/migrations/latest/shadcn-package-imports-exports/migration.js.map +0 -1
- package/src/migrations/latest/shx-fs-commands/migration.js.map +0 -1
- package/src/migrations/latest/smithy-extension-trait-aliases/migration.js.map +0 -1
- package/src/migrations/latest/terraform-fmt-check/migration.js.map +0 -1
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +0 -1
- package/src/migrations/latest/terraform-validate-without-backend/migration.js.map +0 -1
- package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +0 -1
- /package/src/migrations/latest/{add-assemble-target → sandbox-pattern-nested-stacks}/migration.d.ts +0 -0
- /package/src/migrations/latest/{agent-core-vendor-target → shadcn-cn-package}/migration.d.ts +0 -0
- /package/src/migrations/{latest/dev-target-depends-on-pull-image → v1.0.0-rc.90/0001-dev-target-depends-on-pull-image}/metadata.json +0 -0
- /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.90/0001-dev-target-depends-on-pull-image}/migration.d.ts +0 -0
- /package/src/migrations/{latest/dev-target-depends-on-pull-image → v1.0.0-rc.90/0001-dev-target-depends-on-pull-image}/migration.js +0 -0
- /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/metadata.json +0 -0
- /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.d.ts +0 -0
- /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.js +0 -0
- /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/metadata.json +0 -0
- /package/src/migrations/{latest/dev-target-depends-on-pull-image → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.d.ts +0 -0
- /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.js +0 -0
- /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/metadata.json +0 -0
- /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.d.ts +0 -0
- /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.js +0 -0
- /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/metadata.json +0 -0
- /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.d.ts +0 -0
- /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.js +0 -0
- /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/metadata.json +0 -0
- /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0006-add-assemble-target}/migration.d.ts +0 -0
- /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/migration.js +0 -0
- /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/metadata.json +0 -0
- /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.d.ts +0 -0
- /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.js +0 -0
- /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/metadata.json +0 -0
- /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.d.ts +0 -0
- /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.js +0 -0
- /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/metadata.json +0 -0
- /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.d.ts +0 -0
- /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.js +0 -0
- /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/metadata.json +0 -0
- /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.d.ts +0 -0
- /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.js +0 -0
- /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/metadata.json +0 -0
- /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.d.ts +0 -0
- /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.js +0 -0
- /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/metadata.json +0 -0
- /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.94/0002-shx-fs-commands}/migration.d.ts +0 -0
- /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/migration.js +0 -0
- /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/metadata.json +0 -0
- /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.d.ts +0 -0
- /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.js +0 -0
- /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/metadata.json +0 -0
- /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/migration.d.ts +0 -0
- /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/migration.js +0 -0
- /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/metadata.json +0 -0
- /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/migration.d.ts +0 -0
- /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/migration.js +0 -0
- /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/metadata.json +0 -0
- /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/migration.d.ts +0 -0
- /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/migration.js +0 -0
- /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/metadata.json +0 -0
- /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.d.ts +0 -0
- /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.js +0 -0
- /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/__snapshots__/migration.spec.ts.snap +0 -0
- /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/metadata.json +0 -0
- /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/migration.d.ts +0 -0
- /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/migration.js +0 -0
- /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/metadata.json +0 -0
- /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/migration.d.ts +0 -0
- /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/migration.js +0 -0
- /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0003-terraform-validate-without-backend}/metadata.json +0 -0
- /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.97/0003-terraform-validate-without-backend}/migration.d.ts +0 -0
- /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0003-terraform-validate-without-backend}/migration.js +0 -0
- /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.97/0004-py-lambda-powertools-context}/metadata.json +0 -0
- /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.97/0004-py-lambda-powertools-context}/migration.js +0 -0
- /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/__snapshots__/migration.spec.ts.snap +0 -0
- /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/metadata.json +0 -0
- /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/migration.d.ts +0 -0
- /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/migration.js +0 -0
- /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.97/0006-script-project-quality-gates}/metadata.json +0 -0
- /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.97/0006-script-project-quality-gates}/migration.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0003-terraform-provider-plugin-cache/migration.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 type MigrationReturnObject,\n OverwriteStrategy,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { relative } from 'path';\nimport { TERRAFORM_PROJECT_GENERATOR_INFO } from '../../../terraform/project/generator.js';\nimport {\n addDestructuredImport,\n applyGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { kebabCase } from '../../../utils/names.js';\n\n/**\n * Terraform projects share their provider downloads through\n * `TF_PLUGIN_CACHE_DIR`, so a `terraform init` whose `.terraform` was cleaned\n * links the providers already on disk instead of re-downloading them. The AWS\n * provider alone is several hundred megabytes, which dominated the `test`\n * target's runtime on every cache miss.\n *\n * The cache lives under the already-gitignored `.terraform` at the workspace\n * root, one directory per project. Terraform reports an error and silently falls\n * back to downloading when the directory does not exist, so each target creates\n * it first, and the vended `init` script gets an `env` helper that does the same.\n *\n * A directory per project rather than one shared: two `terraform init` runs\n * filling one cache concurrently each compute a different hash for the same\n * provider, and terraform then rejects the mismatch against the lock file.\n *\n * Nx does not interpolate `{workspaceRoot}` inside `env`, so the value is\n * relative to the target's own `cwd` of `{projectRoot}/src`.\n */\n\nconst TF_PLUGIN_CACHE_DIR = 'TF_PLUGIN_CACHE_DIR';\n\nconst divergedStep = (projectName: string, targetName: string) =>\n `${projectName}: its '${targetName}' target no longer matches the shape the generator produced - left untouched. To reuse provider downloads, set the \\`TF_PLUGIN_CACHE_DIR\\` env var to \\`.terraform/plugin-cache/<projectRoot>\\` under the workspace root (relative to the target's \\`cwd\\`), creating that directory before \\`terraform init\\` runs.`;\n\n/** Path to this project's cache from a target running in `{projectRoot}/src`. */\nconst pluginCacheDirFor = (projectRoot: string) =>\n joinPathFragments(\n relative(joinPathFragments(projectRoot, 'src'), '.') || '.',\n '.terraform',\n 'plugin-cache',\n '{projectRoot}',\n ).replace(/\\\\/g, '/');\n\n/** Whether a target already runs the command, however it is expressed. */\nconst hasCommand = (\n commands: unknown,\n predicate: (command: string) => boolean,\n): boolean =>\n Array.isArray(commands) &&\n commands.some((c) => {\n const command = typeof c === 'string' ? c : (c?.command as string);\n return typeof command === 'string' && predicate(command);\n });\n\n/**\n * Prepend the `make-dir` that creates the cache directory. `forwardAllArgs` is\n * off for it alone, so args meant for `terraform` are not passed to `make-dir`.\n */\nconst withMakeDir = (commands: unknown[], pluginCacheDir: string) => [\n { command: `make-dir ${pluginCacheDir}`, forwardAllArgs: false },\n ...commands,\n];\n\n/**\n * The `terraform init` call in the vended `init` script, matched structurally so\n * formatting and argument layout don't affect whether it is recognised.\n */\nconst INIT_CALL =\n \"`execFileSync('terraform', [$args], { cwd: srcDir, stdio: 'inherit' })`\";\nconst INIT_CALL_WITH_ENV =\n \"`execFileSync('terraform', [$args], { cwd: srcDir, stdio: 'inherit', env: pluginCacheEnv(projectRootRel) })`\";\n\nconst divergedScriptStep = (filePath: string) =>\n `${filePath}: its \\`terraform init\\` call no longer matches the shape the generator produced - left untouched. Pass \\`env: pluginCacheEnv(projectRootRel)\\` to that \\`execFileSync\\` so it shares the provider cache in \\`scripts/env.ts\\`.`;\n\n/**\n * Route the vended `init` script's `terraform init` through the shared cache.\n *\n * Guarded on the helper not already being imported, so a re-run — and a project\n * generated with the cache — is a no-op.\n */\nconst migrateInitScript = async (\n tree: Tree,\n filePath: string,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(filePath)) return;\n if (await matchGritQL(tree, filePath, '`pluginCacheEnv($_)`')) return;\n\n if (!(await matchGritQL(tree, filePath, INIT_CALL))) {\n nextSteps.push(divergedScriptStep(filePath));\n return;\n }\n\n await applyGritQL(tree, filePath, `${INIT_CALL} => ${INIT_CALL_WITH_ENV}`);\n\n // Placed in the generator's import position rather than prepended, so a\n // migrated workspace matches a freshly generated one.\n const awsConfigImport = \"`import { resolveAwsConfig } from './aws-config'`\";\n if (await matchGritQL(tree, filePath, awsConfigImport)) {\n await applyGritQL(\n tree,\n filePath,\n `${awsConfigImport} => \\`import { resolveAwsConfig } from './aws-config';\\nimport { pluginCacheEnv } from './env'\\``,\n );\n } else {\n await addDestructuredImport(tree, filePath, ['pluginCacheEnv'], './env');\n }\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;\n\n const targets = project.targets ?? {};\n const pluginCacheDir = pluginCacheDirFor(project.root);\n let changed = false;\n\n /**\n * Wire the cache into a target that runs `terraform init`. Only the exact\n * shape the generator produced is rewritten; anything else is the user's and\n * is reported instead. Guarded on the env var being absent, so a re-run —\n * and a project already generated with the cache — is a no-op.\n */\n const migrateTarget = (\n targetName: string,\n target: TargetConfiguration | undefined,\n /** Where the commands live: on the target, or under a configuration. */\n commandsHolder: { commands?: unknown; env?: Record<string, string> },\n env: Record<string, string> | undefined,\n ) => {\n if (!target) return;\n if (env?.[TF_PLUGIN_CACHE_DIR]) return;\n\n if (\n !hasCommand(commandsHolder.commands, (c) =>\n c.includes('terraform init'),\n )\n ) {\n nextSteps.push(divergedStep(projectName, targetName));\n return;\n }\n\n commandsHolder.commands = withMakeDir(\n commandsHolder.commands as unknown[],\n pluginCacheDir,\n );\n target.options = {\n ...target.options,\n parallel: false,\n env: { ...target.options?.env, [TF_PLUGIN_CACHE_DIR]: pluginCacheDir },\n };\n changed = true;\n };\n\n // `test` carries its `terraform init -backend=false` on the target itself.\n const test = targets.test;\n if (test?.options) {\n const wasMigrated = test.options.env?.[TF_PLUGIN_CACHE_DIR] !== undefined;\n migrateTarget('test', test, test.options, test.options.env);\n\n // The data dir becomes symlinks into the shared cache, so it is no longer\n // a self-contained artifact worth restoring on another machine. Only the\n // exact output the generator declared is dropped.\n if (\n !wasMigrated &&\n test.outputs?.length === 1 &&\n test.outputs[0] === '{workspaceRoot}/dist/{projectRoot}/terraform-test'\n ) {\n test.outputs = [];\n changed = true;\n }\n }\n\n // `init` carries its command under the `dev` configuration. A library's\n // runs `terraform init` directly; an application's delegates to the vended\n // script, which reads the cache from its own helper rather than the target.\n const init = targets.init;\n const initDev = init?.configurations?.dev;\n if (init?.options && initDev) {\n const isScriptDriven = hasCommand(\n initDev.commands ?? init.options.commands,\n (c) => c.includes('scripts/init.ts'),\n );\n if (!isScriptDriven) {\n // The pre-fix generator vended a single `command`; normalise it to the\n // `commands` array `make-dir` has to be prepended to.\n if (typeof initDev.command === 'string' && !initDev.commands) {\n initDev.commands = [initDev.command];\n delete initDev.command;\n }\n migrateTarget('init', init, initDev, init.options.env);\n }\n }\n\n if (changed) {\n updateProjectConfiguration(tree, projectName, { ...project, targets });\n }\n\n // An application's `init` target runs `terraform init` from the vended\n // script rather than the target, so the cache reaches it via the `env`\n // helper. The helper is new, so KeepExisting adds it while leaving a user's\n // own copy alone; the script that calls it already exists, so it is\n // rewritten below.\n if (tree.exists(joinPathFragments(project.root, 'bootstrap'))) {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n '../../../terraform/project/files/application/scripts',\n ),\n joinPathFragments(project.root, 'scripts'),\n { stateKeyPrefix: kebabCase(projectName) },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n await migrateInitScript(\n tree,\n joinPathFragments(project.root, 'scripts', 'init.ts'),\n nextSteps,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["generateFiles","getProjects","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","relative","TERRAFORM_PROJECT_GENERATOR_INFO","addDestructuredImport","applyGritQL","matchGritQL","formatFilesInSubtree","kebabCase","TF_PLUGIN_CACHE_DIR","divergedStep","projectName","targetName","pluginCacheDirFor","projectRoot","replace","hasCommand","commands","predicate","Array","isArray","some","c","command","withMakeDir","pluginCacheDir","forwardAllArgs","INIT_CALL","INIT_CALL_WITH_ENV","divergedScriptStep","filePath","migrateInitScript","tree","nextSteps","exists","push","awsConfigImport","migration","project","generator","metadata","id","targets","root","changed","migrateTarget","target","commandsHolder","env","includes","options","parallel","test","wasMigrated","undefined","outputs","length","init","initDev","configurations","dev","isScriptDriven","dirname","stateKeyPrefix","overwriteStrategy","KeepExisting"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,WAAW,EACXC,iBAAiB,EAEjBC,iBAAiB,EAGjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,QAAQ,QAAQ,OAAO;AAChC,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SACEC,qBAAqB,EACrBC,WAAW,EACXC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,SAAS,QAAQ,0BAA0B;AAEpD;;;;;;;;;;;;;;;;;;CAkBC,GAED,MAAMC,sBAAsB;AAE5B,MAAMC,eAAe,CAACC,aAAqBC,aACzC,GAAGD,YAAY,OAAO,EAAEC,WAAW,oTAAoT,CAAC;AAE1V,+EAA+E,GAC/E,MAAMC,oBAAoB,CAACC,cACzBf,kBACEG,SAASH,kBAAkBe,aAAa,QAAQ,QAAQ,KACxD,cACA,gBACA,iBACAC,OAAO,CAAC,OAAO;AAEnB,wEAAwE,GACxE,MAAMC,aAAa,CACjBC,UACAC,YAEAC,MAAMC,OAAO,CAACH,aACdA,SAASI,IAAI,CAAC,CAACC;QACb,MAAMC,UAAU,OAAOD,MAAM,WAAWA,IAAKA,GAAGC;QAChD,OAAO,OAAOA,YAAY,YAAYL,UAAUK;IAClD;AAEF;;;CAGC,GACD,MAAMC,cAAc,CAACP,UAAqBQ,iBAA2B;QACnE;YAAEF,SAAS,CAAC,SAAS,EAAEE,gBAAgB;YAAEC,gBAAgB;QAAM;WAC5DT;KACJ;AAED;;;CAGC,GACD,MAAMU,YACJ;AACF,MAAMC,qBACJ;AAEF,MAAMC,qBAAqB,CAACC,WAC1B,GAAGA,SAAS,+NAA+N,CAAC;AAE9O;;;;;CAKC,GACD,MAAMC,oBAAoB,OACxBC,MACAF,UACAG;IAEA,IAAI,CAACD,KAAKE,MAAM,CAACJ,WAAW;IAC5B,IAAI,MAAMxB,YAAY0B,MAAMF,UAAU,yBAAyB;IAE/D,IAAI,CAAE,MAAMxB,YAAY0B,MAAMF,UAAUH,YAAa;QACnDM,UAAUE,IAAI,CAACN,mBAAmBC;QAClC;IACF;IAEA,MAAMzB,YAAY2B,MAAMF,UAAU,GAAGH,UAAU,IAAI,EAAEC,oBAAoB;IAEzE,wEAAwE;IACxE,sDAAsD;IACtD,MAAMQ,kBAAkB;IACxB,IAAI,MAAM9B,YAAY0B,MAAMF,UAAUM,kBAAkB;QACtD,MAAM/B,YACJ2B,MACAF,UACA,GAAGM,gBAAgB,gGAAgG,CAAC;IAExH,OAAO;QACL,MAAMhC,sBAAsB4B,MAAMF,UAAU;YAAC;SAAiB,EAAE;IAClE;AACF;AAEA,eAAe,eAAeO,UAC5BL,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACtB,aAAa2B,QAAQ,IAAIxC,YAAYkC,MAAO;QACtD,MAAMO,YAAaD,QAAQE,QAAQ,EAC/BD;QACJ,IAAIA,cAAcpC,iCAAiCsC,EAAE,EAAE;QAEvD,MAAMC,UAAUJ,QAAQI,OAAO,IAAI,CAAC;QACpC,MAAMjB,iBAAiBZ,kBAAkByB,QAAQK,IAAI;QACrD,IAAIC,UAAU;QAEd;;;;;KAKC,GACD,MAAMC,gBAAgB,CACpBjC,YACAkC,QACA,sEAAsE,GACtEC,gBACAC;YAEA,IAAI,CAACF,QAAQ;YACb,IAAIE,KAAK,CAACvC,oBAAoB,EAAE;YAEhC,IACE,CAACO,WAAW+B,eAAe9B,QAAQ,EAAE,CAACK,IACpCA,EAAE2B,QAAQ,CAAC,oBAEb;gBACAhB,UAAUE,IAAI,CAACzB,aAAaC,aAAaC;gBACzC;YACF;YAEAmC,eAAe9B,QAAQ,GAAGO,YACxBuB,eAAe9B,QAAQ,EACvBQ;YAEFqB,OAAOI,OAAO,GAAG;gBACf,GAAGJ,OAAOI,OAAO;gBACjBC,UAAU;gBACVH,KAAK;oBAAE,GAAGF,OAAOI,OAAO,EAAEF,GAAG;oBAAE,CAACvC,oBAAoB,EAAEgB;gBAAe;YACvE;YACAmB,UAAU;QACZ;QAEA,2EAA2E;QAC3E,MAAMQ,OAAOV,QAAQU,IAAI;QACzB,IAAIA,MAAMF,SAAS;YACjB,MAAMG,cAAcD,KAAKF,OAAO,CAACF,GAAG,EAAE,CAACvC,oBAAoB,KAAK6C;YAChET,cAAc,QAAQO,MAAMA,KAAKF,OAAO,EAAEE,KAAKF,OAAO,CAACF,GAAG;YAE1D,0EAA0E;YAC1E,yEAAyE;YACzE,kDAAkD;YAClD,IACE,CAACK,eACDD,KAAKG,OAAO,EAAEC,WAAW,KACzBJ,KAAKG,OAAO,CAAC,EAAE,KAAK,qDACpB;gBACAH,KAAKG,OAAO,GAAG,EAAE;gBACjBX,UAAU;YACZ;QACF;QAEA,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,MAAMa,OAAOf,QAAQe,IAAI;QACzB,MAAMC,UAAUD,MAAME,gBAAgBC;QACtC,IAAIH,MAAMP,WAAWQ,SAAS;YAC5B,MAAMG,iBAAiB7C,WACrB0C,QAAQzC,QAAQ,IAAIwC,KAAKP,OAAO,CAACjC,QAAQ,EACzC,CAACK,IAAMA,EAAE2B,QAAQ,CAAC;YAEpB,IAAI,CAACY,gBAAgB;gBACnB,uEAAuE;gBACvE,sDAAsD;gBACtD,IAAI,OAAOH,QAAQnC,OAAO,KAAK,YAAY,CAACmC,QAAQzC,QAAQ,EAAE;oBAC5DyC,QAAQzC,QAAQ,GAAG;wBAACyC,QAAQnC,OAAO;qBAAC;oBACpC,OAAOmC,QAAQnC,OAAO;gBACxB;gBACAsB,cAAc,QAAQY,MAAMC,SAASD,KAAKP,OAAO,CAACF,GAAG;YACvD;QACF;QAEA,IAAIJ,SAAS;YACX3C,2BAA2B+B,MAAMrB,aAAa;gBAAE,GAAG2B,OAAO;gBAAEI;YAAQ;QACtE;QAEA,uEAAuE;QACvE,uEAAuE;QACvE,4EAA4E;QAC5E,oEAAoE;QACpE,mBAAmB;QACnB,IAAIV,KAAKE,MAAM,CAACnC,kBAAkBuC,QAAQK,IAAI,EAAE,eAAe;YAC7D9C,cACEmC,MACAjC,kBACE,YAAY+D,OAAO,EACnB,yDAEF/D,kBAAkBuC,QAAQK,IAAI,EAAE,YAChC;gBAAEoB,gBAAgBvD,UAAUG;YAAa,GACzC;gBAAEqD,mBAAmBhE,kBAAkBiE,YAAY;YAAC;YAGtD,MAAMlC,kBACJC,MACAjC,kBAAkBuC,QAAQK,IAAI,EAAE,WAAW,YAC3CV;QAEJ;IACF;IAEA,MAAM1B,qBAAqByB;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0004-python-test-input-scoping/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type ProjectConfiguration,\n readNxJson,\n type TargetConfiguration,\n type Tree,\n updateNxJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { PYTHON_TEST_FILE_EXCLUSIONS } from '../../../py/project/generator.js';\nimport { DEPENDENT_TASKS_OUTPUT_FILES_INPUT } from '../../../ts/lib/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Editing a Python test file used to invalidate the whole build chain for its\n * project, and cascade into every downstream project. Two independent causes:\n *\n * 1. The `production` named input excluded TypeScript specs but nothing Python,\n * and the Python build targets read `default` (every file in the project), so\n * a test file was a build input by construction.\n * 2. `default` consumed *every* output of a dependency task. The Python `test`\n * target writes JUnit and coverage reports that pytest stamps wall-clock time\n * into, so each test run minted a new hash that propagated downstream.\n *\n * Targets whose output genuinely cannot contain a test file move to\n * `production`; `typecheck` deliberately stays on `default`, because `ty` checks\n * the tests directory and must re-run when a test changes.\n */\n\n/** The Python targets whose declared output cannot contain a test file. */\nconst PRODUCTION_SCOPED_TARGETS = ['compile', 'bundle-x86', 'bundle-arm'];\n\n/** The inputs those targets read once scoped to production sources. */\nconst PRODUCTION_INPUTS = ['production', '^production'];\n\n/** The inputs those targets previously read. */\nconst PREVIOUS_INPUTS = ['default', '^production'];\n\n/**\n * Dependent-task-output globs this plugin has vended. Any of them is rewritten\n * to the current one; anything else is the user's own scoping decision.\n */\nconst PREVIOUSLY_VENDED_GLOBS = ['**/*', 'dist/**'];\n\nconst isPythonProject = (project: ProjectConfiguration): boolean =>\n Object.values(project.targets ?? {}).some((target) =>\n String(target?.executor ?? '').startsWith('@nxlv/python'),\n );\n\n/**\n * An OpenAPI spec generation target as the generators vend it: named `openapi`\n * or `<agent>-openapi`, running a command, and writing its spec under\n * `dist/.../openapi`. The extra checks keep a user-authored target that merely\n * shares the suffix from being rescoped, since these targets are identified by\n * declaring no `inputs` at all.\n */\nconst isOpenApiTarget = (\n name: string,\n target?: TargetConfiguration,\n): boolean => {\n if (name !== 'openapi' && !name.endsWith('-openapi')) return false;\n if (!target) return true;\n return (\n target.executor === 'nx:run-commands' &&\n (target.outputs ?? []).some((output) => output.includes('/openapi'))\n );\n};\n\nconst arraysEqual = (a: readonly unknown[], b: readonly unknown[]): boolean =>\n a.length === b.length && a.every((entry, index) => entry === b[index]);\n\n/**\n * Excludes Python test files from the `production` named input, and narrows the\n * dependent-task-output input so test reports no longer propagate downstream.\n */\nconst migrateNamedInputs = (tree: Tree, nextSteps: string[]): void => {\n const nxJson = readNxJson(tree);\n if (!nxJson) return;\n\n // Seeded as `['default']` when absent, exactly as the generator does. The\n // targets below are rewritten to read `production`, and Nx fails hard on a\n // named input that is not defined, so the two must not diverge.\n const production = nxJson.namedInputs?.production ?? ['default'];\n const nextProduction = [\n ...production,\n ...PYTHON_TEST_FILE_EXCLUSIONS.filter(\n (exclusion) => !production.includes(exclusion),\n ),\n ];\n\n const defaultInput = nxJson.namedInputs?.default;\n let nextDefault = defaultInput;\n if (defaultInput) {\n const glob = DEPENDENT_TASKS_OUTPUT_FILES_INPUT.dependentTasksOutputFiles;\n // Only an entry this plugin vended is rewritten; a different glob is the\n // user's own scoping decision.\n nextDefault = defaultInput.map((input) =>\n typeof input === 'object' &&\n input !== null &&\n 'dependentTasksOutputFiles' in input &&\n PREVIOUSLY_VENDED_GLOBS.includes(\n input.dependentTasksOutputFiles as string,\n )\n ? { ...input, dependentTasksOutputFiles: glob }\n : input,\n );\n const hadVendedEntry = nextDefault.some(\n (input) =>\n typeof input === 'object' &&\n input !== null &&\n 'dependentTasksOutputFiles' in input &&\n input.dependentTasksOutputFiles === glob,\n );\n const hasCustomEntry = defaultInput.some(\n (input) =>\n typeof input === 'object' &&\n input !== null &&\n 'dependentTasksOutputFiles' in input &&\n !PREVIOUSLY_VENDED_GLOBS.includes(\n input.dependentTasksOutputFiles as string,\n ) &&\n input.dependentTasksOutputFiles !== glob,\n );\n if (!hadVendedEntry && hasCustomEntry) {\n nextSteps.push(\n `nx.json's 'default' named input scopes 'dependentTasksOutputFiles' to a custom glob — left untouched. Narrow it to '${glob}' so timestamped test reports do not invalidate downstream tasks.`,\n );\n }\n }\n\n updateNxJson(tree, {\n ...nxJson,\n namedInputs: {\n ...nxJson.namedInputs,\n production: nextProduction,\n ...(nextDefault ? { default: nextDefault } : {}),\n },\n });\n};\n\n/**\n * Scopes a Python project's build-chain targets to production sources. Only\n * targets still carrying the inputs the generator vended are rewritten, so a\n * project whose inputs the user has tuned is reported rather than clobbered.\n */\nconst migrateProjectTargets = (\n tree: Tree,\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): void => {\n let changed = false;\n\n for (const [targetName, target] of Object.entries(project.targets ?? {})) {\n if (\n !PRODUCTION_SCOPED_TARGETS.includes(targetName) &&\n !isOpenApiTarget(targetName, target)\n ) {\n continue;\n }\n\n const inputs = target.inputs;\n\n // Already migrated, so a re-run is a no-op.\n if (inputs && arraysEqual(inputs as unknown[], PRODUCTION_INPUTS)) {\n continue;\n }\n\n // The OpenAPI targets declared no inputs at all, so they fell back to\n // `default`. Everything else carried the vended pair.\n const isVendedShape = inputs\n ? arraysEqual(inputs as unknown[], PREVIOUS_INPUTS)\n : isOpenApiTarget(targetName, target);\n\n if (!isVendedShape) {\n nextSteps.push(\n `${projectName}:${targetName}: 'inputs' has diverged from the generated shape — left untouched. Scope it to ['production', '^production'] so Python test edits do not invalidate it.`,\n );\n continue;\n }\n\n target.inputs = [...PRODUCTION_INPUTS];\n changed = true;\n }\n\n if (changed) {\n updateProjectConfiguration(tree, projectName, project);\n }\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n migrateNamedInputs(tree, nextSteps);\n\n for (const [projectName, project] of getProjects(tree)) {\n if (!isPythonProject(project)) continue;\n migrateProjectTargets(tree, projectName, project, nextSteps);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","readNxJson","updateNxJson","updateProjectConfiguration","PYTHON_TEST_FILE_EXCLUSIONS","DEPENDENT_TASKS_OUTPUT_FILES_INPUT","formatFilesInSubtree","PRODUCTION_SCOPED_TARGETS","PRODUCTION_INPUTS","PREVIOUS_INPUTS","PREVIOUSLY_VENDED_GLOBS","isPythonProject","project","Object","values","targets","some","target","String","executor","startsWith","isOpenApiTarget","name","endsWith","outputs","output","includes","arraysEqual","a","b","length","every","entry","index","migrateNamedInputs","tree","nextSteps","nxJson","production","namedInputs","nextProduction","filter","exclusion","defaultInput","default","nextDefault","glob","dependentTasksOutputFiles","map","input","hadVendedEntry","hasCustomEntry","push","migrateProjectTargets","projectName","changed","targetName","entries","inputs","isVendedShape","migration"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0005-vitest-coverage-output-dir/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { isAbsolute } from 'path';\nimport {\n GENERATED_REPORTS_DIRECTORY,\n getCoverageReportsDirectory,\n} from '../../../ts/lib/vitest.js';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport {\n BIOME_TEST_OUTPUT_EXCLUDE,\n formatFilesInSubtree,\n} from '../../../utils/format.js';\nimport { updateGitIgnore } from '../../../utils/git.js';\n\n/**\n * Point each project's vitest coverage directory at the workspace's `dist`.\n *\n * `@nx/vitest` writes `reportsDirectory: './test-output/vitest/coverage'`, which\n * resolves inside the project. Coverage is off by default, so the directory stays\n * dormant until someone runs `vitest --coverage` — at which point the HTML\n * reporter's bundled third-party scripts land in the project, where the `format`\n * target reformats them (failing every later build) and the `default` named input\n * counts them, so no task in the project can be cached again.\n *\n * Alongside the rewrite, the coverage directory an older release already wrote\n * into the project is deleted and `test-output` is added to the workspace\n * `.gitignore`, so the reporter's vendored third-party scripts can neither be\n * committed nor picked up by `license#sync`.\n *\n * Guardrails:\n * - The pattern is anchored to the exact literal `@nx/vitest` generated, and\n * scoped to the `coverage` block of the config's own `test` object, so a\n * `reportsDirectory` elsewhere in the file is left alone.\n * - A project whose directory has been repointed keeps its value, and is reported\n * via `nextSteps` instead — as is one whose directory is set on a target, or a\n * `biome.json` whose `files.includes` has diverged from the vended list.\n * - Idempotent: the pattern no longer matches once rewritten.\n */\n\n/**\n * The config filenames to check. Generated projects carry the `.mts` forms; the\n * other extensions vitest supports are included so a project whose config was\n * renamed is still migrated. Safe to widen, because the pattern matched inside is\n * anchored to the exact literal `@nx/vitest` generated.\n */\nconst CONFIG_FILES = [\n 'vitest.config.mts',\n 'vitest.config.ts',\n 'vitest.config.mjs',\n 'vitest.config.js',\n 'vite.config.mts',\n 'vite.config.ts',\n 'vite.config.mjs',\n 'vite.config.js',\n];\n\n/**\n * The `coverage` block of the object the config factory returns, scoped so a\n * `coverage` option elsewhere in the file is not matched.\n */\nconst coveragePattern = (body: string): string =>\n `\\`test: { $props }\\` where {\n $props <: within \\`defineConfig($_)\\`,\n $props <: some \\`coverage: { $cov }\\`,\n ${body}\n}`;\n\n/** Matches a coverage block still carrying the directory `@nx/vitest` generated. */\nconst GENERATED_DIRECTORY_PATTERN = coveragePattern(\n `$cov <: some \\`reportsDirectory: '${GENERATED_REPORTS_DIRECTORY}'\\``,\n);\n\n/** Matches a coverage block that declares a `reportsDirectory` at all. */\nconst ANY_DIRECTORY_PATTERN = coveragePattern(\n '$cov <: some `reportsDirectory: $_`',\n);\n\n/** Rewrites the generated directory to the one under `dist` for a project root. */\nconst rewriteDirectoryPattern = (projectRoot: string): string =>\n coveragePattern(\n `$cov <: some \\`reportsDirectory: '${GENERATED_REPORTS_DIRECTORY}'\\` as $reportsDirectory,\n $reportsDirectory => \\`reportsDirectory: '${getCoverageReportsDirectory(projectRoot)}'\\``,\n );\n\n/** Matches a coverage block already pointing at the directory under `dist`. */\nconst migratedDirectoryPattern = (projectRoot: string): string =>\n coveragePattern(\n `$cov <: some \\`reportsDirectory: '${getCoverageReportsDirectory(projectRoot)}'\\``,\n );\n\n/** The directory an older release wrote coverage into, relative to a project. */\nconst OLD_COVERAGE_DIRECTORY = 'test-output';\n\n/**\n * Exclude test reports from Biome, so a coverage directory pointed anywhere\n * inside the workspace is still never formatted or linted. Anchored to the\n * excludes we vend, so a workspace that has rewritten `files.includes` keeps its\n * own list — and is told to add the exclude itself.\n */\nconst excludeTestOutputFromBiome = (tree: Tree): string[] => {\n if (!tree.exists('biome.json')) {\n return [];\n }\n let unrecognised = false;\n updateJson(tree, 'biome.json', (biome) => {\n const includes: unknown = biome?.files?.includes;\n if (\n !Array.isArray(includes) ||\n includes.includes(BIOME_TEST_OUTPUT_EXCLUDE)\n ) {\n return biome;\n }\n // Placed next to the other build-output excludes. Without that anchor the\n // list has diverged from the one we vend, so leave it to the user.\n if (!includes.includes('!**/out-tsc')) {\n unrecognised = true;\n return biome;\n }\n return {\n ...biome,\n files: {\n ...biome.files,\n includes: includes.flatMap((include) =>\n include === '!**/out-tsc'\n ? [include, BIOME_TEST_OUTPUT_EXCLUDE]\n : [include],\n ),\n },\n };\n });\n return unrecognised\n ? [\n `\\`biome.json\\`: add \\`\"${BIOME_TEST_OUTPUT_EXCLUDE}\"\\` to \\`files.includes\\` so test reports are never formatted or linted. Its \\`files.includes\\` has diverged from the vended list, so it was left as it is.`,\n ]\n : [];\n};\n\n/**\n * Delete the coverage directory an older release wrote inside the project.\n *\n * Left in place it stays git-visible: the vended `.gitignore` covers `dist` but\n * not `test-output`, so the HTML reporter's vendored third-party scripts can be\n * committed, and `license#sync` — which builds its candidate set from\n * git-visible files rather than from `biome.json` — would stamp an Apache-2.0\n * header onto them. Only the reporter's own output is removed; anything else the\n * user keeps there is left alone.\n */\nconst deleteOldCoverageDirectory = (tree: Tree, projectRoot: string): void => {\n const oldDirectory = joinPathFragments(\n projectRoot,\n OLD_COVERAGE_DIRECTORY,\n 'vitest/coverage',\n );\n if (tree.exists(oldDirectory)) {\n tree.delete(oldDirectory);\n }\n};\n\n/**\n * A `reportsDirectory` set on a target rather than in the vitest config, which\n * takes precedence over the config value. `@nx/vitest` supports this shape, so\n * report any that still resolves inside the project — rewriting a target option\n * is the user's call, not this migration's.\n */\nconst targetReportsDirectories = (\n project: ProjectConfiguration,\n): { target: string; reportsDirectory: string }[] => {\n const found: { target: string; reportsDirectory: string }[] = [];\n for (const [target, config] of Object.entries(project.targets ?? {})) {\n for (const options of [\n config.options,\n ...Object.values(config.configurations ?? {}),\n ]) {\n const reportsDirectory: unknown = options?.reportsDirectory;\n // A path escaping the project root is already outside it.\n if (\n typeof reportsDirectory === 'string' &&\n !reportsDirectory.startsWith('..') &&\n !isAbsolute(reportsDirectory)\n ) {\n found.push({ target, reportsDirectory });\n }\n }\n }\n return found;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [...excludeTestOutputFromBiome(tree)];\n\n // Test reports are build output, so ignore them wherever a project writes them.\n updateGitIgnore(tree, '.', (patterns) =>\n patterns.includes(OLD_COVERAGE_DIRECTORY)\n ? patterns\n : [...patterns, OLD_COVERAGE_DIRECTORY],\n );\n\n for (const [name, project] of getProjects(tree)) {\n for (const { target, reportsDirectory } of targetReportsDirectories(\n project,\n )) {\n nextSteps.push(\n `${name}: the \\`${target}\\` target sets \\`reportsDirectory: '${reportsDirectory}'\\`, which resolves inside the project and takes precedence over the vitest config. Point it outside the project (eg \\`${getCoverageReportsDirectory(project.root)}\\`).`,\n );\n }\n\n for (const configFile of CONFIG_FILES) {\n const configPath = joinPathFragments(project.root, configFile);\n if (!tree.exists(configPath)) {\n continue;\n }\n\n if (await matchGritQL(tree, configPath, GENERATED_DIRECTORY_PATTERN)) {\n await applyGritQL(\n tree,\n configPath,\n rewriteDirectoryPattern(project.root),\n );\n deleteOldCoverageDirectory(tree, project.root);\n continue;\n }\n\n // A directory the user repointed is theirs to keep, but it may still sit\n // inside the project, so report it rather than rewriting it. A config\n // declaring no directory at all relies on vitest's default, which this\n // migration has no generated shape to match.\n if (\n (await matchGritQL(tree, configPath, ANY_DIRECTORY_PATTERN)) &&\n !(await matchGritQL(\n tree,\n configPath,\n migratedDirectoryPattern(project.root),\n ))\n ) {\n nextSteps.push(\n `${name}: \\`${configPath}\\` sets its own \\`test.coverage.reportsDirectory\\`. Point it outside the project (eg \\`${getCoverageReportsDirectory(project.root)}\\`) so coverage output is not formatted, linted or treated as a task input.`,\n );\n }\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateJson","isAbsolute","GENERATED_REPORTS_DIRECTORY","getCoverageReportsDirectory","applyGritQL","matchGritQL","BIOME_TEST_OUTPUT_EXCLUDE","formatFilesInSubtree","updateGitIgnore","CONFIG_FILES","coveragePattern","body","GENERATED_DIRECTORY_PATTERN","ANY_DIRECTORY_PATTERN","rewriteDirectoryPattern","projectRoot","migratedDirectoryPattern","OLD_COVERAGE_DIRECTORY","excludeTestOutputFromBiome","tree","exists","unrecognised","biome","includes","files","Array","isArray","flatMap","include","deleteOldCoverageDirectory","oldDirectory","delete","targetReportsDirectories","project","found","target","config","Object","entries","targets","options","values","configurations","reportsDirectory","startsWith","push","migration","nextSteps","patterns","name","root","configFile","configPath"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0006-add-assemble-target/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { TERRAFORM_PROJECT_GENERATOR_INFO } from '../../../terraform/project/generator.js';\nimport { REACT_WEBSITE_APP_GENERATOR_INFO } from '../../../ts/react-website/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n normalizeTargetKeyOrder,\n type TargetDependency,\n} from '../../../utils/nx.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\n\n/**\n * `build` runs everything: it produces a project's deployable artifacts and runs\n * its quality gates (lint, test, typecheck). The deploy targets depended on\n * `^build`, so deploying pulled in every upstream project's gates too — work a\n * deploy does not need.\n *\n * `assemble` is the artifact-only sibling of `build`, which the deploy targets\n * depend on instead. `build` is untouched, so it remains the target that runs\n * everything.\n *\n * Each project's `assemble` is derived from what its own `build` declares rather\n * than from the generator that created it, so a project whose build has been\n * extended with an extra artifact target keeps producing it. Anything this\n * migration cannot classify is reported via `nextSteps` and left alone.\n *\n * A `compile` target depending on `^build` is also narrowed to `^compile`, which\n * is what keeps `^assemble` from pulling the upstream quality gates back in.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n */\n\n/**\n * Targets that produce a deployable artifact, so they belong on `assemble`.\n *\n * `bundle-migration` and `bundle-create-db-user` are the RDB bundles, which the\n * generator registers on `build` directly as well as on `bundle`.\n */\nconst ARTIFACT_TARGETS = [\n 'compile',\n 'bundle',\n 'bundle-migration',\n 'bundle-create-db-user',\n 'docker',\n 'openapi',\n 'operations',\n 'synth',\n 'generate-ssdk',\n];\n\n/**\n * Targets that check the code rather than produce an artifact. Listed so an\n * unrecognised entry is reported rather than silently classified either way.\n *\n * `fmt` is the Terraform formatter, and `checkov` scans what the build has\n * already produced, so neither produces an artifact of its own.\n */\nconst QUALITY_GATES = ['lint', 'format', 'fmt', 'test', 'typecheck', 'checkov'];\n\n/** The CDK targets whose `^build` becomes `^assemble`. */\nconst CDK_DEPLOY_TARGETS = [\n 'synth',\n 'deploy',\n 'deploy-sandbox',\n 'destroy',\n 'destroy-sandbox',\n];\n\n/** True when the project was created by the given generator. */\nconst generatedBy = (project: ProjectConfiguration, id: string): boolean =>\n (project.metadata as { generator?: string } | undefined)?.generator === id;\n\n/**\n * `generate:<name>` targets write generated source (an API client, operations\n * metadata) that the infrastructure reads, so they produce artifacts.\n */\nconst isGenerateTarget = (target: string): boolean =>\n target.startsWith('generate:') || target === 'generate';\n\n/**\n * The `assemble` dependencies derived from a project's `build`.\n *\n * Returns `'unclassifiable'` when `build` declares something this migration\n * cannot classify, so the caller reports it rather than guessing. A `build` that\n * declares nothing at all is not unclassifiable — it yields an empty list, and\n * the project gets a no-op `assemble`.\n */\nconst assembleDependenciesFor = (\n build: ProjectConfiguration['targets'][string] | undefined,\n): TargetDependency[] | 'unclassifiable' => {\n const dependsOn = build?.dependsOn;\n if (dependsOn === undefined) return [];\n if (!Array.isArray(dependsOn)) return 'unclassifiable';\n\n const dependencies: TargetDependency[] = [];\n for (const dependency of dependsOn) {\n // The object form is valid Nx, and this plugin emits it. It names another\n // project's target explicitly, so it is classified on that target.\n if (typeof dependency !== 'string') {\n const objectTarget = (dependency as { target?: unknown })?.target;\n if (typeof objectTarget !== 'string') return 'unclassifiable';\n if (objectTarget === 'build') {\n dependencies.push({ ...dependency, target: 'assemble' });\n continue;\n }\n if (\n ARTIFACT_TARGETS.includes(objectTarget) ||\n isGenerateTarget(objectTarget)\n ) {\n dependencies.push(dependency);\n continue;\n }\n if (QUALITY_GATES.includes(objectTarget)) continue;\n return 'unclassifiable';\n }\n const [, crossProjectTarget] = dependency.match(/^.+:([^:]+)$/) ?? [];\n if (crossProjectTarget === 'build') {\n // Mirror the cross-project edge against the consumed project's own\n // `assemble`, which keeps the artifact-only chain closed.\n dependencies.push(dependency.replace(/:build$/, ':assemble'));\n continue;\n }\n if (ARTIFACT_TARGETS.includes(crossProjectTarget)) {\n // Already names an artifact target on the other project, so it carries\n // over unchanged.\n dependencies.push(dependency);\n continue;\n }\n if (crossProjectTarget && QUALITY_GATES.includes(crossProjectTarget)) {\n continue;\n }\n if (ARTIFACT_TARGETS.includes(dependency) || isGenerateTarget(dependency)) {\n dependencies.push(dependency);\n continue;\n }\n if (QUALITY_GATES.includes(dependency)) continue;\n return 'unclassifiable';\n }\n return dependencies;\n};\n\n/**\n * Adds the project's `assemble`, derived from its `build`. Returns whether the\n * project was changed.\n */\nconst addAssembleTarget = (\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): boolean => {\n // Already migrated. A project's own `package` target is deliberately left\n // alone: that name is for publishing to a package manager, a different job.\n if (project.targets.assemble) return false;\n\n // Nothing to derive an `assemble` from, so there is nothing to do. Consumers\n // reference `<project>:build`, which is untouched.\n if (!project.targets.build) return false;\n\n const dependencies = assembleDependenciesFor(project.targets.build);\n\n if (dependencies === 'unclassifiable') {\n // Consumers have already been repointed at this project's `assemble`, and Nx\n // silently skips a dependency whose target does not exist, so say so: an\n // unmigrated project here means its artifacts stop being built for a deploy.\n nextSteps.push(\n `Add an 'assemble' target to ${projectName} by hand — its 'build' target declares dependencies this migration does not recognise. It should depend on whichever of build's dependencies produce deployable artifacts, and on none of its lint/test/typecheck gates. Projects that consume ${projectName} now depend on '${projectName}:assemble', and Nx silently skips a dependency on a target that does not exist, so until you add it a deploy will not rebuild this project's artifacts.`,\n );\n return false;\n }\n\n project.targets.assemble = normalizeTargetKeyOrder(\n dependencies.length > 0\n ? { dependsOn: dependencies }\n : { executor: 'nx:noop' },\n );\n return true;\n};\n\n/** Repoints one entry of a target's `dependsOn`. */\nconst repoint = (\n target: ProjectConfiguration['targets'][string] | undefined,\n from: string,\n to: string,\n): 'repointed' | 'already' | 'diverged' => {\n const dependsOn = target?.dependsOn;\n if (!Array.isArray(dependsOn)) return 'diverged';\n if (dependsOn.includes(to)) return 'already';\n const index = dependsOn.indexOf(from);\n if (index === -1) return 'diverged';\n dependsOn[index] = to;\n return 'repointed';\n};\n\n/** Points a CDK infrastructure project's deploy targets at `^assemble`. */\nconst migrateCdkDeployTargets = (\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): boolean => {\n let changed = false;\n const diverged: string[] = [];\n\n for (const name of CDK_DEPLOY_TARGETS) {\n if (!project.targets[name]) continue;\n const result = repoint(project.targets[name], '^build', '^assemble');\n if (result === 'repointed') changed = true;\n if (result === 'diverged') diverged.push(name);\n }\n\n if (diverged.length > 0) {\n const targets = diverged.map((t) => `'${t}'`).join(', ');\n const singular = diverged.length === 1;\n nextSteps.push(\n `Point ${targets} on ${projectName} at '^assemble' by hand — ${singular ? 'it does' : 'they do'} not depend on '^build' as the generator left ${singular ? 'it' : 'them'}.`,\n );\n }\n return changed;\n};\n\n/**\n * Points a Terraform application's `plan` at `assemble`, so planning no longer\n * runs the module tests.\n */\nconst migrateTerraformPlanTarget = (\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): boolean => {\n const result = repoint(project.targets.plan, 'build', 'assemble');\n if (result === 'diverged') {\n nextSteps.push(\n `Point 'plan' on ${projectName} at 'assemble' by hand — it does not depend on 'build' as the generator left it.`,\n );\n }\n return result === 'repointed';\n};\n\n/**\n * A website's `compile` needs its dependencies' declarations, which `compile`\n * emits — not their lint or test results. Narrowing it is what keeps `^assemble`\n * from pulling the upstream quality gates back in.\n *\n * Keyed off the target's shape rather than the generator, so a project that\n * adopted the same `^build` compile is narrowed too. A project the plugin did\n * not generate is reported, since its `compile` may depend on `^build` for a\n * reason this migration cannot see.\n */\nconst narrowCompileTarget = (\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): boolean => {\n if (repoint(project.targets.compile, '^build', '^compile') !== 'repointed') {\n return false;\n }\n if (!generatedBy(project, REACT_WEBSITE_APP_GENERATOR_INFO.id)) {\n nextSteps.push(\n `Narrowed 'compile' on ${projectName} from '^build' to '^compile', so it no longer waits for its dependencies' lint and test targets. Revert it if that project's compile relied on an upstream step that only 'build' runs.`,\n );\n }\n return true;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n project.targets ??= {};\n\n let changed = addAssembleTarget(projectName, project, nextSteps);\n\n if (generatedBy(project, INFRA_APP_GENERATOR_INFO.id)) {\n // `synth` is the cloud assembly, so it belongs on `assemble`; `checkov`\n // scans that assembly and stays a `build`-only gate.\n const assemble = project.targets.assemble;\n if (assemble?.dependsOn && !assemble.dependsOn.includes('synth')) {\n assemble.dependsOn.push('synth');\n changed = true;\n }\n changed =\n migrateCdkDeployTargets(projectName, project, nextSteps) || changed;\n }\n\n if (\n generatedBy(project, TERRAFORM_PROJECT_GENERATOR_INFO.id) &&\n project.projectType === 'application'\n ) {\n changed =\n migrateTerraformPlanTarget(projectName, project, nextSteps) || changed;\n }\n\n changed = narrowCompileTarget(projectName, project, nextSteps) || changed;\n\n if (changed) {\n updateProjectConfiguration(tree, projectName, {\n ...project,\n targets: sortObjectKeys(project.targets),\n });\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","TERRAFORM_PROJECT_GENERATOR_INFO","REACT_WEBSITE_APP_GENERATOR_INFO","formatFilesInSubtree","normalizeTargetKeyOrder","sortObjectKeys","ARTIFACT_TARGETS","QUALITY_GATES","CDK_DEPLOY_TARGETS","generatedBy","project","id","metadata","generator","isGenerateTarget","target","startsWith","assembleDependenciesFor","build","dependsOn","undefined","Array","isArray","dependencies","dependency","objectTarget","push","includes","crossProjectTarget","match","replace","addAssembleTarget","projectName","nextSteps","targets","assemble","length","executor","repoint","from","to","index","indexOf","migrateCdkDeployTargets","changed","diverged","name","result","map","t","join","singular","migrateTerraformPlanTarget","plan","narrowCompileTarget","compile","migration","tree","projectType"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0007-docker-target-cache-soundness/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { IMAGE_BUILD_CACHE } from '../../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Stop Nx caching the targets that build and scan container images.\n *\n * A built image lives in the container engine's store, not under any `outputs`\n * path, so there was nothing for Nx to restore on a cache hit: `build` reported\n * success for an image the engine no longer had, and the `trivy` target that\n * depends on it reported a cached pass against that missing image — so a stale\n * or absent image could clear both a build and a vulnerability scan.\n *\n * The container engine's layer cache already makes the rebuild cheap and, unlike\n * Nx's, it cannot claim a hit for an image that isn't there.\n *\n * A target named as one of these but no longer running the engine has been\n * reworked by the user, so it is left untouched and reported via `nextSteps`.\n */\n\n/** Names the generators give the targets that build or scan an image. */\nconst IMAGE_TARGET_NAME = /(^|-)(docker|trivy)$/;\n\n/** Commands that build an image, or read one back out of the engine to scan it. */\nconst CONTAINER_ENGINE_COMMAND = /\\b(docker|finch)\\s+(build|save)\\b/;\n\n/**\n * The `Dockerfile` the TypeScript image targets declared as their output. It is\n * a copy made on the way into the build context, never a product of the build,\n * so it is dropped along with the caching it existed to support.\n */\nconst VENDED_DOCKERFILE_OUTPUT = /\\/bundle\\/(agent|mcp)\\/[^/]+\\/Dockerfile$/;\n\n/** The directory the scan target stages its tarball and ignore file in. */\nconst VENDED_SCAN_OUTPUT = /\\/trivy\\/[^/]+$/;\n\n/**\n * Outputs the generators declare on these targets. Neither is the artifact the\n * target's success stands for, so dropping their caching loses nothing. An\n * output beyond these belongs to a target the user has repurposed, whose product\n * may genuinely be on disk and soundly cacheable.\n */\nconst isVendedOutput = (output: string): boolean =>\n VENDED_DOCKERFILE_OUTPUT.test(output) || VENDED_SCAN_OUTPUT.test(output);\n\n/** Every command a target runs, however its options spell them. */\nconst targetCommands = (target: TargetConfiguration): string[] => {\n const { command, commands } = (target.options ?? {}) as {\n command?: unknown;\n commands?: unknown;\n };\n return [\n ...(typeof command === 'string' ? [command] : []),\n ...(Array.isArray(commands) ? commands : []),\n ].filter((c): c is string => typeof c === 'string');\n};\n\nconst divergedMessage = (projectName: string, targetName: string) =>\n `${projectName}:${targetName}: has diverged from the generated shape - left untouched. Set \\`\"cache\": false\\` on it by hand if it builds or scans a container image: the image lives in the container engine rather than under the target's \\`outputs\\`, so a cache hit can report success for an image that is no longer there.`;\n\nconst ownOutputsMessage = (projectName: string, targetName: string) =>\n `${projectName}:${targetName}: declares outputs of its own, so it was left cacheable. If its result depends on a container image rather than only on those outputs, set \\`\"cache\": false\\` on it by hand: the image lives in the container engine, so a cache hit can report success for an image that is no longer there.`;\n\n/** Applies the fix to one target, reporting one it declines to touch. */\nconst migrateTarget = (\n projectName: string,\n targetName: string,\n target: TargetConfiguration,\n nextSteps: string[],\n): boolean => {\n // A target with `cache` unset is not cached unless `targetDefaults` opts it\n // in, and one already set to false is sound, so only an explicitly cacheable\n // one needs rewriting. Both leave a re-run a no-op.\n if (target.cache !== true) return false;\n\n if (!targetCommands(target).some((c) => CONTAINER_ENGINE_COMMAND.test(c))) {\n nextSteps.push(divergedMessage(projectName, targetName));\n return false;\n }\n\n // Running the engine does not by itself make a target's result uncacheable:\n // one that also declares outputs of its own may well produce the artifact its\n // success stands for on disk (a `docker save` tarball, a test report), and\n // that is soundly cacheable. Only the shapes the generators vend are rewritten.\n const ownOutputs = target.outputs?.filter((o) => !isVendedOutput(o)) ?? [];\n if (ownOutputs.length > 0) {\n nextSteps.push(ownOutputsMessage(projectName, targetName));\n return false;\n }\n\n target.cache = IMAGE_BUILD_CACHE;\n\n // The scan keeps its staging directory: it is a real directory on disk, and\n // dropping it would leave the tarball behind on a later run.\n const outputs = target.outputs?.filter(\n (o) => !VENDED_DOCKERFILE_OUTPUT.test(o),\n );\n if (outputs && outputs.length === 0) {\n delete target.outputs;\n } else if (outputs) {\n target.outputs = outputs;\n }\n\n return true;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n let changed = false;\n\n for (const [targetName, target] of Object.entries(project.targets ?? {})) {\n // Matched on the name so a target reworked to no longer run the engine is\n // still found and reported, rather than silently left cacheable.\n if (!IMAGE_TARGET_NAME.test(targetName)) continue;\n\n changed =\n migrateTarget(projectName, targetName, target, nextSteps) || changed;\n }\n\n if (changed) {\n updateProjectConfiguration(\n tree,\n projectName,\n project as ProjectConfiguration,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","IMAGE_BUILD_CACHE","formatFilesInSubtree","IMAGE_TARGET_NAME","CONTAINER_ENGINE_COMMAND","VENDED_DOCKERFILE_OUTPUT","VENDED_SCAN_OUTPUT","isVendedOutput","output","test","targetCommands","target","command","commands","options","Array","isArray","filter","c","divergedMessage","projectName","targetName","ownOutputsMessage","migrateTarget","nextSteps","cache","some","push","ownOutputs","outputs","o","length","migration","tree","project","changed","Object","entries","targets"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAKXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,iBAAiB,QAAQ,2BAA2B;AAC7D,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;;;CAcC,GAED,uEAAuE,GACvE,MAAMC,oBAAoB;AAE1B,iFAAiF,GACjF,MAAMC,2BAA2B;AAEjC;;;;CAIC,GACD,MAAMC,2BAA2B;AAEjC,yEAAyE,GACzE,MAAMC,qBAAqB;AAE3B;;;;;CAKC,GACD,MAAMC,iBAAiB,CAACC,SACtBH,yBAAyBI,IAAI,CAACD,WAAWF,mBAAmBG,IAAI,CAACD;AAEnE,iEAAiE,GACjE,MAAME,iBAAiB,CAACC;IACtB,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAIF,OAAOG,OAAO,IAAI,CAAC;IAIlD,OAAO;WACD,OAAOF,YAAY,WAAW;YAACA;SAAQ,GAAG,EAAE;WAC5CG,MAAMC,OAAO,CAACH,YAAYA,WAAW,EAAE;KAC5C,CAACI,MAAM,CAAC,CAACC,IAAmB,OAAOA,MAAM;AAC5C;AAEA,MAAMC,kBAAkB,CAACC,aAAqBC,aAC5C,GAAGD,YAAY,CAAC,EAAEC,WAAW,mSAAmS,CAAC;AAEnU,MAAMC,oBAAoB,CAACF,aAAqBC,aAC9C,GAAGD,YAAY,CAAC,EAAEC,WAAW,6RAA6R,CAAC;AAE7T,uEAAuE,GACvE,MAAME,gBAAgB,CACpBH,aACAC,YACAV,QACAa;IAEA,4EAA4E;IAC5E,6EAA6E;IAC7E,oDAAoD;IACpD,IAAIb,OAAOc,KAAK,KAAK,MAAM,OAAO;IAElC,IAAI,CAACf,eAAeC,QAAQe,IAAI,CAAC,CAACR,IAAMd,yBAAyBK,IAAI,CAACS,KAAK;QACzEM,UAAUG,IAAI,CAACR,gBAAgBC,aAAaC;QAC5C,OAAO;IACT;IAEA,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,gFAAgF;IAChF,MAAMO,aAAajB,OAAOkB,OAAO,EAAEZ,OAAO,CAACa,IAAM,CAACvB,eAAeuB,OAAO,EAAE;IAC1E,IAAIF,WAAWG,MAAM,GAAG,GAAG;QACzBP,UAAUG,IAAI,CAACL,kBAAkBF,aAAaC;QAC9C,OAAO;IACT;IAEAV,OAAOc,KAAK,GAAGxB;IAEf,4EAA4E;IAC5E,6DAA6D;IAC7D,MAAM4B,UAAUlB,OAAOkB,OAAO,EAAEZ,OAC9B,CAACa,IAAM,CAACzB,yBAAyBI,IAAI,CAACqB;IAExC,IAAID,WAAWA,QAAQE,MAAM,KAAK,GAAG;QACnC,OAAOpB,OAAOkB,OAAO;IACvB,OAAO,IAAIA,SAAS;QAClBlB,OAAOkB,OAAO,GAAGA;IACnB;IAEA,OAAO;AACT;AAEA,eAAe,eAAeG,UAC5BC,IAAU;IAEV,MAAMT,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACJ,aAAac,QAAQ,IAAInC,YAAYkC,MAAO;QACtD,IAAIE,UAAU;QAEd,KAAK,MAAM,CAACd,YAAYV,OAAO,IAAIyB,OAAOC,OAAO,CAACH,QAAQI,OAAO,IAAI,CAAC,GAAI;YACxE,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,CAACnC,kBAAkBM,IAAI,CAACY,aAAa;YAEzCc,UACEZ,cAAcH,aAAaC,YAAYV,QAAQa,cAAcW;QACjE;QAEA,IAAIA,SAAS;YACXnC,2BACEiC,MACAb,aACAc;QAEJ;IACF;IAEA,MAAMhC,qBAAqB+B;IAE3B,OAAO;QAAET;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0008-declare-cacheable-target-inputs/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * A cacheable target declaring no `inputs` gets Nx's implicit\n * `[\"default\", \"^default\"]`, which reads a dependency's whole project directory\n * — its README, its dev scripts, everything. That is wider than the explicit\n * inputs its siblings carry, so editing a dependency's README re-ran targets\n * whose output could not possibly change.\n *\n * Which explicit inputs are right depends on whether the target has a\n * `dependsOn`. `default` carries a transitive `dependentTasksOutputFiles` entry,\n * which Nx resolves against the task's upstream tasks — so a target with an\n * upstream task still hashes the dependency output it consumes through it, and\n * `[\"default\"]` is enough. A target with no `dependsOn` has nothing for that\n * entry to resolve against, so `default` collapses to the project's own files\n * and dropping `^default` would remove the last edge to the dependency. Those\n * keep a dependency input: `[\"default\", \"^production\"]`.\n */\n\n/** Targets whose `dependsOn` keeps the dependency edge inside `default`. */\nconst DEFAULT_ONLY_NAMES = [\n 'bundle',\n 'bundle-migration',\n 'bundle-create-db-user',\n 'operations',\n];\n\n/**\n * Suffix of the OpenAPI spec targets, which carry a per-agent prefix\n * (`my-agent-openapi`) on a project hosting more than one.\n *\n * These have no `dependsOn`, and their spec serialises models a dependency may\n * own, so they keep a dependency input — without it a dependency's model change\n * serves a stale spec, and that spec feeds client generation.\n */\nconst OPENAPI_SUFFIX = 'openapi';\n\nconst CHECKOV_TARGET = 'checkov';\n\n/**\n * Inputs for a target with no upstream task to resolve `default`'s transitive\n * `dependentTasksOutputFiles` against. `^production` rather than `^default` so a\n * dependency's test edits still do not invalidate it.\n */\nconst WITH_DEPENDENCY_INPUTS = ['default', '^production'];\n\n/** Whether a target is one of the ones narrowed to `[\"default\"]`. */\nconst isDefaultOnlyTarget = (name: string): boolean =>\n DEFAULT_ONLY_NAMES.includes(name);\n\n/** Whether a target is an OpenAPI spec target, which has no `dependsOn`. */\nconst isOpenApiTarget = (name: string): boolean =>\n name === OPENAPI_SUFFIX || name.endsWith(`-${OPENAPI_SUFFIX}`);\n\n/**\n * Whether a target still looks like the one the generators produced: a\n * run-commands target declaring where it writes. A target with no declared\n * outputs is not one of ours, and is the user's to scope since only they know\n * what it reads.\n *\n * The location is not checked. `operations` writes generated Terraform sources\n * under `packages/common/terraform/src/generated/`, not `dist`, so requiring\n * `dist` would mean this migration could never match a real one.\n */\nconst matchesVendedShape = (target: TargetConfiguration): boolean =>\n target.executor === 'nx:run-commands' &&\n Array.isArray(target.outputs) &&\n target.outputs.length > 0 &&\n target.outputs.every((output) => typeof output === 'string');\n\n/** The inputs a target should declare, or undefined to leave it alone. */\nconst inputsFor = (\n name: string,\n target: TargetConfiguration,\n): string[] | undefined => {\n // Only a cacheable target with no inputs at all falls back to Nx's implicit\n // ones, so one already declaring inputs is left as it is — which also makes\n // re-running this a no-op.\n if (!target.cache || target.inputs) return undefined;\n if (!matchesVendedShape(target)) return undefined;\n // `checkov` resolves the relative Terraform modules a project consumes, so it\n // keeps a dependency edge rather than dropping one.\n if (name === CHECKOV_TARGET || isOpenApiTarget(name)) {\n return WITH_DEPENDENCY_INPUTS;\n }\n return isDefaultOnlyTarget(name) ? ['default'] : undefined;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n let changed = false;\n\n for (const [name, target] of Object.entries(project.targets ?? {})) {\n const inputs = inputsFor(name, target);\n if (!inputs) continue;\n\n project.targets[name] = { ...target, inputs };\n changed = true;\n }\n\n if (changed) {\n updateProjectConfiguration(tree, projectName, project);\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","formatFilesInSubtree","DEFAULT_ONLY_NAMES","OPENAPI_SUFFIX","CHECKOV_TARGET","WITH_DEPENDENCY_INPUTS","isDefaultOnlyTarget","name","includes","isOpenApiTarget","endsWith","matchesVendedShape","target","executor","Array","isArray","outputs","length","every","output","inputsFor","cache","inputs","undefined","migration","tree","nextSteps","projectName","project","changed","Object","entries","targets"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;;;;CAeC,GAED,0EAA0E,GAC1E,MAAMC,qBAAqB;IACzB;IACA;IACA;IACA;CACD;AAED;;;;;;;CAOC,GACD,MAAMC,iBAAiB;AAEvB,MAAMC,iBAAiB;AAEvB;;;;CAIC,GACD,MAAMC,yBAAyB;IAAC;IAAW;CAAc;AAEzD,mEAAmE,GACnE,MAAMC,sBAAsB,CAACC,OAC3BL,mBAAmBM,QAAQ,CAACD;AAE9B,0EAA0E,GAC1E,MAAME,kBAAkB,CAACF,OACvBA,SAASJ,kBAAkBI,KAAKG,QAAQ,CAAC,CAAC,CAAC,EAAEP,gBAAgB;AAE/D;;;;;;;;;CASC,GACD,MAAMQ,qBAAqB,CAACC,SAC1BA,OAAOC,QAAQ,KAAK,qBACpBC,MAAMC,OAAO,CAACH,OAAOI,OAAO,KAC5BJ,OAAOI,OAAO,CAACC,MAAM,GAAG,KACxBL,OAAOI,OAAO,CAACE,KAAK,CAAC,CAACC,SAAW,OAAOA,WAAW;AAErD,wEAAwE,GACxE,MAAMC,YAAY,CAChBb,MACAK;IAEA,4EAA4E;IAC5E,4EAA4E;IAC5E,2BAA2B;IAC3B,IAAI,CAACA,OAAOS,KAAK,IAAIT,OAAOU,MAAM,EAAE,OAAOC;IAC3C,IAAI,CAACZ,mBAAmBC,SAAS,OAAOW;IACxC,8EAA8E;IAC9E,oDAAoD;IACpD,IAAIhB,SAASH,kBAAkBK,gBAAgBF,OAAO;QACpD,OAAOF;IACT;IACA,OAAOC,oBAAoBC,QAAQ;QAAC;KAAU,GAAGgB;AACnD;AAEA,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACC,aAAaC,QAAQ,IAAI7B,YAAY0B,MAAO;QACtD,IAAII,UAAU;QAEd,KAAK,MAAM,CAACtB,MAAMK,OAAO,IAAIkB,OAAOC,OAAO,CAACH,QAAQI,OAAO,IAAI,CAAC,GAAI;YAClE,MAAMV,SAASF,UAAUb,MAAMK;YAC/B,IAAI,CAACU,QAAQ;YAEbM,QAAQI,OAAO,CAACzB,KAAK,GAAG;gBAAE,GAAGK,MAAM;gBAAEU;YAAO;YAC5CO,UAAU;QACZ;QAEA,IAAIA,SAAS;YACX7B,2BAA2ByB,MAAME,aAAaC;QAChD;IACF;IAEA,MAAM3B,qBAAqBwB;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0009-terraform-fmt-check/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addLicenseCheckToLintTarget } from '../../../license/config.js';\nimport {\n TERRAFORM_FORMAT_TARGET,\n TERRAFORM_PROJECT_GENERATOR_INFO,\n} from '../../../terraform/project/generator.js';\nimport { applyGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { sortObjectKeys } from '../../../utils/object.js';\n\n/**\n * Converges a Terraform project's format target on the shape ts and py projects\n * carry: a `format` target that checks, a `fix` configuration that writes, and a\n * `lint` target orchestrating it so `run-many --target lint` reaches Terraform\n * projects with its `fix` and `skip-lint` configurations propagating.\n *\n * The target was named `fmt` and ran `terraform fmt`, which rewrites the files it\n * reads. Those files are its own declared `inputs`, so every run changed the hash\n * it had just been computed from and it could never cache-hit — Nx reported it\n * flaky on every build. That per-run write is also what kept the vended\n * `providers.tf` backend block aligned, so this realigns it.\n */\n\n/** The command the base target ran before it checked rather than wrote. */\nconst WRITING_COMMAND = 'terraform fmt';\n\n/**\n * The `backend \"s3\"` arguments the generator vends. Realignment only applies to a\n * block holding exactly these.\n */\nconst BACKEND_ARGUMENTS = ['encrypt', 'use_lockfile'];\n\n/** Matches the arguments of a `backend \"s3\"` block, and their alignment. */\nconst BACKEND_BLOCK = /backend\\s+\"s3\"\\s*\\{([^}]*)\\}/;\nconst BACKEND_ARGUMENT = /^[ \\t]*([A-Za-z_][A-Za-z0-9_]*)([ \\t]*)=/gm;\n\n/**\n * The arguments a `providers.tf` declares in its `backend \"s3\"` block, in order,\n * each with the column its `=` currently sits at.\n */\nconst readBackendArguments = (\n contents: string,\n): { name: string; column: number }[] | undefined => {\n const block = BACKEND_BLOCK.exec(contents)?.[1];\n if (block === undefined) return undefined;\n return [...block.matchAll(BACKEND_ARGUMENT)].map(([, name, gap]) => ({\n name,\n column: name.length + gap.length,\n }));\n};\n\n/**\n * Realigns the `backend \"s3\"` arguments in an application's `providers.tf`, which\n * the checking target requires and the per-run write had been supplying.\n *\n * `terraform fmt` aligns `=` to the widest key in the whole block, so a block\n * carrying arguments beyond the two vended ones has a width this cannot know.\n * Such a block is left alone and reported: rewriting it to the vended width\n * would push those two out of alignment with the user's own arguments and fail\n * the very check this migration installs.\n */\nconst realignProviders = async (\n tree: Tree,\n projectName: string,\n projectRoot: string,\n nextSteps: string[],\n): Promise<void> => {\n const filePath = joinPathFragments(projectRoot, 'src', 'providers.tf');\n if (!tree.exists(filePath)) return;\n\n const declared = readBackendArguments(tree.read(filePath, 'utf-8') ?? '');\n if (!declared?.length) return;\n\n const isVendedBlock =\n declared.length === BACKEND_ARGUMENTS.length &&\n declared.every(({ name }) => BACKEND_ARGUMENTS.includes(name));\n if (!isVendedBlock) {\n nextSteps.push(\n `${filePath}: its \\`backend \"s3\"\\` block declares arguments beyond the generated ones, so its alignment was left as it is. Run \\`nx run ${projectName}:format --configuration=fix\\` if the new format check reports it.`,\n );\n return;\n }\n\n const width = Math.max(...BACKEND_ARGUMENTS.map((name) => name.length));\n\n // Already at the width `terraform fmt` aligns this block to, so a re-run — and\n // a workspace whose file is formatted — is a no-op.\n if (declared.every(({ column }) => column === width)) return;\n\n // Each argument is realigned around whatever value it holds, so a value the\n // user changed is preserved. An argument whose name already fills the width\n // rewrites to a textually identical pattern, which GritQL notes; the rewrite\n // still normalises the whitespace around its `=`, which is the point.\n for (const { name } of declared) {\n await applyGritQL(\n tree,\n filePath,\n `language hcl\\n\\`${name} = $value\\` => \\`${name.padEnd(width)} = $value\\`` +\n ` where { $value <: within \\`backend \"s3\" { $_ }\\` }`,\n );\n }\n};\n\n/** The target name this migration converges on, matching ts and py projects. */\nconst FORMAT_TARGET = 'format';\n/** The name the generator vended this target under before the rename. */\nconst LEGACY_TARGET = 'fmt';\n\n/**\n * Repoints `dependsOn` entries naming the old target at the new one. A stale\n * entry is not an error in Nx — it silently drops the edge — so `build` would\n * stop checking formatting altogether.\n */\nconst repointDependsOn = (project: ProjectConfiguration): boolean => {\n let changed = false;\n for (const target of Object.values(project.targets ?? {})) {\n const dependsOn = target.dependsOn;\n if (!Array.isArray(dependsOn) || !dependsOn.includes(LEGACY_TARGET)) {\n continue;\n }\n target.dependsOn = dependsOn.map((entry) =>\n entry === LEGACY_TARGET ? FORMAT_TARGET : entry,\n );\n changed = true;\n }\n return changed;\n};\n\n/**\n * Renames the `fmt` target to `format`, moves it onto the checking form, and\n * adds the `lint` target that orchestrates it.\n *\n * A target whose command is not the one the generator produced is the user's, so\n * it is reported instead. Both the vended name and the new one are accepted as\n * the starting point, so a workspace part-way through converges either way.\n */\nconst migrateProject = (\n projectName: string,\n project: ProjectConfiguration,\n nextSteps: string[],\n): boolean => {\n const targets = project.targets ?? {};\n const existingName = targets[FORMAT_TARGET]\n ? FORMAT_TARGET\n : targets[LEGACY_TARGET]\n ? LEGACY_TARGET\n : undefined;\n if (!existingName) return false;\n\n const format = targets[existingName];\n let changed = false;\n\n if (format.options?.command === WRITING_COMMAND) {\n targets[existingName] = {\n ...format,\n inputs: TERRAFORM_FORMAT_TARGET.inputs,\n options: {\n ...format.options,\n command: TERRAFORM_FORMAT_TARGET.options.command,\n },\n // The user's own configurations win, as their `options` do above: someone\n // who set `fix` to `terraform fmt -recursive` to cover nested modules\n // keeps it.\n configurations: {\n ...TERRAFORM_FORMAT_TARGET.configurations,\n ...format.configurations,\n },\n };\n changed = true;\n } else if (!format.configurations?.fix) {\n nextSteps.push(\n `${projectName}: its '${existingName}' target has been customised, so it was left as it is. Have it run \\`${TERRAFORM_FORMAT_TARGET.options.command}\\` and move the writing form to a 'fix' configuration — writing from the base target rewrites the inputs its cache key is computed from, so it can never cache-hit.`,\n );\n return false;\n }\n\n if (existingName === LEGACY_TARGET) {\n targets[FORMAT_TARGET] = targets[LEGACY_TARGET];\n delete targets[LEGACY_TARGET];\n changed = true;\n }\n\n changed = repointDependsOn(project) || changed;\n\n if (!targets.lint) {\n targets.lint = { dependsOn: [FORMAT_TARGET] };\n changed = true;\n }\n\n return changed;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;\n\n if (migrateProject(projectName, project, nextSteps)) {\n updateProjectConfiguration(tree, projectName, {\n ...project,\n targets: sortObjectKeys(project.targets),\n });\n // The new `lint` target checks licenses alongside formatting, as every\n // other linting project's does in a workspace that has run `license`.\n addLicenseCheckToLintTarget(tree, projectName);\n }\n\n await realignProviders(tree, projectName, project.root, nextSteps);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","addLicenseCheckToLintTarget","TERRAFORM_FORMAT_TARGET","TERRAFORM_PROJECT_GENERATOR_INFO","applyGritQL","formatFilesInSubtree","sortObjectKeys","WRITING_COMMAND","BACKEND_ARGUMENTS","BACKEND_BLOCK","BACKEND_ARGUMENT","readBackendArguments","contents","block","exec","undefined","matchAll","map","name","gap","column","length","realignProviders","tree","projectName","projectRoot","nextSteps","filePath","exists","declared","read","isVendedBlock","every","includes","push","width","Math","max","padEnd","FORMAT_TARGET","LEGACY_TARGET","repointDependsOn","project","changed","target","Object","values","targets","dependsOn","Array","isArray","entry","migrateProject","existingName","format","options","command","inputs","configurations","fix","lint","migration","generator","metadata","id","root"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.92/0001-react-website-unique-dev-ports/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n readProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { REACT_WEBSITE_APP_GENERATOR_INFO } from '../../../ts/react-website/app/generator.js';\nimport { COGNITO_AUTH_GENERATOR_INFO } from '../../../ts/react-website/cognito-auth/generator.js';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport type { Iac } from '../../../utils/iac.js';\nimport { addLocalCallbackUrl } from '../../../utils/identity-constructs/identity-constructs.js';\nimport type { ComponentMetadata } from '../../../utils/nx.js';\nimport { assignPort, getExistingProjectPort } from '../../../utils/port.js';\n\n/**\n * Assign each react-website project its own dev-server and preview port, and allow-list them for any connected Cognito auth\n *\n * Before this migration every react-website project's `vite.config.mts` hardcoded\n * `server.port: 4200` / `preview.port: 4300`. Vite itself already auto-increments\n * past a port already in use, so multiple websites don't actually collide when run\n * concurrently — but which port each one lands on then depends on start order and\n * can't be known ahead of time. Today's generator assigns each website an explicit,\n * deterministic dev-server port (tracked in project metadata, mirroring\n * `assignPort`'s existing use elsewhere) specifically so it - and its preview port,\n * always the dev-server port + 100 - can be allow-listed on the shared Cognito\n * construct/module for any website that has added auth. This migration backfills\n * both for existing workspaces.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Transform source with GritQL (`applyGritQL`, `matchGritQL`), not regexes or\n * string replacements: it matches the AST, so it holds up against however the\n * user's copy has been formatted. Use `updateJson` for JSON.\n * - Pattern-match before writing: skip files that have diverged from the shape\n * your generators produce and report them via `nextSteps`, or consider a\n * hybrid migration, rather than clobbering the user's changes.\n * - `nextSteps` is for work left for the user to do by hand, not a log of the\n * edits you made: an edit that applied cleanly needs no entry.\n * - Idempotent: re-running must be a no-op.\n * - Format what you write: finish with `formatFilesInSubtree` so the files your\n * migration wrote are formatted correctly.\n */\n\ninterface WebsiteProjectMetadata {\n readonly generator?: string;\n readonly components?: ComponentMetadata[];\n}\n\n/**\n * Set a vite.config.mts `server`/`preview` block's port. Checks whether it\n * already holds the target value first — the rewrite pattern is a no-op\n * `port: N` => `port: N` in that case, which GritQL reports as \"no match\"\n * indistinguishably from the block not existing at all.\n */\nconst patchVitePort = async (\n tree: Tree,\n viteConfigPath: string,\n target: 'server' | 'preview',\n port: number,\n): Promise<boolean> => {\n if (!tree.exists(viteConfigPath)) {\n return false;\n }\n const alreadyCorrect = await matchGritQL(\n tree,\n viteConfigPath,\n `\\`${target}: { $props }\\` where { $props <: contains \\`port: ${port}\\` }`,\n );\n if (alreadyCorrect) {\n return true;\n }\n return applyGritQL(\n tree,\n viteConfigPath,\n `\\`${target}: { $props }\\` where { $props <: contains \\`port: $_\\` => \\`port: ${port}\\` }`,\n );\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n // Codepoint order, so re-runs and different machines assign the same ports.\n const websiteNames: string[] = [...getProjects(tree).entries()]\n .filter(\n ([, project]) =>\n (project.metadata as WebsiteProjectMetadata | undefined)?.generator ===\n REACT_WEBSITE_APP_GENERATOR_INFO.id,\n )\n .map(([name]) => name)\n .sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n\n for (const name of websiteNames) {\n const project: ProjectConfiguration = readProjectConfiguration(tree, name);\n if (getExistingProjectPort(project) !== undefined) {\n // Already migrated (or generated by a version that already assigns\n // ports) - skip so re-running is a no-op.\n continue;\n }\n\n const viteConfigPath = joinPathFragments(project.root, 'vite.config.mts');\n const port = assignPort(tree, project, 4200);\n const previewPort = port + 100;\n\n if (!(await patchVitePort(tree, viteConfigPath, 'server', port))) {\n nextSteps.push(\n `${viteConfigPath}: could not find the expected 'server' block to set its dev-server port to ${port} - set it by hand so it matches the Cognito callback URL this migration is allow-listing for it.`,\n );\n }\n if (!(await patchVitePort(tree, viteConfigPath, 'preview', previewPort))) {\n nextSteps.push(\n `${viteConfigPath}: could not find the expected 'preview' block to set its port to ${previewPort} - set it by hand so it matches the Cognito callback URL this migration is allow-listing for it.`,\n );\n }\n\n // Persists the port assignPort just recorded on `project.metadata.ports`.\n updateProjectConfiguration(tree, name, project);\n }\n\n // Allow-list the (possibly just-assigned) ports of every website that has\n // added Cognito auth, on whichever shared identity construct/module it uses.\n // Re-reads each project fresh, since the pass above may have persisted a\n // port this project didn't have when websiteNames was first read.\n for (const name of websiteNames) {\n const project = readProjectConfiguration(tree, name);\n const authComponent = (\n (project.metadata as WebsiteProjectMetadata | undefined)?.components ?? []\n ).find((c) => c.generator === COGNITO_AUTH_GENERATOR_INFO.id);\n if (!authComponent) {\n continue;\n }\n\n const devPort = getExistingProjectPort(project);\n const iac = authComponent.iac as Iac | undefined;\n if (devPort === undefined || !iac) {\n // Shouldn't happen: the pass above assigns a port to every website project.\n continue;\n }\n\n for (const port of [devPort, devPort + 100]) {\n if (!(await addLocalCallbackUrl(tree, iac, port))) {\n nextSteps.push(\n `The shared Cognito user identity ${iac === 'cdk' ? 'construct' : 'module'} has diverged from the generated shape - left untouched. To sign in against ${name}'s local dev server on port ${port}, add 'http://localhost:${port}' to its local callback/logout URLs by hand.`,\n );\n }\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","readProjectConfiguration","updateProjectConfiguration","REACT_WEBSITE_APP_GENERATOR_INFO","COGNITO_AUTH_GENERATOR_INFO","applyGritQL","matchGritQL","formatFilesInSubtree","addLocalCallbackUrl","assignPort","getExistingProjectPort","patchVitePort","tree","viteConfigPath","target","port","exists","alreadyCorrect","migration","nextSteps","websiteNames","entries","filter","project","metadata","generator","id","map","name","sort","a","b","undefined","root","previewPort","push","authComponent","components","find","c","devPort","iac"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.94/0001-infra-deploy-express-mode/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Deploy using CloudFormation express mode from the deploy-sandbox target of\n * ts#infra projects, and wait for full stabilization everywhere else.\n *\n * Express mode completes each resource operation as soon as its configuration is\n * applied rather than waiting for full stabilization, which is a much faster\n * iteration cycle for development deploys. It returns before resources have\n * settled, so it suits only the stage you iterate on.\n *\n * `deploy-sandbox` therefore gets it, since it only ever deploys the sandbox\n * stage. `deploy` names whichever stage you give it, including beta and prod, and\n * `deploy-ci` runs from a pipeline - both wait for full stabilization.\n */\n\nconst EXPRESS_FLAG = '--express';\nconst NO_EXPRESS_FLAG = '--no-express';\n\n/** Whether `deploy-sandbox` should carry the flag, and `deploy` should not. */\nconst WANTS_EXPRESS: Record<string, boolean> = {\n 'deploy-sandbox': true,\n deploy: false,\n};\n\n/**\n * Whether the command is one of the deploy commands this migration vends -\n * either a direct `cdk deploy`, or the stage-config `infra-deploy.ts` script\n * that wraps it. Anything else has been hand-written and is reported rather\n * than rewritten.\n */\nconst isGeneratedDeployCommand = (command: string): boolean =>\n /(^|\\s)cdk\\s+deploy(\\s|$)/.test(command) ||\n command.includes('infra-deploy.ts');\n\nconst divergedNextStep = (\n projectName: string,\n target: string,\n wantsExpress: boolean,\n): string =>\n wantsExpress\n ? `${projectName}: its ${target} target has been customised, so it was left as it is. Add \"${EXPRESS_FLAG}\" to the target's command to deploy using CloudFormation express mode.`\n : `${projectName}: its ${target} target has been customised, so it was left as it is. Remove \"${EXPRESS_FLAG}\" from the target's command so it waits for full resource stabilization - this target can name any stage, including production.`;\n\n/** Drops the flag wherever it sits, leaving the rest of the command untouched. */\nconst withoutExpress = (command: string): string =>\n command\n .split(/\\s+/)\n .filter((arg) => arg !== EXPRESS_FLAG)\n .join(' ');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n for (const [name, project] of getProjects(tree)) {\n if (\n (project.metadata as { generator?: string } | undefined)?.generator !==\n INFRA_APP_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n let projectChanged = false;\n\n for (const [targetName, wantsExpress] of Object.entries(WANTS_EXPRESS)) {\n const target: TargetConfiguration | undefined =\n project.targets?.[targetName];\n const command = target?.options?.command;\n if (!target || typeof command !== 'string') {\n continue;\n }\n\n const args = command.split(/\\s+/);\n const hasExpress = args.includes(EXPRESS_FLAG);\n\n // Already in the wanted state, so re-running - and a project generated\n // after this change - is a no-op.\n if (hasExpress === wantsExpress) {\n continue;\n }\n\n // `--no-express` is a deliberate opt-out, so honour it rather than\n // flipping the user back to express mode.\n if (wantsExpress && args.includes(NO_EXPRESS_FLAG)) {\n continue;\n }\n\n if (!isGeneratedDeployCommand(command)) {\n nextSteps.push(divergedNextStep(name, targetName, wantsExpress));\n continue;\n }\n\n // Appended last so it stays clear of the stage pattern, which the\n // stage-config deploy script reads from the first positional argument.\n target.options.command = wantsExpress\n ? `${command} ${EXPRESS_FLAG}`\n : withoutExpress(command);\n projectChanged = true;\n }\n\n if (projectChanged) {\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","EXPRESS_FLAG","NO_EXPRESS_FLAG","WANTS_EXPRESS","deploy","isGeneratedDeployCommand","command","test","includes","divergedNextStep","projectName","target","wantsExpress","withoutExpress","split","filter","arg","join","migration","tree","nextSteps","migrated","name","project","metadata","generator","id","projectChanged","targetName","Object","entries","targets","options","args","hasExpress","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;CAYC,GAED,MAAMC,eAAe;AACrB,MAAMC,kBAAkB;AAExB,6EAA6E,GAC7E,MAAMC,gBAAyC;IAC7C,kBAAkB;IAClBC,QAAQ;AACV;AAEA;;;;;CAKC,GACD,MAAMC,2BAA2B,CAACC,UAChC,2BAA2BC,IAAI,CAACD,YAChCA,QAAQE,QAAQ,CAAC;AAEnB,MAAMC,mBAAmB,CACvBC,aACAC,QACAC,eAEAA,eACI,GAAGF,YAAY,MAAM,EAAEC,OAAO,2DAA2D,EAAEV,aAAa,sEAAsE,CAAC,GAC/K,GAAGS,YAAY,MAAM,EAAEC,OAAO,8DAA8D,EAAEV,aAAa,+HAA+H,CAAC;AAEjP,gFAAgF,GAChF,MAAMY,iBAAiB,CAACP,UACtBA,QACGQ,KAAK,CAAC,OACNC,MAAM,CAAC,CAACC,MAAQA,QAAQf,cACxBgB,IAAI,CAAC;AAEV,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAI1B,YAAYsB,MAAO;QAC/C,IACE,AAACI,QAAQC,QAAQ,EAAyCC,cAC1D1B,yBAAyB2B,EAAE,EAC3B;YACA;QACF;QAEA,IAAIC,iBAAiB;QAErB,KAAK,MAAM,CAACC,YAAYhB,aAAa,IAAIiB,OAAOC,OAAO,CAAC3B,eAAgB;YACtE,MAAMQ,SACJY,QAAQQ,OAAO,EAAE,CAACH,WAAW;YAC/B,MAAMtB,UAAUK,QAAQqB,SAAS1B;YACjC,IAAI,CAACK,UAAU,OAAOL,YAAY,UAAU;gBAC1C;YACF;YAEA,MAAM2B,OAAO3B,QAAQQ,KAAK,CAAC;YAC3B,MAAMoB,aAAaD,KAAKzB,QAAQ,CAACP;YAEjC,uEAAuE;YACvE,kCAAkC;YAClC,IAAIiC,eAAetB,cAAc;gBAC/B;YACF;YAEA,mEAAmE;YACnE,0CAA0C;YAC1C,IAAIA,gBAAgBqB,KAAKzB,QAAQ,CAACN,kBAAkB;gBAClD;YACF;YAEA,IAAI,CAACG,yBAAyBC,UAAU;gBACtCc,UAAUe,IAAI,CAAC1B,iBAAiBa,MAAMM,YAAYhB;gBAClD;YACF;YAEA,kEAAkE;YAClE,uEAAuE;YACvED,OAAOqB,OAAO,CAAC1B,OAAO,GAAGM,eACrB,GAAGN,QAAQ,CAAC,EAAEL,cAAc,GAC5BY,eAAeP;YACnBqB,iBAAiB;QACnB;QAEA,IAAIA,gBAAgB;YAClB7B,2BAA2BqB,MAAMG,MAAMC;YACvCF,WAAW;QACb;IACF;IAEA,IAAIA,UAAU;QACZ,MAAMrB,qBAAqBmB;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.94/0002-shx-fs-commands/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n getProjects,\n type MigrationReturnObject,\n type ProjectConfiguration,\n removeDependenciesFromPackageJson,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * One `shx` replaces the four single purpose filesystem CLIs the targets ran.\n * Its `cp` is several times faster than `ncp` on a large tree, and a single\n * dependency covers every operation the generators vend.\n *\n * `shx cp -R` follows POSIX `cp`, which nests the source inside an existing\n * destination rather than merging into it, so a directory copy becomes\n * `shx cp -R <src>/. <dst>`. That form also copies dotfiles, which a `<src>/*`\n * glob would silently skip — `node_modules/.bin` depends on them. A file copy\n * needs neither, so it stays a plain `shx cp`.\n *\n * Whether an `ncp` copied a file or a directory is not recoverable from the\n * command, so each source is matched against the shapes the generators vend. A\n * command that matches none of them has been edited by the user, and is left\n * alone and reported: rewriting it with the wrong form would either nest a\n * directory a level too deep or fail outright.\n *\n * A `cpy` becomes two commands rather than one joined by `&&`, which is a shell\n * operator and so no more portable than the builtins `shx` replaces.\n */\n\n/** The four CLIs this replaces, dropped from the root manifest. */\nconst REPLACED_PACKAGES = ['ncp', 'rimraf', 'make-dir-cli', 'cpy-cli'];\n\n/**\n * Sources the generators copy as a whole directory. Everything else they copy\n * names a single file, so an unmatched source is neither and is left untouched.\n *\n * - a Python bundle (`bundle-arm`/`bundle-x86`), copied into a package or an\n * image build context\n * - a Python module tree, copied into a code package under its module name\n * - the generated Server SDK, copied into a Smithy API's `src/generated`\n * - `prisma` and Alembic `migrations`, copied into a migration bundle\n */\nconst DIRECTORY_SOURCE = [\n /(^|\\/)bundle-(arm|x86)$/,\n /(^|\\/)build\\/ssdk$/,\n /(^|\\/)prisma$/,\n /(^|\\/)migrations$/,\n];\n\n/**\n * Files the generators copy whose name carries no extension, so the extension\n * test below would otherwise read them as directories. A `Dockerfile` variant is\n * renamed on the way in (`Dockerfile.migration` -> `Dockerfile`), so this matches\n * the source's leading segment rather than the whole name.\n */\nconst EXTENSIONLESS_FILE = /(^|\\/)Dockerfile(\\.[^/]+)?$/;\n\n/**\n * A Python code package copies the project's source root in under the module\n * name, which is the same segment repeated — `.../src/my_agent my_agent`. The\n * source is a directory whose name is the project's, so it is recognised by the\n * destination repeating the source's last segment rather than by a fixed name.\n */\nconst isModuleTreeCopy = (src: string, dst: string): boolean => {\n const segment = src.split('/').pop();\n return (\n !!segment && !segment.includes('.') && dst.split('/').pop() === segment\n );\n};\n\nconst isDirectorySource = (src: string, dst: string): boolean =>\n !EXTENSIONLESS_FILE.test(src) &&\n (DIRECTORY_SOURCE.some((p) => p.test(src)) || isModuleTreeCopy(src, dst));\n\n/**\n * A copy naming a file on both sides, which every other vended `ncp` does. A\n * name carrying an extension is a file — as is a `Dockerfile`, which does not.\n */\nconst isFileCopy = (src: string, dst: string): boolean => {\n const [s, d] = [src.split('/').pop() ?? '', dst.split('/').pop() ?? ''];\n return (\n (s.includes('.') || EXTENSIONLESS_FILE.test(src)) &&\n (d.includes('.') || EXTENSIONLESS_FILE.test(dst))\n );\n};\n\nconst NCP = /^ncp\\s+(\\S+)\\s+(\\S+)$/;\nconst RIMRAF = /^rimraf\\s+(\\S+)$/;\nconst MAKE_DIR = /^make-dir\\s+(\\S+)$/;\n/** The one shape `cpGlobToFile` vends, whose glob is quoted and dest renamed. */\nconst CPY = /^cpy\\s+\"([^\"]+)\"\\s+(\\S+)\\s+--flat\\s+--rename=(\\S+)$/;\n\n/**\n * Rewrite one command into the commands that replace it, or return null to leave\n * it alone. Anything already using `shx` is returned unchanged so a re-run is a\n * no-op.\n */\nconst rewrite = (command: string): string[] | null => {\n const trimmed = command.trim();\n\n const rimraf = RIMRAF.exec(trimmed);\n if (rimraf) return [`shx rm -rf ${rimraf[1]}`];\n\n const makeDir = MAKE_DIR.exec(trimmed);\n if (makeDir) return [`shx mkdir -p ${makeDir[1]}`];\n\n const cpy = CPY.exec(trimmed);\n if (cpy) {\n // `shx cp` writes through to a named destination file and fails if its\n // parent is missing, so the destination directory is a step of its own.\n return [`shx mkdir -p ${cpy[2]}`, `shx cp \"${cpy[1]}\" ${cpy[2]}/${cpy[3]}`];\n }\n\n const ncp = NCP.exec(trimmed);\n if (ncp) {\n const [, src, dst] = ncp;\n if (isDirectorySource(src, dst)) return [`shx cp -R ${src}/. ${dst}`];\n if (isFileCopy(src, dst)) return [`shx cp ${src} ${dst}`];\n return null;\n }\n\n return null;\n};\n\n/** Whether a command is one this migration is responsible for rewriting. */\nconst isReplacedCommand = (command: string): boolean =>\n /^(ncp|rimraf|make-dir|cpy)\\s/.test(command.trim());\n\nconst divergedStep = (\n projectName: string,\n targetName: string,\n command: string,\n) =>\n `${projectName}:${targetName}: left \\`${command}\\` untouched - it does not match a copy the generator produced, so whether it copies a file or a directory could not be determined. Replace it by hand with \\`shx cp <src> <dst>\\` for a file, or \\`shx cp -R <src>/. <dst>\\` for a directory (the trailing \\`/.\\` merges the contents instead of nesting the directory inside the destination).`;\n\n/**\n * Rewrite every command a target runs, in place. Commands are either strings or\n * `{ command }` objects, and a target uses `command` for a single one.\n *\n * One command can become several, which are steps of the same operation and so\n * must run in order — the target is pinned to `parallel: false` when that\n * happens.\n */\nconst migrateTarget = (\n projectName: string,\n targetName: string,\n target: TargetConfiguration,\n nextSteps: string[],\n): boolean => {\n const options = target.options as\n | { command?: unknown; commands?: unknown; parallel?: unknown }\n | undefined;\n if (!options) return false;\n\n let changed = false;\n let split = false;\n\n /** The commands replacing one, or the original where it is left alone. */\n const rewriteOne = (command: string): string[] => {\n if (!isReplacedCommand(command)) return [command];\n const replacement = rewrite(command);\n if (replacement === null) {\n nextSteps.push(divergedStep(projectName, targetName, command.trim()));\n return [command];\n }\n changed = true;\n if (replacement.length > 1) split = true;\n return replacement;\n };\n\n if (typeof options.command === 'string') {\n const replacement = rewriteOne(options.command);\n if (replacement.length > 1) {\n // `commands` is the only option that runs more than one.\n delete options.command;\n options.commands = replacement;\n } else {\n options.command = replacement[0];\n }\n } else if (Array.isArray(options.commands)) {\n options.commands = options.commands.flatMap((entry) => {\n if (typeof entry === 'string') return rewriteOne(entry);\n if (\n entry &&\n typeof entry === 'object' &&\n typeof (entry as { command?: unknown }).command === 'string'\n ) {\n const e = entry as { command: string };\n return rewriteOne(e.command).map((command) => ({ ...e, command }));\n }\n return [entry];\n });\n }\n\n if (split) options.parallel = false;\n\n return changed;\n};\n\n/** Every command every target in the workspace runs. */\nconst allCommands = (tree: Tree): string[] => {\n const commands: string[] = [];\n for (const [, project] of getProjects(tree)) {\n for (const target of Object.values(project.targets ?? {})) {\n const options = target.options as\n | { command?: unknown; commands?: unknown }\n | undefined;\n if (typeof options?.command === 'string') commands.push(options.command);\n if (Array.isArray(options?.commands)) {\n for (const entry of options.commands) {\n if (typeof entry === 'string') commands.push(entry);\n else if (\n typeof (entry as { command?: unknown })?.command === 'string'\n )\n commands.push((entry as { command: string }).command);\n }\n }\n }\n }\n return commands;\n};\n\n/** The CLI a package provides, as the rewritten commands would name it. */\nconst CLI_NAME: Record<string, string> = {\n ncp: 'ncp',\n rimraf: 'rimraf',\n 'make-dir-cli': 'make-dir',\n 'cpy-cli': 'cpy',\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n let changed = false;\n\n for (const [targetName, target] of Object.entries(project.targets ?? {})) {\n changed =\n migrateTarget(projectName, targetName, target, nextSteps) || changed;\n }\n\n if (changed) {\n updateProjectConfiguration(\n tree,\n projectName,\n project as ProjectConfiguration,\n );\n }\n }\n\n addDependenciesToPackageJson(tree, {}, { shx: TS_VERSIONS.shx });\n\n // Only the CLIs nothing runs any more: a command this migration declined to\n // rewrite, or one the user added, still needs the package it calls.\n const commands = allCommands(tree);\n const unused = REPLACED_PACKAGES.filter(\n (pkg) =>\n !commands.some((c) =>\n new RegExp(`(^|[^\\\\w-])${CLI_NAME[pkg]}\\\\s`).test(c),\n ),\n );\n removeDependenciesFromPackageJson(tree, unused, unused);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["addDependenciesToPackageJson","getProjects","removeDependenciesFromPackageJson","updateProjectConfiguration","formatFilesInSubtree","TS_VERSIONS","REPLACED_PACKAGES","DIRECTORY_SOURCE","EXTENSIONLESS_FILE","isModuleTreeCopy","src","dst","segment","split","pop","includes","isDirectorySource","test","some","p","isFileCopy","s","d","NCP","RIMRAF","MAKE_DIR","CPY","rewrite","command","trimmed","trim","rimraf","exec","makeDir","cpy","ncp","isReplacedCommand","divergedStep","projectName","targetName","migrateTarget","target","nextSteps","options","changed","rewriteOne","replacement","push","length","commands","Array","isArray","flatMap","entry","e","map","parallel","allCommands","tree","project","Object","values","targets","CLI_NAME","migration","entries","shx","unused","filter","pkg","c","RegExp"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.94/0003-agent-core-vendor-target/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n ADOT_VENDOR_TARGET_NAME,\n adotVendorDir,\n} from '../../../utils/agent-core-packaging.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * A TypeScript AgentCore code package installed the AWS Distro for OpenTelemetry\n * into the package directory as its last packaging step. That target's `inputs`\n * are the project's source, so editing an agent re-ran the install — several\n * seconds of npm work whose result depends only on the pinned ADOT version.\n *\n * The install moves to its own target Nx caches independently. It declares no\n * `inputs`, since the version it pins is part of the command and Nx hashes a\n * target's configuration, so a version bump still invalidates it while a source\n * edit no longer does. Packaging copies the vendored tree instead.\n *\n * The vendor directory is a sibling of the package directory, not a path inside\n * it: Nx replaces a cached target's whole declared output directory on restore,\n * so nesting one target's output inside another's makes each wipe the other's\n * work on a cache hit.\n *\n * A packaging target that no longer matches the shape the generator vended has\n * been reworked by the user, so it is left untouched and reported.\n *\n * The filesystem commands are spelled with `shx`: the migration that replaced the\n * single purpose CLIs was committed first, and `latest` migrations run in the\n * order their folders were committed, so it has already run by the time this one\n * does.\n */\n\n/** The ADOT install as the packaging target ran it, capturing its `--prefix`. */\nconst ADOT_INSTALL =\n /^npm install --prefix (\\S+) .*@aws\\/aws-distro-opentelemetry-node-autoinstrumentation@(\\S+)\\s*$/;\n\nconst divergedStep = (projectName: string, targetName: string) =>\n `${projectName}:${targetName}: installs the OpenTelemetry distro but no longer matches the shape the generator produced - left untouched. To stop the install re-running whenever the project's source changes, move it to its own target with no \\`inputs\\` and an \\`outputs\\` directory outside this target's, and copy that directory in here instead.`;\n\n/** Commands a target runs, as plain strings. */\nconst commandsOf = (target: TargetConfiguration): string[] => {\n const { commands } = (target.options ?? {}) as { commands?: unknown };\n return Array.isArray(commands)\n ? commands.filter((c): c is string => typeof c === 'string')\n : [];\n};\n\n/**\n * Copy the vendored `node_modules` into the package. `-R` and the trailing `/.`\n * merge the directory's contents rather than nesting it inside the destination.\n */\nconst copyCommand = (vendorDir: string, packageDir: string): string =>\n `shx cp -R ${joinPathFragments(vendorDir, 'node_modules')}/. ${joinPathFragments(packageDir, 'node_modules')}`;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n let changed = false;\n const vendorDir = adotVendorDir(project.root);\n\n for (const [targetName, target] of Object.entries(project.targets ?? {})) {\n if (targetName === ADOT_VENDOR_TARGET_NAME) continue;\n\n const commands = commandsOf(target);\n const installIndex = commands.findIndex((c) => ADOT_INSTALL.test(c));\n if (installIndex < 0) continue;\n\n const install = commands[installIndex];\n const [, prefix] = ADOT_INSTALL.exec(install)!;\n\n // The install targets the directory this target packages into, and it\n // copies the bundle in with shx. Anything else has been reworked.\n const packageDir = prefix;\n const copiesBundle = commands.some(\n (c) => c !== install && c.startsWith('shx cp '),\n );\n const declaresPackageOutput = (target.outputs ?? []).some((o) =>\n o.endsWith(packageDir),\n );\n if (!copiesBundle || !declaresPackageOutput) {\n nextSteps.push(divergedStep(projectName, targetName));\n continue;\n }\n\n project.targets![ADOT_VENDOR_TARGET_NAME] ??= {\n cache: true,\n inputs: [],\n outputs: [`{workspaceRoot}/${vendorDir}`],\n executor: 'nx:run-commands',\n options: {\n commands: [\n `shx rm -rf ${vendorDir}`,\n `shx mkdir -p ${vendorDir}`,\n install.replace(prefix, vendorDir),\n ],\n parallel: false,\n },\n };\n\n const updated = [...commands];\n updated[installIndex] = copyCommand(vendorDir, packageDir);\n target.options!.commands = updated;\n target.dependsOn = [\n ...(target.dependsOn ?? []),\n ADOT_VENDOR_TARGET_NAME,\n ].filter((d, i, all) => all.indexOf(d) === i);\n\n changed = true;\n }\n\n if (changed) {\n updateProjectConfiguration(\n tree,\n projectName,\n project as ProjectConfiguration,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","ADOT_VENDOR_TARGET_NAME","adotVendorDir","formatFilesInSubtree","ADOT_INSTALL","divergedStep","projectName","targetName","commandsOf","target","commands","options","Array","isArray","filter","c","copyCommand","vendorDir","packageDir","migration","tree","nextSteps","project","changed","root","Object","entries","targets","installIndex","findIndex","test","install","prefix","exec","copiesBundle","some","startsWith","declaresPackageOutput","outputs","o","endsWith","push","cache","inputs","executor","replace","parallel","updated","dependsOn","d","i","all","indexOf"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAKjBC,0BAA0B,QACrB,aAAa;AACpB,SACEC,uBAAuB,EACvBC,aAAa,QACR,yCAAyC;AAChD,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GAED,+EAA+E,GAC/E,MAAMC,eACJ;AAEF,MAAMC,eAAe,CAACC,aAAqBC,aACzC,GAAGD,YAAY,CAAC,EAAEC,WAAW,4TAA4T,CAAC;AAE5V,8CAA8C,GAC9C,MAAMC,aAAa,CAACC;IAClB,MAAM,EAAEC,QAAQ,EAAE,GAAID,OAAOE,OAAO,IAAI,CAAC;IACzC,OAAOC,MAAMC,OAAO,CAACH,YACjBA,SAASI,MAAM,CAAC,CAACC,IAAmB,OAAOA,MAAM,YACjD,EAAE;AACR;AAEA;;;CAGC,GACD,MAAMC,cAAc,CAACC,WAAmBC,aACtC,CAAC,UAAU,EAAEnB,kBAAkBkB,WAAW,gBAAgB,GAAG,EAAElB,kBAAkBmB,YAAY,iBAAiB;AAEhH,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACf,aAAagB,QAAQ,IAAIxB,YAAYsB,MAAO;QACtD,IAAIG,UAAU;QACd,MAAMN,YAAYf,cAAcoB,QAAQE,IAAI;QAE5C,KAAK,MAAM,CAACjB,YAAYE,OAAO,IAAIgB,OAAOC,OAAO,CAACJ,QAAQK,OAAO,IAAI,CAAC,GAAI;YACxE,IAAIpB,eAAeN,yBAAyB;YAE5C,MAAMS,WAAWF,WAAWC;YAC5B,MAAMmB,eAAelB,SAASmB,SAAS,CAAC,CAACd,IAAMX,aAAa0B,IAAI,CAACf;YACjE,IAAIa,eAAe,GAAG;YAEtB,MAAMG,UAAUrB,QAAQ,CAACkB,aAAa;YACtC,MAAM,GAAGI,OAAO,GAAG5B,aAAa6B,IAAI,CAACF;YAErC,sEAAsE;YACtE,kEAAkE;YAClE,MAAMb,aAAac;YACnB,MAAME,eAAexB,SAASyB,IAAI,CAChC,CAACpB,IAAMA,MAAMgB,WAAWhB,EAAEqB,UAAU,CAAC;YAEvC,MAAMC,wBAAwB,AAAC5B,CAAAA,OAAO6B,OAAO,IAAI,EAAE,AAAD,EAAGH,IAAI,CAAC,CAACI,IACzDA,EAAEC,QAAQ,CAACtB;YAEb,IAAI,CAACgB,gBAAgB,CAACG,uBAAuB;gBAC3ChB,UAAUoB,IAAI,CAACpC,aAAaC,aAAaC;gBACzC;YACF;YAEAe,QAAQK,OAAO,AAAC,CAAC1B,wBAAwB,KAAK;gBAC5CyC,OAAO;gBACPC,QAAQ,EAAE;gBACVL,SAAS;oBAAC,CAAC,gBAAgB,EAAErB,WAAW;iBAAC;gBACzC2B,UAAU;gBACVjC,SAAS;oBACPD,UAAU;wBACR,CAAC,WAAW,EAAEO,WAAW;wBACzB,CAAC,aAAa,EAAEA,WAAW;wBAC3Bc,QAAQc,OAAO,CAACb,QAAQf;qBACzB;oBACD6B,UAAU;gBACZ;YACF;YAEA,MAAMC,UAAU;mBAAIrC;aAAS;YAC7BqC,OAAO,CAACnB,aAAa,GAAGZ,YAAYC,WAAWC;YAC/CT,OAAOE,OAAO,CAAED,QAAQ,GAAGqC;YAC3BtC,OAAOuC,SAAS,GAAG;mBACbvC,OAAOuC,SAAS,IAAI,EAAE;gBAC1B/C;aACD,CAACa,MAAM,CAAC,CAACmC,GAAGC,GAAGC,MAAQA,IAAIC,OAAO,CAACH,OAAOC;YAE3C3B,UAAU;QACZ;QAEA,IAAIA,SAAS;YACXvB,2BACEoB,MACAd,aACAgB;QAEJ;IACF;IAEA,MAAMnB,qBAAqBiB;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.95/0001-rolldown-config-bundle-transient/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport {\n BIOME_ROLLDOWN_CONFIG_BUNDLE_EXCLUDE,\n formatFilesInSubtree,\n ROLLDOWN_CONFIG_BUNDLE_GLOB,\n} from '../../../utils/format.js';\nimport { updateGitIgnore } from '../../../utils/git.js';\n\n/**\n * Keep rolldown's transient config bundle out of Biome's and git's reach.\n *\n * Loading a `rolldown.config.ts` bundles it to `rolldown.config.<hash>.js` in the\n * config's own directory, imports it, then unlinks it. The `bundle`, `format` and\n * `lint` targets of a project all run concurrently, so a `format` sweeping the\n * project mid-bundle sees a machine-generated file and reports it unformatted —\n * failing the target for no fault of the source. Being git-visible, the file\n * could also be committed, or picked up by `license#sync`, which builds its\n * candidate set from git-visible files rather than from `biome.json`.\n *\n * Guardrails:\n * - The Biome exclude is anchored to the excludes we vend. A workspace whose\n * `files.includes` has diverged keeps its own list, and is reported via\n * `nextSteps` instead.\n * - Only projects carrying a `rolldown.config.ts` get the git ignore, matching\n * where the generator writes it.\n * - Idempotent: both edits are guarded on the pattern already being present.\n */\n\n/** The config filename whose loading produces the transient bundle. */\nconst ROLLDOWN_CONFIG = 'rolldown.config.ts';\n\n/**\n * Exclude the transient bundle from Biome. Anchored to `!**\\/out-tsc`, the\n * build-output exclude the vended list places these next to — without it the list\n * has diverged from the one we vend, so leave it to the user.\n */\nconst excludeFromBiome = (tree: Tree): string[] => {\n if (!tree.exists('biome.json')) {\n return [];\n }\n let unrecognised = false;\n updateJson(tree, 'biome.json', (biome) => {\n const includes: unknown = biome?.files?.includes;\n if (\n !Array.isArray(includes) ||\n includes.includes(BIOME_ROLLDOWN_CONFIG_BUNDLE_EXCLUDE)\n ) {\n return biome;\n }\n if (!includes.includes('!**/out-tsc')) {\n unrecognised = true;\n return biome;\n }\n return {\n ...biome,\n files: {\n ...biome.files,\n includes: includes.flatMap((include) =>\n include === '!**/out-tsc'\n ? [include, BIOME_ROLLDOWN_CONFIG_BUNDLE_EXCLUDE]\n : [include],\n ),\n },\n };\n });\n return unrecognised\n ? [\n `\\`biome.json\\`: add \\`\"${BIOME_ROLLDOWN_CONFIG_BUNDLE_EXCLUDE}\"\\` to \\`files.includes\\` so the transient bundle rolldown writes while loading a TypeScript config is never formatted or linted. Its \\`files.includes\\` has diverged from the vended list, so it was left as it is.`,\n ]\n : [];\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [...excludeFromBiome(tree)];\n\n for (const [, project] of getProjects(tree)) {\n if (!tree.exists(joinPathFragments(project.root, ROLLDOWN_CONFIG))) {\n continue;\n }\n updateGitIgnore(tree, project.root, (patterns) =>\n patterns.includes(ROLLDOWN_CONFIG_BUNDLE_GLOB)\n ? patterns\n : [...patterns, ROLLDOWN_CONFIG_BUNDLE_GLOB],\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateJson","BIOME_ROLLDOWN_CONFIG_BUNDLE_EXCLUDE","formatFilesInSubtree","ROLLDOWN_CONFIG_BUNDLE_GLOB","updateGitIgnore","ROLLDOWN_CONFIG","excludeFromBiome","tree","exists","unrecognised","biome","includes","files","Array","isArray","flatMap","include","migration","nextSteps","project","root","patterns"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAGjBC,UAAU,QACL,aAAa;AACpB,SACEC,oCAAoC,EACpCC,oBAAoB,EACpBC,2BAA2B,QACtB,2BAA2B;AAClC,SAASC,eAAe,QAAQ,wBAAwB;AAExD;;;;;;;;;;;;;;;;;;CAkBC,GAED,qEAAqE,GACrE,MAAMC,kBAAkB;AAExB;;;;CAIC,GACD,MAAMC,mBAAmB,CAACC;IACxB,IAAI,CAACA,KAAKC,MAAM,CAAC,eAAe;QAC9B,OAAO,EAAE;IACX;IACA,IAAIC,eAAe;IACnBT,WAAWO,MAAM,cAAc,CAACG;QAC9B,MAAMC,WAAoBD,OAAOE,OAAOD;QACxC,IACE,CAACE,MAAMC,OAAO,CAACH,aACfA,SAASA,QAAQ,CAACV,uCAClB;YACA,OAAOS;QACT;QACA,IAAI,CAACC,SAASA,QAAQ,CAAC,gBAAgB;YACrCF,eAAe;YACf,OAAOC;QACT;QACA,OAAO;YACL,GAAGA,KAAK;YACRE,OAAO;gBACL,GAAGF,MAAME,KAAK;gBACdD,UAAUA,SAASI,OAAO,CAAC,CAACC,UAC1BA,YAAY,gBACR;wBAACA;wBAASf;qBAAqC,GAC/C;wBAACe;qBAAQ;YAEjB;QACF;IACF;IACA,OAAOP,eACH;QACE,CAAC,uBAAuB,EAAER,qCAAqC,oNAAoN,CAAC;KACrR,GACD,EAAE;AACR;AAEA,eAAe,eAAegB,UAC5BV,IAAU;IAEV,MAAMW,YAAsB;WAAIZ,iBAAiBC;KAAM;IAEvD,KAAK,MAAM,GAAGY,QAAQ,IAAIrB,YAAYS,MAAO;QAC3C,IAAI,CAACA,KAAKC,MAAM,CAACT,kBAAkBoB,QAAQC,IAAI,EAAEf,mBAAmB;YAClE;QACF;QACAD,gBAAgBG,MAAMY,QAAQC,IAAI,EAAE,CAACC,WACnCA,SAASV,QAAQ,CAACR,+BACdkB,WACA;mBAAIA;gBAAUlB;aAA4B;IAElD;IAEA,MAAMD,qBAAqBK;IAE3B,OAAO;QAAEW;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.95/0002-agent-connection-pin-strands-peers/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { joinPathFragments, type Tree } from '@nx/devkit';\nimport { AGENT_CONNECTION_PROJECT_DIR } from '../../../utils/agent-connection/agent-connection.js';\nimport { addDependenciesToPackageJson } from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\nconst CLIENT_S3 = '@aws-sdk/client-s3';\nconst STRANDS_SDK = '@strands-agents/sdk';\n\n/**\n * `@aws-sdk/client-s3` is an optional peer of `@strands-agents/sdk` that the\n * shared agent-connection project never imports, so it went undeclared. pnpm\n * then auto-installs its own copy there while a project that does declare it\n * gets the catalog's, and those two resolutions give `@strands-agents/sdk` two\n * peer-suffixed instances of the same version.\n *\n * Anything importing both projects then sees two nominal identities of every SDK\n * type — `Agent`, `McpClient`, `Plugin` — and fails to compile with \"Types have\n * separate declarations of a private property\". Declaring it keeps the version\n * on the catalog, collapsing both to one instance.\n */\nexport default async function migration(tree: Tree): Promise<void> {\n const packageJsonPath = joinPathFragments(\n AGENT_CONNECTION_PROJECT_DIR,\n 'package.json',\n );\n if (!tree.exists(packageJsonPath)) {\n return;\n }\n\n // Only where a strands client is actually present — that is what pulls the peer.\n const packageJson = JSON.parse(tree.read(packageJsonPath, 'utf-8') ?? '{}');\n if (!packageJson.dependencies?.[STRANDS_SDK]) {\n return;\n }\n\n addDependenciesToPackageJson(\n tree,\n { [CLIENT_S3]: TS_VERSIONS[CLIENT_S3] },\n {},\n packageJsonPath,\n );\n\n await formatFilesInSubtree(tree);\n}\n"],"names":["joinPathFragments","AGENT_CONNECTION_PROJECT_DIR","addDependenciesToPackageJson","formatFilesInSubtree","TS_VERSIONS","CLIENT_S3","STRANDS_SDK","migration","tree","packageJsonPath","exists","packageJson","JSON","parse","read","dependencies"],"mappings":"AAAA;;;CAGC,GACD,SAASA,iBAAiB,QAAmB,aAAa;AAC1D,SAASC,4BAA4B,QAAQ,sDAAsD;AACnG,SAASC,4BAA4B,QAAQ,iCAAiC;AAC9E,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,WAAW,QAAQ,6BAA6B;AAEzD,MAAMC,YAAY;AAClB,MAAMC,cAAc;AAEpB;;;;;;;;;;;CAWC,GACD,eAAe,eAAeC,UAAUC,IAAU;IAChD,MAAMC,kBAAkBT,kBACtBC,8BACA;IAEF,IAAI,CAACO,KAAKE,MAAM,CAACD,kBAAkB;QACjC;IACF;IAEA,iFAAiF;IACjF,MAAME,cAAcC,KAAKC,KAAK,CAACL,KAAKM,IAAI,CAACL,iBAAiB,YAAY;IACtE,IAAI,CAACE,YAAYI,YAAY,EAAE,CAACT,YAAY,EAAE;QAC5C;IACF;IAEAJ,6BACEM,MACA;QAAE,CAACH,UAAU,EAAED,WAAW,CAACC,UAAU;IAAC,GACtC,CAAC,GACDI;IAGF,MAAMN,qBAAqBK;AAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.95/0003-ignore-package-manager-temp-files/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Tree } from '@nx/devkit';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { updateGitIgnore } from '../../../utils/git.js';\n\n/** The temporary files pnpm writes while materialising packages. */\nconst TEMP_FILE_PATTERN = '_tmp_*';\n\n/**\n * pnpm creates `_tmp_<pid>_<hash>` files at the workspace root while it\n * materialises packages. Left unignored, Nx's watcher invalidates the project\n * graph on every install, so a watch-mode `dev` target running at the time\n * rebuilds the graph continuously and never starts the command it wraps.\n */\nexport default async function migration(tree: Tree): Promise<void> {\n // Only pnpm writes these, so key off its lockfile rather than the workspace\n // file — a workspace on another package manager may still carry one.\n if (!tree.exists('pnpm-lock.yaml')) {\n return;\n }\n\n updateGitIgnore(tree, '.', (patterns) =>\n patterns.includes(TEMP_FILE_PATTERN)\n ? patterns\n : [...patterns, TEMP_FILE_PATTERN],\n );\n\n await formatFilesInSubtree(tree);\n}\n"],"names":["formatFilesInSubtree","updateGitIgnore","TEMP_FILE_PATTERN","migration","tree","exists","patterns","includes"],"mappings":"AAAA;;;CAGC,GAED,SAASA,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,eAAe,QAAQ,wBAAwB;AAExD,kEAAkE,GAClE,MAAMC,oBAAoB;AAE1B;;;;;CAKC,GACD,eAAe,eAAeC,UAAUC,IAAU;IAChD,4EAA4E;IAC5E,qEAAqE;IACrE,IAAI,CAACA,KAAKC,MAAM,CAAC,mBAAmB;QAClC;IACF;IAEAJ,gBAAgBG,MAAM,KAAK,CAACE,WAC1BA,SAASC,QAAQ,CAACL,qBACdI,WACA;eAAIA;YAAUJ;SAAkB;IAGtC,MAAMF,qBAAqBI;AAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.95/0004-shadcn-package-imports-exports/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n readJson,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { REACT_WEBSITE_APP_GENERATOR_INFO } from '../../../ts/react-website/app/generator.js';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport {\n addDependenciesToPackageJson,\n getLocalDependencySpecifier,\n} from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_SHADCN_DIR,\n} from '../../../utils/shared-constructs-constants.js';\nimport { getSharedShadcnFullyQualifiedName } from '../../../utils/shared-shadcn.js';\n\n/**\n * Move the shared shadcn package off a `tsconfig.base.json` `paths` alias onto\n * `package.json` `imports`/`exports`.\n *\n * shadcn 4.x's CLI resolves `components.json`'s aliases via Node's package\n * resolution (`imports`/`exports`), not tsconfig `paths` - its own resolver\n * naively joins a tsconfig-declared alias against whichever directory it's\n * invoked from, so the repo-root-relative `paths` mapping this plugin used to\n * vend breaks the moment `shadcn add` is run with `-c packages/common/shadcn`\n * (as its own monorepo-root preflight now tells the user to). This migration\n * carries an existing workspace onto the shape today's generators produce:\n * local `#...` imports for the package's own internal component references,\n * a public `exports` map for every other consumer, and a real `workspace:*`\n * dependency on each consumer so that map actually resolves.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Only touches a `packages/common/shadcn` this plugin's generators produced\n * (guarded by `components.json`'s aliases still matching the old shape).\n * - Internal imports are rewritten by exact module specifier per file found\n * under `src/{components/ui,lib,hooks}`, so a component a user added by hand\n * after the original generation is covered too, and a specifier the\n * migration doesn't recognise is left alone and reported.\n * - Idempotent: every write is guarded by the old shape still being present.\n */\n\nconst libraryRoot = joinPathFragments(PACKAGES_DIR, SHARED_SHADCN_DIR);\nconst componentsJsonPath = joinPathFragments(libraryRoot, 'components.json');\nconst packageJsonPath = joinPathFragments(libraryRoot, 'package.json');\n\ninterface ComponentsJsonAliases {\n readonly components?: string;\n readonly utils?: string;\n readonly hooks?: string;\n readonly lib?: string;\n readonly ui?: string;\n}\n\nconst oldAliases = (fqn: string): ComponentsJsonAliases => ({\n components: `${fqn}/components`,\n utils: `${fqn}/lib/utils`,\n hooks: `${fqn}/hooks`,\n lib: `${fqn}/lib`,\n ui: `${fqn}/components/ui`,\n});\n\nconst newAliases: Required<ComponentsJsonAliases> = {\n components: '#components',\n utils: '#lib/utils',\n hooks: '#hooks',\n lib: '#lib',\n ui: '#components/ui',\n};\n\nconst newPackageManifestFields = {\n imports: {\n '#components/*': './src/components/*.tsx',\n '#lib/*': './src/lib/*.ts',\n '#hooks/*': './src/hooks/*.ts',\n },\n exports: {\n '.': './src/index.ts',\n './styles/*': './src/styles/*',\n './components/*': './src/components/*.tsx',\n './lib/*': './src/lib/*.ts',\n './hooks/*': './src/hooks/*.ts',\n },\n};\n\n/**\n * Rewrite an import's module specifier, keeping its bindings - `$bindings`\n * holds whatever the file imports, so a binding a user added survives.\n */\nconst importPattern = (from: string, to: string): string =>\n `\\`import { $bindings } from '${from}'\\` => \\`import { $bindings } from '${to}'\\``;\n\n/** Whether the file still imports the old specifier under any other form. */\nconst hasRemainingImport = (from: string): string =>\n `\\`import $_ from '${from}'\\``;\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(componentsJsonPath) || !tree.exists(packageJsonPath)) {\n return { nextSteps };\n }\n\n const fullyQualifiedName = getSharedShadcnFullyQualifiedName(tree);\n const currentAliases =\n readJson<{ aliases?: ComponentsJsonAliases }>(tree, componentsJsonPath)\n .aliases ?? {};\n const expectedOldAliases = oldAliases(fullyQualifiedName);\n const onOldShape = (\n Object.keys(newAliases) as (keyof ComponentsJsonAliases)[]\n ).every((key) => currentAliases[key] === expectedOldAliases[key]);\n\n if (!onOldShape) {\n if (\n (Object.keys(newAliases) as (keyof ComponentsJsonAliases)[]).some(\n (key) => currentAliases[key] !== newAliases[key],\n )\n ) {\n nextSteps.push(\n `${componentsJsonPath}: aliases have diverged from both the old and current generated shape - left untouched. Migrate them to the shadcn CLI's imports/exports monorepo pattern by hand: https://ui.shadcn.com/docs/monorepo`,\n );\n }\n await formatFilesInSubtree(tree);\n return { nextSteps };\n }\n\n // Rewrite every source file's internal references to this package's own\n // components/lib/hooks, keyed off the files actually present so a\n // hand-added component is covered too.\n const internalDirs: Array<{\n dir: string;\n extension: string;\n oldSubpath: string;\n newPrefix: string;\n }> = [\n {\n dir: joinPathFragments(libraryRoot, 'src', 'components', 'ui'),\n extension: '.tsx',\n oldSubpath: 'components/ui',\n newPrefix: '#components/ui',\n },\n {\n dir: joinPathFragments(libraryRoot, 'src', 'lib'),\n extension: '.ts',\n oldSubpath: 'lib',\n newPrefix: '#lib',\n },\n {\n dir: joinPathFragments(libraryRoot, 'src', 'hooks'),\n extension: '.ts',\n oldSubpath: 'hooks',\n newPrefix: '#hooks',\n },\n ];\n\n const renames: Array<{ old: string; renamed: string }> = [];\n const sourceFiles: string[] = [];\n for (const { dir, extension, oldSubpath, newPrefix } of internalDirs) {\n if (!tree.exists(dir)) {\n continue;\n }\n for (const entry of tree.children(dir)) {\n if (!entry.endsWith(extension)) {\n continue;\n }\n const baseName = entry.slice(0, -extension.length);\n renames.push({\n old: `${fullyQualifiedName}/${oldSubpath}/${baseName}`,\n renamed: `${newPrefix}/${baseName}`,\n });\n sourceFiles.push(joinPathFragments(dir, entry));\n }\n }\n\n for (const sourceFile of sourceFiles) {\n for (const { old, renamed } of renames) {\n await applyGritQL(tree, sourceFile, importPattern(old, renamed));\n // A namespace or default import of the same specifier is left as it\n // is - reported rather than rewritten, so a diverged file is never\n // clobbered.\n if (await matchGritQL(tree, sourceFile, hasRemainingImport(old))) {\n nextSteps.push(\n `${sourceFile}: still imports '${old}' in a form this migration does not rewrite - update it to '${renamed}' by hand.`,\n );\n }\n }\n }\n\n updateJson(tree, componentsJsonPath, (json) => ({\n ...json,\n aliases: newAliases,\n }));\n\n updateJson(tree, packageJsonPath, (json) => ({\n ...json,\n ...newPackageManifestFields,\n }));\n\n updateJson(tree, 'tsconfig.base.json', (json) => {\n const paths = { ...(json.compilerOptions?.paths ?? {}) };\n delete paths[`${fullyQualifiedName}/*`];\n return {\n ...json,\n compilerOptions: {\n ...json.compilerOptions,\n paths,\n },\n };\n });\n\n // Every website generated with ux=shadcn needs a real dependency on the\n // shared package now that it resolves through `exports`, not `paths`.\n for (const project of getProjects(tree).values()) {\n const metadata = project.metadata as\n | { generator?: string; ux?: string }\n | undefined;\n if (\n metadata?.generator !== REACT_WEBSITE_APP_GENERATOR_INFO.id ||\n metadata.ux !== 'shadcn'\n ) {\n continue;\n }\n addDependenciesToPackageJson(\n tree,\n { [fullyQualifiedName]: getLocalDependencySpecifier(tree) },\n {},\n joinPathFragments(project.root, 'package.json'),\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","readJson","updateJson","REACT_WEBSITE_APP_GENERATOR_INFO","applyGritQL","matchGritQL","addDependenciesToPackageJson","getLocalDependencySpecifier","formatFilesInSubtree","PACKAGES_DIR","SHARED_SHADCN_DIR","getSharedShadcnFullyQualifiedName","libraryRoot","componentsJsonPath","packageJsonPath","oldAliases","fqn","components","utils","hooks","lib","ui","newAliases","newPackageManifestFields","imports","exports","importPattern","from","to","hasRemainingImport","migration","tree","nextSteps","exists","fullyQualifiedName","currentAliases","aliases","expectedOldAliases","onOldShape","Object","keys","every","key","some","push","internalDirs","dir","extension","oldSubpath","newPrefix","renames","sourceFiles","entry","children","endsWith","baseName","slice","length","old","renamed","sourceFile","json","paths","compilerOptions","project","values","metadata","generator","id","ux","root"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport {\n applyGritQL,\n GRIT_INSERT_PLACEHOLDER,\n insertViaGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * The CDK `Gateway` L2 types its `gatewayUrl` as `string | undefined`, so\n * reaching through the vended `AgentCoreGateway` construct to\n * `gateway.gateway.gatewayUrl` does not typecheck where a `string` is required —\n * the DCR proxy's `upstreamUrl`, for example. `AgentCoreGateway` gains a\n * non-optional `gatewayUrl` accessor falling back to the CloudFormation\n * attribute, which `addGateway` and the vended app-level gateway constructs then\n * read.\n */\n\nconst CONSTRUCTS_SRC = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src`;\n\nconst GATEWAY_CONSTRUCT_FILE = `${CONSTRUCTS_SRC}/core/agentcore-gateway/agentcore-gateway.ts`;\n\nconst GATEWAYS_DIR = `${CONSTRUCTS_SRC}/app/gateways`;\n\nconst GATEWAY_URL_ACCESSOR = `/**\n * The gateway's URL endpoint. The Gateway L2 types its own \\`gatewayUrl\\` as\n * optional and only populates it when created from its own props, so fall\n * back to the CloudFormation attribute.\n */\n public get gatewayUrl(): string {\n return (\n this.gateway.gatewayUrl ??\n (this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl\n );\n }`;\n\nconst divergedCoreMessage = `${GATEWAY_CONSTRUCT_FILE}: the AgentCoreGateway construct has diverged from the generated shape - left untouched. To use a gateway's URL where a \\`string\\` is required, add a \\`public get gatewayUrl(): string\\` accessor returning \\`this.gateway.gatewayUrl ?? (this.gateway.node.defaultChild as agentcore.CfnGateway).attrGatewayUrl\\`.`;\n\n/**\n * Add the `gatewayUrl` accessor to the vended core construct, and route\n * `addGateway` and the shape it requires of its argument through it. Returns\n * whether the core construct ends up carrying the accessor — app-level\n * constructs may only be pointed at it once it exists.\n */\nconst migrateCoreConstruct = async (\n tree: Tree,\n nextSteps: string[],\n): Promise<boolean> => {\n if (!tree.exists(GATEWAY_CONSTRUCT_FILE)) {\n return false;\n }\n\n const hasAccessor = await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`public get gatewayUrl(): string { $_ }`',\n );\n\n if (!hasAccessor) {\n // Anchored on the grantPrincipal accessor, present in every vended version.\n const added = await insertViaGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`public get grantPrincipal(): iam.IPrincipal { $body }\\` as $accessor => \\`$accessor\n\n ${GRIT_INSERT_PLACEHOLDER}\\``,\n GATEWAY_URL_ACCESSOR,\n );\n if (!added) {\n nextSteps.push(divergedCoreMessage);\n return false;\n }\n }\n\n const addGatewayUsesAccessor = await matchGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n '`gatewayUrl: gateway.gatewayUrl`',\n );\n\n if (!addGatewayUsesAccessor) {\n // The accessor is part of the shape addGateway requires of its argument.\n await applyGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`readonly gatewayName: string\\` as $member => \\`$member;\n readonly gatewayUrl: string\\``,\n );\n\n // addGateway reads the accessor rather than repeating the fallback inline.\n await applyGritQL(\n tree,\n GATEWAY_CONSTRUCT_FILE,\n `\\`this.addGatewayTarget({ gatewayTargetName: $name, gatewayUrl: $url, gatewayArn: $arn })\\` where {\n $url <: contains \\`attrGatewayUrl\\`\n} => \\`this.addGatewayTarget({\n gatewayTargetName: $name,\n gatewayUrl: gateway.gatewayUrl,\n gatewayArn: $arn,\n })\\``,\n );\n }\n\n return true;\n};\n\n/**\n * Point each vended app-level gateway construct's runtime config entry at the\n * accessor.\n */\nconst migrateAppConstructs = async (tree: Tree): Promise<void> => {\n if (!tree.exists(GATEWAYS_DIR)) {\n return;\n }\n for (const dir of tree.children(GATEWAYS_DIR)) {\n const constructFile = `${GATEWAYS_DIR}/${dir}/${dir}.ts`;\n if (!tree.exists(constructFile)) {\n continue;\n }\n await applyGritQL(\n tree,\n constructFile,\n '`this.gateway.gatewayUrl` => `this.gatewayUrl`',\n );\n }\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n // The app constructs read the accessor, so they may only be migrated once the\n // core construct carries it.\n if (await migrateCoreConstruct(tree, nextSteps)) {\n await migrateAppConstructs(tree);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","CONSTRUCTS_SRC","GATEWAY_CONSTRUCT_FILE","GATEWAYS_DIR","GATEWAY_URL_ACCESSOR","divergedCoreMessage","migrateCoreConstruct","tree","nextSteps","exists","hasAccessor","added","push","addGatewayUsesAccessor","migrateAppConstructs","dir","children","constructFile","migration"],"mappings":"AAAA;;;CAGC,GAED,SACEA,WAAW,EACXC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,qBAAqB,QAChB,gDAAgD;AAEvD;;;;;;;;CAQC,GAED,MAAMC,iBAAiB,GAAGF,aAAa,CAAC,EAAEC,sBAAsB,IAAI,CAAC;AAErE,MAAME,yBAAyB,GAAGD,eAAe,4CAA4C,CAAC;AAE9F,MAAME,eAAe,GAAGF,eAAe,aAAa,CAAC;AAErD,MAAMG,uBAAuB,CAAC;;;;;;;;;;GAU3B,CAAC;AAEJ,MAAMC,sBAAsB,GAAGH,uBAAuB,oTAAoT,CAAC;AAE3W;;;;;CAKC,GACD,MAAMI,uBAAuB,OAC3BC,MACAC;IAEA,IAAI,CAACD,KAAKE,MAAM,CAACP,yBAAyB;QACxC,OAAO;IACT;IAEA,MAAMQ,cAAc,MAAMb,YACxBU,MACAL,wBACA;IAGF,IAAI,CAACQ,aAAa;QAChB,4EAA4E;QAC5E,MAAMC,QAAQ,MAAMf,gBAClBW,MACAL,wBACA,CAAC;;EAEL,EAAEP,wBAAwB,EAAE,CAAC,EACzBS;QAEF,IAAI,CAACO,OAAO;YACVH,UAAUI,IAAI,CAACP;YACf,OAAO;QACT;IACF;IAEA,MAAMQ,yBAAyB,MAAMhB,YACnCU,MACAL,wBACA;IAGF,IAAI,CAACW,wBAAwB;QAC3B,yEAAyE;QACzE,MAAMnB,YACJa,MACAL,wBACA,CAAC;mCAC4B,CAAC;QAGhC,2EAA2E;QAC3E,MAAMR,YACJa,MACAL,wBACA,CAAC;;;;;;QAMC,CAAC;IAEP;IAEA,OAAO;AACT;AAEA;;;CAGC,GACD,MAAMY,uBAAuB,OAAOP;IAClC,IAAI,CAACA,KAAKE,MAAM,CAACN,eAAe;QAC9B;IACF;IACA,KAAK,MAAMY,OAAOR,KAAKS,QAAQ,CAACb,cAAe;QAC7C,MAAMc,gBAAgB,GAAGd,aAAa,CAAC,EAAEY,IAAI,CAAC,EAAEA,IAAI,GAAG,CAAC;QACxD,IAAI,CAACR,KAAKE,MAAM,CAACQ,gBAAgB;YAC/B;QACF;QACA,MAAMvB,YACJa,MACAU,eACA;IAEJ;AACF;AAEA,eAAe,eAAeC,UAC5BX,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,8EAA8E;IAC9E,6BAA6B;IAC7B,IAAI,MAAMF,qBAAqBC,MAAMC,YAAY;QAC/C,MAAMM,qBAAqBP;IAC7B;IAEA,MAAMT,qBAAqBS;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Point the CDK infrastructure `checkov` target's cache inputs at the project\n * rather than at the synth output directory.\n *\n * The target declared `[\"{workspaceRoot}/dist/{projectRoot}/cdk.out\"]`, a\n * fileset input. Nx resolves a fileset against the files it tracks, and `dist`\n * is gitignored — so the input matched nothing and hashed to a constant. Once\n * the scan had been cached, every later run was a hit: adding a non-compliant\n * resource to a stack left `build` reporting success, and restored a\n * `checkov_report.json` recording zero resources scanned.\n *\n * `[\"default\"]` is what its `synth` sibling declares. It covers the project's\n * own sources and carries the transitive `dependentTasksOutputFiles` entry from\n * `nx.json`, which Nx resolves against the upstream `synth` task — so the hash\n * follows the template the scan actually reads.\n */\n\nconst CHECKOV_TARGET = 'checkov';\n\n/** The inputs the pre-fix generator declared, replaced in place. */\nconst VENDED_INPUTS = ['{workspaceRoot}/dist/{projectRoot}/cdk.out'];\n\n/** The inputs the generator declares now, matching the `synth` sibling. */\nconst FIXED_INPUTS = ['default'];\n\nconst divergedMessage = (projectName: string) =>\n `${projectName}:${CHECKOV_TARGET}: its \\`inputs\\` have diverged from the generated shape - left untouched. Confirm they cover the synthesized template the scan reads: an input pointed only at \\`dist\\` matches no tracked file, so the scan can report a cached pass on infrastructure it never scanned.`;\n\n/** Whether a target's inputs are exactly the ones the generator vended. */\nconst hasVendedInputs = (target: TargetConfiguration): boolean =>\n Array.isArray(target.inputs) &&\n target.inputs.length === VENDED_INPUTS.length &&\n target.inputs.every((input, index) => input === VENDED_INPUTS[index]);\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (generator !== INFRA_APP_GENERATOR_INFO.id) continue;\n\n const target = project.targets?.[CHECKOV_TARGET];\n if (!target) continue;\n\n // A target already declaring the fixed inputs needs nothing, which also\n // makes a re-run — and a project generated after the fix — a no-op.\n if (\n Array.isArray(target.inputs) &&\n target.inputs.length === FIXED_INPUTS.length &&\n target.inputs.every((input, index) => input === FIXED_INPUTS[index])\n ) {\n continue;\n }\n\n if (!hasVendedInputs(target)) {\n nextSteps.push(divergedMessage(projectName));\n continue;\n }\n\n target.inputs = [...FIXED_INPUTS];\n updateProjectConfiguration(\n tree,\n projectName,\n project as ProjectConfiguration,\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","CHECKOV_TARGET","VENDED_INPUTS","FIXED_INPUTS","divergedMessage","projectName","hasVendedInputs","target","Array","isArray","inputs","length","every","input","index","migration","tree","nextSteps","project","generator","metadata","id","targets","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAKXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;;;;CAeC,GAED,MAAMC,iBAAiB;AAEvB,kEAAkE,GAClE,MAAMC,gBAAgB;IAAC;CAA6C;AAEpE,yEAAyE,GACzE,MAAMC,eAAe;IAAC;CAAU;AAEhC,MAAMC,kBAAkB,CAACC,cACvB,GAAGA,YAAY,CAAC,EAAEJ,eAAe,yQAAyQ,CAAC;AAE7S,yEAAyE,GACzE,MAAMK,kBAAkB,CAACC,SACvBC,MAAMC,OAAO,CAACF,OAAOG,MAAM,KAC3BH,OAAOG,MAAM,CAACC,MAAM,KAAKT,cAAcS,MAAM,IAC7CJ,OAAOG,MAAM,CAACE,KAAK,CAAC,CAACC,OAAOC,QAAUD,UAAUX,aAAa,CAACY,MAAM;AAEtE,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACZ,aAAaa,QAAQ,IAAIrB,YAAYmB,MAAO;QACtD,MAAMG,YAAaD,QAAQE,QAAQ,EAC/BD;QACJ,IAAIA,cAAcpB,yBAAyBsB,EAAE,EAAE;QAE/C,MAAMd,SAASW,QAAQI,OAAO,EAAE,CAACrB,eAAe;QAChD,IAAI,CAACM,QAAQ;QAEb,wEAAwE;QACxE,oEAAoE;QACpE,IACEC,MAAMC,OAAO,CAACF,OAAOG,MAAM,KAC3BH,OAAOG,MAAM,CAACC,MAAM,KAAKR,aAAaQ,MAAM,IAC5CJ,OAAOG,MAAM,CAACE,KAAK,CAAC,CAACC,OAAOC,QAAUD,UAAUV,YAAY,CAACW,MAAM,GACnE;YACA;QACF;QAEA,IAAI,CAACR,gBAAgBC,SAAS;YAC5BU,UAAUM,IAAI,CAACnB,gBAAgBC;YAC/B;QACF;QAEAE,OAAOG,MAAM,GAAG;eAAIP;SAAa;QACjCL,2BACEkB,MACAX,aACAa;IAEJ;IAEA,MAAMlB,qBAAqBgB;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type ProjectConfiguration,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { relative } from 'path';\nimport { TERRAFORM_PROJECT_GENERATOR_INFO } from '../../../terraform/project/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Run `validate` against a backendless `terraform init` of its own, so it works\n * on a fresh workspace.\n *\n * It previously depended on the `init` target. On an application project that\n * runs the vended `scripts/init.ts`, which configures the S3 backend and fails\n * with a raw `NoSuchBucket` trace until `bootstrap` has created the state\n * bucket — so the first target the guide invites the reader to try was\n * unrunnable, while `lint`, `test` and `checkov` all worked.\n *\n * `-backend=false` installs the modules and providers validation needs without\n * configuring the backend, exactly as `test` already does, so no credentials are\n * involved. `TF_DATA_DIR` keeps that `.terraform` out of `src` so it never races\n * the backend-configured targets over the shared one, and the shared plugin\n * cache means the providers are linked rather than re-downloaded.\n */\n\nconst VALIDATE_TARGET = 'validate';\n\n/** The command the pre-fix target ran, on its own. */\nconst VENDED_COMMAND = 'terraform validate';\n\nconst divergedMessage = (projectName: string) =>\n `${projectName}:${VALIDATE_TARGET}: has diverged from the generated shape - left untouched. To run it before \\`bootstrap\\`, have it run \\`terraform init -backend=false\\` ahead of \\`terraform validate\\` rather than depending on the \\`init\\` target, which configures the S3 backend.`;\n\n/** Path from a target running in `{projectRoot}/src` to the workspace root. */\nconst rootRelativePathFrom = (projectRoot: string) =>\n (relative(joinPathFragments(projectRoot, 'src'), '.') || '.').replace(\n /\\\\/g,\n '/',\n );\n\n/** Whether the target is the exact shape the pre-fix generator produced. */\nconst hasVendedShape = (target: TargetConfiguration): boolean =>\n target.executor === 'nx:run-commands' &&\n target.options?.command === VENDED_COMMAND &&\n !target.options?.commands &&\n target.options?.cwd === '{projectRoot}/src' &&\n target.dependsOn?.length === 1 &&\n target.dependsOn[0] === 'init';\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [projectName, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (generator !== TERRAFORM_PROJECT_GENERATOR_INFO.id) continue;\n\n const target = project.targets?.[VALIDATE_TARGET];\n if (!target) continue;\n\n // A target already running its own init needs nothing, which also makes a\n // re-run — and a project generated after the fix — a no-op.\n if (target.options?.env?.TF_DATA_DIR) continue;\n\n if (!hasVendedShape(target)) {\n nextSteps.push(divergedMessage(projectName));\n continue;\n }\n\n const rootRelativePath = rootRelativePathFrom(project.root);\n const pluginCacheDir = joinPathFragments(\n rootRelativePath,\n '.terraform',\n 'plugin-cache',\n '{projectRoot}',\n ).replace(/\\\\/g, '/');\n const validateDataDir = joinPathFragments(\n rootRelativePath,\n 'dist',\n '{projectRoot}',\n 'terraform-validate',\n ).replace(/\\\\/g, '/');\n\n const { command: _command, ...options } = target.options;\n const { dependsOn: _dependsOn, ...rest } = target;\n\n project.targets[VALIDATE_TARGET] = {\n ...rest,\n // `^production` mirrors `test`: validation resolves the relative modules a\n // project consumes, so a change in one must invalidate it.\n inputs: ['default', '^production'],\n // `TF_DATA_DIR` is terraform's working directory, not an artifact — its\n // provider entries are symlinks into the shared plugin cache.\n outputs: [],\n options: {\n ...options,\n commands: [\n { command: `shx mkdir -p ${pluginCacheDir}`, forwardAllArgs: false },\n 'terraform init -backend=false',\n VENDED_COMMAND,\n ],\n parallel: false,\n env: {\n ...options.env,\n TF_DATA_DIR: validateDataDir,\n TF_PLUGIN_CACHE_DIR: pluginCacheDir,\n },\n },\n };\n\n updateProjectConfiguration(\n tree,\n projectName,\n project as ProjectConfiguration,\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","relative","TERRAFORM_PROJECT_GENERATOR_INFO","formatFilesInSubtree","VALIDATE_TARGET","VENDED_COMMAND","divergedMessage","projectName","rootRelativePathFrom","projectRoot","replace","hasVendedShape","target","executor","options","command","commands","cwd","dependsOn","length","migration","tree","nextSteps","project","generator","metadata","id","targets","env","TF_DATA_DIR","push","rootRelativePath","root","pluginCacheDir","validateDataDir","_command","_dependsOn","rest","inputs","outputs","forwardAllArgs","parallel","TF_PLUGIN_CACHE_DIR"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAKjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,QAAQ,QAAQ,OAAO;AAChC,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;;;;;;;CAeC,GAED,MAAMC,kBAAkB;AAExB,oDAAoD,GACpD,MAAMC,iBAAiB;AAEvB,MAAMC,kBAAkB,CAACC,cACvB,GAAGA,YAAY,CAAC,EAAEH,gBAAgB,sPAAsP,CAAC;AAE3R,6EAA6E,GAC7E,MAAMI,uBAAuB,CAACC,cAC5B,AAACR,CAAAA,SAASF,kBAAkBU,aAAa,QAAQ,QAAQ,GAAE,EAAGC,OAAO,CACnE,OACA;AAGJ,0EAA0E,GAC1E,MAAMC,iBAAiB,CAACC,SACtBA,OAAOC,QAAQ,KAAK,qBACpBD,OAAOE,OAAO,EAAEC,YAAYV,kBAC5B,CAACO,OAAOE,OAAO,EAAEE,YACjBJ,OAAOE,OAAO,EAAEG,QAAQ,uBACxBL,OAAOM,SAAS,EAAEC,WAAW,KAC7BP,OAAOM,SAAS,CAAC,EAAE,KAAK;AAE1B,eAAe,eAAeE,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACf,aAAagB,QAAQ,IAAIzB,YAAYuB,MAAO;QACtD,MAAMG,YAAaD,QAAQE,QAAQ,EAC/BD;QACJ,IAAIA,cAActB,iCAAiCwB,EAAE,EAAE;QAEvD,MAAMd,SAASW,QAAQI,OAAO,EAAE,CAACvB,gBAAgB;QACjD,IAAI,CAACQ,QAAQ;QAEb,0EAA0E;QAC1E,4DAA4D;QAC5D,IAAIA,OAAOE,OAAO,EAAEc,KAAKC,aAAa;QAEtC,IAAI,CAAClB,eAAeC,SAAS;YAC3BU,UAAUQ,IAAI,CAACxB,gBAAgBC;YAC/B;QACF;QAEA,MAAMwB,mBAAmBvB,qBAAqBe,QAAQS,IAAI;QAC1D,MAAMC,iBAAiBlC,kBACrBgC,kBACA,cACA,gBACA,iBACArB,OAAO,CAAC,OAAO;QACjB,MAAMwB,kBAAkBnC,kBACtBgC,kBACA,QACA,iBACA,sBACArB,OAAO,CAAC,OAAO;QAEjB,MAAM,EAAEK,SAASoB,QAAQ,EAAE,GAAGrB,SAAS,GAAGF,OAAOE,OAAO;QACxD,MAAM,EAAEI,WAAWkB,UAAU,EAAE,GAAGC,MAAM,GAAGzB;QAE3CW,QAAQI,OAAO,CAACvB,gBAAgB,GAAG;YACjC,GAAGiC,IAAI;YACP,2EAA2E;YAC3E,2DAA2D;YAC3DC,QAAQ;gBAAC;gBAAW;aAAc;YAClC,wEAAwE;YACxE,8DAA8D;YAC9DC,SAAS,EAAE;YACXzB,SAAS;gBACP,GAAGA,OAAO;gBACVE,UAAU;oBACR;wBAAED,SAAS,CAAC,aAAa,EAAEkB,gBAAgB;wBAAEO,gBAAgB;oBAAM;oBACnE;oBACAnC;iBACD;gBACDoC,UAAU;gBACVb,KAAK;oBACH,GAAGd,QAAQc,GAAG;oBACdC,aAAaK;oBACbQ,qBAAqBT;gBACvB;YACF;QACF;QAEAjC,2BACEqB,MACAd,aACAgB;IAEJ;IAEA,MAAMpB,qBAAqBkB;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { LAMBDA_FUNCTION_GENERATOR_INFO } from '../../../py/lambda-function/generator.js';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport type { ComponentMetadata } from '../../../utils/nx.js';\n\n/**\n * Wire powertools Lambda context injection and the cold start metric into\n * handlers generated by py#lambda-function.\n *\n * `@logger.inject_lambda_context` is what annotates each log record with the\n * function name, request id, memory size and cold start flag, and\n * `capture_cold_start_metric` is what emits the `ColdStart` metric.\n *\n * Both rewrites are scoped to the decorator list of the `lambda_handler`\n * definition, so a `@metrics.log_metrics` decorating another function in the\n * same module is left alone.\n */\nconst INJECT_CONTEXT = '@logger.inject_lambda_context';\nconst LOG_METRICS_OLD = '@metrics.log_metrics';\nconst LOG_METRICS_NEW = '@metrics.log_metrics(capture_cold_start_metric=True)';\n\nconst HANDLER_DECORATORS = (body: string) => `language python\ndecorated_definition($decorators, $definition) where {\n $definition <: contains \\`lambda_handler\\`,\n ${body}\n}`;\n\n/** The shape the generator produces: a bare `log_metrics` below the tracer. */\nconst GENERATED_SHAPE =\n HANDLER_DECORATORS(`$decorators <: contains \\`@tracer.capture_lambda_handler\\`,\n $decorators <: contains \\`${LOG_METRICS_OLD}\\``);\n\nconst ALREADY_MIGRATED =\n HANDLER_DECORATORS(`$decorators <: contains \\`${INJECT_CONTEXT}\\`,\n $decorators <: contains \\`${LOG_METRICS_NEW}\\``);\n\nconst REWRITE =\n HANDLER_DECORATORS(`$decorators <: contains \\`@tracer.capture_lambda_handler\\` => raw\\`@tracer.capture_lambda_handler\n${INJECT_CONTEXT}\\`,\n $decorators <: contains \\`${LOG_METRICS_OLD}\\` => \\`${LOG_METRICS_NEW}\\``);\n\nconst migrateHandler = async (\n tree: Tree,\n handlerPath: string,\n nextSteps: string[],\n): Promise<void> => {\n if (!tree.exists(handlerPath)) return;\n\n if (await matchGritQL(tree, handlerPath, ALREADY_MIGRATED)) return;\n\n if (!(await matchGritQL(tree, handlerPath, GENERATED_SHAPE))) {\n nextSteps.push(\n `${handlerPath}: diverged from the generated py#lambda-function shape - left untouched. To annotate logs with the Lambda context and emit a ColdStart metric, add \\`${INJECT_CONTEXT}\\` to the handler and change \\`${LOG_METRICS_OLD}\\` to \\`${LOG_METRICS_NEW}\\`.`,\n );\n return;\n }\n\n await applyGritQL(tree, handlerPath, REWRITE);\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const project of getProjects(tree).values()) {\n const components = (\n (project.metadata as { components?: ComponentMetadata[] })?.components ??\n []\n ).filter(\n (component) => component.generator === LAMBDA_FUNCTION_GENERATOR_INFO.id,\n );\n\n for (const component of components) {\n if (!component.path) continue;\n await migrateHandler(\n tree,\n joinPathFragments(project.root, component.path),\n nextSteps,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","LAMBDA_FUNCTION_GENERATOR_INFO","applyGritQL","matchGritQL","formatFilesInSubtree","INJECT_CONTEXT","LOG_METRICS_OLD","LOG_METRICS_NEW","HANDLER_DECORATORS","body","GENERATED_SHAPE","ALREADY_MIGRATED","REWRITE","migrateHandler","tree","handlerPath","nextSteps","exists","push","migration","project","values","components","metadata","filter","component","generator","id","path","root"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,8BAA8B,QAAQ,2CAA2C;AAC1F,SAASC,WAAW,EAAEC,WAAW,QAAQ,wBAAwB;AACjE,SAASC,oBAAoB,QAAQ,2BAA2B;AAGhE;;;;;;;;;;;CAWC,GACD,MAAMC,iBAAiB;AACvB,MAAMC,kBAAkB;AACxB,MAAMC,kBAAkB;AAExB,MAAMC,qBAAqB,CAACC,OAAiB,CAAC;;;EAG5C,EAAEA,KAAK;CACR,CAAC;AAEF,6EAA6E,GAC7E,MAAMC,kBACJF,mBAAmB,CAAC;4BACM,EAAEF,gBAAgB,EAAE,CAAC;AAEjD,MAAMK,mBACJH,mBAAmB,CAAC,0BAA0B,EAAEH,eAAe;4BACrC,EAAEE,gBAAgB,EAAE,CAAC;AAEjD,MAAMK,UACJJ,mBAAmB,CAAC;AACtB,EAAEH,eAAe;4BACW,EAAEC,gBAAgB,QAAQ,EAAEC,gBAAgB,EAAE,CAAC;AAE3E,MAAMM,iBAAiB,OACrBC,MACAC,aACAC;IAEA,IAAI,CAACF,KAAKG,MAAM,CAACF,cAAc;IAE/B,IAAI,MAAMZ,YAAYW,MAAMC,aAAaJ,mBAAmB;IAE5D,IAAI,CAAE,MAAMR,YAAYW,MAAMC,aAAaL,kBAAmB;QAC5DM,UAAUE,IAAI,CACZ,GAAGH,YAAY,qJAAqJ,EAAEV,eAAe,+BAA+B,EAAEC,gBAAgB,QAAQ,EAAEC,gBAAgB,GAAG,CAAC;QAEtQ;IACF;IAEA,MAAML,YAAYY,MAAMC,aAAaH;AACvC;AAEA,eAAe,eAAeO,UAC5BL,IAAU;IAEV,MAAME,YAAsB,EAAE;IAE9B,KAAK,MAAMI,WAAWrB,YAAYe,MAAMO,MAAM,GAAI;QAChD,MAAMC,aAAa,AACjB,CAAA,AAACF,QAAQG,QAAQ,EAA2CD,cAC5D,EAAE,AAAD,EACDE,MAAM,CACN,CAACC,YAAcA,UAAUC,SAAS,KAAKzB,+BAA+B0B,EAAE;QAG1E,KAAK,MAAMF,aAAaH,WAAY;YAClC,IAAI,CAACG,UAAUG,IAAI,EAAE;YACrB,MAAMf,eACJC,MACAd,kBAAkBoB,QAAQS,IAAI,EAAEJ,UAAUG,IAAI,GAC9CZ;QAEJ;IACF;IAEA,MAAMZ,qBAAqBU;IAE3B,OAAO;QAAEE;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { SMITHY_PROJECT_GENERATOR_INFO } from '../../../smithy/project/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/** The traits the connection generator vends, each named after its OpenAPI key. */\nconst TRAITS = ['query', 'mutation', 'cursor'] as const;\n\n/**\n * Matches a bare `@specificationExtension` applied to the named structure, with\n * the `@trait` and `@specificationExtension` traits adjacent to the `structure`\n * they annotate. A declaration that already carries an argument does not match.\n */\nconst bareDeclaration = (trait: string) =>\n new RegExp(\n `(@trait\\\\s*\\\\n\\\\s*@specificationExtension)(\\\\s*\\\\n\\\\s*structure\\\\s+${trait}\\\\s*\\\\{)`,\n );\n\n/**\n * Give each trait in a Smithy model's `extensions.smithy` an explicit\n * `@specificationExtension(as: \"...\")` alias.\n *\n * Without the alias Smithy derives the OpenAPI key from the trait's shape id and\n * emits a namespace-prefixed key (`x-<namespace>-query`), which the client code\n * generator does not read — so the `@query`, `@mutation` and `@cursor` traits\n * have no effect on the generated client. The alias pins each key to the\n * unprefixed name the generator recognises.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Smithy IDL is not a language GritQL parses, so each edit is anchored to the\n * exact `@trait` + `@specificationExtension` + `structure <name>` triple the\n * generator vends.\n * - A declaration that already carries an `as:` argument, or that has diverged\n * from the vended shape, is left alone and reported via `nextSteps`.\n * - Idempotent: an aliased declaration no longer matches the bare pattern.\n */\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [, project] of getProjects(tree)) {\n if (\n ((project.metadata as any) ?? {}).generator !==\n SMITHY_PROJECT_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n const extensionsPath = joinPathFragments(\n project.sourceRoot ?? joinPathFragments(project.root, 'src'),\n 'extensions.smithy',\n );\n if (!tree.exists(extensionsPath)) {\n continue;\n }\n\n const before = tree.read(extensionsPath, 'utf-8') ?? '';\n let after = before;\n const skipped: string[] = [];\n\n for (const trait of TRAITS) {\n if (after.includes(`@specificationExtension(as: \"x-${trait}\")`)) {\n // Already aliased.\n continue;\n }\n const bare = bareDeclaration(trait);\n if (!bare.test(after)) {\n skipped.push(trait);\n continue;\n }\n after = after.replace(bare, `$1(as: \"x-${trait}\")$2`);\n }\n\n if (after !== before) {\n tree.write(extensionsPath, after);\n }\n\n if (skipped.length > 0) {\n nextSteps.push(\n `${extensionsPath}: add ${skipped\n .map((trait) => `\\`(as: \"x-${trait}\")\\``)\n .join(\n ', ',\n )} to the \\`@specificationExtension\\` trait on ${skipped.map((trait) => `\\`${trait}\\``).join(', ')}, so Smithy emits the ${skipped.map((trait) => `\\`x-${trait}\\``).join(', ')} OpenAPI ${skipped.length === 1 ? 'key' : 'keys'} the client generator reads.`,\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","SMITHY_PROJECT_GENERATOR_INFO","formatFilesInSubtree","TRAITS","bareDeclaration","trait","RegExp","migration","tree","nextSteps","project","metadata","generator","id","extensionsPath","sourceRoot","root","exists","before","read","after","skipped","includes","bare","test","push","replace","write","length","map","join"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,6BAA6B,QAAQ,uCAAuC;AACrF,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE,iFAAiF,GACjF,MAAMC,SAAS;IAAC;IAAS;IAAY;CAAS;AAE9C;;;;CAIC,GACD,MAAMC,kBAAkB,CAACC,QACvB,IAAIC,OACF,CAAC,mEAAmE,EAAED,MAAM,QAAQ,CAAC;AAGzF;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,eAAe,eAAeE,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,GAAGC,QAAQ,IAAIX,YAAYS,MAAO;QAC3C,IACE,AAAC,CAAA,AAACE,QAAQC,QAAQ,IAAY,CAAC,CAAA,EAAGC,SAAS,KAC3CX,8BAA8BY,EAAE,EAChC;YACA;QACF;QAEA,MAAMC,iBAAiBd,kBACrBU,QAAQK,UAAU,IAAIf,kBAAkBU,QAAQM,IAAI,EAAE,QACtD;QAEF,IAAI,CAACR,KAAKS,MAAM,CAACH,iBAAiB;YAChC;QACF;QAEA,MAAMI,SAASV,KAAKW,IAAI,CAACL,gBAAgB,YAAY;QACrD,IAAIM,QAAQF;QACZ,MAAMG,UAAoB,EAAE;QAE5B,KAAK,MAAMhB,SAASF,OAAQ;YAC1B,IAAIiB,MAAME,QAAQ,CAAC,CAAC,+BAA+B,EAAEjB,MAAM,EAAE,CAAC,GAAG;gBAE/D;YACF;YACA,MAAMkB,OAAOnB,gBAAgBC;YAC7B,IAAI,CAACkB,KAAKC,IAAI,CAACJ,QAAQ;gBACrBC,QAAQI,IAAI,CAACpB;gBACb;YACF;YACAe,QAAQA,MAAMM,OAAO,CAACH,MAAM,CAAC,UAAU,EAAElB,MAAM,IAAI,CAAC;QACtD;QAEA,IAAIe,UAAUF,QAAQ;YACpBV,KAAKmB,KAAK,CAACb,gBAAgBM;QAC7B;QAEA,IAAIC,QAAQO,MAAM,GAAG,GAAG;YACtBnB,UAAUgB,IAAI,CACZ,GAAGX,eAAe,MAAM,EAAEO,QACvBQ,GAAG,CAAC,CAACxB,QAAU,CAAC,UAAU,EAAEA,MAAM,IAAI,CAAC,EACvCyB,IAAI,CACH,MACA,6CAA6C,EAAET,QAAQQ,GAAG,CAAC,CAACxB,QAAU,CAAC,EAAE,EAAEA,MAAM,EAAE,CAAC,EAAEyB,IAAI,CAAC,MAAM,sBAAsB,EAAET,QAAQQ,GAAG,CAAC,CAACxB,QAAU,CAAC,IAAI,EAAEA,MAAM,EAAE,CAAC,EAAEyB,IAAI,CAAC,MAAM,SAAS,EAAET,QAAQO,MAAM,KAAK,IAAI,QAAQ,OAAO,4BAA4B,CAAC;QAEnQ;IACF;IAEA,MAAM1B,qBAAqBM;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { AGENTCORE_GATEWAY_GENERATOR_INFO } from '../../../agentcore-gateway/generator.js';\nimport { AGENTCORE_HARNESS_GENERATOR_INFO } from '../../../agentcore-harness/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addScriptProjectTargets } from '../../../utils/script-project-targets.js';\n\n/**\n * AgentCore Gateway and Harness projects host TypeScript that runs through\n * `tsx` — a Gateway's `local-dev.ts` (which the connection generators edit) and\n * a Harness's `scripts/chat.ts`. Neither project had a `tsconfig.json` or a\n * `build`, `lint`, `format` or `typecheck` target, so that code was invisible to\n * `nx run-many --target build --all` and a type error in it only surfaced at\n * runtime.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n */\n\n/** The generators whose projects gain the gates. */\nconst SCRIPT_PROJECT_GENERATORS = [\n AGENTCORE_GATEWAY_GENERATOR_INFO.id,\n AGENTCORE_HARNESS_GENERATOR_INFO.id,\n];\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [, project] of getProjects(tree)) {\n const generator = (project.metadata as { generator?: string } | undefined)\n ?.generator;\n if (!generator || !SCRIPT_PROJECT_GENERATORS.includes(generator)) {\n continue;\n }\n // Already migrated (or the user added their own gates).\n if (project.targets?.typecheck) {\n continue;\n }\n // A project that has been reworked into a compiled `ts#project` owns its own\n // tsconfig graph, so leave it alone rather than layering a `noEmit` config on\n // top of one that emits.\n if (tree.exists(joinPathFragments(project.root, 'tsconfig.lib.json'))) {\n nextSteps.push(\n `Project '${project.name}' has a tsconfig.lib.json, so its quality gates were left as they are. Confirm its build covers the TypeScript at ${project.root}.`,\n );\n continue;\n }\n\n addScriptProjectTargets(tree, { project });\n updateProjectConfiguration(tree, project.name, project);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["getProjects","joinPathFragments","updateProjectConfiguration","AGENTCORE_GATEWAY_GENERATOR_INFO","AGENTCORE_HARNESS_GENERATOR_INFO","formatFilesInSubtree","addScriptProjectTargets","SCRIPT_PROJECT_GENERATORS","id","migration","tree","nextSteps","project","generator","metadata","includes","targets","typecheck","exists","root","push","name"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,EAGjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,uBAAuB,QAAQ,2CAA2C;AAEnF;;;;;;;;;;;CAWC,GAED,kDAAkD,GAClD,MAAMC,4BAA4B;IAChCJ,iCAAiCK,EAAE;IACnCJ,iCAAiCI,EAAE;CACpC;AAED,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,GAAGC,QAAQ,IAAIZ,YAAYU,MAAO;QAC3C,MAAMG,YAAaD,QAAQE,QAAQ,EAC/BD;QACJ,IAAI,CAACA,aAAa,CAACN,0BAA0BQ,QAAQ,CAACF,YAAY;YAChE;QACF;QACA,wDAAwD;QACxD,IAAID,QAAQI,OAAO,EAAEC,WAAW;YAC9B;QACF;QACA,6EAA6E;QAC7E,8EAA8E;QAC9E,yBAAyB;QACzB,IAAIP,KAAKQ,MAAM,CAACjB,kBAAkBW,QAAQO,IAAI,EAAE,uBAAuB;YACrER,UAAUS,IAAI,CACZ,CAAC,SAAS,EAAER,QAAQS,IAAI,CAAC,kHAAkH,EAAET,QAAQO,IAAI,CAAC,CAAC,CAAC;YAE9J;QACF;QAEAb,wBAAwBI,MAAM;YAAEE;QAAQ;QACxCV,2BAA2BQ,MAAME,QAAQS,IAAI,EAAET;IACjD;IAEA,MAAMP,qBAAqBK;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -253,7 +253,7 @@ export default {
|
|
|
253
253
|
|
|
254
254
|
exports[`preset generator > should run successfully > biome.json 1`] = `
|
|
255
255
|
"{
|
|
256
|
-
"$schema": "https://biomejs.dev/schemas/2.5.
|
|
256
|
+
"$schema": "https://biomejs.dev/schemas/2.5.12/schema.json",
|
|
257
257
|
"root": true,
|
|
258
258
|
"formatter": {
|
|
259
259
|
"enabled": true,
|
|
@@ -422,7 +422,7 @@ catalog:
|
|
|
422
422
|
'@nx/js': 23.2.0
|
|
423
423
|
'@nx/workspace': 23.2.0
|
|
424
424
|
typescript: ~6.0.3
|
|
425
|
-
'@biomejs/biome': 2.5.
|
|
425
|
+
'@biomejs/biome': 2.5.12
|
|
426
426
|
'@aws/nx-plugin': ^0.0.0
|
|
427
427
|
'@aws/nx-plugin-mcp': ^0.0.0
|
|
428
428
|
"
|
|
@@ -766,11 +766,11 @@ dependencies = [
|
|
|
766
766
|
"aws-lambda-powertools==3.34.0",
|
|
767
767
|
"aws-opentelemetry-distro==0.19.0",
|
|
768
768
|
"bedrock-agentcore==1.22.0",
|
|
769
|
-
"boto3==1.43.
|
|
769
|
+
"boto3==1.43.89",
|
|
770
770
|
"fastapi==0.141.1",
|
|
771
771
|
"mcp==1.28.1",
|
|
772
772
|
"strands-agents==1.54.0",
|
|
773
|
-
"strands-agents-tools==0.8.
|
|
773
|
+
"strands-agents-tools==0.8.8",
|
|
774
774
|
"uvicorn==0.52.4"
|
|
775
775
|
]
|
|
776
776
|
|