@aws/nx-plugin 1.0.0-rc.96 → 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 +124 -84
- package/package.json +3 -3
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/agentcore-gateway/generator.js +6 -0
- package/src/agentcore-gateway/generator.js.map +1 -1
- package/src/agentcore-gateway/react-connection/__snapshots__/generator.spec.ts.snap +4 -1
- package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +68 -4
- package/src/agentcore-harness/generator.js +6 -0
- package/src/agentcore-harness/generator.js.map +1 -1
- package/src/connection/gateway-runtime-config.js +1 -1
- package/src/connection/gateway-runtime-config.js.map +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +10 -10
- package/src/infra/app/generator.js +39 -9
- package/src/infra/app/generator.js.map +1 -1
- package/src/init/generator.d.ts +1 -1
- package/src/init/generator.js +8 -6
- package/src/init/generator.js.map +1 -1
- package/src/init/schema.d.js.map +1 -1
- package/src/init/schema.d.ts +1 -0
- package/src/init/schema.json +5 -0
- 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/mcp-server/server.js +2 -0
- package/src/mcp-server/server.js.map +1 -1
- package/src/mcp-server/tools/best-practices.d.ts +28 -0
- package/src/mcp-server/tools/best-practices.js +43 -0
- package/src/mcp-server/tools/best-practices.js.map +1 -0
- package/src/mcp-server/tools/general-guidance.d.ts +1 -1
- package/src/mcp-server/tools/general-guidance.js +13 -4
- package/src/mcp-server/tools/general-guidance.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/metadata.json +3 -0
- package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.js +26 -28
- 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.d.ts +6 -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.d.ts +6 -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/__snapshots__/migration.spec.ts.snap +84 -0
- package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.js +94 -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/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.js +58 -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/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.js +84 -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/metadata.json +3 -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 +58 -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/__snapshots__/migration.spec.ts.snap +25 -0
- package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.d.ts +28 -0
- package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.js +75 -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/metadata.json +3 -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 +53 -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/preset/generator.js +4 -25
- package/src/preset/generator.js.map +1 -1
- 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/__snapshots__/generator.spec.ts.snap +4 -1
- package/src/py/agent/react-connection/generator.d.ts +1 -7
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +10 -12
- package/src/py/dynamodb/generator.js +34 -7
- package/src/py/dynamodb/generator.js.map +1 -1
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +4 -3
- package/src/py/lambda-function/files/handler/__lambdaFunctionSnakeCase__.py.template +2 -1
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
- package/src/py/project/schema.json +3 -1
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +31 -15
- package/src/py/rdb/files/Dockerfile.create-db-user.template +7 -3
- package/src/py/rdb/files/Dockerfile.migration.template +7 -3
- package/src/py/rdb/generator.js +29 -28
- package/src/py/rdb/generator.js.map +1 -1
- package/src/smithy/project/__snapshots__/generator.spec.ts.snap +5 -5
- package/src/smithy/react-connection/files/model/extensions.smithy.template +3 -3
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
- package/src/smithy/ts/api/generator.js +7 -2
- package/src/smithy/ts/api/generator.js.map +1 -1
- package/src/terraform/project/generator.js +34 -10
- package/src/terraform/project/generator.js.map +1 -1
- 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/trpc/backend/generator.js +7 -1
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/react/generator.js +6 -0
- package/src/trpc/react/generator.js.map +1 -1
- 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/generator.js +3 -3
- package/src/ts/agent/generator.js.map +1 -1
- 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 -4
- package/src/ts/dynamodb/generator.js +30 -6
- package/src/ts/dynamodb/generator.js.map +1 -1
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/lib/biome.d.ts +15 -1
- package/src/ts/lib/biome.js +79 -63
- package/src/ts/lib/biome.js.map +1 -1
- package/src/ts/lib/generator.js +11 -7
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/ts-project-utils.d.ts +14 -0
- package/src/ts/lib/ts-project-utils.js +24 -0
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- 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/mcp-server/generator.js +3 -3
- package/src/ts/mcp-server/generator.js.map +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 +13 -8
- package/src/ts/rdb/files/Dockerfile.template +5 -0
- package/src/ts/rdb/generator.d.ts +8 -0
- package/src/ts/rdb/generator.js +28 -24
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +39 -0
- package/src/ts/rdb/trpc-connection/generator.js +13 -0
- package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
- package/src/ts/react-website/agui/files/common/src/components/__agentNameKebabCase__-chat.tsx.template +9 -0
- package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +4 -1
- package/src/ts/react-website/agui/generator.d.ts +1 -5
- package/src/ts/react-website/agui/generator.js +6 -2
- package/src/ts/react-website/agui/generator.js.map +1 -1
- 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/app/generator.js +3 -8
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
- package/src/utils/agent-connection/agent-connection.d.ts +2 -1
- package/src/utils/agent-connection/agent-connection.js +6 -1
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +11 -7
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +14 -6
- package/src/utils/agent-core-packaging.js +5 -5
- package/src/utils/agent-core-packaging.js.map +1 -1
- package/src/utils/api-constructs/api-constructs.d.ts +5 -0
- package/src/utils/api-constructs/api-constructs.js +8 -0
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +4 -2
- package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +4 -2
- package/src/utils/ast.d.ts +10 -0
- package/src/utils/ast.js +87 -15
- 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/docker.d.ts +11 -0
- package/src/utils/docker.js +16 -3
- package/src/utils/docker.js.map +1 -1
- package/src/utils/dynamodb-config.d.ts +48 -0
- package/src/utils/dynamodb-config.js +44 -0
- package/src/utils/dynamodb-config.js.map +1 -0
- package/src/utils/dynamodb-constructs/files/cdk/app/dynamodb/__nameKebabCase__.ts.template +8 -4
- 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/git-secrets.d.ts +28 -0
- package/src/utils/git-secrets.js +66 -0
- package/src/utils/git-secrets.js.map +1 -0
- package/src/utils/init.js +7 -6
- package/src/utils/init.js.map +1 -1
- package/src/utils/local-project-dependency.d.ts +28 -0
- package/src/utils/local-project-dependency.js +40 -0
- package/src/utils/local-project-dependency.js.map +1 -0
- package/src/utils/nx.d.ts +14 -0
- package/src/utils/nx.js +30 -0
- package/src/utils/nx.js.map +1 -1
- package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +11 -6
- package/src/utils/script-project-targets.d.ts +26 -0
- package/src/utils/script-project-targets.js +75 -0
- package/src/utils/script-project-targets.js.map +1 -0
- 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 -50
- package/src/utils/versions.js +55 -49
- package/src/utils/versions.js.map +1 -1
- package/src/utils/website-constructs/files/cdk/app/static-websites/__websiteNameKebabCase__.ts.template +8 -4
- 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/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/ignore-package-manager-temp-files/migration.js.map +0 -1
- package/src/migrations/latest/infra-deploy-express-mode/metadata.json +0 -3
- 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/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/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/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/vitest-coverage-output-dir/migration.js.map +0 -1
- package/src/py/dynamodb/files/__name__/__init__.py.template +0 -6
- package/src/py/dynamodb/files/__name__/entities/__init__.py.template +0 -4
- package/src/py/dynamodb/files/config.json.template +0 -24
- package/src/ts/dynamodb/files/config.json.template +0 -24
- package/src/ts/dynamodb/files/src/entities/index.ts.template +0 -1
- package/src/ts/dynamodb/files/src/index.ts.template +0 -2
- /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/declare-cacheable-target-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/dev-target-depends-on-pull-image → 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/docker-target-cache-soundness → 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/infra-deploy-express-mode → 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/open-api-codegen-executor → 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/python-test-input-scoping → 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/react-website-unique-dev-ports → 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/rolldown-config-bundle-transient → 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/shadcn-package-imports-exports → 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/shx-fs-commands → 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/terraform-fmt-check → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.d.ts +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/terraform-provider-plugin-cache → 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/vitest-coverage-output-dir → 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/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/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.js +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { getProjects, updateProjectConfiguration } from "@nx/devkit";
|
|
5
|
+
import { INFRA_APP_GENERATOR_INFO } from "../../../infra/app/generator.js";
|
|
6
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
7
|
+
/**
|
|
8
|
+
* Widen the stage pattern of the sandbox targets of ts#infra projects from
|
|
9
|
+
* `<stage>/*` to `<stage>/**`.
|
|
10
|
+
*
|
|
11
|
+
* A single `*` matches the stage's own stacks but nothing below them, so it
|
|
12
|
+
* misses stacks a construct creates inside a stack - such as the `us-east-1`
|
|
13
|
+
* WebACL stack a website creates for its CloudFront distribution.
|
|
14
|
+
* `cdk destroy` only deletes the stacks its pattern selects, so
|
|
15
|
+
* `destroy-sandbox` left that stack, and the WebACL it bills for, deployed.
|
|
16
|
+
*/ const SANDBOX_TARGETS = [
|
|
17
|
+
'deploy-sandbox',
|
|
18
|
+
'destroy-sandbox'
|
|
19
|
+
];
|
|
20
|
+
/** A quoted or bare stage pattern ending in a single `*`, ie `"my-sandbox/*"`. */ const SINGLE_STAR_PATTERN = /^("?)\S+\/\*\1$/;
|
|
21
|
+
const widen = (token)=>token.replace(/\/\*("?)$/, '/**$1');
|
|
22
|
+
/**
|
|
23
|
+
* Whether the command is one of the deploy/destroy commands this generator
|
|
24
|
+
* vends - either a direct `cdk deploy`/`cdk destroy`, or the stage-config
|
|
25
|
+
* script that wraps it. Anything else has been hand-written and is reported
|
|
26
|
+
* rather than rewritten.
|
|
27
|
+
*/ const isGeneratedCommand = (command)=>/(^|\s)cdk\s+(deploy|destroy)(\s|$)/.test(command) || command.includes('infra-deploy.ts') || command.includes('infra-destroy.ts');
|
|
28
|
+
export default async function migration(tree) {
|
|
29
|
+
const nextSteps = [];
|
|
30
|
+
let migrated = false;
|
|
31
|
+
for (const [name, project] of getProjects(tree)){
|
|
32
|
+
if (project.metadata?.generator !== INFRA_APP_GENERATOR_INFO.id) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
let projectChanged = false;
|
|
36
|
+
for (const targetName of SANDBOX_TARGETS){
|
|
37
|
+
const target = project.targets?.[targetName];
|
|
38
|
+
const command = target?.options?.command;
|
|
39
|
+
if (!target || typeof command !== 'string') {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const args = command.split(/\s+/);
|
|
43
|
+
// Nothing to widen: already `/**`, or the pattern has been removed. Keeps
|
|
44
|
+
// re-runs - and a project generated after this change - a no-op.
|
|
45
|
+
if (!args.some((arg)=>SINGLE_STAR_PATTERN.test(arg))) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!isGeneratedCommand(command)) {
|
|
49
|
+
nextSteps.push(`${name}: its ${targetName} target has been customised, so it was left as it is. Widen its stage pattern from "<stage>/*" to "<stage>/**" so it also matches stacks nested below the stage's stacks, such as a website's WebACL stack.`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
target.options.command = args.map((arg)=>SINGLE_STAR_PATTERN.test(arg) ? widen(arg) : arg).join(' ');
|
|
53
|
+
projectChanged = true;
|
|
54
|
+
}
|
|
55
|
+
if (projectChanged) {
|
|
56
|
+
updateProjectConfiguration(tree, name, project);
|
|
57
|
+
migrated = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (migrated) {
|
|
61
|
+
await formatFilesInSubtree(tree);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
nextSteps
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/sandbox-pattern-nested-stacks/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type MigrationReturnObject,\n type TargetConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { INFRA_APP_GENERATOR_INFO } from '../../../infra/app/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\n\n/**\n * Widen the stage pattern of the sandbox targets of ts#infra projects from\n * `<stage>/*` to `<stage>/**`.\n *\n * A single `*` matches the stage's own stacks but nothing below them, so it\n * misses stacks a construct creates inside a stack - such as the `us-east-1`\n * WebACL stack a website creates for its CloudFront distribution.\n * `cdk destroy` only deletes the stacks its pattern selects, so\n * `destroy-sandbox` left that stack, and the WebACL it bills for, deployed.\n */\n\nconst SANDBOX_TARGETS = ['deploy-sandbox', 'destroy-sandbox'];\n\n/** A quoted or bare stage pattern ending in a single `*`, ie `\"my-sandbox/*\"`. */\nconst SINGLE_STAR_PATTERN = /^(\"?)\\S+\\/\\*\\1$/;\n\nconst widen = (token: string): string => token.replace(/\\/\\*(\"?)$/, '/**$1');\n\n/**\n * Whether the command is one of the deploy/destroy commands this generator\n * vends - either a direct `cdk deploy`/`cdk destroy`, or the stage-config\n * script that wraps it. Anything else has been hand-written and is reported\n * rather than rewritten.\n */\nconst isGeneratedCommand = (command: string): boolean =>\n /(^|\\s)cdk\\s+(deploy|destroy)(\\s|$)/.test(command) ||\n command.includes('infra-deploy.ts') ||\n command.includes('infra-destroy.ts');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n let migrated = false;\n\n for (const [name, project] of getProjects(tree)) {\n if (\n (project.metadata as { generator?: string } | undefined)?.generator !==\n INFRA_APP_GENERATOR_INFO.id\n ) {\n continue;\n }\n\n let projectChanged = false;\n\n for (const targetName of SANDBOX_TARGETS) {\n const target: TargetConfiguration | undefined =\n project.targets?.[targetName];\n const command = target?.options?.command;\n if (!target || typeof command !== 'string') {\n continue;\n }\n\n const args = command.split(/\\s+/);\n // Nothing to widen: already `/**`, or the pattern has been removed. Keeps\n // re-runs - and a project generated after this change - a no-op.\n if (!args.some((arg) => SINGLE_STAR_PATTERN.test(arg))) {\n continue;\n }\n\n if (!isGeneratedCommand(command)) {\n nextSteps.push(\n `${name}: its ${targetName} target has been customised, so it was left as it is. Widen its stage pattern from \"<stage>/*\" to \"<stage>/**\" so it also matches stacks nested below the stage's stacks, such as a website's WebACL stack.`,\n );\n continue;\n }\n\n target.options.command = args\n .map((arg) => (SINGLE_STAR_PATTERN.test(arg) ? widen(arg) : arg))\n .join(' ');\n projectChanged = true;\n }\n\n if (projectChanged) {\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","INFRA_APP_GENERATOR_INFO","formatFilesInSubtree","SANDBOX_TARGETS","SINGLE_STAR_PATTERN","widen","token","replace","isGeneratedCommand","command","test","includes","migration","tree","nextSteps","migrated","name","project","metadata","generator","id","projectChanged","targetName","target","targets","options","args","split","some","arg","push","map","join"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,wBAAwB,QAAQ,kCAAkC;AAC3E,SAASC,oBAAoB,QAAQ,2BAA2B;AAEhE;;;;;;;;;CASC,GAED,MAAMC,kBAAkB;IAAC;IAAkB;CAAkB;AAE7D,gFAAgF,GAChF,MAAMC,sBAAsB;AAE5B,MAAMC,QAAQ,CAACC,QAA0BA,MAAMC,OAAO,CAAC,aAAa;AAEpE;;;;;CAKC,GACD,MAAMC,qBAAqB,CAACC,UAC1B,qCAAqCC,IAAI,CAACD,YAC1CA,QAAQE,QAAQ,CAAC,sBACjBF,QAAQE,QAAQ,CAAC;AAEnB,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAIlB,YAAYc,MAAO;QAC/C,IACE,AAACI,QAAQC,QAAQ,EAAyCC,cAC1DlB,yBAAyBmB,EAAE,EAC3B;YACA;QACF;QAEA,IAAIC,iBAAiB;QAErB,KAAK,MAAMC,cAAcnB,gBAAiB;YACxC,MAAMoB,SACJN,QAAQO,OAAO,EAAE,CAACF,WAAW;YAC/B,MAAMb,UAAUc,QAAQE,SAAShB;YACjC,IAAI,CAACc,UAAU,OAAOd,YAAY,UAAU;gBAC1C;YACF;YAEA,MAAMiB,OAAOjB,QAAQkB,KAAK,CAAC;YAC3B,0EAA0E;YAC1E,iEAAiE;YACjE,IAAI,CAACD,KAAKE,IAAI,CAAC,CAACC,MAAQzB,oBAAoBM,IAAI,CAACmB,OAAO;gBACtD;YACF;YAEA,IAAI,CAACrB,mBAAmBC,UAAU;gBAChCK,UAAUgB,IAAI,CACZ,GAAGd,KAAK,MAAM,EAAEM,WAAW,2MAA2M,CAAC;gBAEzO;YACF;YAEAC,OAAOE,OAAO,CAAChB,OAAO,GAAGiB,KACtBK,GAAG,CAAC,CAACF,MAASzB,oBAAoBM,IAAI,CAACmB,OAAOxB,MAAMwB,OAAOA,KAC3DG,IAAI,CAAC;YACRX,iBAAiB;QACnB;QAEA,IAAIA,gBAAgB;YAClBrB,2BAA2Ba,MAAMG,MAAMC;YACvCF,WAAW;QACb;IACF;IAEA,IAAIA,UAAU;QACZ,MAAMb,qBAAqBW;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { joinPathFragments, readJson } from "@nx/devkit";
|
|
5
|
+
import { applyGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
6
|
+
import { addDependenciesToPackageJson, removeDependenciesFromPackageJson } from "../../../utils/dependencies.js";
|
|
7
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
8
|
+
import { PACKAGES_DIR, SHARED_SHADCN_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
9
|
+
import { TS_VERSIONS } from "../../../utils/versions.js";
|
|
10
|
+
/**
|
|
11
|
+
* Move the shared shadcn package onto the `cn` package.
|
|
12
|
+
*
|
|
13
|
+
* The shadcn registry now serves components importing `cn` from the `cn`
|
|
14
|
+
* package and declares it as a registry dependency, so a component added by
|
|
15
|
+
* `shadcn add` no longer resolves the package's own `#lib/utils` helper. This
|
|
16
|
+
* carries an existing workspace onto that shape: the components import `cn`,
|
|
17
|
+
* `src/lib/utils.ts` becomes the single-line re-export shadcn's own install
|
|
18
|
+
* guide prescribes, which keeps every consumer importing `cn` through
|
|
19
|
+
* `<scope>common-shadcn/lib/utils` working, and clsx / tailwind-merge are
|
|
20
|
+
* dropped now that nothing imports them.
|
|
21
|
+
*
|
|
22
|
+
* How to write a migration:
|
|
23
|
+
* - https://nx.dev/docs/kb/migration-generators
|
|
24
|
+
* - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject
|
|
25
|
+
*
|
|
26
|
+
* Guardrails:
|
|
27
|
+
* - Only touches a `packages/common/shadcn` this plugin's generators produced,
|
|
28
|
+
* guarded by `components.json`'s aliases still matching the generated shape.
|
|
29
|
+
* - An import is only rewritten when `cn` is its sole binding, so a file also
|
|
30
|
+
* pulling a user's own helper out of `#lib/utils` keeps resolving through the
|
|
31
|
+
* re-export.
|
|
32
|
+
* - `src/lib/utils.ts` is only rewritten while it still holds the generated
|
|
33
|
+
* `twMerge(clsx(...))` helper; a customised one is reported instead.
|
|
34
|
+
* - clsx / tailwind-merge are only dropped once nothing under `src` imports
|
|
35
|
+
* them.
|
|
36
|
+
* - Idempotent: every write is guarded by the old shape still being present.
|
|
37
|
+
*/ const libraryRoot = joinPathFragments(PACKAGES_DIR, SHARED_SHADCN_DIR);
|
|
38
|
+
const componentsJsonPath = joinPathFragments(libraryRoot, 'components.json');
|
|
39
|
+
const packageJsonPath = joinPathFragments(libraryRoot, 'package.json');
|
|
40
|
+
const srcRoot = joinPathFragments(libraryRoot, 'src');
|
|
41
|
+
const utilsPath = joinPathFragments(srcRoot, 'lib', 'utils.ts');
|
|
42
|
+
/** The aliases today's generators write, which this migration leaves in place. */ const generatedAliases = {
|
|
43
|
+
components: '#components',
|
|
44
|
+
utils: '#lib/utils',
|
|
45
|
+
hooks: '#hooks',
|
|
46
|
+
lib: '#lib',
|
|
47
|
+
ui: '#components/ui'
|
|
48
|
+
};
|
|
49
|
+
const CN_IMPORT_REWRITE = `\`import { cn } from '#lib/utils'\` => \`import { cn } from 'cn'\``;
|
|
50
|
+
/** The generated helper, whichever way the user's formatter has laid it out. */ const GENERATED_CN_HELPER = `\`twMerge(clsx($_))\``;
|
|
51
|
+
const importsPackage = (name)=>`\`import $_ from '${name}'\``;
|
|
52
|
+
const REEXPORT_UTILS = `export { cn } from 'cn';\n`;
|
|
53
|
+
const DROPPED_PACKAGES = [
|
|
54
|
+
'clsx',
|
|
55
|
+
'tailwind-merge'
|
|
56
|
+
];
|
|
57
|
+
/** Every `.ts`/`.tsx` file in the package's source tree. */ const sourceFiles = (tree, dir)=>{
|
|
58
|
+
if (!tree.exists(dir)) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
return tree.children(dir).flatMap((entry)=>{
|
|
62
|
+
const path = joinPathFragments(dir, entry);
|
|
63
|
+
if (!tree.isFile(path)) {
|
|
64
|
+
return sourceFiles(tree, path);
|
|
65
|
+
}
|
|
66
|
+
return path.endsWith('.ts') || path.endsWith('.tsx') ? [
|
|
67
|
+
path
|
|
68
|
+
] : [];
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
export default async function migration(tree) {
|
|
72
|
+
const nextSteps = [];
|
|
73
|
+
if (!tree.exists(componentsJsonPath) || !tree.exists(packageJsonPath)) {
|
|
74
|
+
return {
|
|
75
|
+
nextSteps
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const aliases = readJson(tree, componentsJsonPath).aliases ?? {};
|
|
79
|
+
if (Object.entries(generatedAliases).some(([k, v])=>aliases[k] !== v)) {
|
|
80
|
+
return {
|
|
81
|
+
nextSteps
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const files = sourceFiles(tree, srcRoot);
|
|
85
|
+
for (const file of files){
|
|
86
|
+
await applyGritQL(tree, file, CN_IMPORT_REWRITE);
|
|
87
|
+
}
|
|
88
|
+
if (tree.exists(utilsPath)) {
|
|
89
|
+
if (await matchGritQL(tree, utilsPath, GENERATED_CN_HELPER)) {
|
|
90
|
+
tree.write(utilsPath, REEXPORT_UTILS);
|
|
91
|
+
} else if (tree.read(utilsPath, 'utf-8') !== REEXPORT_UTILS) {
|
|
92
|
+
nextSteps.push(`${utilsPath}: no longer holds the generated cn helper - left untouched. Re-export cn from the 'cn' package by hand so consumers importing it from here keep working.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
addDependenciesToPackageJson(tree, {
|
|
96
|
+
cn: TS_VERSIONS.cn
|
|
97
|
+
}, {}, packageJsonPath);
|
|
98
|
+
const stillImported = new Set();
|
|
99
|
+
for (const file of sourceFiles(tree, srcRoot)){
|
|
100
|
+
for (const name of DROPPED_PACKAGES){
|
|
101
|
+
if (await matchGritQL(tree, file, importsPackage(name))) {
|
|
102
|
+
stillImported.add(name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const dropped = DROPPED_PACKAGES.filter((name)=>!stillImported.has(name));
|
|
107
|
+
removeDependenciesFromPackageJson(tree, dropped, dropped, packageJsonPath);
|
|
108
|
+
await formatFilesInSubtree(tree);
|
|
109
|
+
return {
|
|
110
|
+
nextSteps
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/shadcn-cn-package/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n readJson,\n type Tree,\n} from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport {\n addDependenciesToPackageJson,\n removeDependenciesFromPackageJson,\n} from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_SHADCN_DIR,\n} from '../../../utils/shared-constructs-constants.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * Move the shared shadcn package onto the `cn` package.\n *\n * The shadcn registry now serves components importing `cn` from the `cn`\n * package and declares it as a registry dependency, so a component added by\n * `shadcn add` no longer resolves the package's own `#lib/utils` helper. This\n * carries an existing workspace onto that shape: the components import `cn`,\n * `src/lib/utils.ts` becomes the single-line re-export shadcn's own install\n * guide prescribes, which keeps every consumer importing `cn` through\n * `<scope>common-shadcn/lib/utils` working, and clsx / tailwind-merge are\n * dropped now that nothing imports them.\n *\n * How to write a migration:\n * - https://nx.dev/docs/kb/migration-generators\n * - What `nextSteps` means: https://nx.dev/docs/reference/devkit/MigrationReturnObject\n *\n * Guardrails:\n * - Only touches a `packages/common/shadcn` this plugin's generators produced,\n * guarded by `components.json`'s aliases still matching the generated shape.\n * - An import is only rewritten when `cn` is its sole binding, so a file also\n * pulling a user's own helper out of `#lib/utils` keeps resolving through the\n * re-export.\n * - `src/lib/utils.ts` is only rewritten while it still holds the generated\n * `twMerge(clsx(...))` helper; a customised one is reported instead.\n * - clsx / tailwind-merge are only dropped once nothing under `src` imports\n * them.\n * - Idempotent: every write is guarded by the old shape still being present.\n */\n\nconst libraryRoot = joinPathFragments(PACKAGES_DIR, SHARED_SHADCN_DIR);\nconst componentsJsonPath = joinPathFragments(libraryRoot, 'components.json');\nconst packageJsonPath = joinPathFragments(libraryRoot, 'package.json');\nconst srcRoot = joinPathFragments(libraryRoot, 'src');\nconst utilsPath = joinPathFragments(srcRoot, 'lib', 'utils.ts');\n\n/** The aliases today's generators write, which this migration leaves in place. */\nconst generatedAliases: Record<string, string> = {\n components: '#components',\n utils: '#lib/utils',\n hooks: '#hooks',\n lib: '#lib',\n ui: '#components/ui',\n};\n\nconst CN_IMPORT_REWRITE = `\\`import { cn } from '#lib/utils'\\` => \\`import { cn } from 'cn'\\``;\n\n/** The generated helper, whichever way the user's formatter has laid it out. */\nconst GENERATED_CN_HELPER = `\\`twMerge(clsx($_))\\``;\n\nconst importsPackage = (name: string): string => `\\`import $_ from '${name}'\\``;\n\nconst REEXPORT_UTILS = `export { cn } from 'cn';\\n`;\n\nconst DROPPED_PACKAGES = ['clsx', 'tailwind-merge'] as const;\n\n/** Every `.ts`/`.tsx` file in the package's source tree. */\nconst sourceFiles = (tree: Tree, dir: string): string[] => {\n if (!tree.exists(dir)) {\n return [];\n }\n return tree.children(dir).flatMap((entry) => {\n const path = joinPathFragments(dir, entry);\n if (!tree.isFile(path)) {\n return sourceFiles(tree, path);\n }\n return path.endsWith('.ts') || path.endsWith('.tsx') ? [path] : [];\n });\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(componentsJsonPath) || !tree.exists(packageJsonPath)) {\n return { nextSteps };\n }\n\n const aliases =\n readJson<{ aliases?: Record<string, string> }>(tree, componentsJsonPath)\n .aliases ?? {};\n if (Object.entries(generatedAliases).some(([k, v]) => aliases[k] !== v)) {\n return { nextSteps };\n }\n\n const files = sourceFiles(tree, srcRoot);\n\n for (const file of files) {\n await applyGritQL(tree, file, CN_IMPORT_REWRITE);\n }\n\n if (tree.exists(utilsPath)) {\n if (await matchGritQL(tree, utilsPath, GENERATED_CN_HELPER)) {\n tree.write(utilsPath, REEXPORT_UTILS);\n } else if (tree.read(utilsPath, 'utf-8') !== REEXPORT_UTILS) {\n nextSteps.push(\n `${utilsPath}: no longer holds the generated cn helper - left untouched. Re-export cn from the 'cn' package by hand so consumers importing it from here keep working.`,\n );\n }\n }\n\n addDependenciesToPackageJson(\n tree,\n { cn: TS_VERSIONS.cn },\n {},\n packageJsonPath,\n );\n\n const stillImported = new Set<string>();\n for (const file of sourceFiles(tree, srcRoot)) {\n for (const name of DROPPED_PACKAGES) {\n if (await matchGritQL(tree, file, importsPackage(name))) {\n stillImported.add(name);\n }\n }\n }\n\n const dropped = DROPPED_PACKAGES.filter((name) => !stillImported.has(name));\n removeDependenciesFromPackageJson(tree, dropped, dropped, packageJsonPath);\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","readJson","applyGritQL","matchGritQL","addDependenciesToPackageJson","removeDependenciesFromPackageJson","formatFilesInSubtree","PACKAGES_DIR","SHARED_SHADCN_DIR","TS_VERSIONS","libraryRoot","componentsJsonPath","packageJsonPath","srcRoot","utilsPath","generatedAliases","components","utils","hooks","lib","ui","CN_IMPORT_REWRITE","GENERATED_CN_HELPER","importsPackage","name","REEXPORT_UTILS","DROPPED_PACKAGES","sourceFiles","tree","dir","exists","children","flatMap","entry","path","isFile","endsWith","migration","nextSteps","aliases","Object","entries","some","k","v","files","file","write","read","push","cn","stillImported","Set","add","dropped","filter","has"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0001-dev-target-depends-on-pull-image/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 { TS_DYNAMODB_GENERATOR_INFO } from '../../../ts/dynamodb/generator.js';\nimport { TS_RDB_GENERATOR_INFO } from '../../../ts/rdb/generator.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { addDependencyToTargetIfNotPresent } from '../../../utils/nx.js';\n\n/**\n * Make the dev target of ts#dynamodb and ts#rdb projects depend on pull-image\n *\n * Without it, `nx dev` starts the container (and, for DynamoDB, creates the\n * local table) while the image is still being fetched, so a first run on a\n * machine without the image races the pull.\n */\n\nconst GENERATOR_IDS = [TS_DYNAMODB_GENERATOR_INFO.id, TS_RDB_GENERATOR_INFO.id];\n\nconst PULL_IMAGE_TARGET = 'pull-image';\n\nconst startsGeneratedContainer = (project: ProjectConfiguration): boolean => {\n const { command, commands } = project.targets?.dev?.options ?? {};\n return [...(commands ?? []), ...(command ? [command] : [])].some(\n (c: string) => typeof c === 'string' && c.includes('start-container.ts'),\n );\n};\n\nconst divergedNextStep = (projectName: string): string =>\n `${projectName}: its dev target has been customised, so it was left as it is. Add \"${PULL_IMAGE_TARGET}\" to the target's dependsOn so the container image is fetched before the container starts.`;\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 (!GENERATOR_IDS.includes((project.metadata as any)?.generator)) {\n continue;\n }\n\n const dev = project.targets?.dev;\n if (!dev || !project.targets?.[PULL_IMAGE_TARGET]) {\n continue;\n }\n\n // Nx requires an array here. Anything else is hand-written and is reported\n // rather than rewritten, so a malformed value is never spread or clobbered.\n if (dev.dependsOn !== undefined && !Array.isArray(dev.dependsOn)) {\n nextSteps.push(divergedNextStep(name));\n continue;\n }\n\n const alreadyDependsOnPullImage = (dev.dependsOn ?? []).some(\n (dependency) =>\n dependency === PULL_IMAGE_TARGET ||\n (typeof dependency === 'object' &&\n dependency !== null &&\n dependency.target === PULL_IMAGE_TARGET &&\n dependency.projects === undefined),\n );\n if (alreadyDependsOnPullImage) {\n continue;\n }\n\n if (!startsGeneratedContainer(project)) {\n nextSteps.push(divergedNextStep(name));\n continue;\n }\n\n addDependencyToTargetIfNotPresent(project, 'dev', PULL_IMAGE_TARGET);\n updateProjectConfiguration(tree, name, project);\n migrated = true;\n }\n\n if (migrated) {\n await formatFilesInSubtree(tree);\n }\n\n return { nextSteps };\n}\n"],"names":["getProjects","updateProjectConfiguration","TS_DYNAMODB_GENERATOR_INFO","TS_RDB_GENERATOR_INFO","formatFilesInSubtree","addDependencyToTargetIfNotPresent","GENERATOR_IDS","id","PULL_IMAGE_TARGET","startsGeneratedContainer","project","command","commands","targets","dev","options","some","c","includes","divergedNextStep","projectName","migration","tree","nextSteps","migrated","name","metadata","generator","dependsOn","undefined","Array","isArray","push","alreadyDependsOnPullImage","dependency","target","projects"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AACpB,SAASC,0BAA0B,QAAQ,oCAAoC;AAC/E,SAASC,qBAAqB,QAAQ,+BAA+B;AACrE,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,iCAAiC,QAAQ,uBAAuB;AAEzE;;;;;;CAMC,GAED,MAAMC,gBAAgB;IAACJ,2BAA2BK,EAAE;IAAEJ,sBAAsBI,EAAE;CAAC;AAE/E,MAAMC,oBAAoB;AAE1B,MAAMC,2BAA2B,CAACC;IAChC,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGF,QAAQG,OAAO,EAAEC,KAAKC,WAAW,CAAC;IAChE,OAAO;WAAKH,YAAY,EAAE;WAAOD,UAAU;YAACA;SAAQ,GAAG,EAAE;KAAE,CAACK,IAAI,CAC9D,CAACC,IAAc,OAAOA,MAAM,YAAYA,EAAEC,QAAQ,CAAC;AAEvD;AAEA,MAAMC,mBAAmB,CAACC,cACxB,GAAGA,YAAY,oEAAoE,EAAEZ,kBAAkB,0FAA0F,CAAC;AAEpM,eAAe,eAAea,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAC9B,IAAIC,WAAW;IAEf,KAAK,MAAM,CAACC,MAAMf,QAAQ,IAAIV,YAAYsB,MAAO;QAC/C,IAAI,CAAChB,cAAcY,QAAQ,CAAER,QAAQgB,QAAQ,EAAUC,YAAY;YACjE;QACF;QAEA,MAAMb,MAAMJ,QAAQG,OAAO,EAAEC;QAC7B,IAAI,CAACA,OAAO,CAACJ,QAAQG,OAAO,EAAE,CAACL,kBAAkB,EAAE;YACjD;QACF;QAEA,2EAA2E;QAC3E,4EAA4E;QAC5E,IAAIM,IAAIc,SAAS,KAAKC,aAAa,CAACC,MAAMC,OAAO,CAACjB,IAAIc,SAAS,GAAG;YAChEL,UAAUS,IAAI,CAACb,iBAAiBM;YAChC;QACF;QAEA,MAAMQ,4BAA4B,AAACnB,CAAAA,IAAIc,SAAS,IAAI,EAAE,AAAD,EAAGZ,IAAI,CAC1D,CAACkB,aACCA,eAAe1B,qBACd,OAAO0B,eAAe,YACrBA,eAAe,QACfA,WAAWC,MAAM,KAAK3B,qBACtB0B,WAAWE,QAAQ,KAAKP;QAE9B,IAAII,2BAA2B;YAC7B;QACF;QAEA,IAAI,CAACxB,yBAAyBC,UAAU;YACtCa,UAAUS,IAAI,CAACb,iBAAiBM;YAChC;QACF;QAEApB,kCAAkCK,SAAS,OAAOF;QAClDP,2BAA2BqB,MAAMG,MAAMf;QACvCc,WAAW;IACb;IAEA,IAAIA,UAAU;QACZ,MAAMpB,qBAAqBkB;IAC7B;IAEA,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/v1.0.0-rc.90/0002-open-api-codegen-executor/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 type { OpenApiCodegenTarget } from '../../../open-api/codegen/executor-schema';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport { normalizeTargetKeyOrder } from '../../../utils/nx.js';\nimport { OPEN_API_CODEGEN_EXECUTOR } from '../../../utils/open-api-codegen-target.js';\n\n/**\n * Codegen targets ran `nx g @aws/nx-plugin:open-api#<generator>` through\n * `nx:run-commands`, paying a second full Nx bootstrap — project graph, plugin\n * resolution and schema validation — for every codegen step. They now use the\n * `open-api-codegen` executor, which runs the same generator in the Nx process\n * that is already running.\n *\n * Only the command shape the generators produced is rewritten. A target that has\n * been customised — an extra flag, a chained command, options beyond `commands` —\n * is the user's, so it is left as it is and reported.\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 the executor can run, by the collection name they had. */\nconst GENERATORS: Record<string, OpenApiCodegenTarget> = {\n 'open-api#ts-client': 'ts-client',\n 'open-api#ts-hooks': 'ts-hooks',\n 'open-api#ts-metadata': 'ts-metadata',\n 'open-api#json-metadata': 'json-metadata',\n};\n\n/**\n * Matches a whole generated codegen command, binding the generator name and its\n * two paths. Anchored, so a command carrying anything else does not match and is\n * reported instead of rewritten.\n */\nconst CODEGEN_COMMAND =\n /^nx g @aws\\/nx-plugin:(?<generator>[\\w#-]+) --openApiSpecPath=\"(?<specPath>[^\"]+)\" --outputPath=\"(?<outputPath>[^\"]+)\" --no-interactive$/;\n\ninterface CodegenOptions {\n readonly generator: OpenApiCodegenTarget;\n readonly openApiSpecPath: string;\n readonly outputPath: string;\n}\n\n/**\n * The command a target runs, when it is a single-command `nx:run-commands` — the\n * shape the generators produced. A target carrying several commands, or options\n * beyond `commands`, has diverged.\n */\nconst singleCommand = (target: TargetConfiguration): string | undefined => {\n if (target.executor !== 'nx:run-commands') return undefined;\n const options = target.options as Record<string, unknown> | undefined;\n if (!options || Object.keys(options).length !== 1) return undefined;\n const commands = options.commands;\n if (!Array.isArray(commands) || commands.length !== 1) return undefined;\n return typeof commands[0] === 'string' ? commands[0] : undefined;\n};\n\n/** Parses a generated codegen command, or undefined if it is not one. */\nconst parseCodegenCommand = (command: string): CodegenOptions | undefined => {\n const groups = CODEGEN_COMMAND.exec(command)?.groups;\n if (!groups) return undefined;\n const generator = GENERATORS[groups.generator];\n if (!generator) return undefined;\n return {\n generator,\n openApiSpecPath: groups.specPath,\n outputPath: groups.outputPath,\n };\n};\n\n/**\n * Whether a target invokes an OpenAPI generator without being the shape the\n * generators produced, so it must be reported rather than rewritten.\n *\n * Continuous targets are excluded. The vended `watch-generate:<api>-client`\n * wraps `nx watch -- nx run <project>:<codegen target>`, which references the\n * codegen target rather than the generator, so it never matches here anyway. But\n * a watch target rewritten to invoke the generator directly would, and telling\n * its owner to switch to the executor would be wrong advice: `nx watch` runs\n * until interrupted, which a single executor invocation cannot express.\n *\n * `continuous` is the property that makes that true, so it is what is checked —\n * rather than the `watch-` name prefix, which is only a convention.\n */\nconst hasCustomisedCodegenCommand = (target: TargetConfiguration): boolean =>\n target.executor === 'nx:run-commands' &&\n !target.continuous &&\n JSON.stringify(target.options ?? {}).includes('@aws/nx-plugin:open-api#');\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 const command = singleCommand(target);\n const options = command ? parseCodegenCommand(command) : undefined;\n\n if (!options) {\n if (hasCustomisedCodegenCommand(target)) {\n nextSteps.push(\n `${projectName}:${targetName} has diverged from the generated shape — left untouched. Switch it to the '${OPEN_API_CODEGEN_EXECUTOR}' executor to avoid a nested Nx invocation.`,\n );\n }\n continue;\n }\n\n project.targets[targetName] = normalizeTargetKeyOrder({\n ...target,\n executor: OPEN_API_CODEGEN_EXECUTOR,\n options,\n });\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","normalizeTargetKeyOrder","OPEN_API_CODEGEN_EXECUTOR","GENERATORS","CODEGEN_COMMAND","singleCommand","target","executor","undefined","options","Object","keys","length","commands","Array","isArray","parseCodegenCommand","command","groups","exec","generator","openApiSpecPath","specPath","outputPath","hasCustomisedCodegenCommand","continuous","JSON","stringify","includes","migration","tree","nextSteps","projectName","project","changed","targetName","entries","targets","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAIXC,0BAA0B,QACrB,aAAa;AAEpB,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SAASC,uBAAuB,QAAQ,uBAAuB;AAC/D,SAASC,yBAAyB,QAAQ,4CAA4C;AAEtF;;;;;;;;;;;;;;CAcC,GAED,0EAA0E,GAC1E,MAAMC,aAAmD;IACvD,sBAAsB;IACtB,qBAAqB;IACrB,wBAAwB;IACxB,0BAA0B;AAC5B;AAEA;;;;CAIC,GACD,MAAMC,kBACJ;AAQF;;;;CAIC,GACD,MAAMC,gBAAgB,CAACC;IACrB,IAAIA,OAAOC,QAAQ,KAAK,mBAAmB,OAAOC;IAClD,MAAMC,UAAUH,OAAOG,OAAO;IAC9B,IAAI,CAACA,WAAWC,OAAOC,IAAI,CAACF,SAASG,MAAM,KAAK,GAAG,OAAOJ;IAC1D,MAAMK,WAAWJ,QAAQI,QAAQ;IACjC,IAAI,CAACC,MAAMC,OAAO,CAACF,aAAaA,SAASD,MAAM,KAAK,GAAG,OAAOJ;IAC9D,OAAO,OAAOK,QAAQ,CAAC,EAAE,KAAK,WAAWA,QAAQ,CAAC,EAAE,GAAGL;AACzD;AAEA,uEAAuE,GACvE,MAAMQ,sBAAsB,CAACC;IAC3B,MAAMC,SAASd,gBAAgBe,IAAI,CAACF,UAAUC;IAC9C,IAAI,CAACA,QAAQ,OAAOV;IACpB,MAAMY,YAAYjB,UAAU,CAACe,OAAOE,SAAS,CAAC;IAC9C,IAAI,CAACA,WAAW,OAAOZ;IACvB,OAAO;QACLY;QACAC,iBAAiBH,OAAOI,QAAQ;QAChCC,YAAYL,OAAOK,UAAU;IAC/B;AACF;AAEA;;;;;;;;;;;;;CAaC,GACD,MAAMC,8BAA8B,CAAClB,SACnCA,OAAOC,QAAQ,KAAK,qBACpB,CAACD,OAAOmB,UAAU,IAClBC,KAAKC,SAAS,CAACrB,OAAOG,OAAO,IAAI,CAAC,GAAGmB,QAAQ,CAAC;AAEhD,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,KAAK,MAAM,CAACC,aAAaC,QAAQ,IAAInC,YAAYgC,MAAO;QACtD,IAAII,UAAU;QAEd,KAAK,MAAM,CAACC,YAAY7B,OAAO,IAAII,OAAO0B,OAAO,CAACH,QAAQI,OAAO,IAAI,CAAC,GAAI;YACxE,MAAMpB,UAAUZ,cAAcC;YAC9B,MAAMG,UAAUQ,UAAUD,oBAAoBC,WAAWT;YAEzD,IAAI,CAACC,SAAS;gBACZ,IAAIe,4BAA4BlB,SAAS;oBACvCyB,UAAUO,IAAI,CACZ,GAAGN,YAAY,CAAC,EAAEG,WAAW,2EAA2E,EAAEjC,0BAA0B,2CAA2C,CAAC;gBAEpL;gBACA;YACF;YAEA+B,QAAQI,OAAO,CAACF,WAAW,GAAGlC,wBAAwB;gBACpD,GAAGK,MAAM;gBACTC,UAAUL;gBACVO;YACF;YACAyB,UAAU;QACZ;QAEA,IAAIA,SAAS;YACXnC,2BAA2B+B,MAAME,aAAaC;QAChD;IACF;IAEA,MAAMjC,qBAAqB8B;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -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":"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"}
|
|
@@ -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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"}
|