@aws/nx-plugin 1.0.0-rc.96 → 1.0.0-rc.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/LICENSE-THIRD-PARTY +9 -9
  2. package/migrations.json +124 -84
  3. package/package.json +3 -3
  4. package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +2 -2
  5. package/src/agentcore-gateway/generator.js +6 -0
  6. package/src/agentcore-gateway/generator.js.map +1 -1
  7. package/src/agentcore-gateway/react-connection/__snapshots__/generator.spec.ts.snap +4 -1
  8. package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +68 -4
  9. package/src/agentcore-harness/generator.js +6 -0
  10. package/src/agentcore-harness/generator.js.map +1 -1
  11. package/src/connection/gateway-runtime-config.js +1 -1
  12. package/src/connection/gateway-runtime-config.js.map +1 -1
  13. package/src/infra/app/__snapshots__/generator.spec.ts.snap +10 -10
  14. package/src/infra/app/generator.js +39 -9
  15. package/src/infra/app/generator.js.map +1 -1
  16. package/src/init/generator.d.ts +1 -1
  17. package/src/init/generator.js +8 -6
  18. package/src/init/generator.js.map +1 -1
  19. package/src/init/schema.d.js.map +1 -1
  20. package/src/init/schema.d.ts +1 -0
  21. package/src/init/schema.json +5 -0
  22. package/src/internal/test-matrix/generator.js +2 -2
  23. package/src/internal/test-matrix/generator.js.map +1 -1
  24. package/src/license/sync/generator.d.ts +10 -0
  25. package/src/license/sync/generator.js +1 -1
  26. package/src/license/sync/generator.js.map +1 -1
  27. package/src/mcp-server/server.js +2 -0
  28. package/src/mcp-server/server.js.map +1 -1
  29. package/src/mcp-server/tools/best-practices.d.ts +28 -0
  30. package/src/mcp-server/tools/best-practices.js +43 -0
  31. package/src/mcp-server/tools/best-practices.js.map +1 -0
  32. package/src/mcp-server/tools/general-guidance.d.ts +1 -1
  33. package/src/mcp-server/tools/general-guidance.js +13 -4
  34. package/src/mcp-server/tools/general-guidance.js.map +1 -1
  35. package/src/migrations/latest/sandbox-pattern-nested-stacks/metadata.json +3 -0
  36. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js +68 -0
  37. package/src/migrations/latest/sandbox-pattern-nested-stacks/migration.js.map +1 -0
  38. package/src/migrations/latest/shadcn-cn-package/metadata.json +3 -0
  39. package/src/migrations/latest/shadcn-cn-package/migration.js +114 -0
  40. package/src/migrations/latest/shadcn-cn-package/migration.js.map +1 -0
  41. package/src/migrations/v1.0.0-rc.90/0001-dev-target-depends-on-pull-image/migration.js.map +1 -0
  42. package/src/migrations/v1.0.0-rc.90/0002-open-api-codegen-executor/migration.js.map +1 -0
  43. package/src/migrations/v1.0.0-rc.90/0003-terraform-provider-plugin-cache/migration.js.map +1 -0
  44. package/src/migrations/v1.0.0-rc.90/0004-python-test-input-scoping/migration.js.map +1 -0
  45. package/src/migrations/v1.0.0-rc.90/0005-vitest-coverage-output-dir/migration.js.map +1 -0
  46. package/src/migrations/v1.0.0-rc.90/0006-add-assemble-target/migration.js.map +1 -0
  47. package/src/migrations/v1.0.0-rc.90/0007-docker-target-cache-soundness/migration.js.map +1 -0
  48. package/src/migrations/v1.0.0-rc.90/0008-declare-cacheable-target-inputs/migration.js.map +1 -0
  49. package/src/migrations/v1.0.0-rc.90/0009-terraform-fmt-check/migration.js.map +1 -0
  50. package/src/migrations/v1.0.0-rc.92/0001-react-website-unique-dev-ports/migration.js.map +1 -0
  51. package/src/migrations/v1.0.0-rc.94/0001-infra-deploy-express-mode/metadata.json +3 -0
  52. package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.js +26 -28
  53. package/src/migrations/v1.0.0-rc.94/0001-infra-deploy-express-mode/migration.js.map +1 -0
  54. package/src/migrations/v1.0.0-rc.94/0002-shx-fs-commands/migration.js.map +1 -0
  55. package/src/migrations/v1.0.0-rc.94/0003-agent-core-vendor-target/migration.js.map +1 -0
  56. package/src/migrations/v1.0.0-rc.95/0001-rolldown-config-bundle-transient/migration.d.ts +6 -0
  57. package/src/migrations/v1.0.0-rc.95/0001-rolldown-config-bundle-transient/migration.js.map +1 -0
  58. package/src/migrations/v1.0.0-rc.95/0002-agent-connection-pin-strands-peers/migration.js.map +1 -0
  59. package/src/migrations/v1.0.0-rc.95/0003-ignore-package-manager-temp-files/migration.js.map +1 -0
  60. package/src/migrations/v1.0.0-rc.95/0004-shadcn-package-imports-exports/migration.d.ts +6 -0
  61. package/src/migrations/v1.0.0-rc.95/0004-shadcn-package-imports-exports/migration.js.map +1 -0
  62. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/__snapshots__/migration.spec.ts.snap +84 -0
  63. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/metadata.json +3 -0
  64. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.d.ts +6 -0
  65. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.js +94 -0
  66. package/src/migrations/v1.0.0-rc.97/0001-gateway-url-accessor/migration.js.map +1 -0
  67. package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/metadata.json +3 -0
  68. package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.d.ts +6 -0
  69. package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.js +58 -0
  70. package/src/migrations/v1.0.0-rc.97/0002-checkov-scan-cache-inputs/migration.js.map +1 -0
  71. package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/metadata.json +3 -0
  72. package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.d.ts +6 -0
  73. package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.js +84 -0
  74. package/src/migrations/v1.0.0-rc.97/0003-terraform-validate-without-backend/migration.js.map +1 -0
  75. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/metadata.json +3 -0
  76. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.d.ts +6 -0
  77. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.js +58 -0
  78. package/src/migrations/v1.0.0-rc.97/0004-py-lambda-powertools-context/migration.js.map +1 -0
  79. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/__snapshots__/migration.spec.ts.snap +25 -0
  80. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/metadata.json +3 -0
  81. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.d.ts +28 -0
  82. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.js +75 -0
  83. package/src/migrations/v1.0.0-rc.97/0005-smithy-extension-trait-aliases/migration.js.map +1 -0
  84. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/metadata.json +3 -0
  85. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.d.ts +6 -0
  86. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.js +53 -0
  87. package/src/migrations/v1.0.0-rc.97/0006-script-project-quality-gates/migration.js.map +1 -0
  88. package/src/preset/__snapshots__/generator.spec.ts.snap +2 -2
  89. package/src/preset/generator.js +4 -25
  90. package/src/preset/generator.js.map +1 -1
  91. package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +2 -2
  92. package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +4 -4
  93. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +4 -4
  94. package/src/py/agent/a2a-connection/generator.d.ts +1 -1
  95. package/src/py/agent/gateway-connection/generator.d.ts +1 -1
  96. package/src/py/agent/mcp-connection/generator.d.ts +1 -1
  97. package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +4 -1
  98. package/src/py/agent/react-connection/generator.d.ts +1 -7
  99. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +10 -12
  100. package/src/py/dynamodb/generator.js +34 -7
  101. package/src/py/dynamodb/generator.js.map +1 -1
  102. package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +12 -12
  103. package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +4 -3
  104. package/src/py/lambda-function/files/handler/__lambdaFunctionSnakeCase__.py.template +2 -1
  105. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
  106. package/src/py/project/schema.json +3 -1
  107. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +31 -15
  108. package/src/py/rdb/files/Dockerfile.create-db-user.template +7 -3
  109. package/src/py/rdb/files/Dockerfile.migration.template +7 -3
  110. package/src/py/rdb/generator.js +29 -28
  111. package/src/py/rdb/generator.js.map +1 -1
  112. package/src/smithy/project/__snapshots__/generator.spec.ts.snap +5 -5
  113. package/src/smithy/react-connection/files/model/extensions.smithy.template +3 -3
  114. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +8 -8
  115. package/src/smithy/ts/api/generator.js +7 -2
  116. package/src/smithy/ts/api/generator.js.map +1 -1
  117. package/src/terraform/project/generator.js +34 -10
  118. package/src/terraform/project/generator.js.map +1 -1
  119. package/src/terraform/project/schema.d.js +0 -3
  120. package/src/terraform/project/schema.d.js.map +1 -1
  121. package/src/terraform/project/schema.d.ts +0 -4
  122. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +12 -12
  123. package/src/trpc/backend/generator.js +7 -1
  124. package/src/trpc/backend/generator.js.map +1 -1
  125. package/src/trpc/react/generator.js +6 -0
  126. package/src/trpc/react/generator.js.map +1 -1
  127. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +4 -4
  128. package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -2
  129. package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +2 -2
  130. package/src/ts/agent/generator.js +3 -3
  131. package/src/ts/agent/generator.js.map +1 -1
  132. package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -2
  133. package/src/ts/agent/react-connection/generator.d.ts +1 -9
  134. package/src/ts/astro-docs/files/translation/scripts/translate.ts.template +47 -2
  135. package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +1 -1
  136. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +6 -4
  137. package/src/ts/dynamodb/generator.js +30 -6
  138. package/src/ts/dynamodb/generator.js.map +1 -1
  139. package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +2 -2
  140. package/src/ts/lib/biome.d.ts +15 -1
  141. package/src/ts/lib/biome.js +79 -63
  142. package/src/ts/lib/biome.js.map +1 -1
  143. package/src/ts/lib/generator.js +11 -7
  144. package/src/ts/lib/generator.js.map +1 -1
  145. package/src/ts/lib/ts-project-utils.d.ts +14 -0
  146. package/src/ts/lib/ts-project-utils.js +24 -0
  147. package/src/ts/lib/ts-project-utils.js.map +1 -1
  148. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +3 -3
  149. package/src/ts/mcp-server/files/app/http.ts.template +1 -1
  150. package/src/ts/mcp-server/generator.js +3 -3
  151. package/src/ts/mcp-server/generator.js.map +1 -1
  152. package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +2 -2
  153. package/src/ts/nx-generator/files/local/generator.spec.ts.template +2 -2
  154. package/src/ts/nx-migration/generator.js +3 -1
  155. package/src/ts/nx-migration/generator.js.map +1 -1
  156. package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +1 -25
  157. package/src/ts/nx-plugin/generator.js +19 -17
  158. package/src/ts/nx-plugin/generator.js.map +1 -1
  159. package/src/ts/nx-plugin/utils.d.ts +21 -0
  160. package/src/ts/nx-plugin/utils.js +41 -1
  161. package/src/ts/nx-plugin/utils.js.map +1 -1
  162. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +13 -8
  163. package/src/ts/rdb/files/Dockerfile.template +5 -0
  164. package/src/ts/rdb/generator.d.ts +8 -0
  165. package/src/ts/rdb/generator.js +28 -24
  166. package/src/ts/rdb/generator.js.map +1 -1
  167. package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +39 -0
  168. package/src/ts/rdb/trpc-connection/generator.js +13 -0
  169. package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
  170. package/src/ts/react-website/agui/files/common/src/components/__agentNameKebabCase__-chat.tsx.template +9 -0
  171. package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +4 -1
  172. package/src/ts/react-website/agui/generator.d.ts +1 -5
  173. package/src/ts/react-website/agui/generator.js +6 -2
  174. package/src/ts/react-website/agui/generator.js.map +1 -1
  175. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +26 -26
  176. package/src/ts/react-website/app/generator.d.ts +1 -5
  177. package/src/ts/react-website/app/generator.js +3 -8
  178. package/src/ts/react-website/app/generator.js.map +1 -1
  179. package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +2 -2
  180. package/src/utils/agent-connection/agent-connection.d.ts +2 -1
  181. package/src/utils/agent-connection/agent-connection.js +6 -1
  182. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  183. package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +11 -7
  184. package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +14 -6
  185. package/src/utils/agent-core-packaging.js +5 -5
  186. package/src/utils/agent-core-packaging.js.map +1 -1
  187. package/src/utils/api-constructs/api-constructs.d.ts +5 -0
  188. package/src/utils/api-constructs/api-constructs.js +8 -0
  189. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  190. package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +4 -2
  191. package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +4 -2
  192. package/src/utils/ast.d.ts +10 -0
  193. package/src/utils/ast.js +87 -15
  194. package/src/utils/ast.js.map +1 -1
  195. package/src/utils/dependencies.d.ts +10 -0
  196. package/src/utils/dependencies.js +93 -1
  197. package/src/utils/dependencies.js.map +1 -1
  198. package/src/utils/docker.d.ts +11 -0
  199. package/src/utils/docker.js +16 -3
  200. package/src/utils/docker.js.map +1 -1
  201. package/src/utils/dynamodb-config.d.ts +48 -0
  202. package/src/utils/dynamodb-config.js +44 -0
  203. package/src/utils/dynamodb-config.js.map +1 -0
  204. package/src/utils/dynamodb-constructs/files/cdk/app/dynamodb/__nameKebabCase__.ts.template +8 -4
  205. package/src/utils/files/common/shadcn/src/components/ui/alert.tsx.template +1 -2
  206. package/src/utils/files/common/shadcn/src/components/ui/avatar.tsx.template +1 -2
  207. package/src/utils/files/common/shadcn/src/components/ui/breadcrumb.tsx.template +1 -2
  208. package/src/utils/files/common/shadcn/src/components/ui/button.tsx.template +1 -2
  209. package/src/utils/files/common/shadcn/src/components/ui/card.tsx.template +1 -2
  210. package/src/utils/files/common/shadcn/src/components/ui/input.tsx.template +1 -2
  211. package/src/utils/files/common/shadcn/src/components/ui/separator.tsx.template +1 -2
  212. package/src/utils/files/common/shadcn/src/components/ui/sheet.tsx.template +1 -2
  213. package/src/utils/files/common/shadcn/src/components/ui/sidebar.tsx.template +1 -1
  214. package/src/utils/files/common/shadcn/src/components/ui/skeleton.tsx.template +1 -1
  215. package/src/utils/files/common/shadcn/src/components/ui/spinner.tsx.template +1 -2
  216. package/src/utils/files/common/shadcn/src/components/ui/textarea.tsx.template +1 -2
  217. package/src/utils/files/common/shadcn/src/components/ui/tooltip.tsx.template +1 -2
  218. package/src/utils/files/common/shadcn/src/lib/utils.ts.template +1 -6
  219. package/src/utils/git-secrets.d.ts +28 -0
  220. package/src/utils/git-secrets.js +66 -0
  221. package/src/utils/git-secrets.js.map +1 -0
  222. package/src/utils/init.js +7 -6
  223. package/src/utils/init.js.map +1 -1
  224. package/src/utils/local-project-dependency.d.ts +28 -0
  225. package/src/utils/local-project-dependency.js +40 -0
  226. package/src/utils/local-project-dependency.js.map +1 -0
  227. package/src/utils/nx.d.ts +14 -0
  228. package/src/utils/nx.js +30 -0
  229. package/src/utils/nx.js.map +1 -1
  230. package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +11 -6
  231. package/src/utils/script-project-targets.d.ts +26 -0
  232. package/src/utils/script-project-targets.js +75 -0
  233. package/src/utils/script-project-targets.js.map +1 -0
  234. package/src/utils/shared-shadcn.d.ts +1 -3
  235. package/src/utils/shared-shadcn.js +1 -4
  236. package/src/utils/shared-shadcn.js.map +1 -1
  237. package/src/utils/versions.d.ts +52 -50
  238. package/src/utils/versions.js +55 -49
  239. package/src/utils/versions.js.map +1 -1
  240. package/src/utils/website-constructs/files/cdk/app/static-websites/__websiteNameKebabCase__.ts.template +8 -4
  241. package/src/migrations/latest/add-assemble-target/migration.js.map +0 -1
  242. package/src/migrations/latest/agent-connection-pin-strands-peers/migration.js.map +0 -1
  243. package/src/migrations/latest/agent-core-vendor-target/migration.js.map +0 -1
  244. package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +0 -1
  245. package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +0 -1
  246. package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +0 -1
  247. package/src/migrations/latest/ignore-package-manager-temp-files/migration.js.map +0 -1
  248. package/src/migrations/latest/infra-deploy-express-mode/metadata.json +0 -3
  249. package/src/migrations/latest/infra-deploy-express-mode/migration.js.map +0 -1
  250. package/src/migrations/latest/open-api-codegen-executor/migration.js.map +0 -1
  251. package/src/migrations/latest/python-test-input-scoping/migration.js.map +0 -1
  252. package/src/migrations/latest/react-website-unique-dev-ports/migration.js.map +0 -1
  253. package/src/migrations/latest/rolldown-config-bundle-transient/migration.js.map +0 -1
  254. package/src/migrations/latest/shadcn-package-imports-exports/migration.js.map +0 -1
  255. package/src/migrations/latest/shx-fs-commands/migration.js.map +0 -1
  256. package/src/migrations/latest/terraform-fmt-check/migration.js.map +0 -1
  257. package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +0 -1
  258. package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +0 -1
  259. package/src/py/dynamodb/files/__name__/__init__.py.template +0 -6
  260. package/src/py/dynamodb/files/__name__/entities/__init__.py.template +0 -4
  261. package/src/py/dynamodb/files/config.json.template +0 -24
  262. package/src/ts/dynamodb/files/config.json.template +0 -24
  263. package/src/ts/dynamodb/files/src/entities/index.ts.template +0 -1
  264. package/src/ts/dynamodb/files/src/index.ts.template +0 -2
  265. /package/src/migrations/latest/{add-assemble-target → sandbox-pattern-nested-stacks}/migration.d.ts +0 -0
  266. /package/src/migrations/latest/{agent-core-vendor-target → shadcn-cn-package}/migration.d.ts +0 -0
  267. /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
  268. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0001-dev-target-depends-on-pull-image}/migration.d.ts +0 -0
  269. /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
  270. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/metadata.json +0 -0
  271. /package/src/migrations/{latest/dev-target-depends-on-pull-image → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.d.ts +0 -0
  272. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0002-open-api-codegen-executor}/migration.js +0 -0
  273. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/metadata.json +0 -0
  274. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.d.ts +0 -0
  275. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.90/0003-terraform-provider-plugin-cache}/migration.js +0 -0
  276. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/metadata.json +0 -0
  277. /package/src/migrations/{latest/infra-deploy-express-mode → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.d.ts +0 -0
  278. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0004-python-test-input-scoping}/migration.js +0 -0
  279. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/metadata.json +0 -0
  280. /package/src/migrations/{latest/open-api-codegen-executor → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.d.ts +0 -0
  281. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.90/0005-vitest-coverage-output-dir}/migration.js +0 -0
  282. /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/metadata.json +0 -0
  283. /package/src/migrations/{latest/python-test-input-scoping → v1.0.0-rc.90/0006-add-assemble-target}/migration.d.ts +0 -0
  284. /package/src/migrations/{latest/add-assemble-target → v1.0.0-rc.90/0006-add-assemble-target}/migration.js +0 -0
  285. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/metadata.json +0 -0
  286. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.d.ts +0 -0
  287. /package/src/migrations/{latest/docker-target-cache-soundness → v1.0.0-rc.90/0007-docker-target-cache-soundness}/migration.js +0 -0
  288. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/metadata.json +0 -0
  289. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.d.ts +0 -0
  290. /package/src/migrations/{latest/declare-cacheable-target-inputs → v1.0.0-rc.90/0008-declare-cacheable-target-inputs}/migration.js +0 -0
  291. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/metadata.json +0 -0
  292. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.d.ts +0 -0
  293. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.90/0009-terraform-fmt-check}/migration.js +0 -0
  294. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/metadata.json +0 -0
  295. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.d.ts +0 -0
  296. /package/src/migrations/{latest/react-website-unique-dev-ports → v1.0.0-rc.92/0001-react-website-unique-dev-ports}/migration.js +0 -0
  297. /package/src/migrations/{latest/terraform-fmt-check → v1.0.0-rc.94/0001-infra-deploy-express-mode}/migration.d.ts +0 -0
  298. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/metadata.json +0 -0
  299. /package/src/migrations/{latest/terraform-provider-plugin-cache → v1.0.0-rc.94/0002-shx-fs-commands}/migration.d.ts +0 -0
  300. /package/src/migrations/{latest/shx-fs-commands → v1.0.0-rc.94/0002-shx-fs-commands}/migration.js +0 -0
  301. /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/metadata.json +0 -0
  302. /package/src/migrations/{latest/vitest-coverage-output-dir → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.d.ts +0 -0
  303. /package/src/migrations/{latest/agent-core-vendor-target → v1.0.0-rc.94/0003-agent-core-vendor-target}/migration.js +0 -0
  304. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/metadata.json +0 -0
  305. /package/src/migrations/{latest/rolldown-config-bundle-transient → v1.0.0-rc.95/0001-rolldown-config-bundle-transient}/migration.js +0 -0
  306. /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/metadata.json +0 -0
  307. /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
  308. /package/src/migrations/{latest/agent-connection-pin-strands-peers → v1.0.0-rc.95/0002-agent-connection-pin-strands-peers}/migration.js +0 -0
  309. /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/metadata.json +0 -0
  310. /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
  311. /package/src/migrations/{latest/ignore-package-manager-temp-files → v1.0.0-rc.95/0003-ignore-package-manager-temp-files}/migration.js +0 -0
  312. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/metadata.json +0 -0
  313. /package/src/migrations/{latest/shadcn-package-imports-exports → v1.0.0-rc.95/0004-shadcn-package-imports-exports}/migration.js +0 -0
@@ -28,6 +28,16 @@ export declare const addSingleImport: (tree: Tree, filePath: string, variableNam
28
28
  * Note that this will create the file if it does not exist in the tree.
29
29
  */
30
30
  export declare const addStarExport: (tree: Tree, filePath: string, from: string) => Promise<void>;
31
+ /**
32
+ * Adds an `export { <names> } from '<from>';` statement to the given TypeScript
33
+ * file, merging into an existing re-export of the same module when there is one.
34
+ * Note that this will create the file if it does not exist in the tree.
35
+ *
36
+ * Adding to whatever is already there is what lets a barrel the user curates —
37
+ * their own entities, models or components — survive a generator re-run while
38
+ * the generated entry is still registered.
39
+ */
40
+ export declare const addNamedExport: (tree: Tree, filePath: string, names: string[], from: string) => Promise<void>;
31
41
  /**
32
42
  * Return whether or not the given identifier is exported in the source file.
33
43
  * Checks for both `export { Identifier }` and `export type Identifier = ...`.
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,40 @@ 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}';`));
179
+ };
180
+ /**
181
+ * Adds an `export { <names> } from '<from>';` statement to the given TypeScript
182
+ * file, merging into an existing re-export of the same module when there is one.
183
+ * Note that this will create the file if it does not exist in the tree.
184
+ *
185
+ * Adding to whatever is already there is what lets a barrel the user curates —
186
+ * their own entities, models or components — survive a generator re-run while
187
+ * the generated entry is still registered.
188
+ */ export const addNamedExport = async (tree, filePath, names, from)=>{
189
+ from = normalizeModuleSpecifier(tree, from);
190
+ const contents = tree.read(filePath)?.toString() ?? '';
191
+ if (!contents.trim()) {
192
+ tree.write(filePath, `export { ${names.join(', ')} } from '${from}';\n`);
193
+ return;
194
+ }
195
+ const hasExistingExport = await matchGritQL(tree, filePath, `\`export { $_ } from '${from}'\``);
196
+ if (hasExistingExport) {
197
+ for (const name of names){
198
+ await applyGritQL(tree, filePath, `\`export { $names } from '${from}'\` => \`export { $names, ${name} } from '${from}'\` where { $names <: not contains \`${name}\` }`);
199
+ }
200
+ return;
201
+ }
202
+ const missing = [];
203
+ for (const name of names){
204
+ if (!await matchGritQL(tree, filePath, `\`${name}\``)) {
205
+ missing.push(name);
206
+ }
207
+ }
208
+ if (missing.length === 0) {
209
+ return;
210
+ }
211
+ tree.write(filePath, await insertBelowLeadingComments(tree, filePath, contents, `export { ${missing.join(', ')} } from '${from}';`));
140
212
  };
141
213
  /**
142
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 * 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","hasExportDeclaration","source","identifierName","pattern","q","result","applyToFile","content","query","matched","filter","captureGritQL","undefined","captured","node","text","captureGritQLVariable","name","var","captureAllGritQLVariable","bound","push","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;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
- */ import { detectPackageManager, addDependenciesToPackageJson as devkitAddDependenciesToPackageJson, getPackageManagerVersion, readJson, updateJson } from "@nx/devkit";
4
+ */ import { detectPackageManager, addDependenciesToPackageJson as devkitAddDependenciesToPackageJson, removeDependenciesFromPackageJson as devkitRemoveDependenciesFromPackageJson, getPackageManagerVersion, getProjects, joinPathFragments, readJson, updateJson } from "@nx/devkit";
5
5
  import yaml from "js-yaml";
6
6
  import { coerce, gt, gte } from "semver";
7
7
  import { readAwsNxPluginConfig } from "./config/utils.js";
@@ -113,6 +113,98 @@ export const catalogsEnabled = (tree)=>{
113
113
  }
114
114
  return callback;
115
115
  };
116
+ /**
117
+ * Drop-in replacement for devkit's `removeDependenciesFromPackageJson` that
118
+ * also drops the package manager's catalog entry, which devkit leaves behind
119
+ * pointing at a package nothing declares any more.
120
+ *
121
+ * The entry is only dropped once no manifest in the workspace declares the
122
+ * package, so removing it from one project leaves another project's reference
123
+ * resolvable.
124
+ */ export const removeDependenciesFromPackageJson = (tree, dependencies, devDependencies, packageJsonPath = 'package.json')=>{
125
+ const callback = devkitRemoveDependenciesFromPackageJson(tree, dependencies, devDependencies, packageJsonPath);
126
+ if (catalogsEnabled(tree)) {
127
+ const manifests = workspaceManifests(tree, packageJsonPath);
128
+ const removed = [
129
+ ...new Set([
130
+ ...dependencies,
131
+ ...devDependencies
132
+ ])
133
+ ].filter((packageName)=>!manifests.some((manifest)=>MANIFEST_DEPENDENCY_FIELDS.some((field)=>manifest[field]?.[packageName] !== undefined)));
134
+ removeCatalogVersions(tree, removed);
135
+ }
136
+ return callback;
137
+ };
138
+ /**
139
+ * Every manifest that can hold a catalog reference: the root, each project's,
140
+ * and the one just written. Project manifests come from the project graph
141
+ * rather than a tree walk, so a manifest belonging to no project is not seen.
142
+ */ const workspaceManifests = (tree, packageJsonPath)=>[
143
+ ...new Set([
144
+ 'package.json',
145
+ packageJsonPath,
146
+ ...Array.from(getProjects(tree).values()).map((project)=>joinPathFragments(project.root, 'package.json'))
147
+ ])
148
+ ].filter((path)=>tree.exists(path)).map((path)=>readJson(tree, path));
149
+ const MANIFEST_DEPENDENCY_FIELDS = [
150
+ 'dependencies',
151
+ 'devDependencies',
152
+ 'optionalDependencies',
153
+ 'peerDependencies'
154
+ ];
155
+ // Drop entries from the default catalog, mirroring `writeCatalogVersions`.
156
+ const removeCatalogVersions = (tree, packageNames)=>{
157
+ if (packageNames.length === 0) {
158
+ return;
159
+ }
160
+ const withoutRemoved = (catalog)=>{
161
+ if (!catalog || !packageNames.some((name)=>name in catalog)) {
162
+ return undefined;
163
+ }
164
+ return Object.fromEntries(Object.entries(catalog).filter(([name])=>!packageNames.includes(name)));
165
+ };
166
+ switch(detectWorkspacePackageManager(tree)){
167
+ case 'pnpm':
168
+ {
169
+ const workspaceYaml = yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') ?? {};
170
+ const catalog = withoutRemoved(workspaceYaml.catalog);
171
+ if (catalog) {
172
+ tree.write('pnpm-workspace.yaml', yaml.dump({
173
+ ...workspaceYaml,
174
+ catalog
175
+ }, {
176
+ quotingType: "'"
177
+ }));
178
+ }
179
+ break;
180
+ }
181
+ case 'yarn':
182
+ {
183
+ const yarnRc = yaml.load(tree.read('.yarnrc.yml', 'utf-8') ?? '') ?? {};
184
+ const catalog = withoutRemoved(yarnRc.catalog);
185
+ if (catalog) {
186
+ tree.write('.yarnrc.yml', yaml.dump({
187
+ ...yarnRc,
188
+ catalog
189
+ }, {
190
+ quotingType: "'"
191
+ }));
192
+ }
193
+ break;
194
+ }
195
+ case 'bun':
196
+ {
197
+ const catalog = withoutRemoved(readJson(tree, 'package.json').catalog);
198
+ if (catalog) {
199
+ updateJson(tree, 'package.json', (json)=>({
200
+ ...json,
201
+ catalog
202
+ }));
203
+ }
204
+ break;
205
+ }
206
+ }
207
+ };
116
208
  // Convert direct version ranges to `catalog:` references in a single manifest
117
209
  // and record the range in the workspace catalog. Protocol specifiers
118
210
  // (catalog:/workspace:/...) are left alone.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n detectPackageManager,\n addDependenciesToPackageJson as devkitAddDependenciesToPackageJson,\n type GeneratorCallback,\n getPackageManagerVersion,\n type PackageManager,\n readJson,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport yaml from 'js-yaml';\nimport { coerce, gt, gte } from 'semver';\nimport { readAwsNxPluginConfig } from './config/utils.js';\n\n// Minimum version that introduced catalog support per package manager (npm has none).\nconst CATALOG_SUPPORT: Partial<Record<PackageManager, string>> = {\n pnpm: '9.5.0',\n yarn: '4.10.0',\n bun: '1.2.14',\n};\n\n// Prefer tree markers over devkit's `detectPackageManager`, which reads the\n// real filesystem and is nondeterministic for virtual trees in tests.\nexport const detectWorkspacePackageManager = (tree: Tree): PackageManager =>\n tree.exists('pnpm-workspace.yaml') ? 'pnpm' : detectPackageManager(tree.root);\n\n// Coerce a single simple range to a version. Rejects compound ranges\n// (whitespace / `||`), which coerce would silently reduce, plus tags/protocols.\nconst parseSimpleRange = (version: string) => {\n const trimmed = version.trim();\n if (/\\s|\\|\\|/.test(trimmed)) {\n return undefined;\n }\n return coerce(trimmed, { includePrerelease: true }) ?? undefined;\n};\n\nconst versionAtLeast = (version: string, minimum: string): boolean =>\n gte(\n parseSimpleRange(version) ?? '0.0.0',\n parseSimpleRange(minimum) ?? '0.0.0',\n );\n\n// Only a strict upgrade replaces an existing catalog entry, so generating a\n// project never downgrades a version the user raised. Uncomparable entries\n// (tags, complex ranges) are kept.\nconst isVersionUpgrade = (incoming: string, existing: string): boolean => {\n const existingParsed = parseSimpleRange(existing);\n const incomingParsed = parseSimpleRange(incoming);\n if (!existingParsed || !incomingParsed) {\n return false;\n }\n return gt(incomingParsed, existingParsed);\n};\n\n// Keyed by root + package manager; detecting support shells out for a version.\nconst catalogSupportCache = new Map<string, boolean>();\n\n/** Clears the catalog support cache. Only needed by tests. */\nexport const resetCatalogSupportCache = (): void => {\n catalogSupportCache.clear();\n};\n\n// Local-project specifier: the `workspace:` protocol where supported (pnpm,\n// bun, yarn berry), `*` on npm and yarn classic which reject it.\nexport const getLocalDependencySpecifier = (tree: Tree): string => {\n const packageManager = detectWorkspacePackageManager(tree);\n if (packageManager === 'npm') {\n return '*';\n }\n if (packageManager === 'yarn') {\n let major = 2;\n try {\n major = Number.parseInt(\n getPackageManagerVersion('yarn', tree.root).split('.')[0],\n 10,\n );\n } catch {\n // Not installed (e.g. tests) — assume berry.\n }\n if (major < 2) {\n return '*';\n }\n }\n return 'workspace:*';\n};\n\nexport const supportsCatalogs = (tree: Tree): boolean => {\n const packageManager = detectWorkspacePackageManager(tree);\n const cacheKey = `${tree.root}|${packageManager}`;\n const cached = catalogSupportCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n const minimumVersion = CATALOG_SUPPORT[packageManager];\n let supported = false;\n if (minimumVersion) {\n try {\n supported = versionAtLeast(\n getPackageManagerVersion(packageManager, tree.root),\n minimumVersion,\n );\n } catch {\n // Not installed (e.g. tests) — assume a modern version.\n supported = true;\n }\n }\n catalogSupportCache.set(cacheKey, supported);\n return supported;\n};\n\n// True when the package manager supports catalogs and the workspace hasn't\n// opted out via `packageManager.catalogs: false` in aws-nx-plugin.config.mts.\nexport const catalogsEnabled = (tree: Tree): boolean => {\n if (!supportsCatalogs(tree)) {\n return false;\n }\n const config = readAwsNxPluginConfig(tree);\n return config?.packageManager?.catalogs !== false;\n};\n\n/**\n * Drop-in replacement for devkit's `addDependenciesToPackageJson` that records\n * versions in the package manager's catalog when enabled. Callers pass a\n * project manifest path for runtime deps (so `noUndeclaredDependencies` passes)\n * and the root for shared tooling.\n */\nexport const addDependenciesToPackageJson = (\n tree: Tree,\n dependencies: Record<string, string>,\n devDependencies: Record<string, string>,\n packageJsonPath = 'package.json',\n): GeneratorCallback => {\n const callback = devkitAddDependenciesToPackageJson(\n tree,\n dependencies,\n devDependencies,\n packageJsonPath,\n );\n\n if (catalogsEnabled(tree)) {\n const packageNames = [\n ...Object.keys(dependencies),\n ...Object.keys(devDependencies),\n ];\n convertDependenciesToCatalog(tree, packageJsonPath, packageNames);\n // Convert any matching root ranges Nx wrote behind our back (e.g.\n // `@types/node`, `react`) so they don't resolve to a second copy alongside\n // the catalog version. Skipped when the caller already targeted the root.\n if (packageJsonPath !== 'package.json') {\n convertDependenciesToCatalog(tree, 'package.json', packageNames);\n }\n }\n\n return callback;\n};\n\n// Convert direct version ranges to `catalog:` references in a single manifest\n// and record the range in the workspace catalog. Protocol specifiers\n// (catalog:/workspace:/...) are left alone.\nconst convertDependenciesToCatalog = (\n tree: Tree,\n packageJsonPath: string,\n packageNames: string[],\n): void => {\n const catalogUpdates: Record<string, string> = {};\n\n updateJson(tree, packageJsonPath, (json) => {\n for (const field of ['dependencies', 'devDependencies'] as const) {\n for (const packageName of packageNames) {\n const version = json[field]?.[packageName];\n if (version && !version.includes(':')) {\n catalogUpdates[packageName] = version;\n json[field][packageName] = 'catalog:';\n }\n }\n }\n return json;\n });\n\n if (Object.keys(catalogUpdates).length > 0) {\n writeCatalogVersions(tree, catalogUpdates);\n }\n};\n\n// Record ranges in the default catalog, creating it if absent. Only strict\n// upgrades replace existing entries (see `isVersionUpgrade`).\nconst writeCatalogVersions = (\n tree: Tree,\n updates: Record<string, string>,\n): void => {\n const applyUpdates = (\n catalog: Record<string, string> | undefined,\n ): Record<string, string> | undefined => {\n const existing = catalog ?? {};\n const applicable = Object.fromEntries(\n Object.entries(updates).filter(\n ([name, version]) =>\n existing[name] === undefined ||\n isVersionUpgrade(version, existing[name]),\n ),\n );\n if (Object.keys(applicable).length === 0) {\n return undefined;\n }\n return { ...existing, ...applicable };\n };\n\n switch (detectWorkspacePackageManager(tree)) {\n case 'pnpm': {\n const workspaceYaml =\n (yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = applyUpdates(\n workspaceYaml.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump({ ...workspaceYaml, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'yarn': {\n const yarnRc =\n (yaml.load(tree.read('.yarnrc.yml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = applyUpdates(\n yarnRc.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n '.yarnrc.yml',\n yaml.dump({ ...yarnRc, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'bun': {\n const catalog = applyUpdates(\n readJson<{ catalog?: Record<string, string> }>(tree, 'package.json')\n .catalog,\n );\n if (catalog) {\n updateJson(tree, 'package.json', (json) => ({ ...json, catalog }));\n }\n break;\n }\n }\n};\n"],"names":["detectPackageManager","addDependenciesToPackageJson","devkitAddDependenciesToPackageJson","getPackageManagerVersion","readJson","updateJson","yaml","coerce","gt","gte","readAwsNxPluginConfig","CATALOG_SUPPORT","pnpm","yarn","bun","detectWorkspacePackageManager","tree","exists","root","parseSimpleRange","version","trimmed","trim","test","undefined","includePrerelease","versionAtLeast","minimum","isVersionUpgrade","incoming","existing","existingParsed","incomingParsed","catalogSupportCache","Map","resetCatalogSupportCache","clear","getLocalDependencySpecifier","packageManager","major","Number","parseInt","split","supportsCatalogs","cacheKey","cached","get","minimumVersion","supported","set","catalogsEnabled","config","catalogs","dependencies","devDependencies","packageJsonPath","callback","packageNames","Object","keys","convertDependenciesToCatalog","catalogUpdates","json","field","packageName","includes","length","writeCatalogVersions","updates","applyUpdates","catalog","applicable","fromEntries","entries","filter","name","workspaceYaml","load","read","write","dump","quotingType","yarnRc"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/dependencies.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n detectPackageManager,\n addDependenciesToPackageJson as devkitAddDependenciesToPackageJson,\n removeDependenciesFromPackageJson as devkitRemoveDependenciesFromPackageJson,\n type GeneratorCallback,\n getPackageManagerVersion,\n getProjects,\n joinPathFragments,\n type PackageManager,\n readJson,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport yaml from 'js-yaml';\nimport { coerce, gt, gte } from 'semver';\nimport { readAwsNxPluginConfig } from './config/utils.js';\n\n// Minimum version that introduced catalog support per package manager (npm has none).\nconst CATALOG_SUPPORT: Partial<Record<PackageManager, string>> = {\n pnpm: '9.5.0',\n yarn: '4.10.0',\n bun: '1.2.14',\n};\n\n// Prefer tree markers over devkit's `detectPackageManager`, which reads the\n// real filesystem and is nondeterministic for virtual trees in tests.\nexport const detectWorkspacePackageManager = (tree: Tree): PackageManager =>\n tree.exists('pnpm-workspace.yaml') ? 'pnpm' : detectPackageManager(tree.root);\n\n// Coerce a single simple range to a version. Rejects compound ranges\n// (whitespace / `||`), which coerce would silently reduce, plus tags/protocols.\nconst parseSimpleRange = (version: string) => {\n const trimmed = version.trim();\n if (/\\s|\\|\\|/.test(trimmed)) {\n return undefined;\n }\n return coerce(trimmed, { includePrerelease: true }) ?? undefined;\n};\n\nconst versionAtLeast = (version: string, minimum: string): boolean =>\n gte(\n parseSimpleRange(version) ?? '0.0.0',\n parseSimpleRange(minimum) ?? '0.0.0',\n );\n\n// Only a strict upgrade replaces an existing catalog entry, so generating a\n// project never downgrades a version the user raised. Uncomparable entries\n// (tags, complex ranges) are kept.\nconst isVersionUpgrade = (incoming: string, existing: string): boolean => {\n const existingParsed = parseSimpleRange(existing);\n const incomingParsed = parseSimpleRange(incoming);\n if (!existingParsed || !incomingParsed) {\n return false;\n }\n return gt(incomingParsed, existingParsed);\n};\n\n// Keyed by root + package manager; detecting support shells out for a version.\nconst catalogSupportCache = new Map<string, boolean>();\n\n/** Clears the catalog support cache. Only needed by tests. */\nexport const resetCatalogSupportCache = (): void => {\n catalogSupportCache.clear();\n};\n\n// Local-project specifier: the `workspace:` protocol where supported (pnpm,\n// bun, yarn berry), `*` on npm and yarn classic which reject it.\nexport const getLocalDependencySpecifier = (tree: Tree): string => {\n const packageManager = detectWorkspacePackageManager(tree);\n if (packageManager === 'npm') {\n return '*';\n }\n if (packageManager === 'yarn') {\n let major = 2;\n try {\n major = Number.parseInt(\n getPackageManagerVersion('yarn', tree.root).split('.')[0],\n 10,\n );\n } catch {\n // Not installed (e.g. tests) — assume berry.\n }\n if (major < 2) {\n return '*';\n }\n }\n return 'workspace:*';\n};\n\nexport const supportsCatalogs = (tree: Tree): boolean => {\n const packageManager = detectWorkspacePackageManager(tree);\n const cacheKey = `${tree.root}|${packageManager}`;\n const cached = catalogSupportCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n const minimumVersion = CATALOG_SUPPORT[packageManager];\n let supported = false;\n if (minimumVersion) {\n try {\n supported = versionAtLeast(\n getPackageManagerVersion(packageManager, tree.root),\n minimumVersion,\n );\n } catch {\n // Not installed (e.g. tests) — assume a modern version.\n supported = true;\n }\n }\n catalogSupportCache.set(cacheKey, supported);\n return supported;\n};\n\n// True when the package manager supports catalogs and the workspace hasn't\n// opted out via `packageManager.catalogs: false` in aws-nx-plugin.config.mts.\nexport const catalogsEnabled = (tree: Tree): boolean => {\n if (!supportsCatalogs(tree)) {\n return false;\n }\n const config = readAwsNxPluginConfig(tree);\n return config?.packageManager?.catalogs !== false;\n};\n\n/**\n * Drop-in replacement for devkit's `addDependenciesToPackageJson` that records\n * versions in the package manager's catalog when enabled. Callers pass a\n * project manifest path for runtime deps (so `noUndeclaredDependencies` passes)\n * and the root for shared tooling.\n */\nexport const addDependenciesToPackageJson = (\n tree: Tree,\n dependencies: Record<string, string>,\n devDependencies: Record<string, string>,\n packageJsonPath = 'package.json',\n): GeneratorCallback => {\n const callback = devkitAddDependenciesToPackageJson(\n tree,\n dependencies,\n devDependencies,\n packageJsonPath,\n );\n\n if (catalogsEnabled(tree)) {\n const packageNames = [\n ...Object.keys(dependencies),\n ...Object.keys(devDependencies),\n ];\n convertDependenciesToCatalog(tree, packageJsonPath, packageNames);\n // Convert any matching root ranges Nx wrote behind our back (e.g.\n // `@types/node`, `react`) so they don't resolve to a second copy alongside\n // the catalog version. Skipped when the caller already targeted the root.\n if (packageJsonPath !== 'package.json') {\n convertDependenciesToCatalog(tree, 'package.json', packageNames);\n }\n }\n\n return callback;\n};\n\n/**\n * Drop-in replacement for devkit's `removeDependenciesFromPackageJson` that\n * also drops the package manager's catalog entry, which devkit leaves behind\n * pointing at a package nothing declares any more.\n *\n * The entry is only dropped once no manifest in the workspace declares the\n * package, so removing it from one project leaves another project's reference\n * resolvable.\n */\nexport const removeDependenciesFromPackageJson = (\n tree: Tree,\n dependencies: string[],\n devDependencies: string[],\n packageJsonPath = 'package.json',\n): GeneratorCallback => {\n const callback = devkitRemoveDependenciesFromPackageJson(\n tree,\n dependencies,\n devDependencies,\n packageJsonPath,\n );\n\n if (catalogsEnabled(tree)) {\n const manifests = workspaceManifests(tree, packageJsonPath);\n const removed = [...new Set([...dependencies, ...devDependencies])].filter(\n (packageName) =>\n !manifests.some((manifest) =>\n MANIFEST_DEPENDENCY_FIELDS.some(\n (field) => manifest[field]?.[packageName] !== undefined,\n ),\n ),\n );\n removeCatalogVersions(tree, removed);\n }\n\n return callback;\n};\n\ntype Manifest = Record<string, Record<string, string> | undefined>;\n\n/**\n * Every manifest that can hold a catalog reference: the root, each project's,\n * and the one just written. Project manifests come from the project graph\n * rather than a tree walk, so a manifest belonging to no project is not seen.\n */\nconst workspaceManifests = (tree: Tree, packageJsonPath: string): Manifest[] =>\n [\n ...new Set([\n 'package.json',\n packageJsonPath,\n ...Array.from(getProjects(tree).values()).map((project) =>\n joinPathFragments(project.root, 'package.json'),\n ),\n ]),\n ]\n .filter((path) => tree.exists(path))\n .map((path) => readJson<Manifest>(tree, path));\n\nconst MANIFEST_DEPENDENCY_FIELDS = [\n 'dependencies',\n 'devDependencies',\n 'optionalDependencies',\n 'peerDependencies',\n] as const;\n\n// Drop entries from the default catalog, mirroring `writeCatalogVersions`.\nconst removeCatalogVersions = (tree: Tree, packageNames: string[]): void => {\n if (packageNames.length === 0) {\n return;\n }\n\n const withoutRemoved = (\n catalog: Record<string, string> | undefined,\n ): Record<string, string> | undefined => {\n if (!catalog || !packageNames.some((name) => name in catalog)) {\n return undefined;\n }\n return Object.fromEntries(\n Object.entries(catalog).filter(([name]) => !packageNames.includes(name)),\n );\n };\n\n switch (detectWorkspacePackageManager(tree)) {\n case 'pnpm': {\n const workspaceYaml =\n (yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = withoutRemoved(\n workspaceYaml.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump({ ...workspaceYaml, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'yarn': {\n const yarnRc =\n (yaml.load(tree.read('.yarnrc.yml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = withoutRemoved(\n yarnRc.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n '.yarnrc.yml',\n yaml.dump({ ...yarnRc, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'bun': {\n const catalog = withoutRemoved(\n readJson<{ catalog?: Record<string, string> }>(tree, 'package.json')\n .catalog,\n );\n if (catalog) {\n updateJson(tree, 'package.json', (json) => ({ ...json, catalog }));\n }\n break;\n }\n }\n};\n\n// Convert direct version ranges to `catalog:` references in a single manifest\n// and record the range in the workspace catalog. Protocol specifiers\n// (catalog:/workspace:/...) are left alone.\nconst convertDependenciesToCatalog = (\n tree: Tree,\n packageJsonPath: string,\n packageNames: string[],\n): void => {\n const catalogUpdates: Record<string, string> = {};\n\n updateJson(tree, packageJsonPath, (json) => {\n for (const field of ['dependencies', 'devDependencies'] as const) {\n for (const packageName of packageNames) {\n const version = json[field]?.[packageName];\n if (version && !version.includes(':')) {\n catalogUpdates[packageName] = version;\n json[field][packageName] = 'catalog:';\n }\n }\n }\n return json;\n });\n\n if (Object.keys(catalogUpdates).length > 0) {\n writeCatalogVersions(tree, catalogUpdates);\n }\n};\n\n// Record ranges in the default catalog, creating it if absent. Only strict\n// upgrades replace existing entries (see `isVersionUpgrade`).\nconst writeCatalogVersions = (\n tree: Tree,\n updates: Record<string, string>,\n): void => {\n const applyUpdates = (\n catalog: Record<string, string> | undefined,\n ): Record<string, string> | undefined => {\n const existing = catalog ?? {};\n const applicable = Object.fromEntries(\n Object.entries(updates).filter(\n ([name, version]) =>\n existing[name] === undefined ||\n isVersionUpgrade(version, existing[name]),\n ),\n );\n if (Object.keys(applicable).length === 0) {\n return undefined;\n }\n return { ...existing, ...applicable };\n };\n\n switch (detectWorkspacePackageManager(tree)) {\n case 'pnpm': {\n const workspaceYaml =\n (yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = applyUpdates(\n workspaceYaml.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump({ ...workspaceYaml, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'yarn': {\n const yarnRc =\n (yaml.load(tree.read('.yarnrc.yml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {};\n const catalog = applyUpdates(\n yarnRc.catalog as Record<string, string> | undefined,\n );\n if (catalog) {\n tree.write(\n '.yarnrc.yml',\n yaml.dump({ ...yarnRc, catalog }, { quotingType: \"'\" }),\n );\n }\n break;\n }\n case 'bun': {\n const catalog = applyUpdates(\n readJson<{ catalog?: Record<string, string> }>(tree, 'package.json')\n .catalog,\n );\n if (catalog) {\n updateJson(tree, 'package.json', (json) => ({ ...json, catalog }));\n }\n break;\n }\n }\n};\n"],"names":["detectPackageManager","addDependenciesToPackageJson","devkitAddDependenciesToPackageJson","removeDependenciesFromPackageJson","devkitRemoveDependenciesFromPackageJson","getPackageManagerVersion","getProjects","joinPathFragments","readJson","updateJson","yaml","coerce","gt","gte","readAwsNxPluginConfig","CATALOG_SUPPORT","pnpm","yarn","bun","detectWorkspacePackageManager","tree","exists","root","parseSimpleRange","version","trimmed","trim","test","undefined","includePrerelease","versionAtLeast","minimum","isVersionUpgrade","incoming","existing","existingParsed","incomingParsed","catalogSupportCache","Map","resetCatalogSupportCache","clear","getLocalDependencySpecifier","packageManager","major","Number","parseInt","split","supportsCatalogs","cacheKey","cached","get","minimumVersion","supported","set","catalogsEnabled","config","catalogs","dependencies","devDependencies","packageJsonPath","callback","packageNames","Object","keys","convertDependenciesToCatalog","manifests","workspaceManifests","removed","Set","filter","packageName","some","manifest","MANIFEST_DEPENDENCY_FIELDS","field","removeCatalogVersions","Array","from","values","map","project","path","length","withoutRemoved","catalog","name","fromEntries","entries","includes","workspaceYaml","load","read","write","dump","quotingType","yarnRc","json","catalogUpdates","writeCatalogVersions","updates","applyUpdates","applicable"],"mappings":"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"}
@@ -43,6 +43,17 @@ export declare const NODE_IMAGE_DEPENDENCIES: readonly [{
43
43
  }, {
44
44
  readonly name: "minimatch";
45
45
  }];
46
+ /**
47
+ * Packages the prisma CLI install in a vended RDB migration `Dockerfile` pins.
48
+ * The CLI's own ranges resolve both below a known HIGH vulnerability's fix, so
49
+ * the image overrides them. Spread through `ownedElsewhere` for the same reason
50
+ * as {@link NODE_IMAGE_DEPENDENCIES}.
51
+ */
52
+ export declare const PRISMA_IMAGE_DEPENDENCIES: readonly [{
53
+ readonly name: "deepmerge-ts";
54
+ }, {
55
+ readonly name: "mysql2";
56
+ }];
46
57
  /**
47
58
  * Packages the AWS Distro for OpenTelemetry install in a vended `Dockerfile`
48
59
  * pins, for the images that auto-instrument with it. Spread through
@@ -4,7 +4,7 @@
4
4
  */ import { joinPathFragments } from "@nx/devkit";
5
5
  import { forDependencies } from "./declared-dependencies.js";
6
6
  import { FS_DEPENDENCIES, FsCommands } from "./fs.js";
7
- import { addDependencyToTargetIfNotPresent } from "./nx.js";
7
+ import { addDependencyToTargetIfNotPresent, normalizeTargetKeyOrder } from "./nx.js";
8
8
  import { containerImage, TS_VERSIONS } from "./versions.js";
9
9
  /** Dependencies a caller must declare to add a Docker scan target. */ export const DOCKER_DEPENDENCIES = [
10
10
  ...FS_DEPENDENCIES
@@ -49,6 +49,19 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
49
49
  name: 'minimatch'
50
50
  }
51
51
  ];
52
+ /**
53
+ * Packages the prisma CLI install in a vended RDB migration `Dockerfile` pins.
54
+ * The CLI's own ranges resolve both below a known HIGH vulnerability's fix, so
55
+ * the image overrides them. Spread through `ownedElsewhere` for the same reason
56
+ * as {@link NODE_IMAGE_DEPENDENCIES}.
57
+ */ export const PRISMA_IMAGE_DEPENDENCIES = [
58
+ {
59
+ name: 'deepmerge-ts'
60
+ },
61
+ {
62
+ name: 'mysql2'
63
+ }
64
+ ];
52
65
  /**
53
66
  * Packages the AWS Distro for OpenTelemetry install in a vended `Dockerfile`
54
67
  * pins, for the images that auto-instrument with it. Spread through
@@ -102,7 +115,7 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
102
115
  commands.push(`${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`, `${containerEngine} run --rm -v "./${scanDir}":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`);
103
116
  });
104
117
  project.targets ??= {};
105
- project.targets[trivyTargetName] = {
118
+ project.targets[trivyTargetName] = normalizeTargetKeyOrder({
106
119
  // The image being scanned is only reachable through the container engine,
107
120
  // so a restored cache entry would report a pass for an image that may no
108
121
  // longer exist. The scan re-runs and either scans the real image or fails.
@@ -120,7 +133,7 @@ const TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.
120
133
  dependsOn: [
121
134
  dockerTargetName
122
135
  ]
123
- };
136
+ });
124
137
  // Aggregate per-component scan targets under a single `trivy` target. The
125
138
  // scan is intentionally NOT wired into `build`: image scanning is slow and
126
139
  // its result depends on the ever-changing vulnerability database (a scan