@aws/nx-plugin 1.0.0-rc.97 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/LICENSE-THIRD-PARTY +9 -9
  2. package/migrations.json +125 -115
  3. package/package.json +3 -3
  4. package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +1 -1
  5. package/src/infra/app/__snapshots__/generator.spec.ts.snap +4 -4
  6. package/src/infra/app/generator.js +5 -2
  7. package/src/infra/app/generator.js.map +1 -1
  8. package/src/internal/test-matrix/generator.js +2 -2
  9. package/src/internal/test-matrix/generator.js.map +1 -1
  10. package/src/license/sync/generator.d.ts +10 -0
  11. package/src/license/sync/generator.js +1 -1
  12. package/src/license/sync/generator.js.map +1 -1
  13. package/src/migrations/latest/sandbox-pattern-nested-stacks/metadata.json +3 -0
  14. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js +68 -0
  15. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js.map +1 -0
  16. package/src/migrations/latest/shadcn-cn-package/metadata.json +3 -0
  17. package/src/migrations/latest/shadcn-cn-package/migration.js +114 -0
  18. package/src/migrations/latest/shadcn-cn-package/migration.js.map +1 -0
  19. package/src/migrations/v1.0.0-rc.90/0001-dev-target-depends-on-pull-image/migration.js.map +1 -0
  20. package/src/migrations/v1.0.0-rc.90/0002-open-api-codegen-executor/migration.js.map +1 -0
  21. package/src/migrations/v1.0.0-rc.90/0003-terraform-provider-plugin-cache/migration.js.map +1 -0
  22. package/src/migrations/v1.0.0-rc.90/0004-python-test-input-scoping/migration.js.map +1 -0
  23. package/src/migrations/v1.0.0-rc.90/0005-vitest-coverage-output-dir/migration.js.map +1 -0
  24. package/src/migrations/v1.0.0-rc.90/0006-add-assemble-target/migration.js.map +1 -0
  25. package/src/migrations/v1.0.0-rc.90/0007-docker-target-cache-soundness/migration.js.map +1 -0
  26. package/src/migrations/v1.0.0-rc.90/0008-declare-cacheable-target-inputs/migration.js.map +1 -0
  27. package/src/migrations/v1.0.0-rc.90/0009-terraform-fmt-check/migration.js.map +1 -0
  28. package/src/migrations/v1.0.0-rc.92/0001-react-website-unique-dev-ports/migration.js.map +1 -0
  29. package/src/migrations/v1.0.0-rc.94/0001-infra-deploy-express-mode/migration.js.map +1 -0
  30. package/src/migrations/v1.0.0-rc.94/0002-shx-fs-commands/migration.js.map +1 -0
  31. package/src/migrations/v1.0.0-rc.94/0003-agent-core-vendor-target/migration.js.map +1 -0
  32. package/src/migrations/v1.0.0-rc.95/0001-rolldown-config-bundle-transient/migration.js.map +1 -0
  33. package/src/migrations/v1.0.0-rc.95/0002-agent-connection-pin-strands-peers/migration.js.map +1 -0
  34. package/src/migrations/v1.0.0-rc.95/0003-ignore-package-manager-temp-files/migration.js.map +1 -0
  35. package/src/migrations/v1.0.0-rc.95/0004-shadcn-package-imports-exports/migration.js.map +1 -0
  36. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.js.map +1 -0
  37. package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.js.map +1 -0
  38. package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.js.map +1 -0
  39. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.d.ts +6 -0
  40. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.js.map +1 -0
  41. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.js.map +1 -0
  42. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.d.ts +6 -0
  43. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.js.map +1 -0
  44. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  45. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +2 -2
  46. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +4 -4
  47. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +4 -4
  48. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  49. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  50. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  51. package/src/py/agent/react-connection/generator.d.ts +1 -7
  52. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +2 -2
  53. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
  54. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  55. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
  56. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +3 -3
  57. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +5 -5
  58. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
  59. package/src/terraform/project/schema.d.js +0 -3
  60. package/src/terraform/project/schema.d.js.map +1 -1
  61. package/src/terraform/project/schema.d.ts +0 -4
  62. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +12 -12
  63. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +4 -4
  64. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -2
  65. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +2 -2
  66. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -2
  67. package/src/ts/agent/react-connection/generator.d.ts +1 -9
  68. package/src/ts/astro-docs/files/translation/scripts/translate.ts.template +47 -2
  69. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +1 -1
  70. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +6 -6
  71. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  72. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
  73. package/src/ts/mcp-server/files/app/http.ts.template +1 -1
  74. package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +2 -2
  75. package/src/ts/nx-generator/files/local/generator.spec.ts.template +2 -2
  76. package/src/ts/nx-migration/generator.js +3 -1
  77. package/src/ts/nx-migration/generator.js.map +1 -1
  78. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +1 -25
  79. package/src/ts/nx-plugin/generator.js +19 -17
  80. package/src/ts/nx-plugin/generator.js.map +1 -1
  81. package/src/ts/nx-plugin/utils.d.ts +21 -0
  82. package/src/ts/nx-plugin/utils.js +41 -1
  83. package/src/ts/nx-plugin/utils.js.map +1 -1
  84. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +10 -10
  85. package/src/ts/react-website/agui/generator.d.ts +1 -5
  86. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +26 -26
  87. package/src/ts/react-website/app/generator.d.ts +1 -5
  88. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
  89. package/src/utils/ast.js +55 -16
  90. package/src/utils/ast.js.map +1 -1
  91. package/src/utils/dependencies.d.ts +10 -0
  92. package/src/utils/dependencies.js +93 -1
  93. package/src/utils/dependencies.js.map +1 -1
  94. package/src/utils/files/common/shadcn/src/components/ui/alert.tsx.template +1 -2
  95. package/src/utils/files/common/shadcn/src/components/ui/avatar.tsx.template +1 -2
  96. package/src/utils/files/common/shadcn/src/components/ui/breadcrumb.tsx.template +1 -2
  97. package/src/utils/files/common/shadcn/src/components/ui/button.tsx.template +1 -2
  98. package/src/utils/files/common/shadcn/src/components/ui/card.tsx.template +1 -2
  99. package/src/utils/files/common/shadcn/src/components/ui/input.tsx.template +1 -2
  100. package/src/utils/files/common/shadcn/src/components/ui/separator.tsx.template +1 -2
  101. package/src/utils/files/common/shadcn/src/components/ui/sheet.tsx.template +1 -2
  102. package/src/utils/files/common/shadcn/src/components/ui/sidebar.tsx.template +1 -1
  103. package/src/utils/files/common/shadcn/src/components/ui/skeleton.tsx.template +1 -1
  104. package/src/utils/files/common/shadcn/src/components/ui/spinner.tsx.template +1 -2
  105. package/src/utils/files/common/shadcn/src/components/ui/textarea.tsx.template +1 -2
  106. package/src/utils/files/common/shadcn/src/components/ui/tooltip.tsx.template +1 -2
  107. package/src/utils/files/common/shadcn/src/lib/utils.ts.template +1 -6
  108. package/src/utils/shared-shadcn.d.ts +1 -3
  109. package/src/utils/shared-shadcn.js +1 -4
  110. package/src/utils/shared-shadcn.js.map +1 -1
  111. package/src/utils/versions.d.ts +52 -53
  112. package/src/utils/versions.js +51 -52
  113. package/src/utils/versions.js.map +1 -1
  114. package/src/migrations/latest/add-assemble-target/migration.js.map +0 -1
  115. package/src/migrations/latest/agent-connection-pin-strands-peers/migration.js.map +0 -1
  116. package/src/migrations/latest/agent-core-vendor-target/migration.js.map +0 -1
  117. package/src/migrations/latest/checkov-scan-cache-inputs/migration.js.map +0 -1
  118. package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +0 -1
  119. package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +0 -1
  120. package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +0 -1
  121. package/src/migrations/latest/gateway-url-accessor/migration.js.map +0 -1
  122. package/src/migrations/latest/ignore-package-manager-temp-files/migration.js.map +0 -1
  123. package/src/migrations/latest/infra-deploy-express-mode/migration.js.map +0 -1
  124. package/src/migrations/latest/open-api-codegen-executor/migration.js.map +0 -1
  125. package/src/migrations/latest/py-lambda-powertools-context/migration.js.map +0 -1
  126. package/src/migrations/latest/python-test-input-scoping/migration.js.map +0 -1
  127. package/src/migrations/latest/react-website-unique-dev-ports/migration.js.map +0 -1
  128. package/src/migrations/latest/rolldown-config-bundle-transient/migration.js.map +0 -1
  129. package/src/migrations/latest/script-project-quality-gates/migration.js.map +0 -1
  130. package/src/migrations/latest/shadcn-package-imports-exports/migration.js.map +0 -1
  131. package/src/migrations/latest/shx-fs-commands/migration.js.map +0 -1
  132. package/src/migrations/latest/smithy-extension-trait-aliases/migration.js.map +0 -1
  133. package/src/migrations/latest/terraform-fmt-check/migration.js.map +0 -1
  134. package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +0 -1
  135. package/src/migrations/latest/terraform-validate-without-backend/migration.js.map +0 -1
  136. package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +0 -1
  137. /package/src/migrations/latest/{add-assemble-target → sandbox-pattern-nested-stacks}/migration.d.ts +0 -0
  138. /package/src/migrations/latest/{agent-core-vendor-target → shadcn-cn-package}/migration.d.ts +0 -0
  139. /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
  140. /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.90/0001-dev-target-depends-on-pull-image}/migration.d.ts +0 -0
  141. /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
  142. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/metadata.json +0 -0
  143. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.d.ts +0 -0
  144. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.js +0 -0
  145. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/metadata.json +0 -0
  146. /package/src/migrations/{latest/dev-target-depends-on-pull-image → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.d.ts +0 -0
  147. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.js +0 -0
  148. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/metadata.json +0 -0
  149. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.d.ts +0 -0
  150. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.js +0 -0
  151. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/metadata.json +0 -0
  152. /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.d.ts +0 -0
  153. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.js +0 -0
  154. /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/metadata.json +0 -0
  155. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0006-add-assemble-target}/migration.d.ts +0 -0
  156. /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/migration.js +0 -0
  157. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/metadata.json +0 -0
  158. /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.d.ts +0 -0
  159. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.js +0 -0
  160. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/metadata.json +0 -0
  161. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.d.ts +0 -0
  162. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.js +0 -0
  163. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/metadata.json +0 -0
  164. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.d.ts +0 -0
  165. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.js +0 -0
  166. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/metadata.json +0 -0
  167. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.d.ts +0 -0
  168. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.js +0 -0
  169. /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/metadata.json +0 -0
  170. /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.d.ts +0 -0
  171. /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.js +0 -0
  172. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/metadata.json +0 -0
  173. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.94/0002-shx-fs-commands}/migration.d.ts +0 -0
  174. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/migration.js +0 -0
  175. /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/metadata.json +0 -0
  176. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.d.ts +0 -0
  177. /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.js +0 -0
  178. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/metadata.json +0 -0
  179. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/migration.d.ts +0 -0
  180. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/migration.js +0 -0
  181. /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/metadata.json +0 -0
  182. /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
  183. /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/migration.js +0 -0
  184. /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/metadata.json +0 -0
  185. /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
  186. /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/migration.js +0 -0
  187. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/metadata.json +0 -0
  188. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.d.ts +0 -0
  189. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.js +0 -0
  190. /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/__snapshots__/migration.spec.ts.snap +0 -0
  191. /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/metadata.json +0 -0
  192. /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/migration.d.ts +0 -0
  193. /package/src/migrations/{latest/gateway-url-accessor → v1.0.0-rc.97/0001-gateway-url-accessor}/migration.js +0 -0
  194. /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/metadata.json +0 -0
  195. /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/migration.d.ts +0 -0
  196. /package/src/migrations/{latest/checkov-scan-cache-inputs → v1.0.0-rc.97/0002-checkov-scan-cache-inputs}/migration.js +0 -0
  197. /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0003-terraform-validate-without-backend}/metadata.json +0 -0
  198. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.97/0003-terraform-validate-without-backend}/migration.d.ts +0 -0
  199. /package/src/migrations/{latest/terraform-validate-without-backend → v1.0.0-rc.97/0003-terraform-validate-without-backend}/migration.js +0 -0
  200. /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.97/0004-py-lambda-powertools-context}/metadata.json +0 -0
  201. /package/src/migrations/{latest/py-lambda-powertools-context → v1.0.0-rc.97/0004-py-lambda-powertools-context}/migration.js +0 -0
  202. /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/__snapshots__/migration.spec.ts.snap +0 -0
  203. /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/metadata.json +0 -0
  204. /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/migration.d.ts +0 -0
  205. /package/src/migrations/{latest/smithy-extension-trait-aliases → v1.0.0-rc.97/0005-smithy-extension-trait-aliases}/migration.js +0 -0
  206. /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.97/0006-script-project-quality-gates}/metadata.json +0 -0
  207. /package/src/migrations/{latest/script-project-quality-gates → v1.0.0-rc.97/0006-script-project-quality-gates}/migration.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/ts/nx-plugin/utils.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 ProjectConfiguration,\n type Tree,\n updateJson,\n writeJson,\n} from '@nx/devkit';\nimport type { PackageJson } from 'nx/src/utils/package-json';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from '../../utils/declared-dependencies.js';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies.js';\nimport { isEsmWorkspace } from '../../utils/module-format.js';\nimport {\n nxPluginSelfDependency,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { type ITsDepVersion, withVersions } from '../../utils/versions.js';\n\n/** Dependencies a caller must declare to configure an Nx Plugin project. */\nexport const NX_PLUGIN_DEPENDENCIES = [\n { name: '@nx/devkit' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\n/**\n * Read the configuration of a project which can host Nx Plugin generators or\n * migrations, ie a TypeScript project.\n */\nexport const readNxPluginProject = (\n tree: Tree,\n projectName: string,\n): ProjectConfiguration => {\n const project = readProjectConfigurationUnqualified(tree, projectName);\n\n const tsConfigPath = joinPathFragments(project.root, 'tsconfig.json');\n if (!tree.exists(tsConfigPath)) {\n throw new Error(\n `Selected plugin project ${projectName} is not a TypeScript project`,\n );\n }\n\n return project;\n};\n\n/** `package.json` field pointing Nx at one of a plugin's manifests. */\ntype NxPluginManifestField = 'generators' | 'nx-migrations';\n\n/**\n * Create the plugin project's package.json if absent and point it at the given\n * manifest, returning its path.\n */\nexport const configureNxPluginPackageJson = <\n TField extends NxPluginManifestField,\n>(\n tree: Tree,\n project: ProjectConfiguration,\n manifestField: TField,\n manifestValue: PackageJson[TField],\n): string => {\n const pluginPackageJsonPath = joinPathFragments(project.root, 'package.json');\n if (!tree.exists(pluginPackageJsonPath)) {\n writeJson(tree, pluginPackageJsonPath, {\n name: project.name,\n });\n }\n const esm = isEsmWorkspace(tree);\n updateJson(tree, pluginPackageJsonPath, (pkg) => {\n // Match the plugin's module system to the workspace. Nx loads `.ts` files\n // via Node's native type stripping, as ESM (workspace root is\n // `type: module`) or CommonJS accordingly.\n pkg.type ??= esm ? 'module' : 'commonjs';\n pkg.main ??= esm ? './src/index.js' : './src/index';\n pkg[manifestField] ??= manifestValue;\n return pkg;\n });\n return pluginPackageJsonPath;\n};\n\n/**\n * Declare the dependencies the plugin's `.ts` files import on both the\n * workspace and the plugin, since both must resolve for Nx to load them. A\n * no-op inside the plugin's own monorepo, where they are already present.\n */\nexport const addNxPluginDependencies = <const D extends DependencyDeclaration>(\n tree: Tree,\n pluginPackageJsonPath: string,\n declaration: D & MustDeclare<typeof NX_PLUGIN_DEPENDENCIES, D>,\n): void => {\n const selfDependency = nxPluginSelfDependency(tree);\n if (Object.keys(selfDependency).length === 0) {\n return;\n }\n const deps = {\n ...withVersions(\n forDependencies<typeof NX_PLUGIN_DEPENDENCIES>(declaration),\n ['@nx/devkit'],\n ),\n ...selfDependency,\n };\n addDependenciesToPackageJson(tree, {}, deps);\n addDependenciesToPackageJson(tree, deps, {}, pluginPackageJsonPath);\n};\n\n/**\n * Configures a TypeScript project as an Nx Plugin\n */\nexport const configureTsProjectAsNxPlugin = <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n projectName: string,\n declaration: D & MustDeclare<typeof NX_PLUGIN_DEPENDENCIES, D>,\n) => {\n const project = readNxPluginProject(tree, projectName);\n\n // Create an empty generators.json if one dosn't exist\n const generatorsJsonPath = joinPathFragments(project.root, 'generators.json');\n if (!tree.exists(generatorsJsonPath)) {\n writeJson(tree, generatorsJsonPath, {\n generators: {},\n });\n }\n\n const pluginPackageJsonPath = configureNxPluginPackageJson(\n tree,\n project,\n 'generators',\n './generators.json',\n );\n\n addNxPluginDependencies(\n tree,\n pluginPackageJsonPath,\n forDependencies<typeof NX_PLUGIN_DEPENDENCIES>(declaration),\n );\n};\n"],"names":["joinPathFragments","updateJson","writeJson","forDependencies","addDependenciesToPackageJson","isEsmWorkspace","nxPluginSelfDependency","readProjectConfigurationUnqualified","withVersions","NX_PLUGIN_DEPENDENCIES","name","readNxPluginProject","tree","projectName","project","tsConfigPath","root","exists","Error","configureNxPluginPackageJson","manifestField","manifestValue","pluginPackageJsonPath","esm","pkg","type","main","addNxPluginDependencies","declaration","selfDependency","Object","keys","length","deps","configureTsProjectAsNxPlugin","generatorsJsonPath","generators"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,EAGjBC,UAAU,EACVC,SAAS,QACJ,aAAa;AAEpB,SAEEC,eAAe,QAEV,uCAAuC;AAC9C,SAASC,4BAA4B,QAAQ,8BAA8B;AAC3E,SAASC,cAAc,QAAQ,+BAA+B;AAC9D,SACEC,sBAAsB,EACtBC,mCAAmC,QAC9B,oBAAoB;AAC3B,SAA6BC,YAAY,QAAQ,0BAA0B;AAE3E,0EAA0E,GAC1E,OAAO,MAAMC,yBAAyB;IACpC;QAAEC,MAAM;IAAa;CACtB,CAAuD;AAExD;;;CAGC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC;IAEA,MAAMC,UAAUP,oCAAoCK,MAAMC;IAE1D,MAAME,eAAef,kBAAkBc,QAAQE,IAAI,EAAE;IACrD,IAAI,CAACJ,KAAKK,MAAM,CAACF,eAAe;QAC9B,MAAM,IAAIG,MACR,CAAC,wBAAwB,EAAEL,YAAY,4BAA4B,CAAC;IAExE;IAEA,OAAOC;AACT,EAAE;AAKF;;;CAGC,GACD,OAAO,MAAMK,+BAA+B,CAG1CP,MACAE,SACAM,eACAC;IAEA,MAAMC,wBAAwBtB,kBAAkBc,QAAQE,IAAI,EAAE;IAC9D,IAAI,CAACJ,KAAKK,MAAM,CAACK,wBAAwB;QACvCpB,UAAUU,MAAMU,uBAAuB;YACrCZ,MAAMI,QAAQJ,IAAI;QACpB;IACF;IACA,MAAMa,MAAMlB,eAAeO;IAC3BX,WAAWW,MAAMU,uBAAuB,CAACE;QACvC,0EAA0E;QAC1E,8DAA8D;QAC9D,2CAA2C;QAC3CA,IAAIC,IAAI,KAAKF,MAAM,WAAW;QAC9BC,IAAIE,IAAI,KAAKH,MAAM,mBAAmB;QACtCC,GAAG,CAACJ,cAAc,KAAKC;QACvB,OAAOG;IACT;IACA,OAAOF;AACT,EAAE;AAEF;;;;CAIC,GACD,OAAO,MAAMK,0BAA0B,CACrCf,MACAU,uBACAM;IAEA,MAAMC,iBAAiBvB,uBAAuBM;IAC9C,IAAIkB,OAAOC,IAAI,CAACF,gBAAgBG,MAAM,KAAK,GAAG;QAC5C;IACF;IACA,MAAMC,OAAO;QACX,GAAGzB,aACDL,gBAA+CyB,cAC/C;YAAC;SAAa,CACf;QACD,GAAGC,cAAc;IACnB;IACAzB,6BAA6BQ,MAAM,CAAC,GAAGqB;IACvC7B,6BAA6BQ,MAAMqB,MAAM,CAAC,GAAGX;AAC/C,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMY,+BAA+B,CAG1CtB,MACAC,aACAe;IAEA,MAAMd,UAAUH,oBAAoBC,MAAMC;IAE1C,sDAAsD;IACtD,MAAMsB,qBAAqBnC,kBAAkBc,QAAQE,IAAI,EAAE;IAC3D,IAAI,CAACJ,KAAKK,MAAM,CAACkB,qBAAqB;QACpCjC,UAAUU,MAAMuB,oBAAoB;YAClCC,YAAY,CAAC;QACf;IACF;IAEA,MAAMd,wBAAwBH,6BAC5BP,MACAE,SACA,cACA;IAGFa,wBACEf,MACAU,uBACAnB,gBAA+CyB;AAEnD,EAAE"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/ts/nx-plugin/utils.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 ProjectConfiguration,\n type Tree,\n updateJson,\n updateProjectConfiguration,\n writeJson,\n} from '@nx/devkit';\nimport type { PackageJson } from 'nx/src/utils/package-json';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from '../../utils/declared-dependencies.js';\nimport { addDependenciesToPackageJson } from '../../utils/dependencies.js';\nimport { isEsmWorkspace } from '../../utils/module-format.js';\nimport {\n nxPluginSelfDependency,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { type ITsDepVersion, withVersions } from '../../utils/versions.js';\n\n/** Dependencies a caller must declare to configure an Nx Plugin project. */\nexport const NX_PLUGIN_DEPENDENCIES = [\n { name: '@nx/devkit' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\n/**\n * Read the configuration of a project which can host Nx Plugin generators or\n * migrations, ie a TypeScript project.\n */\nexport const readNxPluginProject = (\n tree: Tree,\n projectName: string,\n): ProjectConfiguration => {\n const project = readProjectConfigurationUnqualified(tree, projectName);\n\n const tsConfigPath = joinPathFragments(project.root, 'tsconfig.json');\n if (!tree.exists(tsConfigPath)) {\n throw new Error(\n `Selected plugin project ${projectName} is not a TypeScript project`,\n );\n }\n\n return project;\n};\n\n/** `package.json` field pointing Nx at one of a plugin's manifests. */\ntype NxPluginManifestField = 'generators' | 'nx-migrations';\n\n/**\n * The manifests Nx reads from a published plugin, copied beside the compiled\n * code by the `package` target. `nx migrate` resolves `migrations.json` from the\n * tarball, so it ships even though only `ts#nx-migration` writes it.\n */\nexport const NX_PLUGIN_MANIFESTS = [\n 'generators.json',\n 'executors.json',\n 'migrations.json',\n] as const;\n\n/** The `package` target assets that copy the plugin's manifests into dist. */\nexport const nxPluginManifestAssets = (): {\n input: string;\n glob: string;\n output: string;\n}[] =>\n NX_PLUGIN_MANIFESTS.map((glob) => ({\n input: './{projectRoot}',\n glob,\n output: '.',\n }));\n\n/**\n * Ensure the plugin's `package` target copies every manifest into dist, so a\n * manifest added after the project was generated is still published.\n *\n * Anchored to the `generators.json` asset the target is vended with: a `package`\n * target without it belongs to something other than an Nx Plugin, or has been\n * rewritten, so it is left as it is.\n */\nexport const addNxPluginManifestAssets = (\n tree: Tree,\n project: ProjectConfiguration,\n): void => {\n const assets = project.targets?.package?.options?.assets;\n if (!Array.isArray(assets)) {\n return;\n }\n const globs = new Set(\n assets\n .filter((asset) => typeof asset === 'object' && asset !== null)\n .map((asset) => asset.glob),\n );\n if (!globs.has('generators.json')) {\n return;\n }\n const missing = nxPluginManifestAssets().filter(\n (asset) => !globs.has(asset.glob),\n );\n if (missing.length === 0) {\n return;\n }\n project.targets.package.options.assets = [...assets, ...missing];\n updateProjectConfiguration(tree, project.name, project);\n};\n\n/**\n * Create the plugin project's package.json if absent and point it at the given\n * manifest, returning its path.\n */\nexport const configureNxPluginPackageJson = <\n TField extends NxPluginManifestField,\n>(\n tree: Tree,\n project: ProjectConfiguration,\n manifestField: TField,\n manifestValue: PackageJson[TField],\n): string => {\n const pluginPackageJsonPath = joinPathFragments(project.root, 'package.json');\n if (!tree.exists(pluginPackageJsonPath)) {\n writeJson(tree, pluginPackageJsonPath, {\n name: project.name,\n });\n }\n const esm = isEsmWorkspace(tree);\n updateJson(tree, pluginPackageJsonPath, (pkg) => {\n // Match the plugin's module system to the workspace. Nx loads `.ts` files\n // via Node's native type stripping, as ESM (workspace root is\n // `type: module`) or CommonJS accordingly.\n pkg.type ??= esm ? 'module' : 'commonjs';\n pkg.main ??= esm ? './src/index.js' : './src/index';\n pkg[manifestField] ??= manifestValue;\n return pkg;\n });\n return pluginPackageJsonPath;\n};\n\n/**\n * Declare the dependencies the plugin's `.ts` files import on both the\n * workspace and the plugin, since both must resolve for Nx to load them. A\n * no-op inside the plugin's own monorepo, where they are already present.\n */\nexport const addNxPluginDependencies = <const D extends DependencyDeclaration>(\n tree: Tree,\n pluginPackageJsonPath: string,\n declaration: D & MustDeclare<typeof NX_PLUGIN_DEPENDENCIES, D>,\n): void => {\n const selfDependency = nxPluginSelfDependency(tree);\n if (Object.keys(selfDependency).length === 0) {\n return;\n }\n const deps = {\n ...withVersions(\n forDependencies<typeof NX_PLUGIN_DEPENDENCIES>(declaration),\n ['@nx/devkit'],\n ),\n ...selfDependency,\n };\n addDependenciesToPackageJson(tree, {}, deps);\n addDependenciesToPackageJson(tree, deps, {}, pluginPackageJsonPath);\n};\n\n/**\n * Configures a TypeScript project as an Nx Plugin\n */\nexport const configureTsProjectAsNxPlugin = <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n projectName: string,\n declaration: D & MustDeclare<typeof NX_PLUGIN_DEPENDENCIES, D>,\n) => {\n const project = readNxPluginProject(tree, projectName);\n\n // Create an empty generators.json if one dosn't exist\n const generatorsJsonPath = joinPathFragments(project.root, 'generators.json');\n if (!tree.exists(generatorsJsonPath)) {\n writeJson(tree, generatorsJsonPath, {\n generators: {},\n });\n }\n\n const pluginPackageJsonPath = configureNxPluginPackageJson(\n tree,\n project,\n 'generators',\n './generators.json',\n );\n\n addNxPluginDependencies(\n tree,\n pluginPackageJsonPath,\n forDependencies<typeof NX_PLUGIN_DEPENDENCIES>(declaration),\n );\n};\n"],"names":["joinPathFragments","updateJson","updateProjectConfiguration","writeJson","forDependencies","addDependenciesToPackageJson","isEsmWorkspace","nxPluginSelfDependency","readProjectConfigurationUnqualified","withVersions","NX_PLUGIN_DEPENDENCIES","name","readNxPluginProject","tree","projectName","project","tsConfigPath","root","exists","Error","NX_PLUGIN_MANIFESTS","nxPluginManifestAssets","map","glob","input","output","addNxPluginManifestAssets","assets","targets","package","options","Array","isArray","globs","Set","filter","asset","has","missing","length","configureNxPluginPackageJson","manifestField","manifestValue","pluginPackageJsonPath","esm","pkg","type","main","addNxPluginDependencies","declaration","selfDependency","Object","keys","deps","configureTsProjectAsNxPlugin","generatorsJsonPath","generators"],"mappings":"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"}
@@ -99,8 +99,8 @@ export const handler = async (
99
99
  `;
100
100
 
101
101
  exports[`ts#rdb generator > should add mysql prisma dependencies when engine is MySQL > packages/db/src/index.ts 1`] = `
102
- "export * from './prisma.js';
103
- // Export your library code here
102
+ "// Export your library code here
103
+ export * from './prisma.js';
104
104
  "
105
105
  `;
106
106
 
@@ -848,7 +848,7 @@ terraform {
848
848
  required_providers {
849
849
  aws = {
850
850
  source = "hashicorp/aws"
851
- version = "6.62.0"
851
+ version = "6.63.0"
852
852
  }
853
853
  null = {
854
854
  source = "hashicorp/null"
@@ -1519,7 +1519,7 @@ exports[`ts#rdb generator > should generate terraform modules when iac is Terraf
1519
1519
  }
1520
1520
  aws = {
1521
1521
  source = "hashicorp/aws"
1522
- version = "6.62.0"
1522
+ version = "6.63.0"
1523
1523
  }
1524
1524
  external = {
1525
1525
  source = "hashicorp/external"
@@ -2214,7 +2214,7 @@ terraform {
2214
2214
  required_providers {
2215
2215
  aws = {
2216
2216
  source = "hashicorp/aws"
2217
- version = "6.62.0"
2217
+ version = "6.63.0"
2218
2218
  }
2219
2219
  null = {
2220
2220
  source = "hashicorp/null"
@@ -2885,7 +2885,7 @@ exports[`ts#rdb generator > should generate terraform modules with MySQL engine
2885
2885
  }
2886
2886
  aws = {
2887
2887
  source = "hashicorp/aws"
2888
- version = "6.62.0"
2888
+ version = "6.63.0"
2889
2889
  }
2890
2890
  external = {
2891
2891
  source = "hashicorp/external"
@@ -3679,8 +3679,8 @@ export const handler = async (
3679
3679
  `;
3680
3680
 
3681
3681
  exports[`ts#rdb generator > should generate the aurora shared construct > packages/db/src/index.ts 1`] = `
3682
- "export * from './prisma.js';
3683
- // Export your library code here
3682
+ "// Export your library code here
3683
+ export * from './prisma.js';
3684
3684
  "
3685
3685
  `;
3686
3686
 
@@ -4540,8 +4540,8 @@ WORKDIR \${LAMBDA_TASK_ROOT}
4540
4540
  # HIGH/CRITICAL vulnerabilities into the image.
4541
4541
  RUN printf 'allow-scripts[]=prisma\\nallow-scripts[]=@prisma/engines\\n' > .npmrc \\
4542
4542
  && npm init -y \\
4543
- && npm pkg set "overrides.deepmerge-ts=8.0.0" \\
4544
- && npm pkg set "overrides.mysql2=3.22.0" \\
4543
+ && npm pkg set "overrides.deepmerge-ts=8.0.2" \\
4544
+ && npm pkg set "overrides.mysql2=3.24.3" \\
4545
4545
  && npm install prisma@7.10.0 \\
4546
4546
  && rm .npmrc \\
4547
4547
  && npm uninstall -g npm
@@ -50,11 +50,7 @@ export declare const DEPENDENCIES: import("../../../utils/declared-dependencies.
50
50
  } & {
51
51
  versionOnly: true;
52
52
  }, {
53
- readonly name: "clsx";
54
- } & {
55
- versionOnly: true;
56
- }, {
57
- readonly name: "tailwind-merge";
53
+ readonly name: "cn";
58
54
  } & {
59
55
  versionOnly: true;
60
56
  }, {
@@ -1,10 +1,10 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`react-website generator > TailwindCSS integration > should configure vite with TailwindCSS plugin by default > vite.config.mts-with-tailwind 1`] = `
4
- "import tailwindcss from '@tailwindcss/vite';
4
+ "/// <reference types='vitest' />
5
+ import tailwindcss from '@tailwindcss/vite';
5
6
  import { resolve } from 'path';
6
7
  import { tanstackRouter } from '@tanstack/router-plugin/vite';
7
- /// <reference types='vitest' />
8
8
  import { defineConfig } from 'vite';
9
9
  import react from '@vitejs/plugin-react';
10
10
 
@@ -59,9 +59,9 @@ export default defineConfig(() => ({
59
59
  `;
60
60
 
61
61
  exports[`react-website generator > TailwindCSS integration > should configure vite without TailwindCSS plugin when disabled > vite.config.mts-without-tailwind 1`] = `
62
- "import { resolve } from 'path';
62
+ "/// <reference types='vitest' />
63
+ import { resolve } from 'path';
63
64
  import { tanstackRouter } from '@tanstack/router-plugin/vite';
64
- /// <reference types='vitest' />
65
65
  import { defineConfig } from 'vite';
66
66
  import react from '@vitejs/plugin-react';
67
67
 
@@ -131,7 +131,7 @@ exports[`react-website generator > TailwindCSS integration > terraform iac > sho
131
131
  required_providers {
132
132
  aws = {
133
133
  source = "hashicorp/aws"
134
- version = "6.62.0"
134
+ version = "6.63.0"
135
135
  configuration_aliases = [aws.us_east_1]
136
136
  }
137
137
  null = {
@@ -745,7 +745,7 @@ resource "null_resource" "upload_website_files" {
745
745
  provisioner "local-exec" {
746
746
  command = <<-EOT
747
747
  cd "$ROOT_PATH"
748
- uv run --with boto3==1.43.83 python3 -c "
748
+ uv run --with boto3==1.43.89 python3 -c "
749
749
  import os
750
750
  import sys
751
751
  import boto3
@@ -868,7 +868,7 @@ resource "null_resource" "cloudfront_invalidation" {
868
868
 
869
869
  provisioner "local-exec" {
870
870
  command = <<-EOT
871
- uv run --with boto3==1.43.83 python3 -c "
871
+ uv run --with boto3==1.43.89 python3 -c "
872
872
  import boto3
873
873
  import os
874
874
  import sys
@@ -954,7 +954,7 @@ output "waf_web_acl_arn" {
954
954
  required_providers {
955
955
  aws = {
956
956
  source = "hashicorp/aws"
957
- version = "6.62.0"
957
+ version = "6.63.0"
958
958
  configuration_aliases = [aws.us_east_1]
959
959
  }
960
960
  }
@@ -1060,7 +1060,7 @@ runtime-config.json"
1060
1060
 
1061
1061
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > biome.json 1`] = `
1062
1062
  "{
1063
- "$schema": "https://biomejs.dev/schemas/2.5.11/schema.json",
1063
+ "$schema": "https://biomejs.dev/schemas/2.5.12/schema.json",
1064
1064
  "root": true,
1065
1065
  "formatter": {
1066
1066
  "enabled": true,
@@ -2325,18 +2325,18 @@ exports[`react-website generator > Tanstack router integration > should generate
2325
2325
  - test-app
2326
2326
  - packages/common/*
2327
2327
  catalog:
2328
- '@types/node': 26.4.0
2328
+ '@types/node': 26.4.1
2329
2329
  vite: 8.2.2
2330
2330
  vitest: 4.1.11
2331
2331
  '@vitest/coverage-v8': 4.1.11
2332
- jsdom: 27.4.0
2332
+ jsdom: 29.1.1
2333
2333
  '@nx/vitest': 23.2.0
2334
2334
  constructs: 10.8.1
2335
- aws-cdk-lib: 2.267.0
2335
+ aws-cdk-lib: 2.268.0
2336
2336
  react: 19.2.8
2337
2337
  react-dom: 19.2.8
2338
- '@cloudscape-design/components': 3.0.1356
2339
- '@cloudscape-design/board-components': 3.0.221
2338
+ '@cloudscape-design/components': 3.0.1359
2339
+ '@cloudscape-design/board-components': 3.0.222
2340
2340
  '@cloudscape-design/global-styles': 1.0.67
2341
2341
  tailwindcss: 4.3.3
2342
2342
  '@nx/react': 23.2.0
@@ -2827,8 +2827,8 @@ exports[`react-website generator > Tanstack router integration > should generate
2827
2827
  `;
2828
2828
 
2829
2829
  exports[`react-website generator > Tanstack router integration > should generate website with no router correctly > test-app/vite.config.mts 1`] = `
2830
- "import tailwindcss from '@tailwindcss/vite';
2831
- /// <reference types='vitest' />
2830
+ "/// <reference types='vitest' />
2831
+ import tailwindcss from '@tailwindcss/vite';
2832
2832
  import { defineConfig } from 'vite';
2833
2833
  import react from '@vitejs/plugin-react';
2834
2834
 
@@ -2936,7 +2936,7 @@ runtime-config.json"
2936
2936
 
2937
2937
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > biome.json 1`] = `
2938
2938
  "{
2939
- "$schema": "https://biomejs.dev/schemas/2.5.11/schema.json",
2939
+ "$schema": "https://biomejs.dev/schemas/2.5.12/schema.json",
2940
2940
  "root": true,
2941
2941
  "formatter": {
2942
2942
  "enabled": true,
@@ -4205,18 +4205,18 @@ exports[`react-website generator > Tanstack router integration > should generate
4205
4205
  - test-app
4206
4206
  - packages/common/*
4207
4207
  catalog:
4208
- '@types/node': 26.4.0
4208
+ '@types/node': 26.4.1
4209
4209
  vite: 8.2.2
4210
4210
  vitest: 4.1.11
4211
4211
  '@vitest/coverage-v8': 4.1.11
4212
- jsdom: 27.4.0
4212
+ jsdom: 29.1.1
4213
4213
  '@nx/vitest': 23.2.0
4214
4214
  constructs: 10.8.1
4215
- aws-cdk-lib: 2.267.0
4215
+ aws-cdk-lib: 2.268.0
4216
4216
  react: 19.2.8
4217
4217
  react-dom: 19.2.8
4218
- '@cloudscape-design/components': 3.0.1356
4219
- '@cloudscape-design/board-components': 3.0.221
4218
+ '@cloudscape-design/components': 3.0.1359
4219
+ '@cloudscape-design/board-components': 3.0.222
4220
4220
  '@cloudscape-design/global-styles': 1.0.67
4221
4221
  tailwindcss: 4.3.3
4222
4222
  '@tanstack/react-router': 1.170.32
@@ -4897,10 +4897,10 @@ exports[`react-website generator > Tanstack router integration > should generate
4897
4897
  `;
4898
4898
 
4899
4899
  exports[`react-website generator > Tanstack router integration > should generate website with router correctly > test-app/vite.config.mts 1`] = `
4900
- "import tailwindcss from '@tailwindcss/vite';
4900
+ "/// <reference types='vitest' />
4901
+ import tailwindcss from '@tailwindcss/vite';
4901
4902
  import { resolve } from 'path';
4902
4903
  import { tanstackRouter } from '@tanstack/router-plugin/vite';
4903
- /// <reference types='vitest' />
4904
4904
  import { defineConfig } from 'vite';
4905
4905
  import react from '@vitejs/plugin-react';
4906
4906
 
@@ -5026,10 +5026,10 @@ exports[`react-website generator > should configure TypeScript correctly > tscon
5026
5026
  `;
5027
5027
 
5028
5028
  exports[`react-website generator > should configure vite correctly > vite.config.mts 1`] = `
5029
- "import tailwindcss from '@tailwindcss/vite';
5029
+ "/// <reference types='vitest' />
5030
+ import tailwindcss from '@tailwindcss/vite';
5030
5031
  import { resolve } from 'path';
5031
5032
  import { tanstackRouter } from '@tanstack/router-plugin/vite';
5032
- /// <reference types='vitest' />
5033
5033
  import { defineConfig } from 'vite';
5034
5034
  import react from '@vitejs/plugin-react';
5035
5035
 
@@ -96,11 +96,7 @@ export declare const DEPENDENCIES: import("../../../utils/declared-dependencies.
96
96
  } & {
97
97
  versionOnly: true;
98
98
  }, {
99
- readonly name: "clsx";
100
- } & {
101
- versionOnly: true;
102
- }, {
103
- readonly name: "tailwind-merge";
99
+ readonly name: "cn";
104
100
  } & {
105
101
  versionOnly: true;
106
102
  }, {
@@ -6,7 +6,7 @@ exports[`cognito-auth generator terraform iac > should generate terraform files
6
6
  required_providers {
7
7
  aws = {
8
8
  source = "hashicorp/aws"
9
- version = "6.62.0"
9
+ version = "6.63.0"
10
10
  }
11
11
  null = {
12
12
  source = "hashicorp/null"
@@ -67,7 +67,7 @@ resource "null_resource" "add_callback_url" {
67
67
 
68
68
  provisioner "local-exec" {
69
69
  command = <<-EOT
70
- uv run --with boto3==1.43.83 python -c "
70
+ uv run --with boto3==1.43.89 python -c "
71
71
  import boto3
72
72
  import os
73
73
  import sys
package/src/utils/ast.js CHANGED
@@ -3,6 +3,8 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */ import { QueryBuilder } from "@getgrit/gritql";
5
5
  import * as path from "path";
6
+ import { LANGUAGE_COMMENT_SYNTAX, readLicenseConfig } from "../license/config.js";
7
+ import { parseFile } from "../license/sync/generator.js";
6
8
  import { updateGitIgnore } from "./git.js";
7
9
  import { isEsmWorkspace } from "./module-format.js";
8
10
  const GRIT_DIR = '.grit';
@@ -31,6 +33,49 @@ const assertFilePath = (tree, filePath)=>{
31
33
  throw new Error(`No file located at ${filePath}`);
32
34
  }
33
35
  };
36
+ /**
37
+ * Insert `statement` at the top of a file, below any hashbang and leading
38
+ * comment block. Keeps a license header first in the file, so `license#sync`
39
+ * doesn't see it displaced and prepend a second one.
40
+ *
41
+ * The leading comment is skipped whatever it says — a header, a placeholder or a
42
+ * note — so nothing here has to identify a license.
43
+ *
44
+ * Splits the file with the sync generator's own `parseFile`, resolving the
45
+ * comment syntax the way the sync does: the workspace's configured
46
+ * `commentSyntax` for the extension first, then the built-in table. That way an
47
+ * extension only the user's config covers is still recognised. An extension
48
+ * neither covers has no comment syntax to find, so the statement goes at the top.
49
+ */ const insertBelowLeadingComments = async (tree, filePath, contents, statement)=>{
50
+ const extension = filePath.split('.').pop() ?? '';
51
+ let syntax;
52
+ try {
53
+ syntax = (await readLicenseConfig(tree))?.source?.header?.commentSyntax?.[extension];
54
+ } catch {
55
+ // Reading the config evaluates it, which throws on a config that doesn't
56
+ // load — including this file itself while a generator is mid-edit. A config
57
+ // we can't read must not stop an import being added, so fall back to the
58
+ // defaults. (A config that simply doesn't exist reads as undefined.)
59
+ }
60
+ syntax ??= LANGUAGE_COMMENT_SYNTAX[extension];
61
+ if (!syntax) {
62
+ return `${statement}\n${contents}`;
63
+ }
64
+ const { hashbang, header, body } = parseFile(contents, syntax);
65
+ if (!hashbang && !header) {
66
+ return `${statement}\n${contents}`;
67
+ }
68
+ return [
69
+ ...hashbang ? [
70
+ hashbang
71
+ ] : [],
72
+ ...header ? [
73
+ header
74
+ ] : [],
75
+ statement,
76
+ body
77
+ ].join('\n');
78
+ };
34
79
  export const addDestructuredImport = async (tree, filePath, variableNames, from)=>{
35
80
  assertFilePath(tree, filePath);
36
81
  from = normalizeModuleSpecifier(tree, from);
@@ -44,16 +89,10 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
44
89
  await applyGritQL(tree, filePath, `\`import { $imports } from '${from}'\` => \`import { $imports, ${variableName} } from '${from}'\` where { $imports <: not contains \`${localName}\` }`);
45
90
  }
46
91
  } else {
47
- // No existing import — prepend a new one (after shebang if present)
92
+ // No existing import — add a new one below any hashbang and leading comment
48
93
  const specifiers = variableNames.join(', ');
49
94
  const contents = tree.read(filePath).toString();
50
- const newImport = `import { ${specifiers} } from '${from}';\n`;
51
- if (contents.startsWith('#!')) {
52
- const newlineIndex = contents.indexOf('\n');
53
- tree.write(filePath, `${contents.substring(0, newlineIndex + 1)}${newImport}${contents.substring(newlineIndex + 1)}`);
54
- } else {
55
- tree.write(filePath, `${newImport}${contents}`);
56
- }
95
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, contents, `import { ${specifiers} } from '${from}';`));
57
96
  }
58
97
  };
59
98
  /**
@@ -93,10 +132,11 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
93
132
  if (allAlreadyPresent) {
94
133
  return;
95
134
  }
96
- // No existing `from <module> import` line — prepend one. Ruff's import
97
- // sorter will place it in the right group on the next formatter pass.
135
+ // No existing `from <module> import` line — add one below any hashbang and
136
+ // leading comment. Ruff's import sorter will place it in the right group on
137
+ // the next formatter pass.
98
138
  const specifiers = variableNames.join(', ');
99
- tree.write(filePath, `from ${from} import ${specifiers}\n${beforeContents}`);
139
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, beforeContents, `from ${from} import ${specifiers}`));
100
140
  };
101
141
  /**
102
142
  * Adds an `import <variableName> from '<from>'; statement to the beginning of the file,
@@ -115,9 +155,9 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
115
155
  if (identifierTaken) {
116
156
  throw new Error(`Cannot import ${variableName} from '${from}' in ${filePath}: ${variableName} is already imported from a different module. Rename the project so its generated identifier does not collide.`);
117
157
  }
118
- // Prepend new import to file
158
+ // Add the import below any hashbang and leading comment
119
159
  const contents = tree.read(filePath).toString();
120
- tree.write(filePath, `import ${variableName} from '${from}';\n${contents}`);
160
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, contents, `import ${variableName} from '${from}';`));
121
161
  };
122
162
  /**
123
163
  * Adds an `export * from '<from>'; statement to the given TypeScript file.
@@ -135,8 +175,7 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
135
175
  if (alreadyExported) {
136
176
  return;
137
177
  }
138
- // Prepend new export to file
139
- tree.write(filePath, `export * from '${from}';\n${contents}`);
178
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, contents, `export * from '${from}';`));
140
179
  };
141
180
  /**
142
181
  * Adds an `export { <names> } from '<from>';` statement to the given TypeScript
@@ -169,7 +208,7 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
169
208
  if (missing.length === 0) {
170
209
  return;
171
210
  }
172
- tree.write(filePath, `export { ${missing.join(', ')} } from '${from}';\n${contents}`);
211
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, contents, `export { ${missing.join(', ')} } from '${from}';`));
173
212
  };
174
213
  /**
175
214
  * Return whether or not the given identifier is exported in the source file.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/ast.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { QueryBuilder } from '@getgrit/gritql';\nimport type { Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport { updateGitIgnore } from './git.js';\nimport { isEsmWorkspace } from './module-format.js';\n\nconst GRIT_DIR = '.grit';\n\n/**\n * Normalize a relative module specifier for the workspace's module format.\n * ESM (`nodenext`) requires an explicit `.js` extension on relative imports;\n * CommonJS (`node16`) resolves them extensionless. Callers always pass the ESM\n * form (with `.js`); this strips the extension for CommonJS workspaces.\n */\nconst normalizeModuleSpecifier = (tree: Tree, from: string): string => {\n if (isEsmWorkspace(tree)) {\n return from;\n }\n const isRelative = from.startsWith('./') || from.startsWith('../');\n return isRelative && from.endsWith('.js')\n ? from.slice(0, -'.js'.length)\n : from;\n};\n\n// Pin the gritql native library's \"global\" stdlib directory to <workspace>/.grit so it doesn't try to write to /usr/local/.grit (or wherever node's grandparent resolves to).\nconst ensureGritDir = (tree: Tree) => {\n process.env.GRIT_GLOBAL_DIR ??= path.join(tree.root, GRIT_DIR);\n updateGitIgnore(tree, '.', (patterns) => [...patterns, GRIT_DIR]);\n};\n\nconst assertFilePath = (tree: Tree, filePath: string) => {\n if (!tree.exists(filePath)) {\n throw new Error(`No file located at ${filePath}`);\n }\n};\n\nexport const addDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if there's an existing import from this module\n const hasExistingImport = await matchGritQL(\n tree,\n filePath,\n `\\`import { $_ } from '${from}'\\``,\n );\n\n if (hasExistingImport) {\n // For each new variable, use GritQL rewrite to add it if not already present\n for (const variableName of variableNames) {\n const localName = variableName.includes(' as ')\n ? variableName.split(' as ')[1]\n : variableName;\n // Use rewrite (=>) which correctly handles comma-separated import specifier lists\n await applyGritQL(\n tree,\n filePath,\n `\\`import { $imports } from '${from}'\\` => \\`import { $imports, ${variableName} } from '${from}'\\` where { $imports <: not contains \\`${localName}\\` }`,\n );\n }\n } else {\n // No existing import — prepend a new one (after shebang if present)\n const specifiers = variableNames.join(', ');\n const contents = tree.read(filePath)!.toString();\n const newImport = `import { ${specifiers} } from '${from}';\\n`;\n if (contents.startsWith('#!')) {\n const newlineIndex = contents.indexOf('\\n');\n tree.write(\n filePath,\n `${contents.substring(0, newlineIndex + 1)}${newImport}${contents.substring(newlineIndex + 1)}`,\n );\n } else {\n tree.write(filePath, `${newImport}${contents}`);\n }\n }\n};\n\n/**\n * Ensure a Python `from <module> import <name1>, <name2>, ...` statement\n * exists in the given file. If the module already has a `from <module> import`\n * line, any missing names are appended; otherwise a fresh import statement is\n * prepended to the file (ruff's import sorter will reorder it into place on\n * the next format pass).\n *\n * We try to append first (which only succeeds if an import-from for the\n * module already exists AND the name isn't yet in the list). If nothing\n * was rewritten after trying every requested name, we fall back to checking\n * whether the module is imported at all; if not, we prepend a fresh\n * `from <module> import ...` line.\n */\nexport const addPythonDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n\n // Determine whether there's any `from <module> import ...` line in the file.\n // We detect this by attempting a no-op transformation — the file is unchanged,\n // but a successful match tells us the line exists.\n const beforeContents = tree.read(filePath)!.toString();\n let moduleAlreadyImported = false;\n for (const variableName of variableNames) {\n // Appends the name if the import-from exists and the name isn't already there.\n const appended = await applyGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { $names <: not contains \\`${variableName}\\`, $names += \\`, ${variableName}\\` }`,\n );\n if (appended) {\n moduleAlreadyImported = true;\n }\n }\n\n // If the append succeeded for at least one name, we know the module line\n // exists; we're done. If nothing was appended we need to distinguish\n // between \"module not imported\" (need to add a new line) and \"module\n // imported but all names already present\" (no-op).\n if (moduleAlreadyImported) {\n return;\n }\n\n const allAlreadyPresent = await matchGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { ${variableNames\n .map((n) => `$names <: contains \\`${n}\\``)\n .join(', ')} }`,\n );\n if (allAlreadyPresent) {\n return;\n }\n\n // No existing `from <module> import` line — prepend one. Ruff's import\n // sorter will place it in the right group on the next formatter pass.\n const specifiers = variableNames.join(', ');\n tree.write(filePath, `from ${from} import ${specifiers}\\n${beforeContents}`);\n};\n\n/**\n * Adds an `import <variableName> from '<from>'; statement to the beginning of the file,\n * if it doesn't already exist\n */\nexport const addSingleImport = async (\n tree: Tree,\n filePath: string,\n variableName: string,\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if default import already exists using GritQL\n const alreadyImported = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from '${from}'\\``,\n );\n if (alreadyImported) {\n return;\n }\n\n // The same identifier bound to a different module would be a duplicate\n // declaration, so refuse rather than emit a file that cannot compile.\n const identifierTaken = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from $module\\``,\n );\n if (identifierTaken) {\n throw new Error(\n `Cannot import ${variableName} from '${from}' in ${filePath}: ${variableName} is already imported from a different module. Rename the project so its generated identifier does not collide.`,\n );\n }\n\n // Prepend new import to file\n const contents = tree.read(filePath)!.toString();\n tree.write(filePath, `import ${variableName} from '${from}';\\n${contents}`);\n};\n\n/**\n * Adds an `export * from '<from>'; statement to the given TypeScript file.\n * Note that this will create the file if it does not exist in the tree.\n */\nexport const addStarExport = async (\n tree: Tree,\n filePath: string,\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n // For empty/non-existent files, just write the export\n if (!contents.trim()) {\n tree.write(filePath, `export * from '${from}';\\n`);\n return;\n }\n\n // Check if already exported using GritQL\n const alreadyExported = await matchGritQL(\n tree,\n filePath,\n `\\`export * from '${from}'\\``,\n );\n if (alreadyExported) {\n return;\n }\n\n // Prepend new export to file\n tree.write(filePath, `export * from '${from}';\\n${contents}`);\n};\n\n/**\n * Adds an `export { <names> } from '<from>';` statement to the given TypeScript\n * file, merging into an existing re-export of the same module when there is one.\n * Note that this will create the file if it does not exist in the tree.\n *\n * Adding to whatever is already there is what lets a barrel the user curates —\n * their own entities, models or components — survive a generator re-run while\n * the generated entry is still registered.\n */\nexport const addNamedExport = async (\n tree: Tree,\n filePath: string,\n names: string[],\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n if (!contents.trim()) {\n tree.write(filePath, `export { ${names.join(', ')} } from '${from}';\\n`);\n return;\n }\n\n const hasExistingExport = await matchGritQL(\n tree,\n filePath,\n `\\`export { $_ } from '${from}'\\``,\n );\n\n if (hasExistingExport) {\n for (const name of names) {\n await applyGritQL(\n tree,\n filePath,\n `\\`export { $names } from '${from}'\\` => \\`export { $names, ${name} } from '${from}'\\` where { $names <: not contains \\`${name}\\` }`,\n );\n }\n return;\n }\n\n const missing: string[] = [];\n for (const name of names) {\n if (!(await matchGritQL(tree, filePath, `\\`${name}\\``))) {\n missing.push(name);\n }\n }\n if (missing.length === 0) {\n return;\n }\n\n tree.write(\n filePath,\n `export { ${missing.join(', ')} } from '${from}';\\n${contents}`,\n );\n};\n\n/**\n * Return whether or not the given identifier is exported in the source file.\n * Checks for both `export { Identifier }` and `export type Identifier = ...`.\n */\nexport const hasExportDeclaration = async (\n tree: Tree,\n source: string,\n identifierName: string,\n): Promise<boolean> => {\n ensureGritDir(tree);\n const patterns = [\n `\\`export type ${identifierName} = $_\\``,\n `\\`export { ${identifierName} }\\``,\n `\\`export type { ${identifierName} } from $_\\``,\n ];\n\n for (const pattern of patterns) {\n try {\n const q = new QueryBuilder(`$p => $p where { $p <: ${pattern} }`);\n const result = await q.applyToFile({\n path: 'check.ts',\n content: source,\n });\n if (result !== null) return true;\n } catch {\n // Pattern didn't match, try next\n }\n }\n\n return false;\n};\n\n/**\n * Apply a GritQL pattern to a file in the Nx tree.\n */\nexport const applyGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) throw new Error(`No file at ${filePath}`);\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const query = new QueryBuilder(pattern);\n const result = await query.applyToFile({ path: filePath, content: source });\n if (result && result.content !== source) {\n tree.write(filePath, result.content);\n return true;\n }\n return false;\n};\n\n/**\n * Check whether a GritQL pattern matches anywhere in a file.\n * Returns true if the pattern matches at least once.\n *\n * Accepts raw GritQL, including patterns that start with a `language <name>`\n * header (e.g. `language python\\n\\`print($_)\\``) — the pattern is passed\n * straight through to QueryBuilder without any wrapping rewrite.\n */\nexport const matchGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) return false;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let matched = false;\n try {\n const query = new QueryBuilder(pattern);\n query.filter(() => {\n matched = true;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return false;\n }\n return matched;\n};\n\n/**\n * Capture the source text of the first match of a GritQL pattern.\n *\n * For example `` `dependencyCheck: $_` `` returns the whole\n * `dependencyCheck: { ... }` property text. Returns undefined if nothing\n * matches. The file is not modified.\n */\nexport const captureGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.text();\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Like `captureGritQL`, but returns one metavariable's binding (e.g. `mod`\n * for `$mod`) instead of the whole matched node.\n */\nexport const captureGritQLVariable = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n variableName: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n // The underlying binding lookup requires the `$` sigil.\n const name = variableName.startsWith('$') ? variableName : `$${variableName}`;\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.var(name) ?? undefined;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Like {@link captureAllGritQL}, but returns one metavariable's binding for every\n * match rather than the whole matched node.\n *\n * This is what lets a caller work on the value a pattern isolated — matching\n * `` `runtime: $value` `` and reading `$value` gives `Runtime.NODEJS_24_X` alone,\n * so nothing downstream has to re-derive the assignment around it.\n *\n * A match whose metavariable is unbound contributes nothing, so the result holds\n * only real bindings. Returns undefined if the pattern could not be applied,\n * which an empty array cannot express.\n */\nexport const captureAllGritQLVariable = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n variableName: string,\n): Promise<string[] | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n // The underlying binding lookup requires the `$` sigil.\n const name = variableName.startsWith('$') ? variableName : `$${variableName}`;\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n const bound = node.var(name);\n if (bound !== null && bound !== undefined) {\n captured.push(bound);\n }\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Return the text of every node matching the GritQL pattern, in document order.\n */\nexport const captureAllGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string[]> => {\n if (!tree.exists(filePath)) return [];\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured.push(node.text());\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return [];\n }\n return captured;\n};\n\n/**\n * A unique token that is a valid identifier, so it can stand in for an array\n * element or object property inside a GritQL rewrite.\n */\nexport const GRIT_INSERT_PLACEHOLDER = '__GRIT_INSERT_PLACEHOLDER__';\n\n/**\n * Apply a GritQL rewrite that inserts {@link GRIT_INSERT_PLACEHOLDER}, then\n * replace the placeholder with `text`. Routing user-provided text through a\n * placeholder keeps it out of the GritQL pattern, where quotes, backticks or\n * `${...}` would otherwise break parsing.\n *\n * Any separator (e.g. a leading `, ` when appending to an array) must be part\n * of the GritQL pattern, not `text`. The one adjustment made here: if the\n * placeholder lands after a trailing line comment (`// ...`) — which would\n * comment out the text — the text is moved to its own line.\n *\n * The caller formats afterwards. Returns true if the pattern matched and the\n * file changed.\n */\nexport const insertViaGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n text: string,\n): Promise<boolean> => {\n if (!(await applyGritQL(tree, filePath, pattern))) return false;\n const content = tree.read(filePath)!.toString();\n const at = content.indexOf(GRIT_INSERT_PLACEHOLDER);\n const lineSoFar = content.slice(content.lastIndexOf('\\n', at) + 1, at);\n const replacement = lineSoFar.includes('//') ? `\\n${text}` : text;\n\n // Function replacer so `$` in `text` isn't treated as a replacement pattern.\n tree.write(\n filePath,\n content.replace(GRIT_INSERT_PLACEHOLDER, () => replacement),\n );\n return true;\n};\n\n/**\n * Append `entry` to an array, skipping arrays that already contain it, e.g.\n * `` appendToArrayViaGritQL(tree, file, 'tools:', 'myTool', { scope: 'new Agent($_)' }) ``\n * turns `tools: [a, b]` into `tools: [a, b, myTool]`.\n *\n * `arrayPrefix` is whatever precedes the array literal, including its separator —\n * `'tools:'` for an object property, `'tools='` for a keyword argument or\n * assignment, `'\"tools\":'` for a quoted key. Which separator applies depends on\n * the construct rather than the language, so the caller states it.\n *\n * Appends after the last *element* rather than rewriting the element list with\n * `=>`. GritQL binds a `[$items]` list to its trailing comma too, so\n * `` `[$items]` => `[$items, entry]` `` emits the sparse array `[a, b, , entry]`\n * once the formatter has wrapped the array — a hole that is `undefined` at\n * runtime. (Accumulating with `$items += \", entry\"` is safe by comparison, since\n * it appends within the list rather than re-emitting it; both forms appear in\n * this repo.)\n *\n * `scope` limits the match to an enclosing pattern, so same-named arrays\n * elsewhere in the file are left alone. `skipIfContains` overrides what the\n * append dedupes on, for when the rendered entry is not the identifier to match.\n *\n * The caller formats afterwards. Returns true if the entry was appended.\n */\nexport const appendToArrayViaGritQL = async (\n tree: Tree,\n filePath: string,\n arrayPrefix: string,\n entry: string,\n options: { scope?: string; skipIfContains?: string; language?: 'py' } = {},\n): Promise<boolean> => {\n const { scope, skipIfContains, language } = options;\n const within = (variable: string) =>\n scope ? `${variable} <: within \\`${scope}\\`, ` : '';\n const pattern =\n `or {` +\n // An empty array has no last element to append after.\n ` \\`${arrayPrefix}$arr\\` where { $arr <: \\`[]\\`, ${within('$arr')}` +\n ` $arr => \\`[${GRIT_INSERT_PLACEHOLDER}]\\` },` +\n // Dedupe on the list, append after its last element.\n ` \\`${arrayPrefix}[$items]\\` where {` +\n ` $items <: not contains \\`${skipIfContains ?? entry}\\`, ${within('$items')}` +\n ` $items <: [$..., $last], $last += \\`, ${GRIT_INSERT_PLACEHOLDER}\\` }` +\n ` }`;\n\n return insertViaGritQL(\n tree,\n filePath,\n language === 'py' ? `language python\\n${pattern}` : pattern,\n entry,\n );\n};\n"],"names":["QueryBuilder","path","updateGitIgnore","isEsmWorkspace","GRIT_DIR","normalizeModuleSpecifier","tree","from","isRelative","startsWith","endsWith","slice","length","ensureGritDir","process","env","GRIT_GLOBAL_DIR","join","root","patterns","assertFilePath","filePath","exists","Error","addDestructuredImport","variableNames","hasExistingImport","matchGritQL","variableName","localName","includes","split","applyGritQL","specifiers","contents","read","toString","newImport","newlineIndex","indexOf","write","substring","addPythonDestructuredImport","beforeContents","moduleAlreadyImported","appended","allAlreadyPresent","map","n","addSingleImport","alreadyImported","identifierTaken","addStarExport","trim","alreadyExported","addNamedExport","names","hasExistingExport","name","missing","push","hasExportDeclaration","source","identifierName","pattern","q","result","applyToFile","content","query","matched","filter","captureGritQL","undefined","captured","node","text","captureGritQLVariable","var","captureAllGritQLVariable","bound","captureAllGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","at","lineSoFar","lastIndexOf","replacement","replace","appendToArrayViaGritQL","arrayPrefix","entry","options","scope","skipIfContains","language","within","variable"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/ast.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { QueryBuilder } from '@getgrit/gritql';\nimport type { Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport {\n LANGUAGE_COMMENT_SYNTAX,\n readLicenseConfig,\n} from '../license/config.js';\nimport type { CommentSyntax } from '../license/config-types.js';\nimport { parseFile } from '../license/sync/generator.js';\nimport { updateGitIgnore } from './git.js';\nimport { isEsmWorkspace } from './module-format.js';\n\nconst GRIT_DIR = '.grit';\n\n/**\n * Normalize a relative module specifier for the workspace's module format.\n * ESM (`nodenext`) requires an explicit `.js` extension on relative imports;\n * CommonJS (`node16`) resolves them extensionless. Callers always pass the ESM\n * form (with `.js`); this strips the extension for CommonJS workspaces.\n */\nconst normalizeModuleSpecifier = (tree: Tree, from: string): string => {\n if (isEsmWorkspace(tree)) {\n return from;\n }\n const isRelative = from.startsWith('./') || from.startsWith('../');\n return isRelative && from.endsWith('.js')\n ? from.slice(0, -'.js'.length)\n : from;\n};\n\n// Pin the gritql native library's \"global\" stdlib directory to <workspace>/.grit so it doesn't try to write to /usr/local/.grit (or wherever node's grandparent resolves to).\nconst ensureGritDir = (tree: Tree) => {\n process.env.GRIT_GLOBAL_DIR ??= path.join(tree.root, GRIT_DIR);\n updateGitIgnore(tree, '.', (patterns) => [...patterns, GRIT_DIR]);\n};\n\nconst assertFilePath = (tree: Tree, filePath: string) => {\n if (!tree.exists(filePath)) {\n throw new Error(`No file located at ${filePath}`);\n }\n};\n\n/**\n * Insert `statement` at the top of a file, below any hashbang and leading\n * comment block. Keeps a license header first in the file, so `license#sync`\n * doesn't see it displaced and prepend a second one.\n *\n * The leading comment is skipped whatever it says — a header, a placeholder or a\n * note — so nothing here has to identify a license.\n *\n * Splits the file with the sync generator's own `parseFile`, resolving the\n * comment syntax the way the sync does: the workspace's configured\n * `commentSyntax` for the extension first, then the built-in table. That way an\n * extension only the user's config covers is still recognised. An extension\n * neither covers has no comment syntax to find, so the statement goes at the top.\n */\nconst insertBelowLeadingComments = async (\n tree: Tree,\n filePath: string,\n contents: string,\n statement: string,\n): Promise<string> => {\n const extension = filePath.split('.').pop() ?? '';\n let syntax: CommentSyntax | undefined;\n try {\n syntax = (await readLicenseConfig(tree))?.source?.header?.commentSyntax?.[\n extension\n ];\n } catch {\n // Reading the config evaluates it, which throws on a config that doesn't\n // load — including this file itself while a generator is mid-edit. A config\n // we can't read must not stop an import being added, so fall back to the\n // defaults. (A config that simply doesn't exist reads as undefined.)\n }\n syntax ??= LANGUAGE_COMMENT_SYNTAX[extension];\n if (!syntax) {\n return `${statement}\\n${contents}`;\n }\n\n const { hashbang, header, body } = parseFile(contents, syntax);\n if (!hashbang && !header) {\n return `${statement}\\n${contents}`;\n }\n return [\n ...(hashbang ? [hashbang] : []),\n ...(header ? [header] : []),\n statement,\n body,\n ].join('\\n');\n};\n\nexport const addDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if there's an existing import from this module\n const hasExistingImport = await matchGritQL(\n tree,\n filePath,\n `\\`import { $_ } from '${from}'\\``,\n );\n\n if (hasExistingImport) {\n // For each new variable, use GritQL rewrite to add it if not already present\n for (const variableName of variableNames) {\n const localName = variableName.includes(' as ')\n ? variableName.split(' as ')[1]\n : variableName;\n // Use rewrite (=>) which correctly handles comma-separated import specifier lists\n await applyGritQL(\n tree,\n filePath,\n `\\`import { $imports } from '${from}'\\` => \\`import { $imports, ${variableName} } from '${from}'\\` where { $imports <: not contains \\`${localName}\\` }`,\n );\n }\n } else {\n // No existing import — add a new one below any hashbang and leading comment\n const specifiers = variableNames.join(', ');\n const contents = tree.read(filePath)!.toString();\n tree.write(\n filePath,\n await insertBelowLeadingComments(\n tree,\n filePath,\n contents,\n `import { ${specifiers} } from '${from}';`,\n ),\n );\n }\n};\n\n/**\n * Ensure a Python `from <module> import <name1>, <name2>, ...` statement\n * exists in the given file. If the module already has a `from <module> import`\n * line, any missing names are appended; otherwise a fresh import statement is\n * prepended to the file (ruff's import sorter will reorder it into place on\n * the next format pass).\n *\n * We try to append first (which only succeeds if an import-from for the\n * module already exists AND the name isn't yet in the list). If nothing\n * was rewritten after trying every requested name, we fall back to checking\n * whether the module is imported at all; if not, we prepend a fresh\n * `from <module> import ...` line.\n */\nexport const addPythonDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n\n // Determine whether there's any `from <module> import ...` line in the file.\n // We detect this by attempting a no-op transformation — the file is unchanged,\n // but a successful match tells us the line exists.\n const beforeContents = tree.read(filePath)!.toString();\n let moduleAlreadyImported = false;\n for (const variableName of variableNames) {\n // Appends the name if the import-from exists and the name isn't already there.\n const appended = await applyGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { $names <: not contains \\`${variableName}\\`, $names += \\`, ${variableName}\\` }`,\n );\n if (appended) {\n moduleAlreadyImported = true;\n }\n }\n\n // If the append succeeded for at least one name, we know the module line\n // exists; we're done. If nothing was appended we need to distinguish\n // between \"module not imported\" (need to add a new line) and \"module\n // imported but all names already present\" (no-op).\n if (moduleAlreadyImported) {\n return;\n }\n\n const allAlreadyPresent = await matchGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { ${variableNames\n .map((n) => `$names <: contains \\`${n}\\``)\n .join(', ')} }`,\n );\n if (allAlreadyPresent) {\n return;\n }\n\n // No existing `from <module> import` line — add one below any hashbang and\n // leading comment. Ruff's import sorter will place it in the right group on\n // the next formatter pass.\n const specifiers = variableNames.join(', ');\n tree.write(\n filePath,\n await insertBelowLeadingComments(\n tree,\n filePath,\n beforeContents,\n `from ${from} import ${specifiers}`,\n ),\n );\n};\n\n/**\n * Adds an `import <variableName> from '<from>'; statement to the beginning of the file,\n * if it doesn't already exist\n */\nexport const addSingleImport = async (\n tree: Tree,\n filePath: string,\n variableName: string,\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if default import already exists using GritQL\n const alreadyImported = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from '${from}'\\``,\n );\n if (alreadyImported) {\n return;\n }\n\n // The same identifier bound to a different module would be a duplicate\n // declaration, so refuse rather than emit a file that cannot compile.\n const identifierTaken = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from $module\\``,\n );\n if (identifierTaken) {\n throw new Error(\n `Cannot import ${variableName} from '${from}' in ${filePath}: ${variableName} is already imported from a different module. Rename the project so its generated identifier does not collide.`,\n );\n }\n\n // Add the import below any hashbang and leading comment\n const contents = tree.read(filePath)!.toString();\n tree.write(\n filePath,\n await insertBelowLeadingComments(\n tree,\n filePath,\n contents,\n `import ${variableName} from '${from}';`,\n ),\n );\n};\n\n/**\n * Adds an `export * from '<from>'; statement to the given TypeScript file.\n * Note that this will create the file if it does not exist in the tree.\n */\nexport const addStarExport = async (\n tree: Tree,\n filePath: string,\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n // For empty/non-existent files, just write the export\n if (!contents.trim()) {\n tree.write(filePath, `export * from '${from}';\\n`);\n return;\n }\n\n // Check if already exported using GritQL\n const alreadyExported = await matchGritQL(\n tree,\n filePath,\n `\\`export * from '${from}'\\``,\n );\n if (alreadyExported) {\n return;\n }\n\n tree.write(\n filePath,\n await insertBelowLeadingComments(\n tree,\n filePath,\n contents,\n `export * from '${from}';`,\n ),\n );\n};\n\n/**\n * Adds an `export { <names> } from '<from>';` statement to the given TypeScript\n * file, merging into an existing re-export of the same module when there is one.\n * Note that this will create the file if it does not exist in the tree.\n *\n * Adding to whatever is already there is what lets a barrel the user curates —\n * their own entities, models or components — survive a generator re-run while\n * the generated entry is still registered.\n */\nexport const addNamedExport = async (\n tree: Tree,\n filePath: string,\n names: string[],\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n if (!contents.trim()) {\n tree.write(filePath, `export { ${names.join(', ')} } from '${from}';\\n`);\n return;\n }\n\n const hasExistingExport = await matchGritQL(\n tree,\n filePath,\n `\\`export { $_ } from '${from}'\\``,\n );\n\n if (hasExistingExport) {\n for (const name of names) {\n await applyGritQL(\n tree,\n filePath,\n `\\`export { $names } from '${from}'\\` => \\`export { $names, ${name} } from '${from}'\\` where { $names <: not contains \\`${name}\\` }`,\n );\n }\n return;\n }\n\n const missing: string[] = [];\n for (const name of names) {\n if (!(await matchGritQL(tree, filePath, `\\`${name}\\``))) {\n missing.push(name);\n }\n }\n if (missing.length === 0) {\n return;\n }\n\n tree.write(\n filePath,\n await insertBelowLeadingComments(\n tree,\n filePath,\n contents,\n `export { ${missing.join(', ')} } from '${from}';`,\n ),\n );\n};\n\n/**\n * Return whether or not the given identifier is exported in the source file.\n * Checks for both `export { Identifier }` and `export type Identifier = ...`.\n */\nexport const hasExportDeclaration = async (\n tree: Tree,\n source: string,\n identifierName: string,\n): Promise<boolean> => {\n ensureGritDir(tree);\n const patterns = [\n `\\`export type ${identifierName} = $_\\``,\n `\\`export { ${identifierName} }\\``,\n `\\`export type { ${identifierName} } from $_\\``,\n ];\n\n for (const pattern of patterns) {\n try {\n const q = new QueryBuilder(`$p => $p where { $p <: ${pattern} }`);\n const result = await q.applyToFile({\n path: 'check.ts',\n content: source,\n });\n if (result !== null) return true;\n } catch {\n // Pattern didn't match, try next\n }\n }\n\n return false;\n};\n\n/**\n * Apply a GritQL pattern to a file in the Nx tree.\n */\nexport const applyGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) throw new Error(`No file at ${filePath}`);\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const query = new QueryBuilder(pattern);\n const result = await query.applyToFile({ path: filePath, content: source });\n if (result && result.content !== source) {\n tree.write(filePath, result.content);\n return true;\n }\n return false;\n};\n\n/**\n * Check whether a GritQL pattern matches anywhere in a file.\n * Returns true if the pattern matches at least once.\n *\n * Accepts raw GritQL, including patterns that start with a `language <name>`\n * header (e.g. `language python\\n\\`print($_)\\``) — the pattern is passed\n * straight through to QueryBuilder without any wrapping rewrite.\n */\nexport const matchGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) return false;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let matched = false;\n try {\n const query = new QueryBuilder(pattern);\n query.filter(() => {\n matched = true;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return false;\n }\n return matched;\n};\n\n/**\n * Capture the source text of the first match of a GritQL pattern.\n *\n * For example `` `dependencyCheck: $_` `` returns the whole\n * `dependencyCheck: { ... }` property text. Returns undefined if nothing\n * matches. The file is not modified.\n */\nexport const captureGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.text();\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Like `captureGritQL`, but returns one metavariable's binding (e.g. `mod`\n * for `$mod`) instead of the whole matched node.\n */\nexport const captureGritQLVariable = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n variableName: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n // The underlying binding lookup requires the `$` sigil.\n const name = variableName.startsWith('$') ? variableName : `$${variableName}`;\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.var(name) ?? undefined;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Like {@link captureAllGritQL}, but returns one metavariable's binding for every\n * match rather than the whole matched node.\n *\n * This is what lets a caller work on the value a pattern isolated — matching\n * `` `runtime: $value` `` and reading `$value` gives `Runtime.NODEJS_24_X` alone,\n * so nothing downstream has to re-derive the assignment around it.\n *\n * A match whose metavariable is unbound contributes nothing, so the result holds\n * only real bindings. Returns undefined if the pattern could not be applied,\n * which an empty array cannot express.\n */\nexport const captureAllGritQLVariable = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n variableName: string,\n): Promise<string[] | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n // The underlying binding lookup requires the `$` sigil.\n const name = variableName.startsWith('$') ? variableName : `$${variableName}`;\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n const bound = node.var(name);\n if (bound !== null && bound !== undefined) {\n captured.push(bound);\n }\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Return the text of every node matching the GritQL pattern, in document order.\n */\nexport const captureAllGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string[]> => {\n if (!tree.exists(filePath)) return [];\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured.push(node.text());\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return [];\n }\n return captured;\n};\n\n/**\n * A unique token that is a valid identifier, so it can stand in for an array\n * element or object property inside a GritQL rewrite.\n */\nexport const GRIT_INSERT_PLACEHOLDER = '__GRIT_INSERT_PLACEHOLDER__';\n\n/**\n * Apply a GritQL rewrite that inserts {@link GRIT_INSERT_PLACEHOLDER}, then\n * replace the placeholder with `text`. Routing user-provided text through a\n * placeholder keeps it out of the GritQL pattern, where quotes, backticks or\n * `${...}` would otherwise break parsing.\n *\n * Any separator (e.g. a leading `, ` when appending to an array) must be part\n * of the GritQL pattern, not `text`. The one adjustment made here: if the\n * placeholder lands after a trailing line comment (`// ...`) — which would\n * comment out the text — the text is moved to its own line.\n *\n * The caller formats afterwards. Returns true if the pattern matched and the\n * file changed.\n */\nexport const insertViaGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n text: string,\n): Promise<boolean> => {\n if (!(await applyGritQL(tree, filePath, pattern))) return false;\n const content = tree.read(filePath)!.toString();\n const at = content.indexOf(GRIT_INSERT_PLACEHOLDER);\n const lineSoFar = content.slice(content.lastIndexOf('\\n', at) + 1, at);\n const replacement = lineSoFar.includes('//') ? `\\n${text}` : text;\n\n // Function replacer so `$` in `text` isn't treated as a replacement pattern.\n tree.write(\n filePath,\n content.replace(GRIT_INSERT_PLACEHOLDER, () => replacement),\n );\n return true;\n};\n\n/**\n * Append `entry` to an array, skipping arrays that already contain it, e.g.\n * `` appendToArrayViaGritQL(tree, file, 'tools:', 'myTool', { scope: 'new Agent($_)' }) ``\n * turns `tools: [a, b]` into `tools: [a, b, myTool]`.\n *\n * `arrayPrefix` is whatever precedes the array literal, including its separator —\n * `'tools:'` for an object property, `'tools='` for a keyword argument or\n * assignment, `'\"tools\":'` for a quoted key. Which separator applies depends on\n * the construct rather than the language, so the caller states it.\n *\n * Appends after the last *element* rather than rewriting the element list with\n * `=>`. GritQL binds a `[$items]` list to its trailing comma too, so\n * `` `[$items]` => `[$items, entry]` `` emits the sparse array `[a, b, , entry]`\n * once the formatter has wrapped the array — a hole that is `undefined` at\n * runtime. (Accumulating with `$items += \", entry\"` is safe by comparison, since\n * it appends within the list rather than re-emitting it; both forms appear in\n * this repo.)\n *\n * `scope` limits the match to an enclosing pattern, so same-named arrays\n * elsewhere in the file are left alone. `skipIfContains` overrides what the\n * append dedupes on, for when the rendered entry is not the identifier to match.\n *\n * The caller formats afterwards. Returns true if the entry was appended.\n */\nexport const appendToArrayViaGritQL = async (\n tree: Tree,\n filePath: string,\n arrayPrefix: string,\n entry: string,\n options: { scope?: string; skipIfContains?: string; language?: 'py' } = {},\n): Promise<boolean> => {\n const { scope, skipIfContains, language } = options;\n const within = (variable: string) =>\n scope ? `${variable} <: within \\`${scope}\\`, ` : '';\n const pattern =\n `or {` +\n // An empty array has no last element to append after.\n ` \\`${arrayPrefix}$arr\\` where { $arr <: \\`[]\\`, ${within('$arr')}` +\n ` $arr => \\`[${GRIT_INSERT_PLACEHOLDER}]\\` },` +\n // Dedupe on the list, append after its last element.\n ` \\`${arrayPrefix}[$items]\\` where {` +\n ` $items <: not contains \\`${skipIfContains ?? entry}\\`, ${within('$items')}` +\n ` $items <: [$..., $last], $last += \\`, ${GRIT_INSERT_PLACEHOLDER}\\` }` +\n ` }`;\n\n return insertViaGritQL(\n tree,\n filePath,\n language === 'py' ? `language python\\n${pattern}` : pattern,\n entry,\n );\n};\n"],"names":["QueryBuilder","path","LANGUAGE_COMMENT_SYNTAX","readLicenseConfig","parseFile","updateGitIgnore","isEsmWorkspace","GRIT_DIR","normalizeModuleSpecifier","tree","from","isRelative","startsWith","endsWith","slice","length","ensureGritDir","process","env","GRIT_GLOBAL_DIR","join","root","patterns","assertFilePath","filePath","exists","Error","insertBelowLeadingComments","contents","statement","extension","split","pop","syntax","source","header","commentSyntax","hashbang","body","addDestructuredImport","variableNames","hasExistingImport","matchGritQL","variableName","localName","includes","applyGritQL","specifiers","read","toString","write","addPythonDestructuredImport","beforeContents","moduleAlreadyImported","appended","allAlreadyPresent","map","n","addSingleImport","alreadyImported","identifierTaken","addStarExport","trim","alreadyExported","addNamedExport","names","hasExistingExport","name","missing","push","hasExportDeclaration","identifierName","pattern","q","result","applyToFile","content","query","matched","filter","captureGritQL","undefined","captured","node","text","captureGritQLVariable","var","captureAllGritQLVariable","bound","captureAllGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","at","indexOf","lineSoFar","lastIndexOf","replacement","replace","appendToArrayViaGritQL","arrayPrefix","entry","options","scope","skipIfContains","language","within","variable"],"mappings":"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"}
@@ -16,3 +16,13 @@ export declare const catalogsEnabled: (tree: Tree) => boolean;
16
16
  * and the root for shared tooling.
17
17
  */
18
18
  export declare const addDependenciesToPackageJson: (tree: Tree, dependencies: Record<string, string>, devDependencies: Record<string, string>, packageJsonPath?: string) => GeneratorCallback;
19
+ /**
20
+ * Drop-in replacement for devkit's `removeDependenciesFromPackageJson` that
21
+ * also drops the package manager's catalog entry, which devkit leaves behind
22
+ * pointing at a package nothing declares any more.
23
+ *
24
+ * The entry is only dropped once no manifest in the workspace declares the
25
+ * package, so removing it from one project leaves another project's reference
26
+ * resolvable.
27
+ */
28
+ export declare const removeDependenciesFromPackageJson: (tree: Tree, dependencies: string[], devDependencies: string[], packageJsonPath?: string) => GeneratorCallback;