@aws/nx-plugin 1.0.0-rc.54 → 1.0.0-rc.56

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 (284) hide show
  1. package/migrations.json +50 -0
  2. package/package.json +1 -1
  3. package/src/agentcore-gateway/gateway-connection/generator.js +3 -1
  4. package/src/agentcore-gateway/gateway-connection/generator.js.map +1 -1
  5. package/src/agentcore-gateway/generator.d.ts +49 -1
  6. package/src/agentcore-gateway/generator.js +55 -22
  7. package/src/agentcore-gateway/generator.js.map +1 -1
  8. package/src/agentcore-gateway/mcp-connection/generator.js +3 -1
  9. package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -1
  10. package/src/infra/app/__snapshots__/generator.spec.ts.snap +2 -0
  11. package/src/infra/app/generator.d.ts +43 -0
  12. package/src/infra/app/generator.js +47 -18
  13. package/src/infra/app/generator.js.map +1 -1
  14. package/src/init/generator.d.ts +13 -0
  15. package/src/init/generator.js +14 -3
  16. package/src/init/generator.js.map +1 -1
  17. package/src/migrations/latest/backfill-generator-metadata/migration.d.ts +96 -0
  18. package/src/migrations/latest/backfill-generator-metadata/migration.js +670 -0
  19. package/src/migrations/latest/backfill-generator-metadata/migration.js.map +1 -0
  20. package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.d.ts +6 -0
  21. package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js +89 -0
  22. package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js.map +1 -0
  23. package/src/migrations/latest/modernize-function-props-cast/migration.js +0 -1
  24. package/src/migrations/latest/modernize-function-props-cast/migration.js.map +1 -1
  25. package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js +0 -1
  26. package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js.map +1 -1
  27. package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js +0 -2
  28. package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js.map +1 -1
  29. package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js +0 -1
  30. package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js.map +1 -1
  31. package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js +0 -2
  32. package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js.map +1 -1
  33. package/src/preset/generator.d.ts +13 -0
  34. package/src/preset/generator.js +12 -3
  35. package/src/preset/generator.js.map +1 -1
  36. package/src/py/agent/a2a-connection/generator.d.ts +24 -0
  37. package/src/py/agent/a2a-connection/generator.js +49 -20
  38. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  39. package/src/py/agent/gateway-connection/generator.d.ts +23 -0
  40. package/src/py/agent/gateway-connection/generator.js +45 -11
  41. package/src/py/agent/gateway-connection/generator.js.map +1 -1
  42. package/src/py/agent/generator.d.ts +146 -1
  43. package/src/py/agent/generator.js +173 -76
  44. package/src/py/agent/generator.js.map +1 -1
  45. package/src/py/agent/mcp-connection/generator.d.ts +23 -0
  46. package/src/py/agent/mcp-connection/generator.js +45 -11
  47. package/src/py/agent/mcp-connection/generator.js.map +1 -1
  48. package/src/py/agent/react-connection/generator.d.ts +146 -0
  49. package/src/py/agent/react-connection/generator.js +27 -4
  50. package/src/py/agent/react-connection/generator.js.map +1 -1
  51. package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +0 -2
  52. package/src/py/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +18 -0
  53. package/src/py/dynamodb/agent-connection/generator.js +7 -1
  54. package/src/py/dynamodb/agent-connection/generator.js.map +1 -1
  55. package/src/py/dynamodb/fast-api-connection/__snapshots__/generator.spec.ts.snap +9 -0
  56. package/src/py/dynamodb/fast-api-connection/generator.js +3 -1
  57. package/src/py/dynamodb/fast-api-connection/generator.js.map +1 -1
  58. package/src/py/dynamodb/generator.d.ts +29 -0
  59. package/src/py/dynamodb/generator.js +32 -12
  60. package/src/py/dynamodb/generator.js.map +1 -1
  61. package/src/py/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  62. package/src/py/dynamodb/mcp-server-connection/generator.js +7 -1
  63. package/src/py/dynamodb/mcp-server-connection/generator.js.map +1 -1
  64. package/src/py/fast-api/generator.d.ts +63 -0
  65. package/src/py/fast-api/generator.js +58 -23
  66. package/src/py/fast-api/generator.js.map +1 -1
  67. package/src/py/fast-api/react/generator.d.ts +16 -1
  68. package/src/py/fast-api/react/generator.js +15 -3
  69. package/src/py/fast-api/react/generator.js.map +1 -1
  70. package/src/py/lambda-function/generator.d.ts +21 -0
  71. package/src/py/lambda-function/generator.js +29 -10
  72. package/src/py/lambda-function/generator.js.map +1 -1
  73. package/src/py/mcp-server/generator.d.ts +60 -0
  74. package/src/py/mcp-server/generator.js +62 -25
  75. package/src/py/mcp-server/generator.js.map +1 -1
  76. package/src/py/project/generator.d.ts +13 -0
  77. package/src/py/project/generator.js +29 -10
  78. package/src/py/project/generator.js.map +1 -1
  79. package/src/py/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +19 -0
  80. package/src/py/rdb/agent-connection/generator.js +7 -1
  81. package/src/py/rdb/agent-connection/generator.js.map +1 -1
  82. package/src/py/rdb/fast-api-connection/__snapshots__/generator.spec.ts.snap +7 -0
  83. package/src/py/rdb/fast-api-connection/generator.js +3 -1
  84. package/src/py/rdb/fast-api-connection/generator.js.map +1 -1
  85. package/src/py/rdb/generator.d.ts +89 -0
  86. package/src/py/rdb/generator.js +88 -40
  87. package/src/py/rdb/generator.js.map +1 -1
  88. package/src/py/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  89. package/src/py/rdb/mcp-server-connection/generator.js +7 -1
  90. package/src/py/rdb/mcp-server-connection/generator.js.map +1 -1
  91. package/src/smithy/project/generator.d.ts +7 -0
  92. package/src/smithy/project/generator.js +8 -2
  93. package/src/smithy/project/generator.js.map +1 -1
  94. package/src/smithy/react-connection/generator.d.ts +15 -0
  95. package/src/smithy/react-connection/generator.js +17 -3
  96. package/src/smithy/react-connection/generator.js.map +1 -1
  97. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1 -0
  98. package/src/smithy/ts/api/generator.d.ts +79 -0
  99. package/src/smithy/ts/api/generator.js +77 -33
  100. package/src/smithy/ts/api/generator.js.map +1 -1
  101. package/src/terraform/project/generator.d.ts +50 -0
  102. package/src/terraform/project/generator.js +63 -17
  103. package/src/terraform/project/generator.js.map +1 -1
  104. package/src/trpc/backend/generator.d.ts +84 -0
  105. package/src/trpc/backend/generator.js +98 -38
  106. package/src/trpc/backend/generator.js.map +1 -1
  107. package/src/trpc/react/generator.d.ts +37 -0
  108. package/src/trpc/react/generator.js +63 -26
  109. package/src/trpc/react/generator.js.map +1 -1
  110. package/src/ts/agent/a2a-connection/generator.d.ts +46 -0
  111. package/src/ts/agent/a2a-connection/generator.js +53 -16
  112. package/src/ts/agent/a2a-connection/generator.js.map +1 -1
  113. package/src/ts/agent/gateway-connection/generator.d.ts +37 -0
  114. package/src/ts/agent/gateway-connection/generator.js +41 -14
  115. package/src/ts/agent/gateway-connection/generator.js.map +1 -1
  116. package/src/ts/agent/generator.d.ts +162 -0
  117. package/src/ts/agent/generator.js +166 -75
  118. package/src/ts/agent/generator.js.map +1 -1
  119. package/src/ts/agent/mcp-connection/generator.d.ts +37 -0
  120. package/src/ts/agent/mcp-connection/generator.js +41 -14
  121. package/src/ts/agent/mcp-connection/generator.js.map +1 -1
  122. package/src/ts/agent/react-connection/generator.d.ts +186 -0
  123. package/src/ts/agent/react-connection/generator.js +70 -21
  124. package/src/ts/agent/react-connection/generator.js.map +1 -1
  125. package/src/ts/astro-docs/generator.d.ts +38 -0
  126. package/src/ts/astro-docs/generator.js +58 -19
  127. package/src/ts/astro-docs/generator.js.map +1 -1
  128. package/src/ts/dcr-proxy/generator.d.ts +24 -0
  129. package/src/ts/dcr-proxy/generator.js +31 -14
  130. package/src/ts/dcr-proxy/generator.js.map +1 -1
  131. package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +0 -2
  132. package/src/ts/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +18 -0
  133. package/src/ts/dynamodb/agent-connection/generator.js +7 -1
  134. package/src/ts/dynamodb/agent-connection/generator.js.map +1 -1
  135. package/src/ts/dynamodb/generator.d.ts +41 -0
  136. package/src/ts/dynamodb/generator.js +47 -20
  137. package/src/ts/dynamodb/generator.js.map +1 -1
  138. package/src/ts/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  139. package/src/ts/dynamodb/mcp-server-connection/generator.js +7 -1
  140. package/src/ts/dynamodb/mcp-server-connection/generator.js.map +1 -1
  141. package/src/ts/dynamodb/smithy-connection/__snapshots__/generator.spec.ts.snap +9 -0
  142. package/src/ts/dynamodb/smithy-connection/generator.js +3 -1
  143. package/src/ts/dynamodb/smithy-connection/generator.js.map +1 -1
  144. package/src/ts/dynamodb/trpc-connection/__snapshots__/generator.spec.ts.snap +9 -0
  145. package/src/ts/dynamodb/trpc-connection/generator.js +3 -1
  146. package/src/ts/dynamodb/trpc-connection/generator.js.map +1 -1
  147. package/src/ts/lambda-function/generator.d.ts +38 -0
  148. package/src/ts/lambda-function/generator.js +49 -20
  149. package/src/ts/lambda-function/generator.js.map +1 -1
  150. package/src/ts/lib/generator.d.ts +7 -0
  151. package/src/ts/lib/generator.js +8 -1
  152. package/src/ts/lib/generator.js.map +1 -1
  153. package/src/ts/lib/ts-project-utils.d.ts +3 -1
  154. package/src/ts/lib/ts-project-utils.js +3 -2
  155. package/src/ts/lib/ts-project-utils.js.map +1 -1
  156. package/src/ts/lib/vitest.d.ts +10 -1
  157. package/src/ts/lib/vitest.js +14 -2
  158. package/src/ts/lib/vitest.js.map +1 -1
  159. package/src/ts/mcp-server/generator.d.ts +71 -0
  160. package/src/ts/mcp-server/generator.js +73 -36
  161. package/src/ts/mcp-server/generator.js.map +1 -1
  162. package/src/ts/nx-generator/generator.d.ts +3 -0
  163. package/src/ts/nx-generator/generator.js +8 -2
  164. package/src/ts/nx-generator/generator.js.map +1 -1
  165. package/src/ts/nx-migration/files/migration.ts.template +4 -0
  166. package/src/ts/nx-migration/generator.d.ts +3 -0
  167. package/src/ts/nx-migration/generator.js +8 -2
  168. package/src/ts/nx-migration/generator.js.map +1 -1
  169. package/src/ts/nx-plugin/generator.d.ts +3 -0
  170. package/src/ts/nx-plugin/generator.js +8 -2
  171. package/src/ts/nx-plugin/generator.js.map +1 -1
  172. package/src/ts/nx-plugin/utils.d.ts +7 -2
  173. package/src/ts/nx-plugin/utils.js +10 -4
  174. package/src/ts/nx-plugin/utils.js.map +1 -1
  175. package/src/ts/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +10 -0
  176. package/src/ts/rdb/agent-connection/generator.js +8 -1
  177. package/src/ts/rdb/agent-connection/generator.js.map +1 -1
  178. package/src/ts/rdb/generator.d.ts +101 -0
  179. package/src/ts/rdb/generator.js +93 -41
  180. package/src/ts/rdb/generator.js.map +1 -1
  181. package/src/ts/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +10 -0
  182. package/src/ts/rdb/mcp-server-connection/generator.js +8 -1
  183. package/src/ts/rdb/mcp-server-connection/generator.js.map +1 -1
  184. package/src/ts/rdb/smithy-connection/__snapshots__/generator.spec.ts.snap +9 -0
  185. package/src/ts/rdb/smithy-connection/generator.js +4 -1
  186. package/src/ts/rdb/smithy-connection/generator.js.map +1 -1
  187. package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +9 -0
  188. package/src/ts/rdb/trpc-connection/generator.js +3 -1
  189. package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
  190. package/src/ts/react-website/agui/generator.d.ts +86 -0
  191. package/src/ts/react-website/agui/generator.js +63 -28
  192. package/src/ts/react-website/agui/generator.js.map +1 -1
  193. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +8 -2
  194. package/src/ts/react-website/app/generator.d.ts +136 -1
  195. package/src/ts/react-website/app/generator.js +109 -40
  196. package/src/ts/react-website/app/generator.js.map +1 -1
  197. package/src/ts/react-website/cognito-auth/generator.d.ts +19 -0
  198. package/src/ts/react-website/cognito-auth/generator.js +21 -9
  199. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  200. package/src/utils/add-dependencies.d.ts +38 -0
  201. package/src/utils/add-dependencies.js +83 -0
  202. package/src/utils/add-dependencies.js.map +1 -0
  203. package/src/utils/agent-connection/agent-connection.d.ts +27 -6
  204. package/src/utils/agent-connection/agent-connection.js +47 -18
  205. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  206. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +19 -1
  207. package/src/utils/agent-core-constructs/agent-core-constructs.js +26 -6
  208. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  209. package/src/utils/api-constructs/api-constructs.d.ts +21 -2
  210. package/src/utils/api-constructs/api-constructs.js +26 -5
  211. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  212. package/src/utils/bundle/bundle.d.ts +6 -1
  213. package/src/utils/bundle/bundle.js +8 -2
  214. package/src/utils/bundle/bundle.js.map +1 -1
  215. package/src/utils/commands.d.ts +5 -4
  216. package/src/utils/commands.js +2 -6
  217. package/src/utils/commands.js.map +1 -1
  218. package/src/utils/connection/open-api/react.d.ts +18 -1
  219. package/src/utils/connection/open-api/react.js +27 -3
  220. package/src/utils/connection/open-api/react.js.map +1 -1
  221. package/src/utils/declared-dependencies.d.ts +140 -0
  222. package/src/utils/declared-dependencies.js +64 -0
  223. package/src/utils/declared-dependencies.js.map +1 -0
  224. package/src/utils/docker.d.ts +10 -1
  225. package/src/utils/docker.js +7 -3
  226. package/src/utils/docker.js.map +1 -1
  227. package/src/utils/files/common/scripts/src/dynamodb/start-container.ts.template +0 -1
  228. package/src/utils/fs.d.ts +15 -4
  229. package/src/utils/fs.js +26 -13
  230. package/src/utils/fs.js.map +1 -1
  231. package/src/utils/init.d.ts +14 -1
  232. package/src/utils/init.js +25 -7
  233. package/src/utils/init.js.map +1 -1
  234. package/src/utils/migration-versions.d.ts +25 -6
  235. package/src/utils/migration-versions.js +72 -14
  236. package/src/utils/migration-versions.js.map +1 -1
  237. package/src/utils/nx.d.ts +18 -0
  238. package/src/utils/nx.js +4 -0
  239. package/src/utils/nx.js.map +1 -1
  240. package/src/utils/py.d.ts +3 -2
  241. package/src/utils/py.js +10 -10
  242. package/src/utils/py.js.map +1 -1
  243. package/src/utils/shared-constructs-constants.d.ts +39 -4
  244. package/src/utils/shared-constructs-constants.js +29 -0
  245. package/src/utils/shared-constructs-constants.js.map +1 -1
  246. package/src/utils/shared-constructs.d.ts +4 -1
  247. package/src/utils/shared-constructs.js +5 -4
  248. package/src/utils/shared-constructs.js.map +1 -1
  249. package/src/utils/shared-dynamodb-scripts.d.ts +8 -1
  250. package/src/utils/shared-dynamodb-scripts.js +11 -3
  251. package/src/utils/shared-dynamodb-scripts.js.map +1 -1
  252. package/src/utils/shared-infra-scripts.d.ts +16 -1
  253. package/src/utils/shared-infra-scripts.js +18 -3
  254. package/src/utils/shared-infra-scripts.js.map +1 -1
  255. package/src/utils/shared-rdb-scripts.d.ts +12 -1
  256. package/src/utils/shared-rdb-scripts.js +17 -3
  257. package/src/utils/shared-rdb-scripts.js.map +1 -1
  258. package/src/utils/shared-shadcn.d.ts +26 -1
  259. package/src/utils/shared-shadcn.js +31 -14
  260. package/src/utils/shared-shadcn.js.map +1 -1
  261. package/src/utils/version-upgrade-migration/migration.d.ts +14 -0
  262. package/src/utils/version-upgrade-migration/migration.js +16 -0
  263. package/src/utils/version-upgrade-migration/migration.js.map +1 -0
  264. package/src/utils/version-upgrade-migration/nx-package-updates.d.ts +45 -0
  265. package/src/utils/version-upgrade-migration/nx-package-updates.js +50 -0
  266. package/src/utils/version-upgrade-migration/nx-package-updates.js.map +1 -0
  267. package/src/utils/version-upgrade-migration/owned-dependencies.d.ts +50 -0
  268. package/src/utils/version-upgrade-migration/owned-dependencies.js +98 -0
  269. package/src/utils/version-upgrade-migration/owned-dependencies.js.map +1 -0
  270. package/src/utils/version-upgrade-migration/register.d.ts +23 -0
  271. package/src/utils/version-upgrade-migration/register.js +38 -0
  272. package/src/utils/version-upgrade-migration/register.js.map +1 -0
  273. package/src/utils/version-upgrade-migration/sync-metrics-version.d.ts +13 -0
  274. package/src/utils/version-upgrade-migration/sync-metrics-version.js +33 -0
  275. package/src/utils/version-upgrade-migration/sync-metrics-version.js.map +1 -0
  276. package/src/utils/version-upgrade-migration/sync-vended-versions.d.ts +10 -0
  277. package/src/utils/version-upgrade-migration/sync-vended-versions.js +504 -0
  278. package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -0
  279. package/src/utils/version-upgrade-migration/vended-upgrade.d.ts +14 -0
  280. package/src/utils/version-upgrade-migration/vended-upgrade.js +40 -0
  281. package/src/utils/version-upgrade-migration/vended-upgrade.js.map +1 -0
  282. package/src/utils/versions.d.ts +25 -5
  283. package/src/utils/versions.js +46 -4
  284. package/src/utils/versions.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/migration-versions.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { compare, valid } from 'semver';\n\n/**\n * Version stamping for migrations.\n *\n * A new migration is committed with no `version` — releases are calculated from\n * conventional commits and written only to `dist/` and a git tag, so versions\n * reach the published `migrations.json` two ways:\n *\n * - At release time (`scripts/stamp-migrations.ts`) entries still missing a\n * version are stamped into the compiled `migrations.json`: an already shipped\n * one gets the earliest release tag registering it, and a net-new one gets the\n * version the release is about to publish, which the release job passes in\n * after `nx release version` writes it to the dist manifests.\n * - The weekly `update-versions` PR backfills the version of the release that\n * shipped each migration, moving and re-keying it accordingly\n * (`scripts/backfill-migration-versions.ts`), so source converges on the\n * versions of everything already released.\n *\n * A version already in source always wins, so backfilled entries are stable.\n */\n\nexport interface MigrationsJson {\n generators?: Record<string, { version?: string } & Record<string, unknown>>;\n}\n\n/** Ascending semver comparator for `Array.prototype.sort`. */\nexport const compareVersions = compare;\n\n/** Whether a string is an exact semver version. */\nexport const isValidVersion = (version: string): boolean =>\n valid(version) !== null;\n\n/**\n * Map of migration key -> version of the earliest release that registers it,\n * resolved only for the entries still missing a `version` (one already recorded\n * in source wins, so its history doesn't need reading). A migration that hasn't\n * been released is absent.\n *\n * Walks releases newest first and stops as soon as every entry is resolved: an\n * entry that has disappeared from a release's `migrations.json` was first\n * registered by the release after it, which is the one that shipped it.\n *\n * @param migrations parsed source migrations.json\n * @param versions released versions in descending semver order\n * @param readReleasedMigrations reads the `migrations.json` published by a given\n * version, or undefined if it predates the manifest\n */\nexport const readShippedMigrationVersions = (\n migrations: MigrationsJson,\n versions: string[],\n readReleasedMigrations: (version: string) => MigrationsJson | undefined,\n): Record<string, string> => {\n const shippedVersions: Record<string, string> = {};\n let unresolved = Object.entries(migrations.generators ?? {})\n .filter(([, entry]) => !entry.version)\n .map(([key]) => key);\n\n for (const version of versions) {\n if (unresolved.length === 0) {\n break;\n }\n const registered = new Set(\n Object.keys(readReleasedMigrations(version)?.generators ?? {}),\n );\n // Entries gone at this release keep the version recorded from the release\n // after it (if any) and stop being looked up.\n unresolved = unresolved.filter((key) => registered.has(key));\n for (const key of unresolved) {\n shippedVersions[key] = version;\n }\n }\n\n return shippedVersions;\n};\n\n/**\n * Return a copy of the migrations collection with a `version` stamped onto\n * every generator entry, preserving any already present.\n *\n * @param migrations parsed migrations.json to stamp\n * @param shippedVersions migration key -> version of the earliest release\n * tag that registers it (absent for migrations that haven't shipped)\n * @param pendingVersion version the release is about to publish, stamped onto\n * unshipped migrations so their version is one that really shipped\n */\nexport const stampMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n pendingVersion: string,\n): MigrationsJson => ({\n ...migrations,\n generators: Object.fromEntries(\n Object.entries(migrations.generators ?? {}).map(([name, entry]) => [\n name,\n { version: shippedVersions[name] ?? pendingVersion, ...entry },\n ]),\n ),\n});\n\n/** Directory a newly scaffolded migration lands in, before a release claims it. */\nexport const LATEST_MIGRATIONS_DIR = 'latest';\n\n/** Directory holding the migrations shipped by a given release. */\nexport const versionMigrationsDir = (version: string) => `v${version}`;\n\n/**\n * Key a migration is registered under in `migrations.json`. Prefixed with its\n * directory so reusing a name in a later release can't silently overwrite the\n * one that already shipped.\n */\nexport const migrationKey = (dir: string, name: string) => `${dir}-${name}`;\n\nconst LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;\n\n/** A migration directory move the caller needs to make on disk. */\nexport interface MigrationDirMove {\n name: string;\n version: string;\n from: string;\n to: string;\n}\n\n/**\n * Record the release that shipped each migration on entries without a version,\n * re-keying them and re-pointing their paths at that release's folder, and\n * return the collection alongside the keys that changed and the directory moves\n * to make on disk.\n *\n * Unlike `stampMigrationVersions` this only records already-released versions,\n * leaving the release to decide what a net-new migration gets.\n *\n * @param migrations parsed migrations.json to backfill\n * @param shippedVersions migration key -> version of the earliest release tag\n * that registers it (absent for migrations that haven't shipped)\n */\nexport const backfillMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n): {\n migrations: MigrationsJson;\n backfilled: string[];\n moves: MigrationDirMove[];\n} => {\n const generators: NonNullable<MigrationsJson['generators']> = {};\n const backfilled: string[] = [];\n const moves: MigrationDirMove[] = [];\n\n for (const [key, entry] of Object.entries(migrations.generators ?? {})) {\n const version = shippedVersions[key];\n if (entry.version || !version) {\n generators[key] = entry;\n continue;\n }\n\n const name = key.startsWith(LATEST_KEY_PREFIX)\n ? key.slice(LATEST_KEY_PREFIX.length)\n : key;\n const versionDir = versionMigrationsDir(version);\n const latestSegment = `/${LATEST_MIGRATIONS_DIR}/${name}/`;\n const versionSegment = `/${versionDir}/${name}/`;\n\n // Re-point each path field at the version folder, recording the move the\n // caller needs to make on disk the first time one is found.\n const repointed: Record<string, unknown> = {};\n let moved = false;\n for (const [field, value] of Object.entries(entry)) {\n if (typeof value !== 'string' || !value.includes(latestSegment)) {\n repointed[field] = value;\n continue;\n }\n repointed[field] = value.replace(latestSegment, versionSegment);\n if (!moved) {\n moved = true;\n const dir = value.slice(0, value.indexOf(latestSegment));\n moves.push({\n name,\n version,\n from: `${dir}${latestSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n to: `${dir}${versionSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n });\n }\n }\n\n generators[migrationKey(versionDir, name)] = { version, ...repointed };\n backfilled.push(key);\n }\n\n return { migrations: { ...migrations, generators }, backfilled, moves };\n};\n"],"names":["compare","valid","compareVersions","isValidVersion","version","readShippedMigrationVersions","migrations","versions","readReleasedMigrations","shippedVersions","unresolved","Object","entries","generators","filter","entry","map","key","length","registered","Set","keys","has","stampMigrationVersions","pendingVersion","fromEntries","name","LATEST_MIGRATIONS_DIR","versionMigrationsDir","migrationKey","dir","LATEST_KEY_PREFIX","backfillMigrationVersions","backfilled","moves","startsWith","slice","versionDir","latestSegment","versionSegment","repointed","moved","field","value","includes","replace","indexOf","push","from","to"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/migration-versions.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { compare, valid } from 'semver';\n\n/**\n * Version stamping for migrations.\n *\n * A new migration is committed with no `version` — releases are calculated from\n * conventional commits and written only to `dist/` and a git tag, so versions\n * reach the published `migrations.json` two ways:\n *\n * - At release time (`scripts/stamp-migrations.ts`) entries still missing a\n * version are stamped into the compiled `migrations.json`: an already shipped\n * one gets the earliest release tag registering it, and a net-new one gets the\n * version the release is about to publish, which the release job passes in\n * after `nx release version` writes it to the dist manifests.\n * - The weekly `update-versions` PR backfills the version of the release that\n * shipped each migration, moving and re-keying it accordingly\n * (`scripts/backfill-migration-versions.ts`), so source converges on the\n * versions of everything already released. `packageJsonUpdates` entries are\n * dated in place there too, since their keys never change.\n *\n * A version already in source always wins, so backfilled entries are stable.\n *\n * An entry marked `everyMigration: true` is never backfilled or pinned, and is\n * re-stamped with each pending version, so it runs on every upgrade.\n */\n\nexport interface MigrationsJson {\n generators?: Record<\n string,\n { version?: string; everyMigration?: boolean } & Record<string, unknown>\n >;\n /**\n * Declarative dependency bumps `nx migrate` applies to the root manifest.\n * Keyed by what the bump targets rather than the release that ships it, so an\n * entry is unique from the moment it is written and one release's bump can sit\n * beside the next; nx itself gates on the entry's `version`.\n */\n packageJsonUpdates?: Record<\n string,\n { version: string } & Record<string, unknown>\n >;\n}\n\n/** Ascending semver comparator for `Array.prototype.sort`. */\nexport const compareVersions = compare;\n\n/** Whether a string is an exact semver version. */\nexport const isValidVersion = (version: string): boolean =>\n valid(version) !== null;\n\n/**\n * Map of entry key -> version of the earliest release that registers it, across\n * both `generators` and `packageJsonUpdates`. Resolved only for the entries still\n * missing a version (one already recorded in source wins, so its history doesn't\n * need reading). An entry that hasn't been released is absent.\n *\n * Walks releases newest first and stops as soon as every entry is resolved: an\n * entry that has disappeared from a release's `migrations.json` was first\n * registered by the release after it, which is the one that shipped it.\n *\n * Both sections resolve the same way and share the walk, so the release doesn't\n * read tag history twice. Keys can't collide: a migration is keyed by its own\n * name, an nx bump by the nx version it moves to.\n *\n * @param migrations parsed source migrations.json\n * @param versions released versions in descending semver order\n * @param readReleasedMigrations reads the `migrations.json` published by a given\n * version, or undefined if it predates the manifest\n */\nexport const readShippedMigrationVersions = (\n migrations: MigrationsJson,\n versions: string[],\n readReleasedMigrations: (version: string) => MigrationsJson | undefined,\n): Record<string, string> => {\n const shippedVersions: Record<string, string> = {};\n // A `packageJsonUpdates` entry records `latest` rather than omitting its\n // version, since nx requires the field.\n let unresolved = [\n ...Object.entries(migrations.generators ?? {})\n .filter(([, entry]) => !entry.version)\n .map(([key]) => key),\n ...Object.entries(migrations.packageJsonUpdates ?? {})\n .filter(([, entry]) => entry.version === LATEST_MIGRATIONS_DIR)\n .map(([key]) => key),\n ];\n\n for (const version of versions) {\n if (unresolved.length === 0) {\n break;\n }\n const released = readReleasedMigrations(version);\n const registered = new Set([\n ...Object.keys(released?.generators ?? {}),\n ...Object.keys(released?.packageJsonUpdates ?? {}),\n ]);\n // Entries gone at this release keep the version recorded from the release\n // after it (if any) and stop being looked up.\n unresolved = unresolved.filter((key) => registered.has(key));\n for (const key of unresolved) {\n shippedVersions[key] = version;\n }\n }\n\n return shippedVersions;\n};\n\n/**\n * Return a copy of the migrations collection with a `version` stamped onto\n * every generator entry, preserving any already present, and the pending version\n * recorded on any `packageJsonUpdates` entry still holding `latest`.\n *\n * @param migrations parsed migrations.json to stamp\n * @param shippedVersions migration key -> version of the earliest release\n * tag that registers it (absent for migrations that haven't shipped)\n * @param pendingVersion version the release is about to publish, stamped onto\n * unshipped migrations so their version is one that really shipped\n */\nexport const stampMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n pendingVersion: string,\n): MigrationsJson => ({\n ...migrations,\n generators: Object.fromEntries(\n // `nx migrate` sorts the run ascending by version and preserves the\n // manifest's order among equal versions, so emitting the every-migration\n // entries last is what makes them run after the release's own migrations.\n Object.entries(migrations.generators ?? {})\n .sort(\n ([, a], [, b]) =>\n Number(a.everyMigration ?? false) - Number(b.everyMigration ?? false),\n )\n .map(([name, entry]) => {\n // Source-only marker, stripped from what nx reads.\n const { everyMigration, version: sourceVersion, ...published } = entry;\n // Overrides any source version so it stays ahead of what is installed.\n const version = everyMigration\n ? pendingVersion\n : (sourceVersion ?? shippedVersions[name] ?? pendingVersion);\n return [name, { version, ...published }];\n }),\n ),\n ...(migrations.packageJsonUpdates && {\n packageJsonUpdates: stampPackageJsonUpdates(\n migrations.packageJsonUpdates,\n pendingVersion,\n ),\n }),\n});\n\n/**\n * Version any `packageJsonUpdates` entry still holding `latest` with the release\n * about to publish it, so the nx bump ships under a version `nx migrate` gates on.\n */\nconst stampPackageJsonUpdates = (\n packageJsonUpdates: NonNullable<MigrationsJson['packageJsonUpdates']>,\n pendingVersion: string,\n): NonNullable<MigrationsJson['packageJsonUpdates']> =>\n resolvePackageJsonUpdateVersions(packageJsonUpdates, () => pendingVersion);\n\n/** Directory a newly scaffolded migration lands in, before a release claims it. */\nexport const LATEST_MIGRATIONS_DIR = 'latest';\n\n/** Directory holding the migrations shipped by a given release. */\nexport const versionMigrationsDir = (version: string) => `v${version}`;\n\n/**\n * Key a migration is registered under in `migrations.json`. Prefixed with its\n * directory so reusing a name in a later release can't silently overwrite the\n * one that already shipped.\n */\nexport const migrationKey = (dir: string, name: string) => `${dir}-${name}`;\n\nconst LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;\n\n/** A migration directory move the caller needs to make on disk. */\nexport interface MigrationDirMove {\n name: string;\n version: string;\n from: string;\n to: string;\n}\n\n/**\n * Record the release that shipped each migration on entries without a version,\n * re-keying them and re-pointing their paths at that release's folder, and\n * return the collection alongside the keys that changed and the directory moves\n * to make on disk.\n *\n * Unlike `stampMigrationVersions` this only records already-released versions,\n * leaving the release to decide what a net-new migration gets.\n *\n * @param migrations parsed migrations.json to backfill\n * @param shippedVersions migration key -> version of the earliest release tag\n * that registers it (absent for migrations that haven't shipped)\n */\nexport const backfillMigrationVersions = (\n migrations: MigrationsJson,\n shippedVersions: Record<string, string>,\n): {\n migrations: MigrationsJson;\n backfilled: string[];\n moves: MigrationDirMove[];\n} => {\n const generators: NonNullable<MigrationsJson['generators']> = {};\n const backfilled: string[] = [];\n const moves: MigrationDirMove[] = [];\n // Reported alongside the migrations so the update's PR says an nx bump was\n // dated, and so the caller knows there is something to commit.\n const backfilledUpdates = Object.entries(migrations.packageJsonUpdates ?? {})\n .filter(\n ([key, entry]) =>\n entry.version === LATEST_MIGRATIONS_DIR && shippedVersions[key],\n )\n .map(([key]) => key);\n\n for (const [key, entry] of Object.entries(migrations.generators ?? {})) {\n const version = shippedVersions[key];\n // Pinning an every-migration entry would stop it running on later upgrades.\n if (entry.version || !version || entry.everyMigration) {\n generators[key] = entry;\n continue;\n }\n\n const name = key.startsWith(LATEST_KEY_PREFIX)\n ? key.slice(LATEST_KEY_PREFIX.length)\n : key;\n const versionDir = versionMigrationsDir(version);\n const latestSegment = `/${LATEST_MIGRATIONS_DIR}/${name}/`;\n const versionSegment = `/${versionDir}/${name}/`;\n\n // Re-point each path field at the version folder, recording the move the\n // caller needs to make on disk the first time one is found.\n const repointed: Record<string, unknown> = {};\n let moved = false;\n for (const [field, value] of Object.entries(entry)) {\n if (typeof value !== 'string' || !value.includes(latestSegment)) {\n repointed[field] = value;\n continue;\n }\n repointed[field] = value.replace(latestSegment, versionSegment);\n if (!moved) {\n moved = true;\n const dir = value.slice(0, value.indexOf(latestSegment));\n moves.push({\n name,\n version,\n from: `${dir}${latestSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n to: `${dir}${versionSegment}`.replace(/^\\.\\/|\\/$/g, ''),\n });\n }\n }\n\n generators[migrationKey(versionDir, name)] = { version, ...repointed };\n backfilled.push(key);\n }\n\n return {\n migrations: {\n ...migrations,\n generators,\n ...(migrations.packageJsonUpdates && {\n packageJsonUpdates: resolvePackageJsonUpdateVersions(\n migrations.packageJsonUpdates,\n (key) => shippedVersions[key],\n ),\n }),\n },\n backfilled: [...backfilled, ...backfilledUpdates],\n moves,\n };\n};\n\n/**\n * Record the version each `packageJsonUpdates` entry ships under, for those still\n * holding `latest`.\n *\n * The key already identifies the entry — an nx bump is named for the nx version\n * it moves to — so only the `version` field changes. Nothing is re-keyed, which\n * is what lets one release's bump sit alongside the next without either being\n * overwritten before it ships.\n */\nconst resolvePackageJsonUpdateVersions = (\n packageJsonUpdates: NonNullable<MigrationsJson['packageJsonUpdates']>,\n resolve: (key: string) => string | undefined,\n): NonNullable<MigrationsJson['packageJsonUpdates']> =>\n Object.fromEntries(\n Object.entries(packageJsonUpdates).map(([key, entry]) => {\n const version =\n entry.version === LATEST_MIGRATIONS_DIR ? resolve(key) : undefined;\n return [key, version ? { ...entry, version } : entry];\n }),\n );\n"],"names":["compare","valid","compareVersions","isValidVersion","version","readShippedMigrationVersions","migrations","versions","readReleasedMigrations","shippedVersions","unresolved","Object","entries","generators","filter","entry","map","key","packageJsonUpdates","LATEST_MIGRATIONS_DIR","length","released","registered","Set","keys","has","stampMigrationVersions","pendingVersion","fromEntries","sort","a","b","Number","everyMigration","name","sourceVersion","published","stampPackageJsonUpdates","resolvePackageJsonUpdateVersions","versionMigrationsDir","migrationKey","dir","LATEST_KEY_PREFIX","backfillMigrationVersions","backfilled","moves","backfilledUpdates","startsWith","slice","versionDir","latestSegment","versionSegment","repointed","moved","field","value","includes","replace","indexOf","push","from","to","resolve","undefined"],"mappings":"AAAA;;;CAGC,GACD,SAASA,OAAO,EAAEC,KAAK,QAAQ,SAAS;AA2CxC,4DAA4D,GAC5D,OAAO,MAAMC,kBAAkBF,QAAQ;AAEvC,iDAAiD,GACjD,OAAO,MAAMG,iBAAiB,CAACC,UAC7BH,MAAMG,aAAa,KAAK;AAE1B;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,YACAC,UACAC;IAEA,MAAMC,kBAA0C,CAAC;IACjD,yEAAyE;IACzE,wCAAwC;IACxC,IAAIC,aAAa;WACZC,OAAOC,OAAO,CAACN,WAAWO,UAAU,IAAI,CAAC,GACzCC,MAAM,CAAC,CAAC,GAAGC,MAAM,GAAK,CAACA,MAAMX,OAAO,EACpCY,GAAG,CAAC,CAAC,CAACC,IAAI,GAAKA;WACfN,OAAOC,OAAO,CAACN,WAAWY,kBAAkB,IAAI,CAAC,GACjDJ,MAAM,CAAC,CAAC,GAAGC,MAAM,GAAKA,MAAMX,OAAO,KAAKe,uBACxCH,GAAG,CAAC,CAAC,CAACC,IAAI,GAAKA;KACnB;IAED,KAAK,MAAMb,WAAWG,SAAU;QAC9B,IAAIG,WAAWU,MAAM,KAAK,GAAG;YAC3B;QACF;QACA,MAAMC,WAAWb,uBAAuBJ;QACxC,MAAMkB,aAAa,IAAIC,IAAI;eACtBZ,OAAOa,IAAI,CAACH,UAAUR,cAAc,CAAC;eACrCF,OAAOa,IAAI,CAACH,UAAUH,sBAAsB,CAAC;SACjD;QACD,0EAA0E;QAC1E,8CAA8C;QAC9CR,aAAaA,WAAWI,MAAM,CAAC,CAACG,MAAQK,WAAWG,GAAG,CAACR;QACvD,KAAK,MAAMA,OAAOP,WAAY;YAC5BD,eAAe,CAACQ,IAAI,GAAGb;QACzB;IACF;IAEA,OAAOK;AACT,EAAE;AAEF;;;;;;;;;;CAUC,GACD,OAAO,MAAMiB,yBAAyB,CACpCpB,YACAG,iBACAkB,iBACoB,CAAA;QACpB,GAAGrB,UAAU;QACbO,YAAYF,OAAOiB,WAAW,CAC5B,oEAAoE;QACpE,yEAAyE;QACzE,0EAA0E;QAC1EjB,OAAOC,OAAO,CAACN,WAAWO,UAAU,IAAI,CAAC,GACtCgB,IAAI,CACH,CAAC,GAAGC,EAAE,EAAE,GAAGC,EAAE,GACXC,OAAOF,EAAEG,cAAc,IAAI,SAASD,OAAOD,EAAEE,cAAc,IAAI,QAElEjB,GAAG,CAAC,CAAC,CAACkB,MAAMnB,MAAM;YACjB,mDAAmD;YACnD,MAAM,EAAEkB,cAAc,EAAE7B,SAAS+B,aAAa,EAAE,GAAGC,WAAW,GAAGrB;YACjE,uEAAuE;YACvE,MAAMX,UAAU6B,iBACZN,iBACCQ,iBAAiB1B,eAAe,CAACyB,KAAK,IAAIP;YAC/C,OAAO;gBAACO;gBAAM;oBAAE9B;oBAAS,GAAGgC,SAAS;gBAAC;aAAE;QAC1C;QAEJ,GAAI9B,WAAWY,kBAAkB,IAAI;YACnCA,oBAAoBmB,wBAClB/B,WAAWY,kBAAkB,EAC7BS;QAEJ,CAAC;IACH,CAAA,EAAG;AAEH;;;CAGC,GACD,MAAMU,0BAA0B,CAC9BnB,oBACAS,iBAEAW,iCAAiCpB,oBAAoB,IAAMS;AAE7D,iFAAiF,GACjF,OAAO,MAAMR,wBAAwB,SAAS;AAE9C,iEAAiE,GACjE,OAAO,MAAMoB,uBAAuB,CAACnC,UAAoB,CAAC,CAAC,EAAEA,SAAS,CAAC;AAEvE;;;;CAIC,GACD,OAAO,MAAMoC,eAAe,CAACC,KAAaP,OAAiB,GAAGO,IAAI,CAAC,EAAEP,MAAM,CAAC;AAE5E,MAAMQ,oBAAoB,GAAGvB,sBAAsB,CAAC,CAAC;AAUrD;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMwB,4BAA4B,CACvCrC,YACAG;IAMA,MAAMI,aAAwD,CAAC;IAC/D,MAAM+B,aAAuB,EAAE;IAC/B,MAAMC,QAA4B,EAAE;IACpC,2EAA2E;IAC3E,+DAA+D;IAC/D,MAAMC,oBAAoBnC,OAAOC,OAAO,CAACN,WAAWY,kBAAkB,IAAI,CAAC,GACxEJ,MAAM,CACL,CAAC,CAACG,KAAKF,MAAM,GACXA,MAAMX,OAAO,KAAKe,yBAAyBV,eAAe,CAACQ,IAAI,EAElED,GAAG,CAAC,CAAC,CAACC,IAAI,GAAKA;IAElB,KAAK,MAAM,CAACA,KAAKF,MAAM,IAAIJ,OAAOC,OAAO,CAACN,WAAWO,UAAU,IAAI,CAAC,GAAI;QACtE,MAAMT,UAAUK,eAAe,CAACQ,IAAI;QACpC,4EAA4E;QAC5E,IAAIF,MAAMX,OAAO,IAAI,CAACA,WAAWW,MAAMkB,cAAc,EAAE;YACrDpB,UAAU,CAACI,IAAI,GAAGF;YAClB;QACF;QAEA,MAAMmB,OAAOjB,IAAI8B,UAAU,CAACL,qBACxBzB,IAAI+B,KAAK,CAACN,kBAAkBtB,MAAM,IAClCH;QACJ,MAAMgC,aAAaV,qBAAqBnC;QACxC,MAAM8C,gBAAgB,CAAC,CAAC,EAAE/B,sBAAsB,CAAC,EAAEe,KAAK,CAAC,CAAC;QAC1D,MAAMiB,iBAAiB,CAAC,CAAC,EAAEF,WAAW,CAAC,EAAEf,KAAK,CAAC,CAAC;QAEhD,yEAAyE;QACzE,4DAA4D;QAC5D,MAAMkB,YAAqC,CAAC;QAC5C,IAAIC,QAAQ;QACZ,KAAK,MAAM,CAACC,OAAOC,MAAM,IAAI5C,OAAOC,OAAO,CAACG,OAAQ;YAClD,IAAI,OAAOwC,UAAU,YAAY,CAACA,MAAMC,QAAQ,CAACN,gBAAgB;gBAC/DE,SAAS,CAACE,MAAM,GAAGC;gBACnB;YACF;YACAH,SAAS,CAACE,MAAM,GAAGC,MAAME,OAAO,CAACP,eAAeC;YAChD,IAAI,CAACE,OAAO;gBACVA,QAAQ;gBACR,MAAMZ,MAAMc,MAAMP,KAAK,CAAC,GAAGO,MAAMG,OAAO,CAACR;gBACzCL,MAAMc,IAAI,CAAC;oBACTzB;oBACA9B;oBACAwD,MAAM,GAAGnB,MAAMS,eAAe,CAACO,OAAO,CAAC,cAAc;oBACrDI,IAAI,GAAGpB,MAAMU,gBAAgB,CAACM,OAAO,CAAC,cAAc;gBACtD;YACF;QACF;QAEA5C,UAAU,CAAC2B,aAAaS,YAAYf,MAAM,GAAG;YAAE9B;YAAS,GAAGgD,SAAS;QAAC;QACrER,WAAWe,IAAI,CAAC1C;IAClB;IAEA,OAAO;QACLX,YAAY;YACV,GAAGA,UAAU;YACbO;YACA,GAAIP,WAAWY,kBAAkB,IAAI;gBACnCA,oBAAoBoB,iCAClBhC,WAAWY,kBAAkB,EAC7B,CAACD,MAAQR,eAAe,CAACQ,IAAI;YAEjC,CAAC;QACH;QACA2B,YAAY;eAAIA;eAAeE;SAAkB;QACjDD;IACF;AACF,EAAE;AAEF;;;;;;;;CAQC,GACD,MAAMP,mCAAmC,CACvCpB,oBACA4C,UAEAnD,OAAOiB,WAAW,CAChBjB,OAAOC,OAAO,CAACM,oBAAoBF,GAAG,CAAC,CAAC,CAACC,KAAKF,MAAM;QAClD,MAAMX,UACJW,MAAMX,OAAO,KAAKe,wBAAwB2C,QAAQ7C,OAAO8C;QAC3D,OAAO;YAAC9C;YAAKb,UAAU;gBAAE,GAAGW,KAAK;gBAAEX;YAAQ,IAAIW;SAAM;IACvD"}
package/src/utils/nx.d.ts CHANGED
@@ -57,11 +57,29 @@ export declare const addGeneratorMetadata: (tree: Tree, projectName: string, inf
57
57
  export interface ComponentMetadata {
58
58
  readonly generator: string;
59
59
  readonly name?: string;
60
+ /**
61
+ * What this entry wires up. For a connection that is the target — the thing
62
+ * being connected to — paired with `sourcePath` below.
63
+ */
60
64
  readonly path?: string;
65
+ /**
66
+ * The component the connection is made *from*, when both ends are components
67
+ * of a project rather than whole projects.
68
+ *
69
+ * A connection records the project it lives on and the target it reaches, which
70
+ * alone can't tell which of several components on that project is wired up.
71
+ * Recorded as a path for the same reason `path` is: it identifies a component
72
+ * within its project without depending on a name that may repeat.
73
+ */
74
+ readonly sourcePath?: string;
61
75
  [key: string]: any;
62
76
  }
63
77
  /**
64
78
  * Add metadata about the generator that generated the component to the project.json
79
+ *
80
+ * A connection between two components passes the source's path as
81
+ * `additionalMetadata.sourcePath`, so the pair is identifiable rather than just
82
+ * the two projects.
65
83
  */
66
84
  export declare const addComponentGeneratorMetadata: (tree: Tree, projectName: string, info: {
67
85
  id: string;
package/src/utils/nx.js CHANGED
@@ -105,6 +105,10 @@ export const getPackageVersion = ()=>{
105
105
  };
106
106
  /**
107
107
  * Add metadata about the generator that generated the component to the project.json
108
+ *
109
+ * A connection between two components passes the source's path as
110
+ * `additionalMetadata.sourcePath`, so the pair is identifiable rather than just
111
+ * the two projects.
108
112
  */ export const addComponentGeneratorMetadata = (tree, projectName, info, componentPath, componentName, additionalMetadata)=>{
109
113
  const config = readProjectConfigurationUnqualified(tree, projectName);
110
114
  const existingComponents = config?.metadata?.components ?? [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/nx.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type ProjectConfiguration,\n readJson,\n readProjectConfiguration,\n type TargetConfiguration,\n type TargetDefaultValue,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport * as path from 'path';\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { NX_PLUGIN_MCP_PACKAGE_NAME } from './mcp';\nimport { toSnakeCase } from './names';\nimport { getNpmScope, getNpmScopePrefix } from './npm-scope';\n\nexport type { GeneratorInfo, NxGeneratorInfo } from './generators';\nexport { buildGeneratorInfoList } from './generators';\n\nimport { buildGeneratorInfoList, type GeneratorInfo } from './generators';\n\nconst GENERATORS = buildGeneratorInfoList(\n path.resolve(import.meta.dirname, '..', '..'),\n);\n\n/**\n * List Nx Plugin for AWS generators\n * @param includeHidden include hidden generators (default false)\n */\nexport const listGenerators = (includeHidden = false) =>\n GENERATORS.filter((g) => includeHidden || !g.hidden);\n\n/**\n * Return generator information. Call this from a generator method with import.meta.filename\n */\nexport const getGeneratorInfo = (generatorFileName: string): GeneratorInfo => {\n const { dir, name } = path.parse(path.resolve(generatorFileName));\n const resolvedFactoryPath = path.join(dir, name);\n return GENERATORS.find(\n (generatorInfo) =>\n generatorInfo.resolvedFactoryPath === resolvedFactoryPath,\n );\n};\n\nexport const getPackageVersion = () => {\n return PackageJson.version;\n};\n\n/**\n * True inside the plugin's own monorepo, where the plugin is the source rather\n * than a dependency.\n */\nexport const isNxPluginForAwsWorkspace = (tree: Tree): boolean => {\n const rootPackageJson = tree.exists('package.json')\n ? readJson(tree, 'package.json')\n : undefined;\n return rootPackageJson?.name === '@aws/nx-plugin-source';\n};\n\n/**\n * The `@aws/nx-plugin` devDependency entry for a workspace the plugin generates\n * into, keyed to the version the running generators come from. Empty inside the\n * plugin's own monorepo.\n */\nexport const nxPluginSelfDependency = (tree: Tree): Record<string, string> =>\n isNxPluginForAwsWorkspace(tree)\n ? {}\n : { [PackageJson.name]: `^${PackageJson.version}` };\n\n/**\n * The `@aws/nx-plugin-mcp` devDependency entry, keyed to the running generators'\n * version — the two packages are released in lockstep. Declaring it pins the MCP\n * server the vended config runs in the workspace's lockfile, so upgrading it\n * upgrades the server. Empty inside the plugin's own monorepo.\n */\nexport const nxPluginMcpDependency = (tree: Tree): Record<string, string> =>\n isNxPluginForAwsWorkspace(tree)\n ? {}\n : { [NX_PLUGIN_MCP_PACKAGE_NAME]: `^${PackageJson.version}` };\n\n/**\n * Read a project configuration where the project name may not be fully qualified (ie may omit the scope prefix)\n */\nexport const readProjectConfigurationUnqualified = (\n tree: Tree,\n projectName: string,\n) => {\n try {\n return readProjectConfiguration(tree, projectName);\n } catch (e) {\n // Attempt to find the project without the scope\n const project = [...getProjects(tree).values()].find(\n (p) =>\n p.name &&\n (p.name === `${getNpmScopePrefix(tree)}${projectName}` || // TypeScript fully-qualified name\n p.name === `${toSnakeCase(getNpmScope(tree))}.${projectName}`), // Python fully-qualified name\n );\n if (project) {\n return project;\n }\n throw e;\n }\n};\n\n/**\n * Returns whether a project with the given name already exists in the workspace.\n * The project name may be unqualified (ie may omit the scope prefix).\n */\nexport const projectExists = (tree: Tree, projectName: string): boolean => {\n try {\n readProjectConfigurationUnqualified(tree, projectName);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Add metadata about the generator that generated the project to the project.json\n */\nexport const addGeneratorMetadata = (\n tree: Tree,\n projectName: string,\n info: { id: string },\n additionalMetadata?: { [key: string]: any },\n) => {\n const config = readProjectConfigurationUnqualified(tree, projectName);\n const metadata = {\n ...config?.metadata,\n generator: info.id,\n ...additionalMetadata,\n };\n // Skip the write when nothing changed so re-running doesn't reserialize\n // project.json. metadata is plain JSON built in a fixed key order, so a\n // stringify comparison is exact here.\n if (JSON.stringify(config?.metadata) === JSON.stringify(metadata)) {\n return;\n }\n // Place metadata immediately before targets so the serialized key order is\n // identical whether or not metadata already existed (matching the order Nx\n // normalizes a read config to), keeping the change a pure metadata insert.\n const { targets, ...rest } = config;\n updateProjectConfiguration(tree, config.name, {\n ...rest,\n metadata: metadata as any,\n ...(targets ? { targets } : {}),\n });\n};\n\n/**\n * Represents a component entry in project metadata\n */\nexport interface ComponentMetadata {\n readonly generator: string;\n readonly name?: string;\n readonly path?: string;\n [key: string]: any;\n}\n\n/**\n * Add metadata about the generator that generated the component to the project.json\n */\nexport const addComponentGeneratorMetadata = (\n tree: Tree,\n projectName: string,\n info: { id: string },\n componentPath: string,\n componentName?: string,\n additionalMetadata?: { [key: string]: any },\n) => {\n const config = readProjectConfigurationUnqualified(tree, projectName);\n\n const existingComponents = (config?.metadata as any)?.components ?? [];\n const alreadyAdded = existingComponents.filter(\n (c: any) => c.generator === info.id && c.name === componentName,\n );\n\n if (alreadyAdded.length === 0) {\n const componentMetadata: ComponentMetadata = {\n generator: info.id,\n path: componentPath,\n ...(componentName ? { name: componentName } : {}),\n ...additionalMetadata,\n };\n // Place metadata before targets for a stable serialized key order.\n const { targets, ...rest } = config;\n updateProjectConfiguration(tree, config.name, {\n ...rest,\n metadata: {\n ...config?.metadata,\n components: [...existingComponents, componentMetadata],\n } as any,\n ...(targets ? { targets } : {}),\n });\n }\n};\n\n/**\n * Merge a generator's own config into an `nx.json` `targetDefaults` value,\n * preserving whatever the workspace already had. `apply` receives the config to\n * layer onto and returns the merged config (e.g. `(base) => ({ cache: true,\n * ...base })`); it must be idempotent so re-running the generator is a no-op.\n *\n * Nx 23.1 widened each value to either a config object or an ordered array of\n * filtered entries. The plugin only contributes unfiltered (catch-all) config,\n * so the input's shape is preserved: an object (or unset) stays an object;\n * an array keeps the user's filtered entries and `apply` merges into its first\n * unfiltered entry, prepending one as the base if none exists (Nx layers later\n * matches on top, so our catch-all must stay first to not override a filter).\n */\nexport const mergeTargetDefault = (\n value: TargetDefaultValue | undefined,\n apply: (base: Partial<TargetConfiguration>) => Partial<TargetConfiguration>,\n): TargetDefaultValue => {\n if (!Array.isArray(value)) {\n return apply(value ?? {});\n }\n const catchAllIndex = value.findIndex((entry) => entry.filter === undefined);\n if (catchAllIndex === -1) {\n return [apply({}), ...value];\n }\n return value.map((entry, index) =>\n index === catchAllIndex ? apply(entry) : entry,\n );\n};\n\n/**\n * A single entry in an Nx `dependsOn` array.\n * Matches the shape accepted by Nx without requiring a devkit type import.\n */\nexport type TargetDependency =\n | string\n | {\n projects?: string | string[];\n target: string;\n params?: 'ignore' | 'forward';\n };\n\nconst targetDependencyEquals = (a: TargetDependency, b: TargetDependency) => {\n if (typeof a === 'string' || typeof b === 'string') {\n return a === b;\n }\n if (a.target !== b.target || a.params !== b.params) {\n return false;\n }\n const aProjects = Array.isArray(a.projects)\n ? a.projects\n : a.projects !== undefined\n ? [a.projects]\n : [];\n const bProjects = Array.isArray(b.projects)\n ? b.projects\n : b.projects !== undefined\n ? [b.projects]\n : [];\n if (aProjects.length !== bProjects.length) {\n return false;\n }\n return aProjects.every((p, i) => p === bProjects[i]);\n};\n\n// The order target properties are authored in. Nx preserves a target's\n// authored key order when it reads then rewrites an existing project.json,\n// except `options` and `configurations`, which it always moves to the end (in\n// that order). Keeping `options`/`configurations` last here therefore makes a\n// generator's first-run output byte-identical to subsequent runs (idempotency);\n// the remaining keys are ordered to read intuitively.\nconst NX_TARGET_KEY_ORDER = [\n 'executor',\n 'dependsOn',\n 'continuous',\n 'cache',\n 'inputs',\n 'outputs',\n 'metadata',\n 'defaultConfiguration',\n 'options',\n 'configurations',\n];\n\n/**\n * Reorder a target's keys to match Nx's own serialization order. Nx reorders\n * target properties when it rewrites an existing project.json, so applying the\n * same order when first authoring a target keeps generators idempotent.\n */\nexport const normalizeTargetKeyOrder = <T extends object>(target: T): T =>\n Object.fromEntries(\n Object.entries(target as Record<string, unknown>).sort(([a], [b]) => {\n const ai = NX_TARGET_KEY_ORDER.indexOf(a);\n const bi = NX_TARGET_KEY_ORDER.indexOf(b);\n return (\n (ai === -1 ? NX_TARGET_KEY_ORDER.length : ai) -\n (bi === -1 ? NX_TARGET_KEY_ORDER.length : bi)\n );\n }),\n ) as T;\n\n/**\n * Mutate the project to add the dependency to the target if not already present\n * Adds the target if not present.\n *\n * Accepts either a string target name (e.g. `'build'`) or a dependency config\n * object (e.g. `{ projects: ['foo'], target: 'dev' }`). Deduplicates\n * using deep equality so re-running a generator does not grow `dependsOn`.\n */\nexport const addDependencyToTargetIfNotPresent = (\n project: ProjectConfiguration,\n target: string,\n dependency: TargetDependency,\n) => {\n project.targets ??= {};\n project.targets[target] ??= {};\n project.targets[target].dependsOn ??= [];\n const dependsOn = project.targets[target].dependsOn;\n // Leave existing dependencies in place so re-running does not reorder them;\n // only append when the dependency is genuinely absent.\n if (!dependsOn.some((d) => targetDependencyEquals(d, dependency))) {\n dependsOn.push(dependency);\n }\n // Keep key order aligned with Nx's so first run matches subsequent runs.\n project.targets[target] = normalizeTargetKeyOrder(project.targets[target]);\n};\n\n/**\n * Register a component's `<name>-dev` target under the project-level `dev`\n * target, so `nx run <project>:dev` starts every component in the project.\n *\n * Component generators author their own continuous `<name>-dev` runner and call\n * this to aggregate it. Every component added to the project accumulates its\n * `<name>-dev` under `dev`. Nx keys tasks by `project:target`, so any\n * dependencies shared between components run exactly once.\n */\nexport const addComponentDevTarget = (\n targets: Record<string, ProjectConfiguration['targets'][string]>,\n componentDevTargetName: string,\n) => {\n targets['dev'] ??= { continuous: true, dependsOn: [] };\n const projectDev = targets['dev'];\n projectDev.continuous = true;\n projectDev.dependsOn ??= [];\n // Append in component-creation order; dedupe keeps re-runs idempotent.\n if (!projectDev.dependsOn.includes(componentDevTargetName)) {\n projectDev.dependsOn.push(componentDevTargetName);\n }\n targets['dev'] = normalizeTargetKeyOrder(projectDev);\n};\n"],"names":["getProjects","readJson","readProjectConfiguration","updateProjectConfiguration","path","PackageJson","type","NX_PLUGIN_MCP_PACKAGE_NAME","toSnakeCase","getNpmScope","getNpmScopePrefix","buildGeneratorInfoList","GENERATORS","resolve","dirname","listGenerators","includeHidden","filter","g","hidden","getGeneratorInfo","generatorFileName","dir","name","parse","resolvedFactoryPath","join","find","generatorInfo","getPackageVersion","version","isNxPluginForAwsWorkspace","tree","rootPackageJson","exists","undefined","nxPluginSelfDependency","nxPluginMcpDependency","readProjectConfigurationUnqualified","projectName","e","project","values","p","projectExists","addGeneratorMetadata","info","additionalMetadata","config","metadata","generator","id","JSON","stringify","targets","rest","addComponentGeneratorMetadata","componentPath","componentName","existingComponents","components","alreadyAdded","c","length","componentMetadata","mergeTargetDefault","value","apply","Array","isArray","catchAllIndex","findIndex","entry","map","index","targetDependencyEquals","a","b","target","params","aProjects","projects","bProjects","every","i","NX_TARGET_KEY_ORDER","normalizeTargetKeyOrder","Object","fromEntries","entries","sort","ai","indexOf","bi","addDependencyToTargetIfNotPresent","dependency","dependsOn","some","d","push","addComponentDevTarget","componentDevTargetName","continuous","projectDev","includes"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EAEXC,QAAQ,EACRC,wBAAwB,EAIxBC,0BAA0B,QACrB,aAAa;AACpB,YAAYC,UAAU,OAAO;AAC7B,OAAOC,iBAAiB,0BAA0B;IAAEC,MAAM;AAAO,EAAE;AACnE,SAASC,0BAA0B,QAAQ,WAAQ;AACnD,SAASC,WAAW,QAAQ,aAAU;AACtC,SAASC,WAAW,EAAEC,iBAAiB,QAAQ,iBAAc;AAG7D,SAASC,sBAAsB,QAAQ,kBAAe;AAEtD,SAASA,sBAAsB,QAA4B,kBAAe;AAE1E,MAAMC,aAAaD,uBACjBP,KAAKS,OAAO,CAAC,YAAYC,OAAO,EAAE,MAAM;AAG1C;;;CAGC,GACD,OAAO,MAAMC,iBAAiB,CAACC,gBAAgB,KAAK,GAClDJ,WAAWK,MAAM,CAAC,CAACC,IAAMF,iBAAiB,CAACE,EAAEC,MAAM,EAAE;AAEvD;;CAEC,GACD,OAAO,MAAMC,mBAAmB,CAACC;IAC/B,MAAM,EAAEC,GAAG,EAAEC,IAAI,EAAE,GAAGnB,KAAKoB,KAAK,CAACpB,KAAKS,OAAO,CAACQ;IAC9C,MAAMI,sBAAsBrB,KAAKsB,IAAI,CAACJ,KAAKC;IAC3C,OAAOX,WAAWe,IAAI,CACpB,CAACC,gBACCA,cAAcH,mBAAmB,KAAKA;AAE5C,EAAE;AAEF,OAAO,MAAMI,oBAAoB;IAC/B,OAAOxB,YAAYyB,OAAO;AAC5B,EAAE;AAEF;;;CAGC,GACD,OAAO,MAAMC,4BAA4B,CAACC;IACxC,MAAMC,kBAAkBD,KAAKE,MAAM,CAAC,kBAChCjC,SAAS+B,MAAM,kBACfG;IACJ,OAAOF,iBAAiBV,SAAS;AACnC,EAAE;AAEF;;;;CAIC,GACD,OAAO,MAAMa,yBAAyB,CAACJ,OACrCD,0BAA0BC,QACtB,CAAC,IACD;QAAE,CAAC3B,YAAYkB,IAAI,CAAC,EAAE,CAAC,CAAC,EAAElB,YAAYyB,OAAO,EAAE;IAAC,EAAE;AAExD;;;;;CAKC,GACD,OAAO,MAAMO,wBAAwB,CAACL,OACpCD,0BAA0BC,QACtB,CAAC,IACD;QAAE,CAACzB,2BAA2B,EAAE,CAAC,CAAC,EAAEF,YAAYyB,OAAO,EAAE;IAAC,EAAE;AAElE;;CAEC,GACD,OAAO,MAAMQ,sCAAsC,CACjDN,MACAO;IAEA,IAAI;QACF,OAAOrC,yBAAyB8B,MAAMO;IACxC,EAAE,OAAOC,GAAG;QACV,gDAAgD;QAChD,MAAMC,UAAU;eAAIzC,YAAYgC,MAAMU,MAAM;SAAG,CAACf,IAAI,CAClD,CAACgB,IACCA,EAAEpB,IAAI,IACLoB,CAAAA,EAAEpB,IAAI,KAAK,GAAGb,kBAAkBsB,QAAQO,aAAa,IAAI,kCAAkC;YAC1FI,EAAEpB,IAAI,KAAK,GAAGf,YAAYC,YAAYuB,OAAO,CAAC,EAAEO,aAAa,AAAD;QAElE,IAAIE,SAAS;YACX,OAAOA;QACT;QACA,MAAMD;IACR;AACF,EAAE;AAEF;;;CAGC,GACD,OAAO,MAAMI,gBAAgB,CAACZ,MAAYO;IACxC,IAAI;QACFD,oCAAoCN,MAAMO;QAC1C,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMM,uBAAuB,CAClCb,MACAO,aACAO,MACAC;IAEA,MAAMC,SAASV,oCAAoCN,MAAMO;IACzD,MAAMU,WAAW;QACf,GAAGD,QAAQC,QAAQ;QACnBC,WAAWJ,KAAKK,EAAE;QAClB,GAAGJ,kBAAkB;IACvB;IACA,wEAAwE;IACxE,wEAAwE;IACxE,sCAAsC;IACtC,IAAIK,KAAKC,SAAS,CAACL,QAAQC,cAAcG,KAAKC,SAAS,CAACJ,WAAW;QACjE;IACF;IACA,2EAA2E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,MAAM,EAAEK,OAAO,EAAE,GAAGC,MAAM,GAAGP;IAC7B7C,2BAA2B6B,MAAMgB,OAAOzB,IAAI,EAAE;QAC5C,GAAGgC,IAAI;QACPN,UAAUA;QACV,GAAIK,UAAU;YAAEA;QAAQ,IAAI,CAAC,CAAC;IAChC;AACF,EAAE;AAYF;;CAEC,GACD,OAAO,MAAME,gCAAgC,CAC3CxB,MACAO,aACAO,MACAW,eACAC,eACAX;IAEA,MAAMC,SAASV,oCAAoCN,MAAMO;IAEzD,MAAMoB,qBAAqB,AAACX,QAAQC,UAAkBW,cAAc,EAAE;IACtE,MAAMC,eAAeF,mBAAmB1C,MAAM,CAC5C,CAAC6C,IAAWA,EAAEZ,SAAS,KAAKJ,KAAKK,EAAE,IAAIW,EAAEvC,IAAI,KAAKmC;IAGpD,IAAIG,aAAaE,MAAM,KAAK,GAAG;QAC7B,MAAMC,oBAAuC;YAC3Cd,WAAWJ,KAAKK,EAAE;YAClB/C,MAAMqD;YACN,GAAIC,gBAAgB;gBAAEnC,MAAMmC;YAAc,IAAI,CAAC,CAAC;YAChD,GAAGX,kBAAkB;QACvB;QACA,mEAAmE;QACnE,MAAM,EAAEO,OAAO,EAAE,GAAGC,MAAM,GAAGP;QAC7B7C,2BAA2B6B,MAAMgB,OAAOzB,IAAI,EAAE;YAC5C,GAAGgC,IAAI;YACPN,UAAU;gBACR,GAAGD,QAAQC,QAAQ;gBACnBW,YAAY;uBAAID;oBAAoBK;iBAAkB;YACxD;YACA,GAAIV,UAAU;gBAAEA;YAAQ,IAAI,CAAC,CAAC;QAChC;IACF;AACF,EAAE;AAEF;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMW,qBAAqB,CAChCC,OACAC;IAEA,IAAI,CAACC,MAAMC,OAAO,CAACH,QAAQ;QACzB,OAAOC,MAAMD,SAAS,CAAC;IACzB;IACA,MAAMI,gBAAgBJ,MAAMK,SAAS,CAAC,CAACC,QAAUA,MAAMvD,MAAM,KAAKkB;IAClE,IAAImC,kBAAkB,CAAC,GAAG;QACxB,OAAO;YAACH,MAAM,CAAC;eAAOD;SAAM;IAC9B;IACA,OAAOA,MAAMO,GAAG,CAAC,CAACD,OAAOE,QACvBA,UAAUJ,gBAAgBH,MAAMK,SAASA;AAE7C,EAAE;AAcF,MAAMG,yBAAyB,CAACC,GAAqBC;IACnD,IAAI,OAAOD,MAAM,YAAY,OAAOC,MAAM,UAAU;QAClD,OAAOD,MAAMC;IACf;IACA,IAAID,EAAEE,MAAM,KAAKD,EAAEC,MAAM,IAAIF,EAAEG,MAAM,KAAKF,EAAEE,MAAM,EAAE;QAClD,OAAO;IACT;IACA,MAAMC,YAAYZ,MAAMC,OAAO,CAACO,EAAEK,QAAQ,IACtCL,EAAEK,QAAQ,GACVL,EAAEK,QAAQ,KAAK9C,YACb;QAACyC,EAAEK,QAAQ;KAAC,GACZ,EAAE;IACR,MAAMC,YAAYd,MAAMC,OAAO,CAACQ,EAAEI,QAAQ,IACtCJ,EAAEI,QAAQ,GACVJ,EAAEI,QAAQ,KAAK9C,YACb;QAAC0C,EAAEI,QAAQ;KAAC,GACZ,EAAE;IACR,IAAID,UAAUjB,MAAM,KAAKmB,UAAUnB,MAAM,EAAE;QACzC,OAAO;IACT;IACA,OAAOiB,UAAUG,KAAK,CAAC,CAACxC,GAAGyC,IAAMzC,MAAMuC,SAAS,CAACE,EAAE;AACrD;AAEA,uEAAuE;AACvE,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,sDAAsD;AACtD,MAAMC,sBAAsB;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED;;;;CAIC,GACD,OAAO,MAAMC,0BAA0B,CAAmBR,SACxDS,OAAOC,WAAW,CAChBD,OAAOE,OAAO,CAACX,QAAmCY,IAAI,CAAC,CAAC,CAACd,EAAE,EAAE,CAACC,EAAE;QAC9D,MAAMc,KAAKN,oBAAoBO,OAAO,CAAChB;QACvC,MAAMiB,KAAKR,oBAAoBO,OAAO,CAACf;QACvC,OACE,AAACc,CAAAA,OAAO,CAAC,IAAIN,oBAAoBtB,MAAM,GAAG4B,EAAC,IAC1CE,CAAAA,OAAO,CAAC,IAAIR,oBAAoBtB,MAAM,GAAG8B,EAAC;IAE/C,IACK;AAET;;;;;;;CAOC,GACD,OAAO,MAAMC,oCAAoC,CAC/CrD,SACAqC,QACAiB;IAEAtD,QAAQa,OAAO,KAAK,CAAC;IACrBb,QAAQa,OAAO,CAACwB,OAAO,KAAK,CAAC;IAC7BrC,QAAQa,OAAO,CAACwB,OAAO,CAACkB,SAAS,KAAK,EAAE;IACxC,MAAMA,YAAYvD,QAAQa,OAAO,CAACwB,OAAO,CAACkB,SAAS;IACnD,4EAA4E;IAC5E,uDAAuD;IACvD,IAAI,CAACA,UAAUC,IAAI,CAAC,CAACC,IAAMvB,uBAAuBuB,GAAGH,cAAc;QACjEC,UAAUG,IAAI,CAACJ;IACjB;IACA,yEAAyE;IACzEtD,QAAQa,OAAO,CAACwB,OAAO,GAAGQ,wBAAwB7C,QAAQa,OAAO,CAACwB,OAAO;AAC3E,EAAE;AAEF;;;;;;;;CAQC,GACD,OAAO,MAAMsB,wBAAwB,CACnC9C,SACA+C;IAEA/C,OAAO,CAAC,MAAM,KAAK;QAAEgD,YAAY;QAAMN,WAAW,EAAE;IAAC;IACrD,MAAMO,aAAajD,OAAO,CAAC,MAAM;IACjCiD,WAAWD,UAAU,GAAG;IACxBC,WAAWP,SAAS,KAAK,EAAE;IAC3B,uEAAuE;IACvE,IAAI,CAACO,WAAWP,SAAS,CAACQ,QAAQ,CAACH,yBAAyB;QAC1DE,WAAWP,SAAS,CAACG,IAAI,CAACE;IAC5B;IACA/C,OAAO,CAAC,MAAM,GAAGgC,wBAAwBiB;AAC3C,EAAE"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/nx.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n type ProjectConfiguration,\n readJson,\n readProjectConfiguration,\n type TargetConfiguration,\n type TargetDefaultValue,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport * as path from 'path';\nimport PackageJson from '../../package.json' with { type: 'json' };\nimport { NX_PLUGIN_MCP_PACKAGE_NAME } from './mcp';\nimport { toSnakeCase } from './names';\nimport { getNpmScope, getNpmScopePrefix } from './npm-scope';\n\nexport type { GeneratorInfo, NxGeneratorInfo } from './generators';\nexport { buildGeneratorInfoList } from './generators';\n\nimport { buildGeneratorInfoList, type GeneratorInfo } from './generators';\n\nconst GENERATORS = buildGeneratorInfoList(\n path.resolve(import.meta.dirname, '..', '..'),\n);\n\n/**\n * List Nx Plugin for AWS generators\n * @param includeHidden include hidden generators (default false)\n */\nexport const listGenerators = (includeHidden = false) =>\n GENERATORS.filter((g) => includeHidden || !g.hidden);\n\n/**\n * Return generator information. Call this from a generator method with import.meta.filename\n */\nexport const getGeneratorInfo = (generatorFileName: string): GeneratorInfo => {\n const { dir, name } = path.parse(path.resolve(generatorFileName));\n const resolvedFactoryPath = path.join(dir, name);\n return GENERATORS.find(\n (generatorInfo) =>\n generatorInfo.resolvedFactoryPath === resolvedFactoryPath,\n );\n};\n\nexport const getPackageVersion = () => {\n return PackageJson.version;\n};\n\n/**\n * True inside the plugin's own monorepo, where the plugin is the source rather\n * than a dependency.\n */\nexport const isNxPluginForAwsWorkspace = (tree: Tree): boolean => {\n const rootPackageJson = tree.exists('package.json')\n ? readJson(tree, 'package.json')\n : undefined;\n return rootPackageJson?.name === '@aws/nx-plugin-source';\n};\n\n/**\n * The `@aws/nx-plugin` devDependency entry for a workspace the plugin generates\n * into, keyed to the version the running generators come from. Empty inside the\n * plugin's own monorepo.\n */\nexport const nxPluginSelfDependency = (tree: Tree): Record<string, string> =>\n isNxPluginForAwsWorkspace(tree)\n ? {}\n : { [PackageJson.name]: `^${PackageJson.version}` };\n\n/**\n * The `@aws/nx-plugin-mcp` devDependency entry, keyed to the running generators'\n * version — the two packages are released in lockstep. Declaring it pins the MCP\n * server the vended config runs in the workspace's lockfile, so upgrading it\n * upgrades the server. Empty inside the plugin's own monorepo.\n */\nexport const nxPluginMcpDependency = (tree: Tree): Record<string, string> =>\n isNxPluginForAwsWorkspace(tree)\n ? {}\n : { [NX_PLUGIN_MCP_PACKAGE_NAME]: `^${PackageJson.version}` };\n\n/**\n * Read a project configuration where the project name may not be fully qualified (ie may omit the scope prefix)\n */\nexport const readProjectConfigurationUnqualified = (\n tree: Tree,\n projectName: string,\n) => {\n try {\n return readProjectConfiguration(tree, projectName);\n } catch (e) {\n // Attempt to find the project without the scope\n const project = [...getProjects(tree).values()].find(\n (p) =>\n p.name &&\n (p.name === `${getNpmScopePrefix(tree)}${projectName}` || // TypeScript fully-qualified name\n p.name === `${toSnakeCase(getNpmScope(tree))}.${projectName}`), // Python fully-qualified name\n );\n if (project) {\n return project;\n }\n throw e;\n }\n};\n\n/**\n * Returns whether a project with the given name already exists in the workspace.\n * The project name may be unqualified (ie may omit the scope prefix).\n */\nexport const projectExists = (tree: Tree, projectName: string): boolean => {\n try {\n readProjectConfigurationUnqualified(tree, projectName);\n return true;\n } catch {\n return false;\n }\n};\n\n/**\n * Add metadata about the generator that generated the project to the project.json\n */\nexport const addGeneratorMetadata = (\n tree: Tree,\n projectName: string,\n info: { id: string },\n additionalMetadata?: { [key: string]: any },\n) => {\n const config = readProjectConfigurationUnqualified(tree, projectName);\n const metadata = {\n ...config?.metadata,\n generator: info.id,\n ...additionalMetadata,\n };\n // Skip the write when nothing changed so re-running doesn't reserialize\n // project.json. metadata is plain JSON built in a fixed key order, so a\n // stringify comparison is exact here.\n if (JSON.stringify(config?.metadata) === JSON.stringify(metadata)) {\n return;\n }\n // Place metadata immediately before targets so the serialized key order is\n // identical whether or not metadata already existed (matching the order Nx\n // normalizes a read config to), keeping the change a pure metadata insert.\n const { targets, ...rest } = config;\n updateProjectConfiguration(tree, config.name, {\n ...rest,\n metadata: metadata as any,\n ...(targets ? { targets } : {}),\n });\n};\n\n/**\n * Represents a component entry in project metadata\n */\nexport interface ComponentMetadata {\n readonly generator: string;\n readonly name?: string;\n /**\n * What this entry wires up. For a connection that is the target — the thing\n * being connected to — paired with `sourcePath` below.\n */\n readonly path?: string;\n /**\n * The component the connection is made *from*, when both ends are components\n * of a project rather than whole projects.\n *\n * A connection records the project it lives on and the target it reaches, which\n * alone can't tell which of several components on that project is wired up.\n * Recorded as a path for the same reason `path` is: it identifies a component\n * within its project without depending on a name that may repeat.\n */\n readonly sourcePath?: string;\n [key: string]: any;\n}\n\n/**\n * Add metadata about the generator that generated the component to the project.json\n *\n * A connection between two components passes the source's path as\n * `additionalMetadata.sourcePath`, so the pair is identifiable rather than just\n * the two projects.\n */\nexport const addComponentGeneratorMetadata = (\n tree: Tree,\n projectName: string,\n info: { id: string },\n componentPath: string,\n componentName?: string,\n additionalMetadata?: { [key: string]: any },\n) => {\n const config = readProjectConfigurationUnqualified(tree, projectName);\n\n const existingComponents = (config?.metadata as any)?.components ?? [];\n const alreadyAdded = existingComponents.filter(\n (c: any) => c.generator === info.id && c.name === componentName,\n );\n\n if (alreadyAdded.length === 0) {\n const componentMetadata: ComponentMetadata = {\n generator: info.id,\n path: componentPath,\n ...(componentName ? { name: componentName } : {}),\n ...additionalMetadata,\n };\n // Place metadata before targets for a stable serialized key order.\n const { targets, ...rest } = config;\n updateProjectConfiguration(tree, config.name, {\n ...rest,\n metadata: {\n ...config?.metadata,\n components: [...existingComponents, componentMetadata],\n } as any,\n ...(targets ? { targets } : {}),\n });\n }\n};\n\n/**\n * Merge a generator's own config into an `nx.json` `targetDefaults` value,\n * preserving whatever the workspace already had. `apply` receives the config to\n * layer onto and returns the merged config (e.g. `(base) => ({ cache: true,\n * ...base })`); it must be idempotent so re-running the generator is a no-op.\n *\n * Nx 23.1 widened each value to either a config object or an ordered array of\n * filtered entries. The plugin only contributes unfiltered (catch-all) config,\n * so the input's shape is preserved: an object (or unset) stays an object;\n * an array keeps the user's filtered entries and `apply` merges into its first\n * unfiltered entry, prepending one as the base if none exists (Nx layers later\n * matches on top, so our catch-all must stay first to not override a filter).\n */\nexport const mergeTargetDefault = (\n value: TargetDefaultValue | undefined,\n apply: (base: Partial<TargetConfiguration>) => Partial<TargetConfiguration>,\n): TargetDefaultValue => {\n if (!Array.isArray(value)) {\n return apply(value ?? {});\n }\n const catchAllIndex = value.findIndex((entry) => entry.filter === undefined);\n if (catchAllIndex === -1) {\n return [apply({}), ...value];\n }\n return value.map((entry, index) =>\n index === catchAllIndex ? apply(entry) : entry,\n );\n};\n\n/**\n * A single entry in an Nx `dependsOn` array.\n * Matches the shape accepted by Nx without requiring a devkit type import.\n */\nexport type TargetDependency =\n | string\n | {\n projects?: string | string[];\n target: string;\n params?: 'ignore' | 'forward';\n };\n\nconst targetDependencyEquals = (a: TargetDependency, b: TargetDependency) => {\n if (typeof a === 'string' || typeof b === 'string') {\n return a === b;\n }\n if (a.target !== b.target || a.params !== b.params) {\n return false;\n }\n const aProjects = Array.isArray(a.projects)\n ? a.projects\n : a.projects !== undefined\n ? [a.projects]\n : [];\n const bProjects = Array.isArray(b.projects)\n ? b.projects\n : b.projects !== undefined\n ? [b.projects]\n : [];\n if (aProjects.length !== bProjects.length) {\n return false;\n }\n return aProjects.every((p, i) => p === bProjects[i]);\n};\n\n// The order target properties are authored in. Nx preserves a target's\n// authored key order when it reads then rewrites an existing project.json,\n// except `options` and `configurations`, which it always moves to the end (in\n// that order). Keeping `options`/`configurations` last here therefore makes a\n// generator's first-run output byte-identical to subsequent runs (idempotency);\n// the remaining keys are ordered to read intuitively.\nconst NX_TARGET_KEY_ORDER = [\n 'executor',\n 'dependsOn',\n 'continuous',\n 'cache',\n 'inputs',\n 'outputs',\n 'metadata',\n 'defaultConfiguration',\n 'options',\n 'configurations',\n];\n\n/**\n * Reorder a target's keys to match Nx's own serialization order. Nx reorders\n * target properties when it rewrites an existing project.json, so applying the\n * same order when first authoring a target keeps generators idempotent.\n */\nexport const normalizeTargetKeyOrder = <T extends object>(target: T): T =>\n Object.fromEntries(\n Object.entries(target as Record<string, unknown>).sort(([a], [b]) => {\n const ai = NX_TARGET_KEY_ORDER.indexOf(a);\n const bi = NX_TARGET_KEY_ORDER.indexOf(b);\n return (\n (ai === -1 ? NX_TARGET_KEY_ORDER.length : ai) -\n (bi === -1 ? NX_TARGET_KEY_ORDER.length : bi)\n );\n }),\n ) as T;\n\n/**\n * Mutate the project to add the dependency to the target if not already present\n * Adds the target if not present.\n *\n * Accepts either a string target name (e.g. `'build'`) or a dependency config\n * object (e.g. `{ projects: ['foo'], target: 'dev' }`). Deduplicates\n * using deep equality so re-running a generator does not grow `dependsOn`.\n */\nexport const addDependencyToTargetIfNotPresent = (\n project: ProjectConfiguration,\n target: string,\n dependency: TargetDependency,\n) => {\n project.targets ??= {};\n project.targets[target] ??= {};\n project.targets[target].dependsOn ??= [];\n const dependsOn = project.targets[target].dependsOn;\n // Leave existing dependencies in place so re-running does not reorder them;\n // only append when the dependency is genuinely absent.\n if (!dependsOn.some((d) => targetDependencyEquals(d, dependency))) {\n dependsOn.push(dependency);\n }\n // Keep key order aligned with Nx's so first run matches subsequent runs.\n project.targets[target] = normalizeTargetKeyOrder(project.targets[target]);\n};\n\n/**\n * Register a component's `<name>-dev` target under the project-level `dev`\n * target, so `nx run <project>:dev` starts every component in the project.\n *\n * Component generators author their own continuous `<name>-dev` runner and call\n * this to aggregate it. Every component added to the project accumulates its\n * `<name>-dev` under `dev`. Nx keys tasks by `project:target`, so any\n * dependencies shared between components run exactly once.\n */\nexport const addComponentDevTarget = (\n targets: Record<string, ProjectConfiguration['targets'][string]>,\n componentDevTargetName: string,\n) => {\n targets['dev'] ??= { continuous: true, dependsOn: [] };\n const projectDev = targets['dev'];\n projectDev.continuous = true;\n projectDev.dependsOn ??= [];\n // Append in component-creation order; dedupe keeps re-runs idempotent.\n if (!projectDev.dependsOn.includes(componentDevTargetName)) {\n projectDev.dependsOn.push(componentDevTargetName);\n }\n targets['dev'] = normalizeTargetKeyOrder(projectDev);\n};\n"],"names":["getProjects","readJson","readProjectConfiguration","updateProjectConfiguration","path","PackageJson","type","NX_PLUGIN_MCP_PACKAGE_NAME","toSnakeCase","getNpmScope","getNpmScopePrefix","buildGeneratorInfoList","GENERATORS","resolve","dirname","listGenerators","includeHidden","filter","g","hidden","getGeneratorInfo","generatorFileName","dir","name","parse","resolvedFactoryPath","join","find","generatorInfo","getPackageVersion","version","isNxPluginForAwsWorkspace","tree","rootPackageJson","exists","undefined","nxPluginSelfDependency","nxPluginMcpDependency","readProjectConfigurationUnqualified","projectName","e","project","values","p","projectExists","addGeneratorMetadata","info","additionalMetadata","config","metadata","generator","id","JSON","stringify","targets","rest","addComponentGeneratorMetadata","componentPath","componentName","existingComponents","components","alreadyAdded","c","length","componentMetadata","mergeTargetDefault","value","apply","Array","isArray","catchAllIndex","findIndex","entry","map","index","targetDependencyEquals","a","b","target","params","aProjects","projects","bProjects","every","i","NX_TARGET_KEY_ORDER","normalizeTargetKeyOrder","Object","fromEntries","entries","sort","ai","indexOf","bi","addDependencyToTargetIfNotPresent","dependency","dependsOn","some","d","push","addComponentDevTarget","componentDevTargetName","continuous","projectDev","includes"],"mappings":"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"}
package/src/utils/py.d.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { type Tree } from '@nx/devkit';
2
+ import type { DeclaredPy, DependencyDeclaration } from './declared-dependencies';
2
3
  import { type IPyDepVersion } from './versions';
3
4
  /**
4
5
  * Add dependencies to a pyproject.toml file
5
6
  */
6
- export declare const addDependenciesToPyProjectToml: (tree: Tree, projectRoot: string, deps: IPyDepVersion[]) => void;
7
- export declare const addDependenciesToDependencyGroupInPyProjectToml: (tree: Tree, projectRoot: string, group: string, deps: IPyDepVersion[]) => void;
7
+ export declare const addDependenciesToPyProjectToml: <const D extends DependencyDeclaration>(tree: Tree, projectRoot: string, declaration: D, deps: readonly DeclaredPy<D>[]) => void;
8
+ export declare const addDependenciesToDependencyGroupInPyProjectToml: <const D extends DependencyDeclaration>(tree: Tree, projectRoot: string, group: string, declaration: D, deps: readonly DeclaredPy<D>[]) => void;
8
9
  export interface UvxWithDep {
9
10
  dep: string;
10
11
  version: string;
package/src/utils/py.js CHANGED
@@ -6,7 +6,7 @@ import { joinPathFragments } from "@nx/devkit";
6
6
  import { parsePipRequirementsLine } from "pip-requirements-js";
7
7
  import { normalizeDistributionName } from "./names.js";
8
8
  import { readToml, updateToml } from "./toml.js";
9
- import { withPyVersions } from "./versions.js";
9
+ import { PY_VERSIONS, withPyVersions } from "./versions.js";
10
10
  // Dedup key that distinguishes bare packages from the same package with
11
11
  // extras (e.g. `foo` vs `foo[bar]`), so adding a bare dep doesn't drop a
12
12
  // previously-added variant with extras.
@@ -20,11 +20,11 @@ const depKey = (dep)=>{
20
20
  ].sort().join(',');
21
21
  return extras ? `${parsed.name}[${extras}]` : parsed.name;
22
22
  };
23
- const mergeDeps = (existing, deps)=>{
23
+ const mergeDeps = (declaration, existing, deps)=>{
24
24
  // Update deps in place by key so re-running does not reorder the list:
25
25
  // existing deps keep their position (with their version refreshed), and only
26
26
  // genuinely-new deps are appended.
27
- const incoming = new Map(withPyVersions(deps).map((d)=>[
27
+ const incoming = new Map(withPyVersions(declaration, deps).map((d)=>[
28
28
  depKey(d),
29
29
  d
30
30
  ]));
@@ -39,16 +39,16 @@ const mergeDeps = (existing, deps)=>{
39
39
  };
40
40
  /**
41
41
  * Add dependencies to a pyproject.toml file
42
- */ export const addDependenciesToPyProjectToml = (tree, projectRoot, deps)=>{
42
+ */ export const addDependenciesToPyProjectToml = (tree, projectRoot, declaration, deps)=>{
43
43
  const projectToml = parse(tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'));
44
- projectToml.project.dependencies = mergeDeps(projectToml.project?.dependencies, deps);
44
+ projectToml.project.dependencies = mergeDeps(declaration, projectToml.project?.dependencies, deps);
45
45
  tree.write(joinPathFragments(projectRoot, 'pyproject.toml'), stringify(projectToml));
46
46
  };
47
- export const addDependenciesToDependencyGroupInPyProjectToml = (tree, projectRoot, group, deps)=>{
47
+ export const addDependenciesToDependencyGroupInPyProjectToml = (tree, projectRoot, group, declaration, deps)=>{
48
48
  const projectToml = parse(tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'));
49
49
  projectToml['dependency-groups'] = {
50
50
  ...projectToml['dependency-groups'],
51
- [group]: mergeDeps(projectToml['dependency-groups']?.[group], deps)
51
+ [group]: mergeDeps(declaration, projectToml['dependency-groups']?.[group], deps)
52
52
  };
53
53
  tree.write(joinPathFragments(projectRoot, 'pyproject.toml'), stringify(projectToml));
54
54
  };
@@ -57,9 +57,9 @@ export const addDependenciesToDependencyGroupInPyProjectToml = (tree, projectRoo
57
57
  * Pins the version to the one specified in versions.ts
58
58
  * Optionally specify withDeps to render uvx --with dep==version
59
59
  */ export const uvxCommand = (dep, args, withDeps)=>{
60
- return `uvx --from ${withPyVersions([
61
- dep
62
- ])[0]} ${withDeps ? `${withDeps.map(({ dep, version, specifier })=>`--with ${dep}${specifier ?? '=='}${version}`).join(' ')} ` : ''}${dep}${args ? ` ${args}` : ''}`;
60
+ // Pins the tool for a one-off invocation; nothing is added to a manifest, so
61
+ // this needs no declaration.
62
+ return `uvx --from ${dep}${PY_VERSIONS[dep]} ${withDeps ? `${withDeps.map(({ dep, version, specifier })=>`--with ${dep}${specifier ?? '=='}${version}`).join(' ')} ` : ''}${dep}${args ? ` ${args}` : ''}`;
63
63
  };
64
64
  /**
65
65
  * Resolve the PEP 503 distribution name of a Python project from its
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/py.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { parse, stringify } from '@iarna/toml';\nimport { joinPathFragments, type Tree } from '@nx/devkit';\nimport { parsePipRequirementsLine } from 'pip-requirements-js';\nimport { normalizeDistributionName } from './names';\nimport type { UVPyprojectToml } from './nxlv-python';\nimport { readToml, updateToml } from './toml';\nimport { type IPyDepVersion, withPyVersions } from './versions';\n\n// Dedup key that distinguishes bare packages from the same package with\n// extras (e.g. `foo` vs `foo[bar]`), so adding a bare dep doesn't drop a\n// previously-added variant with extras.\nconst depKey = (dep: string): string => {\n const parsed = parsePipRequirementsLine(dep);\n if (parsed?.type !== 'ProjectName') {\n return dep;\n }\n const extras = [...(parsed.extras ?? [])].sort().join(',');\n return extras ? `${parsed.name}[${extras}]` : parsed.name;\n};\n\nconst mergeDeps = (\n existing: readonly string[] | undefined,\n deps: IPyDepVersion[],\n): string[] => {\n // Update deps in place by key so re-running does not reorder the list:\n // existing deps keep their position (with their version refreshed), and only\n // genuinely-new deps are appended.\n const incoming = new Map(withPyVersions(deps).map((d) => [depKey(d), d]));\n const merged = (existing ?? []).map(\n (dep) => incoming.get(depKey(dep)) ?? dep,\n );\n const existingKeys = new Set((existing ?? []).map(depKey));\n for (const [key, dep] of incoming) {\n if (!existingKeys.has(key)) {\n merged.push(dep);\n }\n }\n return merged;\n};\n\n/**\n * Add dependencies to a pyproject.toml file\n */\nexport const addDependenciesToPyProjectToml = (\n tree: Tree,\n projectRoot: string,\n deps: IPyDepVersion[],\n) => {\n const projectToml = parse(\n tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'),\n ) as UVPyprojectToml;\n projectToml.project.dependencies = mergeDeps(\n projectToml.project?.dependencies,\n deps,\n );\n tree.write(\n joinPathFragments(projectRoot, 'pyproject.toml'),\n stringify(projectToml),\n );\n};\n\nexport const addDependenciesToDependencyGroupInPyProjectToml = (\n tree: Tree,\n projectRoot: string,\n group: string,\n deps: IPyDepVersion[],\n) => {\n const projectToml = parse(\n tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'),\n ) as UVPyprojectToml;\n projectToml['dependency-groups'] = {\n ...projectToml['dependency-groups'],\n [group]: mergeDeps(projectToml['dependency-groups']?.[group], deps),\n };\n tree.write(\n joinPathFragments(projectRoot, 'pyproject.toml'),\n stringify(projectToml),\n );\n};\n\nexport interface UvxWithDep {\n dep: string;\n version: string;\n specifier?: string;\n}\n\n/**\n * Render a uvx command for a given dependency\n * Pins the version to the one specified in versions.ts\n * Optionally specify withDeps to render uvx --with dep==version\n */\nexport const uvxCommand = (\n dep: IPyDepVersion,\n args?: string,\n withDeps?: UvxWithDep[],\n): string => {\n return `uvx --from ${withPyVersions([dep])[0]} ${\n withDeps\n ? `${withDeps\n .map(\n ({ dep, version, specifier }) =>\n `--with ${dep}${specifier ?? '=='}${version}`,\n )\n .join(' ')} `\n : ''\n }${dep}${args ? ` ${args}` : ''}`;\n};\n\n/**\n * Resolve the PEP 503 distribution name of a Python project from its\n * `pyproject.toml` `[project].name`, falling back to normalising the supplied\n * Nx project id when the project has no readable pyproject yet.\n *\n * This is the authoritative name uv writes into `uv.lock`, so it is the value\n * that must appear in a dependent's `[project].dependencies` /\n * `[tool.uv.sources]` for `@nxlv/python` to infer the workspace dependency\n * edge. Always normalised so the result is a valid distribution name even if\n * an older project still carries a dotted `[project].name`.\n */\nconst getPyDistributionName = (\n tree: Tree,\n project: { name?: string; root: string },\n): string => {\n const pyprojectPath = joinPathFragments(project.root, 'pyproject.toml');\n const projectName = tree.exists(pyprojectPath)\n ? (readToml(tree, pyprojectPath) as unknown as UVPyprojectToml).project\n ?.name\n : undefined;\n return normalizeDistributionName(projectName ?? project.name ?? '');\n};\n\n/**\n * Add a workspace dependency from one Python project to another.\n * Adds the dependency to [project].dependencies and [tool.uv.sources].\n *\n * Both projects are passed as Nx project configurations (not names): the\n * dependency's PEP 503 distribution name is derived from its own\n * `pyproject.toml` here, so callers cannot accidentally pass the dotted Nx id\n * (which @nxlv/python splits on `.` and drops, losing the project-graph edge).\n * This is the single entry point all generators use to wire a Python workspace\n * dependency.\n */\nexport const addWorkspaceDependencyToPyProject = (\n tree: Tree,\n dependentProject: { name?: string; root: string },\n dependencyProject: { name?: string; root: string },\n): void => {\n const pyprojectPath = joinPathFragments(\n dependentProject.root,\n 'pyproject.toml',\n );\n if (!tree.exists(pyprojectPath)) {\n return;\n }\n\n const distributionName = getPyDistributionName(tree, dependencyProject);\n\n updateToml(tree, pyprojectPath, (toml: UVPyprojectToml) => {\n // Add to [project].dependencies if not already present\n const deps = toml.project?.dependencies ?? [];\n if (\n !deps.some(\n (d) =>\n d === distributionName ||\n d.startsWith(`${distributionName}>=`) ||\n d.startsWith(`${distributionName}==`),\n )\n ) {\n toml.project.dependencies = [...deps, distributionName];\n }\n\n // Add to [tool.uv.sources] with workspace = true\n toml.tool = toml.tool ?? {};\n (toml.tool as any).uv = (toml.tool as any).uv ?? {};\n (toml.tool as any).uv.sources = (toml.tool as any).uv.sources ?? {};\n (toml.tool as any).uv.sources[distributionName] = {\n workspace: true,\n };\n\n return toml;\n });\n};\n"],"names":["parse","stringify","joinPathFragments","parsePipRequirementsLine","normalizeDistributionName","readToml","updateToml","withPyVersions","depKey","dep","parsed","type","extras","sort","join","name","mergeDeps","existing","deps","incoming","Map","map","d","merged","get","existingKeys","Set","key","has","push","addDependenciesToPyProjectToml","tree","projectRoot","projectToml","read","project","dependencies","write","addDependenciesToDependencyGroupInPyProjectToml","group","uvxCommand","args","withDeps","version","specifier","getPyDistributionName","pyprojectPath","root","projectName","exists","undefined","addWorkspaceDependencyToPyProject","dependentProject","dependencyProject","distributionName","toml","some","startsWith","tool","uv","sources","workspace"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/py.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { parse, stringify } from '@iarna/toml';\nimport { joinPathFragments, type Tree } from '@nx/devkit';\nimport { parsePipRequirementsLine } from 'pip-requirements-js';\nimport type {\n DeclaredPy,\n DependencyDeclaration,\n} from './declared-dependencies';\nimport { normalizeDistributionName } from './names';\nimport type { UVPyprojectToml } from './nxlv-python';\nimport { readToml, updateToml } from './toml';\nimport { type IPyDepVersion, PY_VERSIONS, withPyVersions } from './versions';\n\n// Dedup key that distinguishes bare packages from the same package with\n// extras (e.g. `foo` vs `foo[bar]`), so adding a bare dep doesn't drop a\n// previously-added variant with extras.\nconst depKey = (dep: string): string => {\n const parsed = parsePipRequirementsLine(dep);\n if (parsed?.type !== 'ProjectName') {\n return dep;\n }\n const extras = [...(parsed.extras ?? [])].sort().join(',');\n return extras ? `${parsed.name}[${extras}]` : parsed.name;\n};\n\nconst mergeDeps = (\n declaration: DependencyDeclaration,\n existing: readonly string[] | undefined,\n deps: readonly IPyDepVersion[],\n): string[] => {\n // Update deps in place by key so re-running does not reorder the list:\n // existing deps keep their position (with their version refreshed), and only\n // genuinely-new deps are appended.\n const incoming = new Map(\n withPyVersions(declaration, deps).map((d) => [depKey(d), d]),\n );\n const merged = (existing ?? []).map(\n (dep) => incoming.get(depKey(dep)) ?? dep,\n );\n const existingKeys = new Set((existing ?? []).map(depKey));\n for (const [key, dep] of incoming) {\n if (!existingKeys.has(key)) {\n merged.push(dep);\n }\n }\n return merged;\n};\n\n/**\n * Add dependencies to a pyproject.toml file\n */\nexport const addDependenciesToPyProjectToml = <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n projectRoot: string,\n declaration: D,\n deps: readonly DeclaredPy<D>[],\n) => {\n const projectToml = parse(\n tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'),\n ) as UVPyprojectToml;\n projectToml.project.dependencies = mergeDeps(\n declaration,\n projectToml.project?.dependencies,\n deps,\n );\n tree.write(\n joinPathFragments(projectRoot, 'pyproject.toml'),\n stringify(projectToml),\n );\n};\n\nexport const addDependenciesToDependencyGroupInPyProjectToml = <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n projectRoot: string,\n group: string,\n declaration: D,\n deps: readonly DeclaredPy<D>[],\n) => {\n const projectToml = parse(\n tree.read(joinPathFragments(projectRoot, 'pyproject.toml'), 'utf8'),\n ) as UVPyprojectToml;\n projectToml['dependency-groups'] = {\n ...projectToml['dependency-groups'],\n [group]: mergeDeps(\n declaration,\n projectToml['dependency-groups']?.[group],\n deps,\n ),\n };\n tree.write(\n joinPathFragments(projectRoot, 'pyproject.toml'),\n stringify(projectToml),\n );\n};\n\nexport interface UvxWithDep {\n dep: string;\n version: string;\n specifier?: string;\n}\n\n/**\n * Render a uvx command for a given dependency\n * Pins the version to the one specified in versions.ts\n * Optionally specify withDeps to render uvx --with dep==version\n */\nexport const uvxCommand = (\n dep: IPyDepVersion,\n args?: string,\n withDeps?: UvxWithDep[],\n): string => {\n // Pins the tool for a one-off invocation; nothing is added to a manifest, so\n // this needs no declaration.\n return `uvx --from ${dep}${PY_VERSIONS[dep]} ${\n withDeps\n ? `${withDeps\n .map(\n ({ dep, version, specifier }) =>\n `--with ${dep}${specifier ?? '=='}${version}`,\n )\n .join(' ')} `\n : ''\n }${dep}${args ? ` ${args}` : ''}`;\n};\n\n/**\n * Resolve the PEP 503 distribution name of a Python project from its\n * `pyproject.toml` `[project].name`, falling back to normalising the supplied\n * Nx project id when the project has no readable pyproject yet.\n *\n * This is the authoritative name uv writes into `uv.lock`, so it is the value\n * that must appear in a dependent's `[project].dependencies` /\n * `[tool.uv.sources]` for `@nxlv/python` to infer the workspace dependency\n * edge. Always normalised so the result is a valid distribution name even if\n * an older project still carries a dotted `[project].name`.\n */\nconst getPyDistributionName = (\n tree: Tree,\n project: { name?: string; root: string },\n): string => {\n const pyprojectPath = joinPathFragments(project.root, 'pyproject.toml');\n const projectName = tree.exists(pyprojectPath)\n ? (readToml(tree, pyprojectPath) as unknown as UVPyprojectToml).project\n ?.name\n : undefined;\n return normalizeDistributionName(projectName ?? project.name ?? '');\n};\n\n/**\n * Add a workspace dependency from one Python project to another.\n * Adds the dependency to [project].dependencies and [tool.uv.sources].\n *\n * Both projects are passed as Nx project configurations (not names): the\n * dependency's PEP 503 distribution name is derived from its own\n * `pyproject.toml` here, so callers cannot accidentally pass the dotted Nx id\n * (which @nxlv/python splits on `.` and drops, losing the project-graph edge).\n * This is the single entry point all generators use to wire a Python workspace\n * dependency.\n */\nexport const addWorkspaceDependencyToPyProject = (\n tree: Tree,\n dependentProject: { name?: string; root: string },\n dependencyProject: { name?: string; root: string },\n): void => {\n const pyprojectPath = joinPathFragments(\n dependentProject.root,\n 'pyproject.toml',\n );\n if (!tree.exists(pyprojectPath)) {\n return;\n }\n\n const distributionName = getPyDistributionName(tree, dependencyProject);\n\n updateToml(tree, pyprojectPath, (toml: UVPyprojectToml) => {\n // Add to [project].dependencies if not already present\n const deps = toml.project?.dependencies ?? [];\n if (\n !deps.some(\n (d) =>\n d === distributionName ||\n d.startsWith(`${distributionName}>=`) ||\n d.startsWith(`${distributionName}==`),\n )\n ) {\n toml.project.dependencies = [...deps, distributionName];\n }\n\n // Add to [tool.uv.sources] with workspace = true\n toml.tool = toml.tool ?? {};\n (toml.tool as any).uv = (toml.tool as any).uv ?? {};\n (toml.tool as any).uv.sources = (toml.tool as any).uv.sources ?? {};\n (toml.tool as any).uv.sources[distributionName] = {\n workspace: true,\n };\n\n return toml;\n });\n};\n"],"names":["parse","stringify","joinPathFragments","parsePipRequirementsLine","normalizeDistributionName","readToml","updateToml","PY_VERSIONS","withPyVersions","depKey","dep","parsed","type","extras","sort","join","name","mergeDeps","declaration","existing","deps","incoming","Map","map","d","merged","get","existingKeys","Set","key","has","push","addDependenciesToPyProjectToml","tree","projectRoot","projectToml","read","project","dependencies","write","addDependenciesToDependencyGroupInPyProjectToml","group","uvxCommand","args","withDeps","version","specifier","getPyDistributionName","pyprojectPath","root","projectName","exists","undefined","addWorkspaceDependencyToPyProject","dependentProject","dependencyProject","distributionName","toml","some","startsWith","tool","uv","sources","workspace"],"mappings":"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"}
@@ -1,7 +1,3 @@
1
- /**
2
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
- * SPDX-License-Identifier: Apache-2.0
4
- */
5
1
  export declare const PACKAGES_DIR = "packages";
6
2
  export declare const SHARED_CONSTRUCTS_NAME = "common-constructs";
7
3
  export declare const SHARED_CONSTRUCTS_DIR = "common/constructs";
@@ -14,3 +10,42 @@ export declare const SHARED_INFRA_CONFIG_DIR = "common/infra-config";
14
10
  export declare const SHARED_SCRIPTS_NAME = "common-scripts";
15
11
  export declare const SHARED_SCRIPTS_DIR = "common/scripts";
16
12
  export declare const DYNAMODB_GENERATOR_IDS: string[];
13
+ /**
14
+ * What a generator records about the infrastructure it generated.
15
+ *
16
+ * Every generator that creates infrastructure records the `iac` it used, so a
17
+ * predicate can tell a CDK project from a Terraform one at upgrade time. Absent
18
+ * when the generator was run with no infrastructure, so its presence doubles as
19
+ * "infrastructure was generated" — which is what gates the packages an infra
20
+ * helper adds.
21
+ */
22
+ export interface IacMetadata {
23
+ readonly iac?: string;
24
+ }
25
+ /**
26
+ * Whether infrastructure was generated at all, so the packages an infra helper
27
+ * adds are only claimed where that helper ran.
28
+ *
29
+ * Reads `iac` rather than the generator's own `infra` option: every generator
30
+ * resolves `iac` only on the infra branch, so one recorded field answers both
31
+ * questions and no generator needs a second one.
32
+ */
33
+ export declare const generatedInfrastructure: (m: IacMetadata) => boolean;
34
+ /**
35
+ * Dependencies a caller must declare to use the shared constructs project.
36
+ * Lives here so generators can spread it without importing the generator.
37
+ *
38
+ * `constructs` and `aws-cdk-lib` are gated on CDK because
39
+ * `sharedConstructsGenerator` creates the TypeScript constructs project on that
40
+ * branch alone — a Terraform workspace gets the shared Terraform project and
41
+ * never receives them.
42
+ */
43
+ export declare const SHARED_CONSTRUCTS_DEPENDENCIES: readonly [{
44
+ readonly name: "constructs";
45
+ readonly when: (m: IacMetadata) => boolean;
46
+ }, {
47
+ readonly name: "aws-cdk-lib";
48
+ readonly when: (m: IacMetadata) => boolean;
49
+ }, {
50
+ readonly name: "@types/node";
51
+ }];
@@ -16,5 +16,34 @@ export const DYNAMODB_GENERATOR_IDS = [
16
16
  'ts#dynamodb',
17
17
  'py#dynamodb'
18
18
  ];
19
+ /**
20
+ * Whether infrastructure was generated at all, so the packages an infra helper
21
+ * adds are only claimed where that helper ran.
22
+ *
23
+ * Reads `iac` rather than the generator's own `infra` option: every generator
24
+ * resolves `iac` only on the infra branch, so one recorded field answers both
25
+ * questions and no generator needs a second one.
26
+ */ export const generatedInfrastructure = (m)=>m.iac !== undefined;
27
+ /**
28
+ * Dependencies a caller must declare to use the shared constructs project.
29
+ * Lives here so generators can spread it without importing the generator.
30
+ *
31
+ * `constructs` and `aws-cdk-lib` are gated on CDK because
32
+ * `sharedConstructsGenerator` creates the TypeScript constructs project on that
33
+ * branch alone — a Terraform workspace gets the shared Terraform project and
34
+ * never receives them.
35
+ */ export const SHARED_CONSTRUCTS_DEPENDENCIES = [
36
+ {
37
+ name: 'constructs',
38
+ when: (m)=>m.iac === 'cdk'
39
+ },
40
+ {
41
+ name: 'aws-cdk-lib',
42
+ when: (m)=>m.iac === 'cdk'
43
+ },
44
+ {
45
+ name: '@types/node'
46
+ }
47
+ ];
19
48
 
20
49
  //# sourceMappingURL=shared-constructs-constants.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS"],"mappings":"AAAA;;;CAGC,GAED,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { DeclaredTsDependency } from './declared-dependencies';\nimport type { ITsDepVersion } from './versions';\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n\n/**\n * What a generator records about the infrastructure it generated.\n *\n * Every generator that creates infrastructure records the `iac` it used, so a\n * predicate can tell a CDK project from a Terraform one at upgrade time. Absent\n * when the generator was run with no infrastructure, so its presence doubles as\n * \"infrastructure was generated\" — which is what gates the packages an infra\n * helper adds.\n */\nexport interface IacMetadata {\n readonly iac?: string;\n}\n\n/**\n * Whether infrastructure was generated at all, so the packages an infra helper\n * adds are only claimed where that helper ran.\n *\n * Reads `iac` rather than the generator's own `infra` option: every generator\n * resolves `iac` only on the infra branch, so one recorded field answers both\n * questions and no generator needs a second one.\n */\nexport const generatedInfrastructure = (m: IacMetadata): boolean =>\n m.iac !== undefined;\n\n/**\n * Dependencies a caller must declare to use the shared constructs project.\n * Lives here so generators can spread it without importing the generator.\n *\n * `constructs` and `aws-cdk-lib` are gated on CDK because\n * `sharedConstructsGenerator` creates the TypeScript constructs project on that\n * branch alone — a Terraform workspace gets the shared Terraform project and\n * never receives them.\n */\nexport const SHARED_CONSTRUCTS_DEPENDENCIES = [\n { name: 'constructs', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: 'aws-cdk-lib', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: '@types/node' },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS","generatedInfrastructure","m","iac","undefined","SHARED_CONSTRUCTS_DEPENDENCIES","name","when"],"mappings":"AAAA;;;CAGC,GAID,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC;AAerE;;;;;;;CAOC,GACD,OAAO,MAAMC,0BAA0B,CAACC,IACtCA,EAAEC,GAAG,KAAKC,UAAU;AAEtB;;;;;;;;CAQC,GACD,OAAO,MAAMC,iCAAiC;IAC5C;QAAEC,MAAM;QAAcC,MAAM,CAACL,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IAChE;QAAEG,MAAM;QAAeC,MAAM,CAACL,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IACjE;QAAEG,MAAM;IAAc;CACvB,CAGG"}
@@ -3,8 +3,11 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { type Tree } from '@nx/devkit';
6
+ import type { DependencyDeclaration, MustDeclare } from './declared-dependencies';
6
7
  import type { Iac } from './iac';
8
+ import { SHARED_CONSTRUCTS_DEPENDENCIES } from './shared-constructs-constants';
9
+ export { SHARED_CONSTRUCTS_DEPENDENCIES };
7
10
  export interface SharedConstructsGeneratorOptions {
8
11
  iac: Iac;
9
12
  }
10
- export declare function sharedConstructsGenerator(tree: Tree, options: SharedConstructsGeneratorOptions): Promise<void>;
13
+ export declare function sharedConstructsGenerator<const D extends DependencyDeclaration>(tree: Tree, options: SharedConstructsGeneratorOptions, declaration: D & MustDeclare<typeof SHARED_CONSTRUCTS_DEPENDENCIES, D>): Promise<void>;
@@ -10,9 +10,10 @@ import { formatFilesInSubtree } from "./format.js";
10
10
  import { esmVars } from "./module-format.js";
11
11
  import { getNpmScopePrefix } from "./npm-scope.js";
12
12
  import { getPackageManagerDisplayCommands } from "./pkg-manager.js";
13
- import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_CONSTRUCTS_NAME, SHARED_TERRAFORM_DIR, SHARED_TERRAFORM_NAME } from "./shared-constructs-constants.js";
13
+ import { PACKAGES_DIR, SHARED_CONSTRUCTS_DEPENDENCIES, SHARED_CONSTRUCTS_DIR, SHARED_CONSTRUCTS_NAME, SHARED_TERRAFORM_DIR, SHARED_TERRAFORM_NAME } from "./shared-constructs-constants.js";
14
+ export { SHARED_CONSTRUCTS_DEPENDENCIES };
14
15
  import { terraformProviderVersions, withVersions } from "./versions.js";
15
- export async function sharedConstructsGenerator(tree, options) {
16
+ export async function sharedConstructsGenerator(tree, options, declaration) {
16
17
  const { iac } = options;
17
18
  const npmScopePrefix = getNpmScopePrefix(tree);
18
19
  updateGitignore(tree);
@@ -39,10 +40,10 @@ export async function sharedConstructsGenerator(tree, options) {
39
40
  }, {
40
41
  overwriteStrategy: OverwriteStrategy.Overwrite
41
42
  });
42
- addDependenciesToPackageJson(tree, withVersions([
43
+ addDependenciesToPackageJson(tree, withVersions(declaration, [
43
44
  'constructs',
44
45
  'aws-cdk-lib'
45
- ]), withVersions([
46
+ ]), withVersions(declaration, [
46
47
  '@types/node'
47
48
  ]), joinPathFragments(joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR), 'package.json'));
48
49
  await formatFilesInSubtree(tree);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport terraformProjectGenerator from '../terraform/project/generator';\nimport tsProjectGenerator from '../ts/lib/generator';\nimport { readAwsNxPluginConfig } from './config/utils';\nimport { addDependenciesToPackageJson } from './dependencies';\nimport { formatFilesInSubtree } from './format';\nimport type { Iac } from './iac';\nimport { esmVars } from './module-format';\nimport { getNpmScopePrefix } from './npm-scope';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_CONSTRUCTS_NAME,\n SHARED_TERRAFORM_DIR,\n SHARED_TERRAFORM_NAME,\n} from './shared-constructs-constants';\nimport { terraformProviderVersions, withVersions } from './versions';\n\nexport interface SharedConstructsGeneratorOptions {\n iac: Iac;\n}\n\nexport async function sharedConstructsGenerator(\n tree: Tree,\n options: SharedConstructsGeneratorOptions,\n) {\n const { iac } = options;\n const npmScopePrefix = getNpmScopePrefix(tree);\n updateGitignore(tree);\n\n if (iac === 'cdk') {\n if (\n !tree.exists(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'project.json'),\n )\n ) {\n await tsProjectGenerator(tree, {\n name: SHARED_CONSTRUCTS_NAME,\n directory: PACKAGES_DIR,\n subDirectory: SHARED_CONSTRUCTS_DIR,\n });\n tree.delete(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src'),\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n SHARED_CONSTRUCTS_DIR,\n 'src',\n ),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src'),\n {\n npmScopePrefix,\n scopeAlias: npmScopePrefix,\n tags: readAwsNxPluginConfig(tree)?.tags ?? [],\n ...esmVars(tree),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'common', 'readme'),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n {\n fullyQualifiedName: `${npmScopePrefix}${SHARED_CONSTRUCTS_NAME}`,\n name: SHARED_CONSTRUCTS_NAME,\n pkgMgrCmd: getPackageManagerDisplayCommands().exec,\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n addDependenciesToPackageJson(\n tree,\n withVersions(['constructs', 'aws-cdk-lib']),\n withVersions(['@types/node']),\n joinPathFragments(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n 'package.json',\n ),\n );\n await formatFilesInSubtree(tree);\n }\n }\n\n // Handle Terraform provider\n if (iac === 'terraform') {\n const terraformLibPath = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n );\n if (!tree.exists(joinPathFragments(terraformLibPath, 'project.json'))) {\n await terraformProjectGenerator(tree, {\n name: SHARED_TERRAFORM_NAME,\n directory: joinPathFragments(PACKAGES_DIR, 'common'),\n type: 'library',\n });\n\n // `build` is a no-op orchestration target that produces no files of its\n // own. Terraform writes runtime-config entries into\n // `dist/{projectRoot}/runtime-config` at apply time, and other terraform\n // projects contribute their own entries to the same directory. Without\n // explicit outputs, Nx infers `dist/{projectRoot}` as this target's\n // cached output and, on a cache hit, restores the cached copy over the\n // freshly-applied config — wiping the very values consumers read. Declare\n // no outputs so Nx never treats runtime config as a cacheable artifact.\n updateJson(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'),\n (projectConfig: ProjectConfiguration) => {\n projectConfig.targets ??= {};\n projectConfig.targets.build ??= {};\n projectConfig.targets.build.outputs = [];\n return projectConfig;\n },\n );\n\n tree.delete(joinPathFragments(terraformLibPath, 'src', 'main.tf'));\n\n // Create the metrics.tf file with empty initial values\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'terraform'),\n terraformLibPath,\n { ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await formatFilesInSubtree(tree);\n }\n }\n}\n\nconst updateGitignore = (tree: Tree) => {\n const gitignore = tree.exists('.gitignore')\n ? tree.read('.gitignore', 'utf-8')\n : '';\n const regex = /runtime-config.json/gm;\n const hasRuntimeConfig = regex.test(gitignore ?? '');\n if (hasRuntimeConfig) {\n return;\n }\n tree.write('.gitignore', `${gitignore}\\n\\nruntime-config.json`);\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateJson","terraformProjectGenerator","tsProjectGenerator","readAwsNxPluginConfig","addDependenciesToPackageJson","formatFilesInSubtree","esmVars","getNpmScopePrefix","getPackageManagerDisplayCommands","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_CONSTRUCTS_NAME","SHARED_TERRAFORM_DIR","SHARED_TERRAFORM_NAME","terraformProviderVersions","withVersions","sharedConstructsGenerator","tree","options","iac","npmScopePrefix","updateGitignore","exists","name","directory","subDirectory","delete","dirname","scopeAlias","tags","overwriteStrategy","KeepExisting","fullyQualifiedName","pkgMgrCmd","exec","Overwrite","terraformLibPath","type","projectConfig","targets","build","outputs","gitignore","read","regex","hasRuntimeConfig","test","write"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport terraformProjectGenerator from '../terraform/project/generator';\nimport tsProjectGenerator from '../ts/lib/generator';\nimport { readAwsNxPluginConfig } from './config/utils';\nimport type {\n DependencyDeclaration,\n MustDeclare,\n} from './declared-dependencies';\nimport { addDependenciesToPackageJson } from './dependencies';\nimport { formatFilesInSubtree } from './format';\nimport type { Iac } from './iac';\nimport { esmVars } from './module-format';\nimport { getNpmScopePrefix } from './npm-scope';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DEPENDENCIES,\n SHARED_CONSTRUCTS_DIR,\n SHARED_CONSTRUCTS_NAME,\n SHARED_TERRAFORM_DIR,\n SHARED_TERRAFORM_NAME,\n} from './shared-constructs-constants';\n\nexport { SHARED_CONSTRUCTS_DEPENDENCIES };\n\nimport { terraformProviderVersions, withVersions } from './versions';\n\nexport interface SharedConstructsGeneratorOptions {\n iac: Iac;\n}\n\nexport async function sharedConstructsGenerator<\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n options: SharedConstructsGeneratorOptions,\n declaration: D & MustDeclare<typeof SHARED_CONSTRUCTS_DEPENDENCIES, D>,\n) {\n const { iac } = options;\n const npmScopePrefix = getNpmScopePrefix(tree);\n updateGitignore(tree);\n\n if (iac === 'cdk') {\n if (\n !tree.exists(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'project.json'),\n )\n ) {\n await tsProjectGenerator(tree, {\n name: SHARED_CONSTRUCTS_NAME,\n directory: PACKAGES_DIR,\n subDirectory: SHARED_CONSTRUCTS_DIR,\n });\n tree.delete(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src'),\n );\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n SHARED_CONSTRUCTS_DIR,\n 'src',\n ),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src'),\n {\n npmScopePrefix,\n scopeAlias: npmScopePrefix,\n tags: readAwsNxPluginConfig(tree)?.tags ?? [],\n ...esmVars(tree),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'common', 'readme'),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n {\n fullyQualifiedName: `${npmScopePrefix}${SHARED_CONSTRUCTS_NAME}`,\n name: SHARED_CONSTRUCTS_NAME,\n pkgMgrCmd: getPackageManagerDisplayCommands().exec,\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n addDependenciesToPackageJson(\n tree,\n withVersions(\n declaration as DependencyDeclaration<\n typeof SHARED_CONSTRUCTS_DEPENDENCIES\n >,\n ['constructs', 'aws-cdk-lib'],\n ),\n withVersions(\n declaration as DependencyDeclaration<\n typeof SHARED_CONSTRUCTS_DEPENDENCIES\n >,\n ['@types/node'],\n ),\n joinPathFragments(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n 'package.json',\n ),\n );\n await formatFilesInSubtree(tree);\n }\n }\n\n // Handle Terraform provider\n if (iac === 'terraform') {\n const terraformLibPath = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n );\n if (!tree.exists(joinPathFragments(terraformLibPath, 'project.json'))) {\n await terraformProjectGenerator(tree, {\n name: SHARED_TERRAFORM_NAME,\n directory: joinPathFragments(PACKAGES_DIR, 'common'),\n type: 'library',\n });\n\n // `build` is a no-op orchestration target that produces no files of its\n // own. Terraform writes runtime-config entries into\n // `dist/{projectRoot}/runtime-config` at apply time, and other terraform\n // projects contribute their own entries to the same directory. Without\n // explicit outputs, Nx infers `dist/{projectRoot}` as this target's\n // cached output and, on a cache hit, restores the cached copy over the\n // freshly-applied config — wiping the very values consumers read. Declare\n // no outputs so Nx never treats runtime config as a cacheable artifact.\n updateJson(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'),\n (projectConfig: ProjectConfiguration) => {\n projectConfig.targets ??= {};\n projectConfig.targets.build ??= {};\n projectConfig.targets.build.outputs = [];\n return projectConfig;\n },\n );\n\n tree.delete(joinPathFragments(terraformLibPath, 'src', 'main.tf'));\n\n // Create the metrics.tf file with empty initial values\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'terraform'),\n terraformLibPath,\n { ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await formatFilesInSubtree(tree);\n }\n }\n}\n\nconst updateGitignore = (tree: Tree) => {\n const gitignore = tree.exists('.gitignore')\n ? tree.read('.gitignore', 'utf-8')\n : '';\n const regex = /runtime-config.json/gm;\n const hasRuntimeConfig = regex.test(gitignore ?? '');\n if (hasRuntimeConfig) {\n return;\n }\n tree.write('.gitignore', `${gitignore}\\n\\nruntime-config.json`);\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateJson","terraformProjectGenerator","tsProjectGenerator","readAwsNxPluginConfig","addDependenciesToPackageJson","formatFilesInSubtree","esmVars","getNpmScopePrefix","getPackageManagerDisplayCommands","PACKAGES_DIR","SHARED_CONSTRUCTS_DEPENDENCIES","SHARED_CONSTRUCTS_DIR","SHARED_CONSTRUCTS_NAME","SHARED_TERRAFORM_DIR","SHARED_TERRAFORM_NAME","terraformProviderVersions","withVersions","sharedConstructsGenerator","tree","options","declaration","iac","npmScopePrefix","updateGitignore","exists","name","directory","subDirectory","delete","dirname","scopeAlias","tags","overwriteStrategy","KeepExisting","fullyQualifiedName","pkgMgrCmd","exec","Overwrite","terraformLibPath","type","projectConfig","targets","build","outputs","gitignore","read","regex","hasRuntimeConfig","test","write"],"mappings":"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"}
@@ -3,9 +3,16 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import { type Tree } from '@nx/devkit';
6
+ import type { DependencyDeclaration, MustDeclare } from './declared-dependencies';
7
+ /** Dependencies a caller must declare to use the shared DynamoDB scripts. */
8
+ export declare const SHARED_DYNAMODB_SCRIPTS_DEPENDENCIES: readonly [{
9
+ readonly name: "@aws-sdk/client-dynamodb";
10
+ }, {
11
+ readonly name: "tsx";
12
+ }];
6
13
  /**
7
14
  * Ensures the shared scripts package exists and adds DynamoDB local-dev scripts
8
15
  * to packages/common/scripts/src/dynamodb/. Used by both ts#dynamodb and
9
16
  * py#dynamodb so a single set of TypeScript scripts serves both.
10
17
  */
11
- export declare function sharedDynamoDBScriptsGenerator(tree: Tree): Promise<void>;
18
+ export declare function sharedDynamoDBScriptsGenerator<const D extends DependencyDeclaration>(tree: Tree, declaration: D & MustDeclare<typeof SHARED_DYNAMODB_SCRIPTS_DEPENDENCIES, D>): Promise<void>;
@@ -6,20 +6,28 @@ import { addDependenciesToPackageJson } from "./dependencies.js";
6
6
  import { PACKAGES_DIR, SHARED_SCRIPTS_DIR } from "./shared-constructs-constants.js";
7
7
  import { ensureSharedScriptsProject } from "./shared-scripts.js";
8
8
  import { withVersions } from "./versions.js";
9
+ /** Dependencies a caller must declare to use the shared DynamoDB scripts. */ export const SHARED_DYNAMODB_SCRIPTS_DEPENDENCIES = [
10
+ {
11
+ name: '@aws-sdk/client-dynamodb'
12
+ },
13
+ {
14
+ name: 'tsx'
15
+ }
16
+ ];
9
17
  /**
10
18
  * Ensures the shared scripts package exists and adds DynamoDB local-dev scripts
11
19
  * to packages/common/scripts/src/dynamodb/. Used by both ts#dynamodb and
12
20
  * py#dynamodb so a single set of TypeScript scripts serves both.
13
- */ export async function sharedDynamoDBScriptsGenerator(tree) {
21
+ */ export async function sharedDynamoDBScriptsGenerator(tree, declaration) {
14
22
  const scriptsDir = joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR);
15
23
  await ensureSharedScriptsProject(tree);
16
24
  generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', SHARED_SCRIPTS_DIR, 'src', 'dynamodb'), joinPathFragments(scriptsDir, 'src', 'dynamodb'), {}, {
17
25
  overwriteStrategy: OverwriteStrategy.KeepExisting
18
26
  });
19
- addDependenciesToPackageJson(tree, withVersions([
27
+ addDependenciesToPackageJson(tree, withVersions(declaration, [
20
28
  '@aws-sdk/client-dynamodb'
21
29
  ]), {}, joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'package.json'));
22
- addDependenciesToPackageJson(tree, {}, withVersions([
30
+ addDependenciesToPackageJson(tree, {}, withVersions(declaration, [
23
31
  'tsx'
24
32
  ]));
25
33
  }