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

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 (267) hide show
  1. package/migrations.json +45 -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/preset/generator.d.ts +13 -0
  21. package/src/preset/generator.js +12 -3
  22. package/src/preset/generator.js.map +1 -1
  23. package/src/py/agent/a2a-connection/generator.d.ts +24 -0
  24. package/src/py/agent/a2a-connection/generator.js +49 -20
  25. package/src/py/agent/a2a-connection/generator.js.map +1 -1
  26. package/src/py/agent/gateway-connection/generator.d.ts +23 -0
  27. package/src/py/agent/gateway-connection/generator.js +45 -11
  28. package/src/py/agent/gateway-connection/generator.js.map +1 -1
  29. package/src/py/agent/generator.d.ts +146 -1
  30. package/src/py/agent/generator.js +173 -76
  31. package/src/py/agent/generator.js.map +1 -1
  32. package/src/py/agent/mcp-connection/generator.d.ts +23 -0
  33. package/src/py/agent/mcp-connection/generator.js +45 -11
  34. package/src/py/agent/mcp-connection/generator.js.map +1 -1
  35. package/src/py/agent/react-connection/generator.d.ts +146 -0
  36. package/src/py/agent/react-connection/generator.js +27 -4
  37. package/src/py/agent/react-connection/generator.js.map +1 -1
  38. package/src/py/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +18 -0
  39. package/src/py/dynamodb/agent-connection/generator.js +7 -1
  40. package/src/py/dynamodb/agent-connection/generator.js.map +1 -1
  41. package/src/py/dynamodb/fast-api-connection/__snapshots__/generator.spec.ts.snap +9 -0
  42. package/src/py/dynamodb/fast-api-connection/generator.js +3 -1
  43. package/src/py/dynamodb/fast-api-connection/generator.js.map +1 -1
  44. package/src/py/dynamodb/generator.d.ts +29 -0
  45. package/src/py/dynamodb/generator.js +32 -12
  46. package/src/py/dynamodb/generator.js.map +1 -1
  47. package/src/py/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  48. package/src/py/dynamodb/mcp-server-connection/generator.js +7 -1
  49. package/src/py/dynamodb/mcp-server-connection/generator.js.map +1 -1
  50. package/src/py/fast-api/generator.d.ts +63 -0
  51. package/src/py/fast-api/generator.js +58 -23
  52. package/src/py/fast-api/generator.js.map +1 -1
  53. package/src/py/fast-api/react/generator.d.ts +16 -1
  54. package/src/py/fast-api/react/generator.js +15 -3
  55. package/src/py/fast-api/react/generator.js.map +1 -1
  56. package/src/py/lambda-function/generator.d.ts +21 -0
  57. package/src/py/lambda-function/generator.js +29 -10
  58. package/src/py/lambda-function/generator.js.map +1 -1
  59. package/src/py/mcp-server/generator.d.ts +60 -0
  60. package/src/py/mcp-server/generator.js +62 -25
  61. package/src/py/mcp-server/generator.js.map +1 -1
  62. package/src/py/project/generator.d.ts +13 -0
  63. package/src/py/project/generator.js +29 -10
  64. package/src/py/project/generator.js.map +1 -1
  65. package/src/py/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +19 -0
  66. package/src/py/rdb/agent-connection/generator.js +7 -1
  67. package/src/py/rdb/agent-connection/generator.js.map +1 -1
  68. package/src/py/rdb/fast-api-connection/__snapshots__/generator.spec.ts.snap +7 -0
  69. package/src/py/rdb/fast-api-connection/generator.js +3 -1
  70. package/src/py/rdb/fast-api-connection/generator.js.map +1 -1
  71. package/src/py/rdb/generator.d.ts +89 -0
  72. package/src/py/rdb/generator.js +88 -40
  73. package/src/py/rdb/generator.js.map +1 -1
  74. package/src/py/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  75. package/src/py/rdb/mcp-server-connection/generator.js +7 -1
  76. package/src/py/rdb/mcp-server-connection/generator.js.map +1 -1
  77. package/src/smithy/project/generator.d.ts +7 -0
  78. package/src/smithy/project/generator.js +8 -2
  79. package/src/smithy/project/generator.js.map +1 -1
  80. package/src/smithy/react-connection/generator.d.ts +15 -0
  81. package/src/smithy/react-connection/generator.js +17 -3
  82. package/src/smithy/react-connection/generator.js.map +1 -1
  83. package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1 -0
  84. package/src/smithy/ts/api/generator.d.ts +79 -0
  85. package/src/smithy/ts/api/generator.js +77 -33
  86. package/src/smithy/ts/api/generator.js.map +1 -1
  87. package/src/terraform/project/generator.d.ts +50 -0
  88. package/src/terraform/project/generator.js +63 -17
  89. package/src/terraform/project/generator.js.map +1 -1
  90. package/src/trpc/backend/generator.d.ts +84 -0
  91. package/src/trpc/backend/generator.js +98 -38
  92. package/src/trpc/backend/generator.js.map +1 -1
  93. package/src/trpc/react/generator.d.ts +37 -0
  94. package/src/trpc/react/generator.js +63 -26
  95. package/src/trpc/react/generator.js.map +1 -1
  96. package/src/ts/agent/a2a-connection/generator.d.ts +46 -0
  97. package/src/ts/agent/a2a-connection/generator.js +53 -16
  98. package/src/ts/agent/a2a-connection/generator.js.map +1 -1
  99. package/src/ts/agent/gateway-connection/generator.d.ts +37 -0
  100. package/src/ts/agent/gateway-connection/generator.js +41 -14
  101. package/src/ts/agent/gateway-connection/generator.js.map +1 -1
  102. package/src/ts/agent/generator.d.ts +162 -0
  103. package/src/ts/agent/generator.js +166 -75
  104. package/src/ts/agent/generator.js.map +1 -1
  105. package/src/ts/agent/mcp-connection/generator.d.ts +37 -0
  106. package/src/ts/agent/mcp-connection/generator.js +41 -14
  107. package/src/ts/agent/mcp-connection/generator.js.map +1 -1
  108. package/src/ts/agent/react-connection/generator.d.ts +186 -0
  109. package/src/ts/agent/react-connection/generator.js +70 -21
  110. package/src/ts/agent/react-connection/generator.js.map +1 -1
  111. package/src/ts/astro-docs/generator.d.ts +38 -0
  112. package/src/ts/astro-docs/generator.js +58 -19
  113. package/src/ts/astro-docs/generator.js.map +1 -1
  114. package/src/ts/dcr-proxy/generator.d.ts +24 -0
  115. package/src/ts/dcr-proxy/generator.js +31 -14
  116. package/src/ts/dcr-proxy/generator.js.map +1 -1
  117. package/src/ts/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +18 -0
  118. package/src/ts/dynamodb/agent-connection/generator.js +7 -1
  119. package/src/ts/dynamodb/agent-connection/generator.js.map +1 -1
  120. package/src/ts/dynamodb/generator.d.ts +41 -0
  121. package/src/ts/dynamodb/generator.js +47 -20
  122. package/src/ts/dynamodb/generator.js.map +1 -1
  123. package/src/ts/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +18 -0
  124. package/src/ts/dynamodb/mcp-server-connection/generator.js +7 -1
  125. package/src/ts/dynamodb/mcp-server-connection/generator.js.map +1 -1
  126. package/src/ts/dynamodb/smithy-connection/__snapshots__/generator.spec.ts.snap +9 -0
  127. package/src/ts/dynamodb/smithy-connection/generator.js +3 -1
  128. package/src/ts/dynamodb/smithy-connection/generator.js.map +1 -1
  129. package/src/ts/dynamodb/trpc-connection/__snapshots__/generator.spec.ts.snap +9 -0
  130. package/src/ts/dynamodb/trpc-connection/generator.js +3 -1
  131. package/src/ts/dynamodb/trpc-connection/generator.js.map +1 -1
  132. package/src/ts/lambda-function/generator.d.ts +38 -0
  133. package/src/ts/lambda-function/generator.js +49 -20
  134. package/src/ts/lambda-function/generator.js.map +1 -1
  135. package/src/ts/lib/generator.d.ts +7 -0
  136. package/src/ts/lib/generator.js +8 -1
  137. package/src/ts/lib/generator.js.map +1 -1
  138. package/src/ts/lib/ts-project-utils.d.ts +3 -1
  139. package/src/ts/lib/ts-project-utils.js +3 -2
  140. package/src/ts/lib/ts-project-utils.js.map +1 -1
  141. package/src/ts/lib/vitest.d.ts +10 -1
  142. package/src/ts/lib/vitest.js +14 -2
  143. package/src/ts/lib/vitest.js.map +1 -1
  144. package/src/ts/mcp-server/generator.d.ts +71 -0
  145. package/src/ts/mcp-server/generator.js +73 -36
  146. package/src/ts/mcp-server/generator.js.map +1 -1
  147. package/src/ts/nx-generator/generator.d.ts +3 -0
  148. package/src/ts/nx-generator/generator.js +8 -2
  149. package/src/ts/nx-generator/generator.js.map +1 -1
  150. package/src/ts/nx-migration/generator.d.ts +3 -0
  151. package/src/ts/nx-migration/generator.js +8 -2
  152. package/src/ts/nx-migration/generator.js.map +1 -1
  153. package/src/ts/nx-plugin/generator.d.ts +3 -0
  154. package/src/ts/nx-plugin/generator.js +8 -2
  155. package/src/ts/nx-plugin/generator.js.map +1 -1
  156. package/src/ts/nx-plugin/utils.d.ts +7 -2
  157. package/src/ts/nx-plugin/utils.js +10 -4
  158. package/src/ts/nx-plugin/utils.js.map +1 -1
  159. package/src/ts/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +10 -0
  160. package/src/ts/rdb/agent-connection/generator.js +8 -1
  161. package/src/ts/rdb/agent-connection/generator.js.map +1 -1
  162. package/src/ts/rdb/generator.d.ts +101 -0
  163. package/src/ts/rdb/generator.js +93 -41
  164. package/src/ts/rdb/generator.js.map +1 -1
  165. package/src/ts/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +10 -0
  166. package/src/ts/rdb/mcp-server-connection/generator.js +8 -1
  167. package/src/ts/rdb/mcp-server-connection/generator.js.map +1 -1
  168. package/src/ts/rdb/smithy-connection/__snapshots__/generator.spec.ts.snap +9 -0
  169. package/src/ts/rdb/smithy-connection/generator.js +4 -1
  170. package/src/ts/rdb/smithy-connection/generator.js.map +1 -1
  171. package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +9 -0
  172. package/src/ts/rdb/trpc-connection/generator.js +3 -1
  173. package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
  174. package/src/ts/react-website/agui/generator.d.ts +86 -0
  175. package/src/ts/react-website/agui/generator.js +63 -28
  176. package/src/ts/react-website/agui/generator.js.map +1 -1
  177. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +8 -2
  178. package/src/ts/react-website/app/generator.d.ts +136 -1
  179. package/src/ts/react-website/app/generator.js +109 -40
  180. package/src/ts/react-website/app/generator.js.map +1 -1
  181. package/src/ts/react-website/cognito-auth/generator.d.ts +19 -0
  182. package/src/ts/react-website/cognito-auth/generator.js +21 -9
  183. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  184. package/src/utils/add-dependencies.d.ts +38 -0
  185. package/src/utils/add-dependencies.js +83 -0
  186. package/src/utils/add-dependencies.js.map +1 -0
  187. package/src/utils/agent-connection/agent-connection.d.ts +27 -6
  188. package/src/utils/agent-connection/agent-connection.js +47 -18
  189. package/src/utils/agent-connection/agent-connection.js.map +1 -1
  190. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +19 -1
  191. package/src/utils/agent-core-constructs/agent-core-constructs.js +26 -6
  192. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  193. package/src/utils/api-constructs/api-constructs.d.ts +21 -2
  194. package/src/utils/api-constructs/api-constructs.js +26 -5
  195. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  196. package/src/utils/bundle/bundle.d.ts +6 -1
  197. package/src/utils/bundle/bundle.js +8 -2
  198. package/src/utils/bundle/bundle.js.map +1 -1
  199. package/src/utils/commands.d.ts +5 -4
  200. package/src/utils/commands.js +2 -6
  201. package/src/utils/commands.js.map +1 -1
  202. package/src/utils/connection/open-api/react.d.ts +18 -1
  203. package/src/utils/connection/open-api/react.js +27 -3
  204. package/src/utils/connection/open-api/react.js.map +1 -1
  205. package/src/utils/declared-dependencies.d.ts +140 -0
  206. package/src/utils/declared-dependencies.js +64 -0
  207. package/src/utils/declared-dependencies.js.map +1 -0
  208. package/src/utils/docker.d.ts +10 -1
  209. package/src/utils/docker.js +7 -3
  210. package/src/utils/docker.js.map +1 -1
  211. package/src/utils/fs.d.ts +15 -4
  212. package/src/utils/fs.js +26 -13
  213. package/src/utils/fs.js.map +1 -1
  214. package/src/utils/init.d.ts +14 -1
  215. package/src/utils/init.js +25 -7
  216. package/src/utils/init.js.map +1 -1
  217. package/src/utils/migration-versions.d.ts +15 -1
  218. package/src/utils/migration-versions.js +53 -7
  219. package/src/utils/migration-versions.js.map +1 -1
  220. package/src/utils/nx.d.ts +18 -0
  221. package/src/utils/nx.js +4 -0
  222. package/src/utils/nx.js.map +1 -1
  223. package/src/utils/py.d.ts +3 -2
  224. package/src/utils/py.js +10 -10
  225. package/src/utils/py.js.map +1 -1
  226. package/src/utils/shared-constructs-constants.d.ts +39 -4
  227. package/src/utils/shared-constructs-constants.js +29 -0
  228. package/src/utils/shared-constructs-constants.js.map +1 -1
  229. package/src/utils/shared-constructs.d.ts +4 -1
  230. package/src/utils/shared-constructs.js +5 -4
  231. package/src/utils/shared-constructs.js.map +1 -1
  232. package/src/utils/shared-dynamodb-scripts.d.ts +8 -1
  233. package/src/utils/shared-dynamodb-scripts.js +11 -3
  234. package/src/utils/shared-dynamodb-scripts.js.map +1 -1
  235. package/src/utils/shared-infra-scripts.d.ts +16 -1
  236. package/src/utils/shared-infra-scripts.js +18 -3
  237. package/src/utils/shared-infra-scripts.js.map +1 -1
  238. package/src/utils/shared-rdb-scripts.d.ts +12 -1
  239. package/src/utils/shared-rdb-scripts.js +17 -3
  240. package/src/utils/shared-rdb-scripts.js.map +1 -1
  241. package/src/utils/shared-shadcn.d.ts +26 -1
  242. package/src/utils/shared-shadcn.js +31 -14
  243. package/src/utils/shared-shadcn.js.map +1 -1
  244. package/src/utils/version-upgrade-migration/migration.d.ts +14 -0
  245. package/src/utils/version-upgrade-migration/migration.js +16 -0
  246. package/src/utils/version-upgrade-migration/migration.js.map +1 -0
  247. package/src/utils/version-upgrade-migration/nx-package-updates.d.ts +35 -0
  248. package/src/utils/version-upgrade-migration/nx-package-updates.js +42 -0
  249. package/src/utils/version-upgrade-migration/nx-package-updates.js.map +1 -0
  250. package/src/utils/version-upgrade-migration/owned-dependencies.d.ts +50 -0
  251. package/src/utils/version-upgrade-migration/owned-dependencies.js +98 -0
  252. package/src/utils/version-upgrade-migration/owned-dependencies.js.map +1 -0
  253. package/src/utils/version-upgrade-migration/register.d.ts +18 -0
  254. package/src/utils/version-upgrade-migration/register.js +33 -0
  255. package/src/utils/version-upgrade-migration/register.js.map +1 -0
  256. package/src/utils/version-upgrade-migration/sync-metrics-version.d.ts +13 -0
  257. package/src/utils/version-upgrade-migration/sync-metrics-version.js +33 -0
  258. package/src/utils/version-upgrade-migration/sync-metrics-version.js.map +1 -0
  259. package/src/utils/version-upgrade-migration/sync-vended-versions.d.ts +10 -0
  260. package/src/utils/version-upgrade-migration/sync-vended-versions.js +504 -0
  261. package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -0
  262. package/src/utils/version-upgrade-migration/vended-upgrade.d.ts +14 -0
  263. package/src/utils/version-upgrade-migration/vended-upgrade.js +40 -0
  264. package/src/utils/version-upgrade-migration/vended-upgrade.js.map +1 -0
  265. package/src/utils/versions.d.ts +25 -5
  266. package/src/utils/versions.js +46 -4
  267. package/src/utils/versions.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport { FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { CONTAINER_VERSIONS, TS_VERSIONS } from './versions';\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan (\\`nx run-many --target trivy\\`).\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\n/**\n * Substitution variables for the vended Node `Dockerfile` templates: the npm\n * version to install globally, and the versions its dependency overrides pin.\n */\nexport const nodeImageVersions = () => ({\n npmVersion: TS_VERSIONS.npm,\n minimatchVersion: TS_VERSIONS.minimatch,\n});\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target\n * and wire it under the aggregate \\`trivy\\` target. The scan is not part of\n * \\`build\\` — run \\`nx run-many --target trivy\\` (the root \\`trivy\\` script) in CI.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = (\n tree: Tree,\n options: DockerScanTargetOptions,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;\n\n const fs = new FsCommands(tree);\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target. The\n // scan is intentionally NOT wired into `build`: image scanning is slow and\n // its result depends on the ever-changing vulnerability database (a scan\n // that passes today can fail tomorrow when a new CVE is published), so\n // coupling it to `build` would make local and CI builds non-deterministic.\n // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n};\n"],"names":["joinPathFragments","FsCommands","addDependencyToTargetIfNotPresent","CONTAINER_VERSIONS","TS_VERSIONS","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","nodeImageVersions","npmVersion","npm","minimatchVersion","minimatch","addDockerScanTarget","tree","options","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","trivy","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAASC,UAAU,QAAQ,UAAO;AAClC,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,kBAAkB,EAAEC,WAAW,QAAQ,gBAAa;AAE7D,MAAMC,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,IAAO,CAAA;QACtCC,YAAYJ,YAAYK,GAAG;QAC3BC,kBAAkBN,YAAYO,SAAS;IACzC,CAAA,EAAG;AA0BH;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEJ;IACF,MAAM,EAAEK,SAAS,EAAE,GAAGL;IACtB,MAAMM,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiBtB,kBAAkBoB,aAAaf;IACtD,IAAI,CAACQ,KAAKU,MAAM,CAACD,iBAAiB;QAChCT,KAAKW,KAAK,CAACF,gBAAgBhB;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMmB,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAU3B,kBAAkB,QAAQoB,aAAa,SAASK;IAChE,MAAMG,aAAa,CAAC,kCAAkC,EAAEzB,mBAAmB0B,KAAK,EAAE;IAElF,MAAMC,KAAK,IAAI7B,WAAWY;IAC1B,MAAMkB,WAAW;QACfD,GAAGE,EAAE,CAACL;QACNG,GAAGG,KAAK,CAACN;QACTG,GAAGI,EAAE,CAACZ,gBAAgBtB,kBAAkB2B,SAAStB;KAClD;IAEDc,UAAUgB,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGvB,gBAAgB,SAAS,EAAEhB,kBAAkB2B,SAASW,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGpB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAEU,QAAQ,oBAAoB,EAAEjC,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAU,QAAQyB,OAAO,KAAK,CAAC;IACrBzB,QAAQyB,OAAO,CAACvB,gBAAgB,GAAG;QACjCwB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEhB,SAAS;SAAC;QACvCiB,UAAU;QACV9B,SAAS;YACPiB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC5B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAID,oBAAoB,SAAS;QAC/Bf,kCAAkCa,SAAS,SAASE;IACtD;AACF,EAAE"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/docker.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n} from '@nx/devkit';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from './declared-dependencies';\nimport { FS_DEPENDENCIES, FsCommands } from './fs';\nimport { addDependencyToTargetIfNotPresent } from './nx';\nimport { CONTAINER_VERSIONS, TS_VERSIONS } from './versions';\n\n/** Dependencies a caller must declare to add a Docker scan target. */\nexport const DOCKER_DEPENDENCIES = [...FS_DEPENDENCIES] as const;\n\nconst TRIVY_IGNORE_FILE = '.trivyignore';\n\nconst TRIVY_IGNORE_CONTENTS = `# Trivy ignore file. Add one vulnerability ID (e.g. CVE-2021-12345) per line to\n# suppress it during the image scan (\\`nx run-many --target trivy\\`).\n# https://trivy.dev/latest/docs/configuration/filtering/#by-finding-ids\n`;\n\n/**\n * Substitution variables for the vended Node `Dockerfile` templates: the npm\n * version to install globally, and the versions its dependency overrides pin.\n */\nexport const nodeImageVersions = () => ({\n npmVersion: TS_VERSIONS.npm,\n minimatchVersion: TS_VERSIONS.minimatch,\n});\n\nexport interface DockerScanTargetOptions {\n /**\n * Project configuration to add the scan target to (mutated in place).\n */\n readonly project: ProjectConfiguration;\n /**\n * Container engine command to invoke (\\`docker\\` or \\`finch\\`).\n */\n readonly containerEngine: string;\n /**\n * Name of the scan target to add, e.g. \\`my-agent-trivy\\`.\n */\n readonly trivyTargetName: string;\n /**\n * Name of the docker target that builds the image(s) to scan. The scan\n * target depends on it.\n */\n readonly dockerTargetName: string;\n /**\n * Tags of the images built by the docker target which should be scanned.\n */\n readonly imageTags: string[];\n}\n\n/**\n * Add a cacheable Trivy scan target for the images built by a docker target\n * and wire it under the aggregate \\`trivy\\` target. The scan is not part of\n * \\`build\\` — run \\`nx run-many --target trivy\\` (the root \\`trivy\\` script) in CI.\n *\n * The scan target depends on the docker target and declares the project source\n * as its inputs, so an unchanged image is never re-scanned (a cache hit skips\n * the scan entirely). Each image is saved to a tarball under\n * \\`dist/<projectRoot>/trivy/<scan-key>\\` (kept out of any Docker build context)\n * and scanned with the pinned ECR-hosted Trivy image via a workspace-relative\n * bind mount, so the same commands work under both docker and finch. The scan\n * exits non-zero (exit code 1) on HIGH/CRITICAL vulnerabilities.\n *\n * A \\`.trivyignore\\` is vended at the project root (kept if it already exists)\n * for suppressing findings.\n */\nexport const addDockerScanTarget = <const D extends DependencyDeclaration>(\n tree: Tree,\n options: DockerScanTargetOptions,\n declaration: D & MustDeclare<typeof DOCKER_DEPENDENCIES, D>,\n): void => {\n const { project, containerEngine, trivyTargetName, dockerTargetName } =\n options;\n const { imageTags } = options;\n const projectRoot = project.root;\n\n const ignoreFilePath = joinPathFragments(projectRoot, TRIVY_IGNORE_FILE);\n if (!tree.exists(ignoreFilePath)) {\n tree.write(ignoreFilePath, TRIVY_IGNORE_CONTENTS);\n }\n\n // Stage scan artifacts in a directory unique to this scan target so that\n // sibling targets in the same project (e.g. multiple agents) don't clobber\n // each other's tarballs when run in parallel. The first image tag is unique\n // per target, so it makes a stable, collision-free key.\n const scanKey = imageTags[0].replace(/[^a-zA-Z0-9-]/g, '-');\n const scanDir = joinPathFragments('dist', projectRoot, 'trivy', scanKey);\n const trivyImage = `public.ecr.aws/aquasecurity/trivy:${CONTAINER_VERSIONS.trivy}`;\n\n const fs = new FsCommands(\n tree,\n forDependencies<typeof DOCKER_DEPENDENCIES>(declaration),\n );\n const commands = [\n fs.rm(scanDir),\n fs.mkdir(scanDir),\n fs.cp(ignoreFilePath, joinPathFragments(scanDir, TRIVY_IGNORE_FILE)),\n ];\n\n imageTags.forEach((imageTag, index) => {\n const tarName = `image-${index}.tar`;\n commands.push(\n `${containerEngine} save -o ${joinPathFragments(scanDir, tarName)} ${imageTag}`,\n `${containerEngine} run --rm -v \"./${scanDir}\":/scan ${trivyImage} image --input /scan/${tarName} --ignorefile /scan/${TRIVY_IGNORE_FILE} --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 --no-progress -q`,\n );\n });\n\n project.targets ??= {};\n project.targets[trivyTargetName] = {\n cache: true,\n // The scanned image is fully determined by the project source, so caching\n // on the source ensures an unchanged image is never re-scanned.\n inputs: ['default', '^production'],\n outputs: [`{workspaceRoot}/${scanDir}`],\n executor: 'nx:run-commands',\n options: {\n commands,\n parallel: false,\n },\n dependsOn: [dockerTargetName],\n };\n\n // Aggregate per-component scan targets under a single `trivy` target. The\n // scan is intentionally NOT wired into `build`: image scanning is slow and\n // its result depends on the ever-changing vulnerability database (a scan\n // that passes today can fail tomorrow when a new CVE is published), so\n // coupling it to `build` would make local and CI builds non-deterministic.\n // Run `nx run-many --target trivy` (the root `trivy` script) in CI instead.\n if (trivyTargetName !== 'trivy') {\n addDependencyToTargetIfNotPresent(project, 'trivy', trivyTargetName);\n }\n};\n"],"names":["joinPathFragments","forDependencies","FS_DEPENDENCIES","FsCommands","addDependencyToTargetIfNotPresent","CONTAINER_VERSIONS","TS_VERSIONS","DOCKER_DEPENDENCIES","TRIVY_IGNORE_FILE","TRIVY_IGNORE_CONTENTS","nodeImageVersions","npmVersion","npm","minimatchVersion","minimatch","addDockerScanTarget","tree","options","declaration","project","containerEngine","trivyTargetName","dockerTargetName","imageTags","projectRoot","root","ignoreFilePath","exists","write","scanKey","replace","scanDir","trivyImage","trivy","fs","commands","rm","mkdir","cp","forEach","imageTag","index","tarName","push","targets","cache","inputs","outputs","executor","parallel","dependsOn"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SAEEC,eAAe,QAEV,6BAA0B;AACjC,SAASC,eAAe,EAAEC,UAAU,QAAQ,UAAO;AACnD,SAASC,iCAAiC,QAAQ,UAAO;AACzD,SAASC,kBAAkB,EAAEC,WAAW,QAAQ,gBAAa;AAE7D,oEAAoE,GACpE,OAAO,MAAMC,sBAAsB;OAAIL;CAAgB,CAAU;AAEjE,MAAMM,oBAAoB;AAE1B,MAAMC,wBAAwB,CAAC;;;AAG/B,CAAC;AAED;;;CAGC,GACD,OAAO,MAAMC,oBAAoB,IAAO,CAAA;QACtCC,YAAYL,YAAYM,GAAG;QAC3BC,kBAAkBP,YAAYQ,SAAS;IACzC,CAAA,EAAG;AA0BH;;;;;;;;;;;;;;;CAeC,GACD,OAAO,MAAMC,sBAAsB,CACjCC,MACAC,SACAC;IAEA,MAAM,EAAEC,OAAO,EAAEC,eAAe,EAAEC,eAAe,EAAEC,gBAAgB,EAAE,GACnEL;IACF,MAAM,EAAEM,SAAS,EAAE,GAAGN;IACtB,MAAMO,cAAcL,QAAQM,IAAI;IAEhC,MAAMC,iBAAiB1B,kBAAkBwB,aAAahB;IACtD,IAAI,CAACQ,KAAKW,MAAM,CAACD,iBAAiB;QAChCV,KAAKY,KAAK,CAACF,gBAAgBjB;IAC7B;IAEA,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,wDAAwD;IACxD,MAAMoB,UAAUN,SAAS,CAAC,EAAE,CAACO,OAAO,CAAC,kBAAkB;IACvD,MAAMC,UAAU/B,kBAAkB,QAAQwB,aAAa,SAASK;IAChE,MAAMG,aAAa,CAAC,kCAAkC,EAAE3B,mBAAmB4B,KAAK,EAAE;IAElF,MAAMC,KAAK,IAAI/B,WACba,MACAf,gBAA4CiB;IAE9C,MAAMiB,WAAW;QACfD,GAAGE,EAAE,CAACL;QACNG,GAAGG,KAAK,CAACN;QACTG,GAAGI,EAAE,CAACZ,gBAAgB1B,kBAAkB+B,SAASvB;KAClD;IAEDe,UAAUgB,OAAO,CAAC,CAACC,UAAUC;QAC3B,MAAMC,UAAU,CAAC,MAAM,EAAED,MAAM,IAAI,CAAC;QACpCN,SAASQ,IAAI,CACX,GAAGvB,gBAAgB,SAAS,EAAEpB,kBAAkB+B,SAASW,SAAS,CAAC,EAAEF,UAAU,EAC/E,GAAGpB,gBAAgB,gBAAgB,EAAEW,QAAQ,QAAQ,EAAEC,WAAW,qBAAqB,EAAEU,QAAQ,oBAAoB,EAAElC,kBAAkB,yFAAyF,CAAC;IAEvO;IAEAW,QAAQyB,OAAO,KAAK,CAAC;IACrBzB,QAAQyB,OAAO,CAACvB,gBAAgB,GAAG;QACjCwB,OAAO;QACP,0EAA0E;QAC1E,gEAAgE;QAChEC,QAAQ;YAAC;YAAW;SAAc;QAClCC,SAAS;YAAC,CAAC,gBAAgB,EAAEhB,SAAS;SAAC;QACvCiB,UAAU;QACV/B,SAAS;YACPkB;YACAc,UAAU;QACZ;QACAC,WAAW;YAAC5B;SAAiB;IAC/B;IAEA,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAID,oBAAoB,SAAS;QAC/BjB,kCAAkCe,SAAS,SAASE;IACtD;AACF,EAAE"}
package/src/utils/fs.d.ts CHANGED
@@ -3,14 +3,25 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  import type { Tree } from '@nx/devkit';
6
+ import { type DependencyDeclaration, type MustDeclare } from './declared-dependencies';
7
+ /** Dependencies a caller must declare to use `FsCommands`. */
8
+ export declare const FS_DEPENDENCIES: readonly [{
9
+ readonly name: "ncp";
10
+ }, {
11
+ readonly name: "rimraf";
12
+ }, {
13
+ readonly name: "make-dir-cli";
14
+ }];
6
15
  /**
7
- * Utility class for creating platform agnostic commands for filesystem operations.
8
- * Adds the required dependencies to the root package json
16
+ * Platform agnostic commands for filesystem operations, adding the CLIs they
17
+ * need to the root package.json.
9
18
  */
10
- export declare class FsCommands {
19
+ export declare class FsCommands<D extends DependencyDeclaration> {
11
20
  private tree;
12
- constructor(tree: Tree);
21
+ private declaration;
22
+ constructor(tree: Tree, declaration: D & MustDeclare<typeof FS_DEPENDENCIES, D>);
13
23
  cp(src: string, dst: string): string;
14
24
  rm(dir: string): string;
15
25
  mkdir(dir: string): string;
26
+ private add;
16
27
  }
package/src/utils/fs.js CHANGED
@@ -1,34 +1,47 @@
1
1
  /**
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
- */ import { addDependenciesToPackageJson } from "./dependencies.js";
4
+ */ import { forDependencies } from "./declared-dependencies.js";
5
+ import { addDependenciesToPackageJson } from "./dependencies.js";
5
6
  import { withVersions } from "./versions.js";
7
+ /** Dependencies a caller must declare to use `FsCommands`. */ export const FS_DEPENDENCIES = [
8
+ {
9
+ name: 'ncp'
10
+ },
11
+ {
12
+ name: 'rimraf'
13
+ },
14
+ {
15
+ name: 'make-dir-cli'
16
+ }
17
+ ];
6
18
  /**
7
- * Utility class for creating platform agnostic commands for filesystem operations.
8
- * Adds the required dependencies to the root package json
19
+ * Platform agnostic commands for filesystem operations, adding the CLIs they
20
+ * need to the root package.json.
9
21
  */ export class FsCommands {
10
22
  tree;
11
- constructor(tree){
23
+ declaration;
24
+ constructor(tree, declaration){
12
25
  this.tree = tree;
26
+ this.declaration = declaration;
13
27
  }
14
28
  cp(src, dst) {
15
- addDependenciesToPackageJson(this.tree, {}, withVersions([
16
- 'ncp'
17
- ]));
29
+ this.add('ncp');
18
30
  return `ncp ${src} ${dst}`;
19
31
  }
20
32
  rm(dir) {
21
- addDependenciesToPackageJson(this.tree, {}, withVersions([
22
- 'rimraf'
23
- ]));
33
+ this.add('rimraf');
24
34
  return `rimraf ${dir}`;
25
35
  }
26
36
  mkdir(dir) {
27
- addDependenciesToPackageJson(this.tree, {}, withVersions([
28
- 'make-dir-cli'
29
- ]));
37
+ this.add('make-dir-cli');
30
38
  return `make-dir ${dir}`;
31
39
  }
40
+ add(dep) {
41
+ addDependenciesToPackageJson(this.tree, {}, withVersions(forDependencies(this.declaration), [
42
+ dep
43
+ ]));
44
+ }
32
45
  }
33
46
 
34
47
  //# sourceMappingURL=fs.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/fs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Tree } from '@nx/devkit';\nimport { addDependenciesToPackageJson } from './dependencies';\nimport { withVersions } from './versions';\n\n/**\n * Utility class for creating platform agnostic commands for filesystem operations.\n * Adds the required dependencies to the root package json\n */\nexport class FsCommands {\n private tree: Tree;\n\n constructor(tree: Tree) {\n this.tree = tree;\n }\n\n public cp(src: string, dst: string) {\n addDependenciesToPackageJson(this.tree, {}, withVersions(['ncp']));\n return `ncp ${src} ${dst}`;\n }\n\n public rm(dir: string) {\n addDependenciesToPackageJson(this.tree, {}, withVersions(['rimraf']));\n return `rimraf ${dir}`;\n }\n\n public mkdir(dir: string) {\n addDependenciesToPackageJson(this.tree, {}, withVersions(['make-dir-cli']));\n return `make-dir ${dir}`;\n }\n}\n"],"names":["addDependenciesToPackageJson","withVersions","FsCommands","tree","cp","src","dst","rm","dir","mkdir"],"mappings":"AAAA;;;CAGC,GAED,SAASA,4BAA4B,QAAQ,oBAAiB;AAC9D,SAASC,YAAY,QAAQ,gBAAa;AAE1C;;;CAGC,GACD,OAAO,MAAMC;IACHC,KAAW;IAEnB,YAAYA,IAAU,CAAE;QACtB,IAAI,CAACA,IAAI,GAAGA;IACd;IAEOC,GAAGC,GAAW,EAAEC,GAAW,EAAE;QAClCN,6BAA6B,IAAI,CAACG,IAAI,EAAE,CAAC,GAAGF,aAAa;YAAC;SAAM;QAChE,OAAO,CAAC,IAAI,EAAEI,IAAI,CAAC,EAAEC,KAAK;IAC5B;IAEOC,GAAGC,GAAW,EAAE;QACrBR,6BAA6B,IAAI,CAACG,IAAI,EAAE,CAAC,GAAGF,aAAa;YAAC;SAAS;QACnE,OAAO,CAAC,OAAO,EAAEO,KAAK;IACxB;IAEOC,MAAMD,GAAW,EAAE;QACxBR,6BAA6B,IAAI,CAACG,IAAI,EAAE,CAAC,GAAGF,aAAa;YAAC;SAAe;QACzE,OAAO,CAAC,SAAS,EAAEO,KAAK;IAC1B;AACF"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/fs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { Tree } from '@nx/devkit';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from './declared-dependencies';\nimport { addDependenciesToPackageJson } from './dependencies';\nimport { type ITsDepVersion, withVersions } from './versions';\n\n/** Dependencies a caller must declare to use `FsCommands`. */\nexport const FS_DEPENDENCIES = [\n { name: 'ncp' },\n { name: 'rimraf' },\n { name: 'make-dir-cli' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\n/**\n * Platform agnostic commands for filesystem operations, adding the CLIs they\n * need to the root package.json.\n */\nexport class FsCommands<D extends DependencyDeclaration> {\n private tree: Tree;\n private declaration: D;\n\n constructor(\n tree: Tree,\n declaration: D & MustDeclare<typeof FS_DEPENDENCIES, D>,\n ) {\n this.tree = tree;\n this.declaration = declaration;\n }\n\n public cp(src: string, dst: string) {\n this.add('ncp');\n return `ncp ${src} ${dst}`;\n }\n\n public rm(dir: string) {\n this.add('rimraf');\n return `rimraf ${dir}`;\n }\n\n public mkdir(dir: string) {\n this.add('make-dir-cli');\n return `make-dir ${dir}`;\n }\n\n private add(dep: (typeof FS_DEPENDENCIES)[number]['name']) {\n addDependenciesToPackageJson(\n this.tree,\n {},\n withVersions(forDependencies<typeof FS_DEPENDENCIES>(this.declaration), [\n dep,\n ]),\n );\n }\n}\n"],"names":["forDependencies","addDependenciesToPackageJson","withVersions","FS_DEPENDENCIES","name","FsCommands","tree","declaration","cp","src","dst","add","rm","dir","mkdir","dep"],"mappings":"AAAA;;;CAGC,GAED,SAEEA,eAAe,QAEV,6BAA0B;AACjC,SAASC,4BAA4B,QAAQ,oBAAiB;AAC9D,SAA6BC,YAAY,QAAQ,gBAAa;AAE9D,4DAA4D,GAC5D,OAAO,MAAMC,kBAAkB;IAC7B;QAAEC,MAAM;IAAM;IACd;QAAEA,MAAM;IAAS;IACjB;QAAEA,MAAM;IAAe;CACxB,CAAuD;AAExD;;;CAGC,GACD,OAAO,MAAMC;IACHC,KAAW;IACXC,YAAe;IAEvB,YACED,IAAU,EACVC,WAAuD,CACvD;QACA,IAAI,CAACD,IAAI,GAAGA;QACZ,IAAI,CAACC,WAAW,GAAGA;IACrB;IAEOC,GAAGC,GAAW,EAAEC,GAAW,EAAE;QAClC,IAAI,CAACC,GAAG,CAAC;QACT,OAAO,CAAC,IAAI,EAAEF,IAAI,CAAC,EAAEC,KAAK;IAC5B;IAEOE,GAAGC,GAAW,EAAE;QACrB,IAAI,CAACF,GAAG,CAAC;QACT,OAAO,CAAC,OAAO,EAAEE,KAAK;IACxB;IAEOC,MAAMD,GAAW,EAAE;QACxB,IAAI,CAACF,GAAG,CAAC;QACT,OAAO,CAAC,SAAS,EAAEE,KAAK;IAC1B;IAEQF,IAAII,GAA6C,EAAE;QACzDd,6BACE,IAAI,CAACK,IAAI,EACT,CAAC,GACDJ,aAAaF,gBAAwC,IAAI,CAACO,WAAW,GAAG;YACtEQ;SACD;IAEL;AACF"}
@@ -4,7 +4,20 @@
4
4
  */
5
5
  import { OverwriteStrategy, type Tree } from '@nx/devkit';
6
6
  import { type Containers } from './containers';
7
+ import { type DependencyDeclaration, type MustDeclare } from './declared-dependencies';
7
8
  import type { Iac } from './iac';
9
+ /** Dependencies a caller must declare to apply the workspace init. */
10
+ export declare const INIT_DEPENDENCIES: readonly [{
11
+ readonly name: "nx";
12
+ }, {
13
+ readonly name: "@nx/js";
14
+ }, {
15
+ readonly name: "@nx/workspace";
16
+ }, {
17
+ readonly name: "typescript";
18
+ }, {
19
+ readonly name: "@biomejs/biome";
20
+ }];
8
21
  export declare const PNPM_BUILT_DEPENDENCIES: string[];
9
22
  /**
10
23
  * Options controlling how the workspace is initialised. These mirror the
@@ -56,4 +69,4 @@ export interface ApplyWorkspaceInitOptions {
56
69
  * existing projects — those are decisions for the user (see the "add to an
57
70
  * existing workspace" guide).
58
71
  */
59
- export declare const applyWorkspaceInit: (tree: Tree, { iac, containers, mcp, readmeOverwriteStrategy, overwriteScripts, catalogs, }: ApplyWorkspaceInitOptions) => Promise<void>;
72
+ export declare const applyWorkspaceInit: <const D extends DependencyDeclaration>(tree: Tree, { iac, containers, mcp, readmeOverwriteStrategy, overwriteScripts, catalogs, }: ApplyWorkspaceInitOptions, declaration: D & MustDeclare<typeof INIT_DEPENDENCIES, D>) => Promise<void>;
package/src/utils/init.js CHANGED
@@ -4,7 +4,6 @@
4
4
  */ import { generateFiles, joinPathFragments, OverwriteStrategy, readNxJson, updateJson, updateNxJson } from "@nx/devkit";
5
5
  import { initGenerator } from "@nx/js";
6
6
  import yaml from "js-yaml";
7
- import { readModulePackageJson } from "nx/src/utils/package-json";
8
7
  import GeneratorsJson from "../../generators.json" with {
9
8
  type: 'json'
10
9
  };
@@ -12,6 +11,7 @@ import { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from "../ts/sync/genera
12
11
  import { BASE_TSCONFIG_COMPILER_OPTIONS } from "./base-tsconfig.js";
13
12
  import { ensureAwsNxPluginConfig, updateAwsNxPluginConfig } from "./config/utils.js";
14
13
  import { inferContainers } from "./containers.js";
14
+ import { forDependencies } from "./declared-dependencies.js";
15
15
  import { addDependenciesToPackageJson, detectWorkspacePackageManager } from "./dependencies.js";
16
16
  import { getDefaultBiomeConfig } from "./format.js";
17
17
  import { configureMcpServers } from "./mcp.js";
@@ -24,6 +24,23 @@ const WORKSPACES = [
24
24
  'packages/*'
25
25
  ];
26
26
  const NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';
27
+ /** Dependencies a caller must declare to apply the workspace init. */ export const INIT_DEPENDENCIES = [
28
+ {
29
+ name: 'nx'
30
+ },
31
+ {
32
+ name: '@nx/js'
33
+ },
34
+ {
35
+ name: '@nx/workspace'
36
+ },
37
+ {
38
+ name: 'typescript'
39
+ },
40
+ {
41
+ name: '@biomejs/biome'
42
+ }
43
+ ];
27
44
  // Built dependencies whose install scripts the generated workspace trusts.
28
45
  // `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);
29
46
  // pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will
@@ -157,7 +174,7 @@ export const PNPM_BUILT_DEPENDENCIES = [
157
174
  * compiler options, migrate a workspace's package manager, or restructure
158
175
  * existing projects — those are decisions for the user (see the "add to an
159
176
  * existing workspace" guide).
160
- */ export const applyWorkspaceInit = async (tree, { iac, containers, mcp, readmeOverwriteStrategy = OverwriteStrategy.KeepExisting, overwriteScripts = false, catalogs = true })=>{
177
+ */ export const applyWorkspaceInit = async (tree, { iac, containers, mcp, readmeOverwriteStrategy = OverwriteStrategy.KeepExisting, overwriteScripts = false, catalogs = true }, declaration)=>{
161
178
  const resolvedContainers = !containers || containers === 'infer' ? inferContainers() : containers;
162
179
  // The catalogs flag is written explicitly (even when true) so the workspace
163
180
  // records its dependency-management choice.
@@ -238,12 +255,13 @@ export const PNPM_BUILT_DEPENDENCIES = [
238
255
  // `@nx/js` must be a root dependency for the `@nx/js:typescript-sync`
239
256
  // generator registered in nx.json to resolve (npm doesn't hoist the
240
257
  // plugin's own copy reliably).
241
- const nxVersion = readModulePackageJson('@nx/js').packageJson.version;
242
258
  addDependenciesToPackageJson(tree, {}, {
243
- nx: nxVersion,
244
- '@nx/js': nxVersion,
245
- '@nx/workspace': nxVersion,
246
- ...withVersions([
259
+ ...withVersions(forDependencies(declaration), [
260
+ 'nx',
261
+ '@nx/js',
262
+ '@nx/workspace'
263
+ ]),
264
+ ...withVersions(forDependencies(declaration), [
247
265
  'typescript',
248
266
  '@biomejs/biome'
249
267
  ]),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/init.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 readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport { readModulePackageJson } from 'nx/src/utils/package-json';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport { BASE_TSCONFIG_COMPILER_OPTIONS } from './base-tsconfig';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from './config/utils';\nimport { type Containers, inferContainers } from './containers';\nimport {\n addDependenciesToPackageJson,\n detectWorkspacePackageManager,\n} from './dependencies';\nimport { getDefaultBiomeConfig } from './format';\nimport type { Iac } from './iac';\nimport { configureMcpServers } from './mcp';\nimport { getNpmScope } from './npm-scope';\nimport {\n mergeTargetDefault,\n nxPluginMcpDependency,\n nxPluginSelfDependency,\n} from './nx';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport { workspaceGlobs } from './project-package-json';\nimport { withVersions } from './versions';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nexport const PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\n/**\n * Options controlling how the workspace is initialised. These mirror the\n * preset schema so a workspace created via the preset and one initialised via\n * the `init` generator end up in the same shape.\n */\nexport interface ApplyWorkspaceInitOptions {\n /** The IaC provider to record in the plugin config. */\n readonly iac: Iac;\n /**\n * The container engine to record. `undefined`/`'infer'` picks docker when\n * installed, else finch.\n */\n readonly containers?: Containers | 'infer';\n /** Whether to configure MCP servers for coding agents. Defaults to true. */\n readonly mcp?: boolean;\n /**\n * How to treat the generated workspace README. The preset owns the README of\n * a greenfield workspace (`Overwrite`); the `init` generator must not clobber\n * an existing workspace's README (`KeepExisting`, the default).\n */\n readonly readmeOverwriteStrategy?: OverwriteStrategy;\n /**\n * Whether to overwrite root package.json scripts that already exist. The\n * preset owns a greenfield workspace's scripts (`true`); the `init`\n * generator must not clobber an existing workspace's scripts (`false`,\n * the default) — it only adds the convenience scripts that are absent.\n */\n readonly overwriteScripts?: boolean;\n /**\n * Whether generators use the package manager's dependency catalog. On pnpm\n * this also sets `catalogMode: strict` so `pnpm add` records new deps in the\n * catalog. Defaults to true.\n */\n readonly catalogs?: boolean;\n}\n\n/**\n * Add or repair the pnpm `allowBuilds` / `onlyBuiltDependencies` allowlist for\n * the workspace's `packages` globs, without clobbering any packages the user\n * has already declared.\n *\n * A workspace not created by the preset commonly has either no\n * `pnpm-workspace.yaml`, one missing the `packages` globs, or one carrying the\n * broken `set this to true or false` placeholder pnpm writes when it skips a\n * build script. This makes the file self-consistent so the first generator's\n * install doesn't fail with `ERR_PNPM_IGNORED_BUILDS`.\n */\nconst setUpPnpmWorkspace = (tree: Tree, catalogs: boolean) => {\n const existing = tree.exists('pnpm-workspace.yaml')\n ? ((yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {})\n : {};\n\n // Preserve any packages globs the user already has, ensuring ours are present.\n const packages = Array.from(\n new Set([...((existing.packages as string[]) ?? []), ...WORKSPACES]),\n );\n\n const allowBuilds = {\n ...(typeof existing.allowBuilds === 'object' && existing.allowBuilds\n ? (existing.allowBuilds as Record<string, unknown>)\n : {}),\n // Overwrite any non-boolean (e.g. the \"set this to true or false\"\n // placeholder) with an explicit true for the deps we trust.\n ...Object.fromEntries(PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true])),\n };\n\n // `strict` makes `pnpm add` record new deps in the catalog; it only gates\n // that flow, so pre-declared direct ranges (e.g. tslib) still install.\n // Preserve an explicit user choice.\n const catalogMode = catalogs\n ? (existing.catalogMode ?? 'strict')\n : existing.catalogMode;\n\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n ...existing,\n packages,\n allowBuilds,\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n ...(catalogMode ? { catalogMode } : {}),\n },\n { quotingType: \"'\" },\n ),\n );\n};\n\n/**\n * Configure the workspace's package manager for a monorepo layout.\n *\n * pnpm workspaces are declared in `pnpm-workspace.yaml`; every other package\n * manager reads the `workspaces` field of the root `package.json`.\n */\nconst setUpWorkspaces = (tree: Tree, catalogs: boolean) => {\n if (detectWorkspacePackageManager(tree) === 'pnpm') {\n setUpPnpmWorkspace(tree, catalogs);\n } else {\n updateJson(tree, 'package.json', (json) => {\n // The `workspaces` field may be the object form ({ \"packages\": [...] })\n // accepted by yarn and bun — extend the globs while preserving the form.\n const globs = Array.from(\n new Set([...workspaceGlobs(json.workspaces), ...WORKSPACES]),\n );\n return {\n ...json,\n workspaces:\n json.workspaces !== undefined && !Array.isArray(json.workspaces)\n ? { ...json.workspaces, packages: globs }\n : globs,\n };\n });\n }\n};\n\n/**\n * Ensure the workspace has a `tsconfig.base.json`.\n *\n * `@nx/js` `initGenerator` (with `addTsPlugin`) normally creates this, but it\n * short-circuits when the workspace already has a root `tsconfig.json` — in\n * which case no base file is written and the next project generator fails with\n * `Cannot find tsconfig.base.json`. So we create a compatible one when it's\n * absent. An existing base is left untouched: the user may have tuned it, and\n * rewriting shared compiler options can break other projects (see the\n * \"add to an existing workspace\" guide).\n */\nconst ensureBaseTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.base.json')) {\n return;\n }\n tree.write(\n 'tsconfig.base.json',\n JSON.stringify(\n {\n compilerOptions: {\n ...BASE_TSCONFIG_COMPILER_OPTIONS,\n customConditions: [getNpmScope(tree)],\n },\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Ensure the workspace has a root `tsconfig.json`.\n *\n * Nx's `@nx/js:typescript-sync` generator hard-fails with\n * `Missing root \"tsconfig.json\"` when it's absent. The plugin's TypeScript\n * projects reference each other via this file, so we guarantee a minimal one\n * exists (sync populates its `references`).\n */\nconst ensureRootTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.json')) {\n return;\n }\n tree.write(\n 'tsconfig.json',\n JSON.stringify(\n {\n extends: './tsconfig.base.json',\n files: [],\n references: [],\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Transform an Nx workspace into one ready to run `@aws/nx-plugin` generators.\n *\n * This is the deterministic core shared by the workspace preset and the `init`\n * generator. It is safe to re-run: every step is idempotent (config merges,\n * keyed nx.json / package.json entries, create-if-missing files), so running\n * it against an already-initialised workspace is a no-op.\n *\n * It preserves the workspace's module format: the root package.json `type`\n * field is owned by the preset (written from its `--module` option) and left\n * untouched here. It does NOT rewrite an existing `tsconfig.base.json`'s\n * compiler options, migrate a workspace's package manager, or restructure\n * existing projects — those are decisions for the user (see the \"add to an\n * existing workspace\" guide).\n */\nexport const applyWorkspaceInit = async (\n tree: Tree,\n {\n iac,\n containers,\n mcp,\n readmeOverwriteStrategy = OverwriteStrategy.KeepExisting,\n overwriteScripts = false,\n catalogs = true,\n }: ApplyWorkspaceInitOptions,\n) => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n\n // The catalogs flag is written explicitly (even when true) so the workspace\n // records its dependency-management choice.\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n packageManager: { catalogs },\n });\n\n // Set up the TypeScript plugin, base tsconfig, formatter etc. `@nx/js`\n // creates `tsconfig.base.json` when absent, but skips it when a root\n // `tsconfig.json` already exists — so we ensure both explicitly below.\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n ensureBaseTsConfig(tree);\n ensureRootTsConfig(tree);\n\n setUpWorkspaces(tree, catalogs);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n // Preserve an explicit analytics choice in an existing workspace.\n analytics: (nxJson as { analytics?: boolean }).analytics ?? false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: mergeTargetDefault(nxJson.targetDefaults?.compile, (base) => ({\n ...base,\n syncGenerators: [\n ...(base.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n })),\n },\n });\n\n const CONVENIENCE_SCRIPTS = {\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n // Trivy container image scanning is not part of `build` (its result\n // depends on the ever-changing vulnerability database); run it explicitly,\n // e.g. in CI.\n trivy: 'nx run-many --target trivy --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n };\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n // The root `type` field is owned by the preset (written explicitly from\n // its `--module` option). `init` preserves an existing workspace's field\n // as-is: an ESM workspace already carries `type: \"module\"` (that is how\n // the format is inferred), and introducing a `type` into a CommonJS\n // workspace that lacks one changes behaviour for frameworks that parse it\n // (e.g. Next.js starts treating the app's ESM source as CJS).\n scripts: overwriteScripts\n ? { ...packageJson.scripts, ...CONVENIENCE_SCRIPTS }\n : { ...CONVENIENCE_SCRIPTS, ...packageJson.scripts },\n }));\n\n // Pin the workspace's `nx` to the version the plugin's @nx/* packages are\n // built against. A mismatched workspace nx (even a patch apart) hoists a\n // second nested nx under @nx/js, and the two instances deadlock `nx sync`.\n // `@nx/js` must be a root dependency for the `@nx/js:typescript-sync`\n // generator registered in nx.json to resolve (npm doesn't hoist the\n // plugin's own copy reliably).\n const nxVersion = readModulePackageJson('@nx/js').packageJson.version;\n addDependenciesToPackageJson(\n tree,\n {},\n {\n nx: nxVersion,\n '@nx/js': nxVersion,\n '@nx/workspace': nxVersion,\n ...withVersions(['typescript', '@biomejs/biome']),\n // Declare the plugin the generators are running from, plus the MCP server\n // package the vended config runs, so both are pinned in the workspace's\n // lockfile and upgrading them upgrades what the agents use.\n ...nxPluginSelfDependency(tree),\n ...nxPluginMcpDependency(tree),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write(\n 'biome.json',\n JSON.stringify(getDefaultBiomeConfig(tree), null, 2),\n );\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, '..', 'preset', 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: readmeOverwriteStrategy,\n },\n );\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","yaml","readModulePackageJson","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","BASE_TSCONFIG_COMPILER_OPTIONS","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","addDependenciesToPackageJson","detectWorkspacePackageManager","getDefaultBiomeConfig","configureMcpServers","getNpmScope","mergeTargetDefault","nxPluginMcpDependency","nxPluginSelfDependency","getPackageManagerDisplayCommands","workspaceGlobs","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","PNPM_BUILT_DEPENDENCIES","setUpPnpmWorkspace","tree","catalogs","existing","exists","load","read","packages","Array","from","Set","allowBuilds","Object","fromEntries","map","dep","catalogMode","write","dump","onlyBuiltDependencies","quotingType","setUpWorkspaces","json","globs","workspaces","undefined","isArray","ensureBaseTsConfig","JSON","stringify","compilerOptions","customConditions","ensureRootTsConfig","extends","files","references","applyWorkspaceInit","iac","containers","mcp","readmeOverwriteStrategy","KeepExisting","overwriteScripts","resolvedContainers","provider","engine","packageManager","formatter","addTsPlugin","nxJson","analytics","targetDefaults","compile","base","syncGenerators","filter","g","includes","CONVENIENCE_SCRIPTS","dev","build","lint","test","trivy","packageJson","scripts","nxVersion","version","nx","dirname","projectName","generators","entries","_","v","k","name","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/init.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 readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport { BASE_TSCONFIG_COMPILER_OPTIONS } from './base-tsconfig';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from './config/utils';\nimport { type Containers, inferContainers } from './containers';\nimport {\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from './declared-dependencies';\nimport {\n addDependenciesToPackageJson,\n detectWorkspacePackageManager,\n} from './dependencies';\nimport { getDefaultBiomeConfig } from './format';\nimport type { Iac } from './iac';\nimport { configureMcpServers } from './mcp';\nimport { getNpmScope } from './npm-scope';\nimport {\n mergeTargetDefault,\n nxPluginMcpDependency,\n nxPluginSelfDependency,\n} from './nx';\nimport { getPackageManagerDisplayCommands } from './pkg-manager';\nimport { workspaceGlobs } from './project-package-json';\nimport { type ITsDepVersion, withVersions } from './versions';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n/** Dependencies a caller must declare to apply the workspace init. */\nexport const INIT_DEPENDENCIES = [\n { name: 'nx' },\n { name: '@nx/js' },\n { name: '@nx/workspace' },\n { name: 'typescript' },\n { name: '@biomejs/biome' },\n] as const satisfies readonly { name: ITsDepVersion }[];\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nexport const PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\n/**\n * Options controlling how the workspace is initialised. These mirror the\n * preset schema so a workspace created via the preset and one initialised via\n * the `init` generator end up in the same shape.\n */\nexport interface ApplyWorkspaceInitOptions {\n /** The IaC provider to record in the plugin config. */\n readonly iac: Iac;\n /**\n * The container engine to record. `undefined`/`'infer'` picks docker when\n * installed, else finch.\n */\n readonly containers?: Containers | 'infer';\n /** Whether to configure MCP servers for coding agents. Defaults to true. */\n readonly mcp?: boolean;\n /**\n * How to treat the generated workspace README. The preset owns the README of\n * a greenfield workspace (`Overwrite`); the `init` generator must not clobber\n * an existing workspace's README (`KeepExisting`, the default).\n */\n readonly readmeOverwriteStrategy?: OverwriteStrategy;\n /**\n * Whether to overwrite root package.json scripts that already exist. The\n * preset owns a greenfield workspace's scripts (`true`); the `init`\n * generator must not clobber an existing workspace's scripts (`false`,\n * the default) — it only adds the convenience scripts that are absent.\n */\n readonly overwriteScripts?: boolean;\n /**\n * Whether generators use the package manager's dependency catalog. On pnpm\n * this also sets `catalogMode: strict` so `pnpm add` records new deps in the\n * catalog. Defaults to true.\n */\n readonly catalogs?: boolean;\n}\n\n/**\n * Add or repair the pnpm `allowBuilds` / `onlyBuiltDependencies` allowlist for\n * the workspace's `packages` globs, without clobbering any packages the user\n * has already declared.\n *\n * A workspace not created by the preset commonly has either no\n * `pnpm-workspace.yaml`, one missing the `packages` globs, or one carrying the\n * broken `set this to true or false` placeholder pnpm writes when it skips a\n * build script. This makes the file self-consistent so the first generator's\n * install doesn't fail with `ERR_PNPM_IGNORED_BUILDS`.\n */\nconst setUpPnpmWorkspace = (tree: Tree, catalogs: boolean) => {\n const existing = tree.exists('pnpm-workspace.yaml')\n ? ((yaml.load(tree.read('pnpm-workspace.yaml', 'utf-8') ?? '') as Record<\n string,\n unknown\n >) ?? {})\n : {};\n\n // Preserve any packages globs the user already has, ensuring ours are present.\n const packages = Array.from(\n new Set([...((existing.packages as string[]) ?? []), ...WORKSPACES]),\n );\n\n const allowBuilds = {\n ...(typeof existing.allowBuilds === 'object' && existing.allowBuilds\n ? (existing.allowBuilds as Record<string, unknown>)\n : {}),\n // Overwrite any non-boolean (e.g. the \"set this to true or false\"\n // placeholder) with an explicit true for the deps we trust.\n ...Object.fromEntries(PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true])),\n };\n\n // `strict` makes `pnpm add` record new deps in the catalog; it only gates\n // that flow, so pre-declared direct ranges (e.g. tslib) still install.\n // Preserve an explicit user choice.\n const catalogMode = catalogs\n ? (existing.catalogMode ?? 'strict')\n : existing.catalogMode;\n\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n ...existing,\n packages,\n allowBuilds,\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n ...(catalogMode ? { catalogMode } : {}),\n },\n { quotingType: \"'\" },\n ),\n );\n};\n\n/**\n * Configure the workspace's package manager for a monorepo layout.\n *\n * pnpm workspaces are declared in `pnpm-workspace.yaml`; every other package\n * manager reads the `workspaces` field of the root `package.json`.\n */\nconst setUpWorkspaces = (tree: Tree, catalogs: boolean) => {\n if (detectWorkspacePackageManager(tree) === 'pnpm') {\n setUpPnpmWorkspace(tree, catalogs);\n } else {\n updateJson(tree, 'package.json', (json) => {\n // The `workspaces` field may be the object form ({ \"packages\": [...] })\n // accepted by yarn and bun — extend the globs while preserving the form.\n const globs = Array.from(\n new Set([...workspaceGlobs(json.workspaces), ...WORKSPACES]),\n );\n return {\n ...json,\n workspaces:\n json.workspaces !== undefined && !Array.isArray(json.workspaces)\n ? { ...json.workspaces, packages: globs }\n : globs,\n };\n });\n }\n};\n\n/**\n * Ensure the workspace has a `tsconfig.base.json`.\n *\n * `@nx/js` `initGenerator` (with `addTsPlugin`) normally creates this, but it\n * short-circuits when the workspace already has a root `tsconfig.json` — in\n * which case no base file is written and the next project generator fails with\n * `Cannot find tsconfig.base.json`. So we create a compatible one when it's\n * absent. An existing base is left untouched: the user may have tuned it, and\n * rewriting shared compiler options can break other projects (see the\n * \"add to an existing workspace\" guide).\n */\nconst ensureBaseTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.base.json')) {\n return;\n }\n tree.write(\n 'tsconfig.base.json',\n JSON.stringify(\n {\n compilerOptions: {\n ...BASE_TSCONFIG_COMPILER_OPTIONS,\n customConditions: [getNpmScope(tree)],\n },\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Ensure the workspace has a root `tsconfig.json`.\n *\n * Nx's `@nx/js:typescript-sync` generator hard-fails with\n * `Missing root \"tsconfig.json\"` when it's absent. The plugin's TypeScript\n * projects reference each other via this file, so we guarantee a minimal one\n * exists (sync populates its `references`).\n */\nconst ensureRootTsConfig = (tree: Tree) => {\n if (tree.exists('tsconfig.json')) {\n return;\n }\n tree.write(\n 'tsconfig.json',\n JSON.stringify(\n {\n extends: './tsconfig.base.json',\n files: [],\n references: [],\n },\n null,\n 2,\n ),\n );\n};\n\n/**\n * Transform an Nx workspace into one ready to run `@aws/nx-plugin` generators.\n *\n * This is the deterministic core shared by the workspace preset and the `init`\n * generator. It is safe to re-run: every step is idempotent (config merges,\n * keyed nx.json / package.json entries, create-if-missing files), so running\n * it against an already-initialised workspace is a no-op.\n *\n * It preserves the workspace's module format: the root package.json `type`\n * field is owned by the preset (written from its `--module` option) and left\n * untouched here. It does NOT rewrite an existing `tsconfig.base.json`'s\n * compiler options, migrate a workspace's package manager, or restructure\n * existing projects — those are decisions for the user (see the \"add to an\n * existing workspace\" guide).\n */\nexport const applyWorkspaceInit = async <const D extends DependencyDeclaration>(\n tree: Tree,\n {\n iac,\n containers,\n mcp,\n readmeOverwriteStrategy = OverwriteStrategy.KeepExisting,\n overwriteScripts = false,\n catalogs = true,\n }: ApplyWorkspaceInitOptions,\n declaration: D & MustDeclare<typeof INIT_DEPENDENCIES, D>,\n) => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n\n // The catalogs flag is written explicitly (even when true) so the workspace\n // records its dependency-management choice.\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n packageManager: { catalogs },\n });\n\n // Set up the TypeScript plugin, base tsconfig, formatter etc. `@nx/js`\n // creates `tsconfig.base.json` when absent, but skips it when a root\n // `tsconfig.json` already exists — so we ensure both explicitly below.\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n ensureBaseTsConfig(tree);\n ensureRootTsConfig(tree);\n\n setUpWorkspaces(tree, catalogs);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n // Preserve an explicit analytics choice in an existing workspace.\n analytics: (nxJson as { analytics?: boolean }).analytics ?? false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: mergeTargetDefault(nxJson.targetDefaults?.compile, (base) => ({\n ...base,\n syncGenerators: [\n ...(base.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n })),\n },\n });\n\n const CONVENIENCE_SCRIPTS = {\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n // Trivy container image scanning is not part of `build` (its result\n // depends on the ever-changing vulnerability database); run it explicitly,\n // e.g. in CI.\n trivy: 'nx run-many --target trivy --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n };\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n // The root `type` field is owned by the preset (written explicitly from\n // its `--module` option). `init` preserves an existing workspace's field\n // as-is: an ESM workspace already carries `type: \"module\"` (that is how\n // the format is inferred), and introducing a `type` into a CommonJS\n // workspace that lacks one changes behaviour for frameworks that parse it\n // (e.g. Next.js starts treating the app's ESM source as CJS).\n scripts: overwriteScripts\n ? { ...packageJson.scripts, ...CONVENIENCE_SCRIPTS }\n : { ...CONVENIENCE_SCRIPTS, ...packageJson.scripts },\n }));\n\n // Pin the workspace's `nx` to the version the plugin's @nx/* packages are\n // built against. A mismatched workspace nx (even a patch apart) hoists a\n // second nested nx under @nx/js, and the two instances deadlock `nx sync`.\n // `@nx/js` must be a root dependency for the `@nx/js:typescript-sync`\n // generator registered in nx.json to resolve (npm doesn't hoist the\n // plugin's own copy reliably).\n addDependenciesToPackageJson(\n tree,\n {},\n {\n ...withVersions(forDependencies<typeof INIT_DEPENDENCIES>(declaration), [\n 'nx',\n '@nx/js',\n '@nx/workspace',\n ]),\n ...withVersions(forDependencies<typeof INIT_DEPENDENCIES>(declaration), [\n 'typescript',\n '@biomejs/biome',\n ]),\n // Declare the plugin the generators are running from, plus the MCP server\n // package the vended config runs, so both are pinned in the workspace's\n // lockfile and upgrading them upgrades what the agents use.\n ...nxPluginSelfDependency(tree),\n ...nxPluginMcpDependency(tree),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write(\n 'biome.json',\n JSON.stringify(getDefaultBiomeConfig(tree), null, 2),\n );\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, '..', 'preset', 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: readmeOverwriteStrategy,\n },\n );\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","yaml","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","BASE_TSCONFIG_COMPILER_OPTIONS","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","forDependencies","addDependenciesToPackageJson","detectWorkspacePackageManager","getDefaultBiomeConfig","configureMcpServers","getNpmScope","mergeTargetDefault","nxPluginMcpDependency","nxPluginSelfDependency","getPackageManagerDisplayCommands","workspaceGlobs","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","INIT_DEPENDENCIES","name","PNPM_BUILT_DEPENDENCIES","setUpPnpmWorkspace","tree","catalogs","existing","exists","load","read","packages","Array","from","Set","allowBuilds","Object","fromEntries","map","dep","catalogMode","write","dump","onlyBuiltDependencies","quotingType","setUpWorkspaces","json","globs","workspaces","undefined","isArray","ensureBaseTsConfig","JSON","stringify","compilerOptions","customConditions","ensureRootTsConfig","extends","files","references","applyWorkspaceInit","iac","containers","mcp","readmeOverwriteStrategy","KeepExisting","overwriteScripts","declaration","resolvedContainers","provider","engine","packageManager","formatter","addTsPlugin","nxJson","analytics","targetDefaults","compile","base","syncGenerators","filter","g","includes","CONVENIENCE_SCRIPTS","dev","build","lint","test","trivy","packageJson","scripts","dirname","projectName","generators","entries","_","v","k","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy"],"mappings":"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"}
@@ -21,10 +21,22 @@ import { compare } from 'semver';
21
21
  * versions of everything already released.
22
22
  *
23
23
  * A version already in source always wins, so backfilled entries are stable.
24
+ *
25
+ * An entry marked `everyMigration: true` is never backfilled or pinned, and is
26
+ * re-stamped with each pending version, so it runs on every upgrade.
24
27
  */
25
28
  export interface MigrationsJson {
26
29
  generators?: Record<string, {
27
30
  version?: string;
31
+ everyMigration?: boolean;
32
+ } & Record<string, unknown>>;
33
+ /**
34
+ * Declarative dependency bumps `nx migrate` applies to the root manifest.
35
+ * Keyed `<dir>-<name>` like the migrations so entries from different releases
36
+ * can't collide; nx itself gates on the entry's `version`.
37
+ */
38
+ packageJsonUpdates?: Record<string, {
39
+ version: string;
28
40
  } & Record<string, unknown>>;
29
41
  }
30
42
  /** Ascending semver comparator for `Array.prototype.sort`. */
@@ -49,7 +61,9 @@ export declare const isValidVersion: (version: string) => boolean;
49
61
  export declare const readShippedMigrationVersions: (migrations: MigrationsJson, versions: string[], readReleasedMigrations: (version: string) => MigrationsJson | undefined) => Record<string, string>;
50
62
  /**
51
63
  * Return a copy of the migrations collection with a `version` stamped onto
52
- * every generator entry, preserving any already present.
64
+ * every generator entry, preserving any already present, and any
65
+ * `packageJsonUpdates` entry still keyed `latest` re-keyed to the version it
66
+ * ships under.
53
67
  *
54
68
  * @param migrations parsed migrations.json to stamp
55
69
  * @param shippedVersions migration key -> version of the earliest release
@@ -37,7 +37,9 @@
37
37
  };
38
38
  /**
39
39
  * Return a copy of the migrations collection with a `version` stamped onto
40
- * every generator entry, preserving any already present.
40
+ * every generator entry, preserving any already present, and any
41
+ * `packageJsonUpdates` entry still keyed `latest` re-keyed to the version it
42
+ * ships under.
41
43
  *
42
44
  * @param migrations parsed migrations.json to stamp
43
45
  * @param shippedVersions migration key -> version of the earliest release
@@ -46,14 +48,40 @@
46
48
  * unshipped migrations so their version is one that really shipped
47
49
  */ export const stampMigrationVersions = (migrations, shippedVersions, pendingVersion)=>({
48
50
  ...migrations,
49
- generators: Object.fromEntries(Object.entries(migrations.generators ?? {}).map(([name, entry])=>[
51
+ generators: Object.fromEntries(// `nx migrate` sorts the run ascending by version and preserves the
52
+ // manifest's order among equal versions, so emitting the every-migration
53
+ // entries last is what makes them run after the release's own migrations.
54
+ Object.entries(migrations.generators ?? {}).sort(([, a], [, b])=>Number(a.everyMigration ?? false) - Number(b.everyMigration ?? false)).map(([name, entry])=>{
55
+ // Source-only marker, stripped from what nx reads.
56
+ const { everyMigration, version: sourceVersion, ...published } = entry;
57
+ // Overrides any source version so it stays ahead of what is installed.
58
+ const version = everyMigration ? pendingVersion : sourceVersion ?? shippedVersions[name] ?? pendingVersion;
59
+ return [
50
60
  name,
51
61
  {
52
- version: shippedVersions[name] ?? pendingVersion,
53
- ...entry
62
+ version,
63
+ ...published
54
64
  }
55
- ]))
65
+ ];
66
+ })),
67
+ ...migrations.packageJsonUpdates && {
68
+ packageJsonUpdates: stampPackageJsonUpdates(migrations.packageJsonUpdates, pendingVersion)
69
+ }
56
70
  });
71
+ /**
72
+ * Version any unreleased `packageJsonUpdates` entry and re-key it out of
73
+ * `latest`, so the nx bump ships under the same version as its migrations.
74
+ */ const stampPackageJsonUpdates = (packageJsonUpdates, pendingVersion)=>Object.fromEntries(Object.entries(packageJsonUpdates).map(([key, entry])=>entry.version === LATEST_MIGRATIONS_DIR ? [
75
+ reKeyToVersion(key, pendingVersion),
76
+ {
77
+ ...entry,
78
+ version: pendingVersion
79
+ }
80
+ ] : [
81
+ key,
82
+ entry
83
+ ]));
84
+ /** Swap a `latest-<name>` key for the release that ships it. */ const reKeyToVersion = (key, version)=>key.startsWith(LATEST_KEY_PREFIX) ? migrationKey(versionMigrationsDir(version), key.slice(LATEST_KEY_PREFIX.length)) : key;
57
85
  /** Directory a newly scaffolded migration lands in, before a release claims it. */ export const LATEST_MIGRATIONS_DIR = 'latest';
58
86
  /** Directory holding the migrations shipped by a given release. */ export const versionMigrationsDir = (version)=>`v${version}`;
59
87
  /**
@@ -80,7 +108,8 @@ const LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;
80
108
  const moves = [];
81
109
  for (const [key, entry] of Object.entries(migrations.generators ?? {})){
82
110
  const version = shippedVersions[key];
83
- if (entry.version || !version) {
111
+ // Pinning an every-migration entry would stop it running on later upgrades.
112
+ if (entry.version || !version || entry.everyMigration) {
84
113
  generators[key] = entry;
85
114
  continue;
86
115
  }
@@ -118,11 +147,28 @@ const LATEST_KEY_PREFIX = `${LATEST_MIGRATIONS_DIR}-`;
118
147
  return {
119
148
  migrations: {
120
149
  ...migrations,
121
- generators
150
+ generators,
151
+ ...migrations.packageJsonUpdates && {
152
+ packageJsonUpdates: backfillPackageJsonUpdates(migrations.packageJsonUpdates, // Re-keyed with the earliest release it shipped alongside.
153
+ backfilled.map((key)=>shippedVersions[key]).sort(compareVersions)[0])
154
+ }
122
155
  },
123
156
  backfilled,
124
157
  moves
125
158
  };
126
159
  };
160
+ /**
161
+ * Record the release that shipped an unreleased `packageJsonUpdates` entry,
162
+ * re-keying it out of `latest`, and leave it alone until one has.
163
+ */ const backfillPackageJsonUpdates = (packageJsonUpdates, shippedVersion)=>Object.fromEntries(Object.entries(packageJsonUpdates).map(([key, entry])=>entry.version === LATEST_MIGRATIONS_DIR && shippedVersion ? [
164
+ reKeyToVersion(key, shippedVersion),
165
+ {
166
+ ...entry,
167
+ version: shippedVersion
168
+ }
169
+ ] : [
170
+ key,
171
+ entry
172
+ ]));
127
173
 
128
174
  //# sourceMappingURL=migration-versions.js.map
@@ -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.\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 `<dir>-<name>` like the migrations so entries from different releases\n * can't collide; 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 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, and any\n * `packageJsonUpdates` entry still keyed `latest` re-keyed to the version it\n * ships under.\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 unreleased `packageJsonUpdates` entry and re-key it out of\n * `latest`, so the nx bump ships under the same version as its migrations.\n */\nconst stampPackageJsonUpdates = (\n packageJsonUpdates: NonNullable<MigrationsJson['packageJsonUpdates']>,\n pendingVersion: string,\n): NonNullable<MigrationsJson['packageJsonUpdates']> =>\n Object.fromEntries(\n Object.entries(packageJsonUpdates).map(([key, entry]) =>\n entry.version === LATEST_MIGRATIONS_DIR\n ? [\n reKeyToVersion(key, pendingVersion),\n { ...entry, version: pendingVersion },\n ]\n : [key, entry],\n ),\n );\n\n/** Swap a `latest-<name>` key for the release that ships it. */\nconst reKeyToVersion = (key: string, version: string): string =>\n key.startsWith(LATEST_KEY_PREFIX)\n ? migrationKey(\n versionMigrationsDir(version),\n key.slice(LATEST_KEY_PREFIX.length),\n )\n : key;\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 // 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: backfillPackageJsonUpdates(\n migrations.packageJsonUpdates,\n // Re-keyed with the earliest release it shipped alongside.\n backfilled\n .map((key) => shippedVersions[key])\n .sort(compareVersions)[0],\n ),\n }),\n },\n backfilled,\n moves,\n };\n};\n\n/**\n * Record the release that shipped an unreleased `packageJsonUpdates` entry,\n * re-keying it out of `latest`, and leave it alone until one has.\n */\nconst backfillPackageJsonUpdates = (\n packageJsonUpdates: NonNullable<MigrationsJson['packageJsonUpdates']>,\n shippedVersion: string | undefined,\n): NonNullable<MigrationsJson['packageJsonUpdates']> =>\n Object.fromEntries(\n Object.entries(packageJsonUpdates).map(([key, entry]) =>\n entry.version === LATEST_MIGRATIONS_DIR && shippedVersion\n ? [\n reKeyToVersion(key, shippedVersion),\n { ...entry, version: shippedVersion },\n ]\n : [key, entry],\n ),\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","sort","a","b","Number","everyMigration","name","sourceVersion","published","packageJsonUpdates","stampPackageJsonUpdates","LATEST_MIGRATIONS_DIR","reKeyToVersion","startsWith","LATEST_KEY_PREFIX","migrationKey","versionMigrationsDir","slice","dir","backfillMigrationVersions","backfilled","moves","versionDir","latestSegment","versionSegment","repointed","moved","field","value","includes","replace","indexOf","push","from","to","backfillPackageJsonUpdates","shippedVersion"],"mappings":"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"}
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 ?? [];