@intentius/chant-lexicon-pulumi 0.0.0-stage → 0.124.54

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 (323) hide show
  1. package/README.md +60 -2
  2. package/dist/capability-plugin.d.ts +3 -0
  3. package/dist/capability-plugin.d.ts.map +1 -0
  4. package/dist/capability-plugin.js +14 -0
  5. package/dist/change-set.d.ts +159 -0
  6. package/dist/change-set.d.ts.map +1 -0
  7. package/dist/change-set.js +347 -0
  8. package/dist/codegen/docs-cli.d.ts +3 -0
  9. package/dist/codegen/docs-cli.d.ts.map +1 -0
  10. package/dist/codegen/docs-cli.js +3 -0
  11. package/dist/codegen/docs.d.ts +9 -0
  12. package/dist/codegen/docs.d.ts.map +1 -0
  13. package/dist/codegen/docs.js +52 -0
  14. package/dist/codegen/package.d.ts +8 -0
  15. package/dist/codegen/package.d.ts.map +1 -0
  16. package/dist/codegen/package.js +56 -0
  17. package/dist/composites/pulumi-watch-op.d.ts +60 -0
  18. package/dist/composites/pulumi-watch-op.d.ts.map +1 -0
  19. package/dist/composites/pulumi-watch-op.js +58 -0
  20. package/dist/config.d.ts +59 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +29 -0
  23. package/dist/describe-resources.d.ts +24 -0
  24. package/dist/describe-resources.d.ts.map +1 -0
  25. package/dist/describe-resources.js +97 -0
  26. package/dist/drift-read.d.ts +35 -0
  27. package/dist/drift-read.d.ts.map +1 -0
  28. package/dist/drift-read.js +41 -0
  29. package/dist/drift-record.d.ts +128 -0
  30. package/dist/drift-record.d.ts.map +1 -0
  31. package/dist/drift-record.js +270 -0
  32. package/dist/engine-graph.d.ts +75 -0
  33. package/dist/engine-graph.d.ts.map +1 -0
  34. package/dist/engine-graph.js +100 -0
  35. package/dist/index.d.ts +16 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +16 -0
  38. package/dist/init-templates.d.ts +23 -0
  39. package/dist/init-templates.d.ts.map +1 -0
  40. package/dist/init-templates.js +58 -0
  41. package/dist/integrity.json +29 -0
  42. package/dist/lint/audit-catalog.d.ts +21 -0
  43. package/dist/lint/audit-catalog.d.ts.map +1 -0
  44. package/dist/lint/audit-catalog.js +139 -0
  45. package/dist/lint/post-synth/index.d.ts +3 -0
  46. package/dist/lint/post-synth/index.d.ts.map +1 -0
  47. package/dist/lint/post-synth/index.js +32 -0
  48. package/dist/lint/post-synth/member-read-helpers.d.ts +45 -0
  49. package/dist/lint/post-synth/member-read-helpers.d.ts.map +1 -0
  50. package/dist/lint/post-synth/member-read-helpers.js +103 -0
  51. package/dist/lint/post-synth/pul001.d.ts +18 -0
  52. package/dist/lint/post-synth/pul001.d.ts.map +1 -0
  53. package/dist/lint/post-synth/pul001.js +20 -0
  54. package/dist/lint/post-synth/pul002.d.ts +18 -0
  55. package/dist/lint/post-synth/pul002.d.ts.map +1 -0
  56. package/dist/lint/post-synth/pul002.js +20 -0
  57. package/dist/lint/post-synth/pul003.d.ts +17 -0
  58. package/dist/lint/post-synth/pul003.d.ts.map +1 -0
  59. package/dist/lint/post-synth/pul003.js +21 -0
  60. package/dist/lint/post-synth/pul004.d.ts +13 -0
  61. package/dist/lint/post-synth/pul004.d.ts.map +1 -0
  62. package/dist/lint/post-synth/pul004.js +13 -0
  63. package/dist/lint/post-synth/pul005.d.ts +12 -0
  64. package/dist/lint/post-synth/pul005.d.ts.map +1 -0
  65. package/dist/lint/post-synth/pul005.js +13 -0
  66. package/dist/lint/post-synth/pul006.d.ts +12 -0
  67. package/dist/lint/post-synth/pul006.d.ts.map +1 -0
  68. package/dist/lint/post-synth/pul006.js +13 -0
  69. package/dist/lint/post-synth/pul007.d.ts +13 -0
  70. package/dist/lint/post-synth/pul007.d.ts.map +1 -0
  71. package/dist/lint/post-synth/pul007.js +20 -0
  72. package/dist/lint/post-synth/pul008.d.ts +12 -0
  73. package/dist/lint/post-synth/pul008.d.ts.map +1 -0
  74. package/dist/lint/post-synth/pul008.js +23 -0
  75. package/dist/lint/post-synth/pul009.d.ts +11 -0
  76. package/dist/lint/post-synth/pul009.d.ts.map +1 -0
  77. package/dist/lint/post-synth/pul009.js +19 -0
  78. package/dist/lint/post-synth/pul010.d.ts +13 -0
  79. package/dist/lint/post-synth/pul010.d.ts.map +1 -0
  80. package/dist/lint/post-synth/pul010.js +22 -0
  81. package/dist/lint/post-synth/pul011.d.ts +12 -0
  82. package/dist/lint/post-synth/pul011.d.ts.map +1 -0
  83. package/dist/lint/post-synth/pul011.js +21 -0
  84. package/dist/lint/post-synth/pul012.d.ts +13 -0
  85. package/dist/lint/post-synth/pul012.d.ts.map +1 -0
  86. package/dist/lint/post-synth/pul012.js +20 -0
  87. package/dist/lint/post-synth/pul013.d.ts +14 -0
  88. package/dist/lint/post-synth/pul013.d.ts.map +1 -0
  89. package/dist/lint/post-synth/pul013.js +20 -0
  90. package/dist/lint/post-synth/pul014.d.ts +12 -0
  91. package/dist/lint/post-synth/pul014.d.ts.map +1 -0
  92. package/dist/lint/post-synth/pul014.js +18 -0
  93. package/dist/lint/post-synth/pul015.d.ts +16 -0
  94. package/dist/lint/post-synth/pul015.d.ts.map +1 -0
  95. package/dist/lint/post-synth/pul015.js +19 -0
  96. package/dist/lint/rules/index.d.ts +5 -0
  97. package/dist/lint/rules/index.d.ts.map +1 -0
  98. package/dist/lint/rules/index.js +4 -0
  99. package/dist/lint/rules/member-dir-absolute.d.ts +22 -0
  100. package/dist/lint/rules/member-dir-absolute.d.ts.map +1 -0
  101. package/dist/lint/rules/member-dir-absolute.js +81 -0
  102. package/dist/lsp/completions.d.ts +5 -0
  103. package/dist/lsp/completions.d.ts.map +1 -0
  104. package/dist/lsp/completions.js +120 -0
  105. package/dist/lsp/documents.d.ts +32 -0
  106. package/dist/lsp/documents.d.ts.map +1 -0
  107. package/dist/lsp/documents.js +44 -0
  108. package/dist/lsp/hover.d.ts +11 -0
  109. package/dist/lsp/hover.d.ts.map +1 -0
  110. package/dist/lsp/hover.js +76 -0
  111. package/dist/lsp/keys.d.ts +35 -0
  112. package/dist/lsp/keys.d.ts.map +1 -0
  113. package/dist/lsp/keys.js +146 -0
  114. package/dist/lsp/object-path.d.ts +16 -0
  115. package/dist/lsp/object-path.d.ts.map +1 -0
  116. package/dist/lsp/object-path.js +76 -0
  117. package/dist/lsp/yaml-cursor.d.ts +29 -0
  118. package/dist/lsp/yaml-cursor.d.ts.map +1 -0
  119. package/dist/lsp/yaml-cursor.js +70 -0
  120. package/dist/manifest.json +6 -0
  121. package/dist/member-engine.d.ts +8 -0
  122. package/dist/member-engine.d.ts.map +1 -0
  123. package/dist/member-engine.js +29 -0
  124. package/dist/member-outputs.d.ts +43 -0
  125. package/dist/member-outputs.d.ts.map +1 -0
  126. package/dist/member-outputs.js +82 -0
  127. package/dist/meta.json +1 -0
  128. package/dist/okf/index.md +22 -0
  129. package/dist/okf/rules/PUL001.md +11 -0
  130. package/dist/okf/rules/PUL002.md +11 -0
  131. package/dist/okf/rules/PUL003.md +11 -0
  132. package/dist/okf/rules/PUL004.md +11 -0
  133. package/dist/okf/rules/PUL005.md +11 -0
  134. package/dist/okf/rules/PUL006.md +11 -0
  135. package/dist/okf/rules/PUL007.md +11 -0
  136. package/dist/okf/rules/PUL008.md +11 -0
  137. package/dist/okf/rules/PUL009.md +11 -0
  138. package/dist/okf/rules/PUL010.md +11 -0
  139. package/dist/okf/rules/PUL011.md +11 -0
  140. package/dist/okf/rules/PUL012.md +11 -0
  141. package/dist/okf/rules/PUL013.md +11 -0
  142. package/dist/okf/rules/PUL014.md +11 -0
  143. package/dist/okf/rules/PUL015.md +11 -0
  144. package/dist/okf/rules/PUL101.md +11 -0
  145. package/dist/op/activities/index.d.ts +19 -0
  146. package/dist/op/activities/index.d.ts.map +1 -0
  147. package/dist/op/activities/index.js +17 -0
  148. package/dist/op/activities/pulumi.d.ts +62 -0
  149. package/dist/op/activities/pulumi.d.ts.map +1 -0
  150. package/dist/op/activities/pulumi.js +80 -0
  151. package/dist/op/activity-contracts.d.ts +34 -0
  152. package/dist/op/activity-contracts.d.ts.map +1 -0
  153. package/dist/op/activity-contracts.js +40 -0
  154. package/dist/op/builders.d.ts +20 -0
  155. package/dist/op/builders.d.ts.map +1 -0
  156. package/dist/op/builders.js +19 -0
  157. package/dist/package-cli.d.ts +3 -0
  158. package/dist/package-cli.d.ts.map +1 -0
  159. package/dist/package-cli.js +12 -0
  160. package/dist/plugin.d.ts +3 -0
  161. package/dist/plugin.d.ts.map +1 -0
  162. package/dist/plugin.js +201 -0
  163. package/dist/rules/member-dir-absolute.ts +83 -0
  164. package/dist/rules/member-read-helpers.ts +122 -0
  165. package/dist/rules/pul001.ts +38 -0
  166. package/dist/rules/pul002.ts +38 -0
  167. package/dist/rules/pul003.ts +43 -0
  168. package/dist/rules/pul004.ts +32 -0
  169. package/dist/rules/pul005.ts +31 -0
  170. package/dist/rules/pul006.ts +31 -0
  171. package/dist/rules/pul007.ts +35 -0
  172. package/dist/rules/pul008.ts +35 -0
  173. package/dist/rules/pul009.ts +32 -0
  174. package/dist/rules/pul010.ts +42 -0
  175. package/dist/rules/pul011.ts +38 -0
  176. package/dist/rules/pul012.ts +35 -0
  177. package/dist/rules/pul013.ts +35 -0
  178. package/dist/rules/pul014.ts +32 -0
  179. package/dist/rules/pul015.ts +37 -0
  180. package/dist/run.d.ts +201 -0
  181. package/dist/run.d.ts.map +1 -0
  182. package/dist/run.js +437 -0
  183. package/dist/serializer.d.ts +8 -0
  184. package/dist/serializer.d.ts.map +1 -0
  185. package/dist/serializer.js +12 -0
  186. package/dist/skills/chant-pulumi-plunge.md +51 -0
  187. package/dist/skills/chant-pulumi-stack-export.md +54 -0
  188. package/dist/skills/chant-pulumi.md +83 -0
  189. package/dist/stack-outputs.d.ts +18 -0
  190. package/dist/stack-outputs.d.ts.map +1 -0
  191. package/dist/stack-outputs.js +55 -0
  192. package/dist/types/index.d.ts +3 -0
  193. package/dist/values.d.ts +58 -0
  194. package/dist/values.d.ts.map +1 -0
  195. package/dist/values.js +155 -0
  196. package/dist/workspace-member.d.ts +87 -0
  197. package/dist/workspace-member.d.ts.map +1 -0
  198. package/dist/workspace-member.js +197 -0
  199. package/package.json +74 -4
  200. package/schemas/pulumi.schema.json +34 -0
  201. package/src/capability-plugin.ts +25 -0
  202. package/src/change-set.test.ts +235 -0
  203. package/src/change-set.ts +405 -0
  204. package/src/codegen/docs-cli.ts +4 -0
  205. package/src/codegen/docs.ts +58 -0
  206. package/src/codegen/package.ts +63 -0
  207. package/src/composites/pulumi-watch-op.test.ts +42 -0
  208. package/src/composites/pulumi-watch-op.ts +85 -0
  209. package/src/config.ts +43 -0
  210. package/src/describe-resources.test.ts +112 -0
  211. package/src/describe-resources.ts +118 -0
  212. package/src/drift-read.test.ts +106 -0
  213. package/src/drift-read.ts +73 -0
  214. package/src/drift-record.test.ts +197 -0
  215. package/src/drift-record.ts +326 -0
  216. package/src/engine-graph.test.ts +141 -0
  217. package/src/engine-graph.ts +149 -0
  218. package/src/index.ts +60 -0
  219. package/src/init-templates.ts +83 -0
  220. package/src/lint/audit-catalog.test.ts +33 -0
  221. package/src/lint/audit-catalog.ts +174 -0
  222. package/src/lint/post-synth/index.ts +35 -0
  223. package/src/lint/post-synth/member-read-helpers.ts +122 -0
  224. package/src/lint/post-synth/post-synth.test.ts +199 -0
  225. package/src/lint/post-synth/pul001.ts +38 -0
  226. package/src/lint/post-synth/pul002.ts +38 -0
  227. package/src/lint/post-synth/pul003.ts +43 -0
  228. package/src/lint/post-synth/pul004.ts +32 -0
  229. package/src/lint/post-synth/pul005.ts +31 -0
  230. package/src/lint/post-synth/pul006.ts +31 -0
  231. package/src/lint/post-synth/pul007.ts +35 -0
  232. package/src/lint/post-synth/pul008.ts +35 -0
  233. package/src/lint/post-synth/pul009.ts +32 -0
  234. package/src/lint/post-synth/pul010.ts +42 -0
  235. package/src/lint/post-synth/pul011.ts +38 -0
  236. package/src/lint/post-synth/pul012.ts +35 -0
  237. package/src/lint/post-synth/pul013.ts +35 -0
  238. package/src/lint/post-synth/pul014.ts +32 -0
  239. package/src/lint/post-synth/pul015.ts +37 -0
  240. package/src/lint/rules/index.ts +7 -0
  241. package/src/lint/rules/member-dir-absolute.test.ts +37 -0
  242. package/src/lint/rules/member-dir-absolute.ts +83 -0
  243. package/src/lsp/completions.test.ts +69 -0
  244. package/src/lsp/completions.ts +119 -0
  245. package/src/lsp/documents.ts +48 -0
  246. package/src/lsp/hover.test.ts +56 -0
  247. package/src/lsp/hover.ts +83 -0
  248. package/src/lsp/keys.ts +169 -0
  249. package/src/lsp/object-path.ts +71 -0
  250. package/src/lsp/yaml-cursor.ts +85 -0
  251. package/src/member-engine.ts +30 -0
  252. package/src/member-outputs.test.ts +317 -0
  253. package/src/member-outputs.ts +138 -0
  254. package/src/op/activities/index.ts +18 -0
  255. package/src/op/activities/pulumi.ts +135 -0
  256. package/src/op/activity-contracts.ts +54 -0
  257. package/src/op/builders.ts +30 -0
  258. package/src/package-cli.ts +14 -0
  259. package/src/plugin.test.ts +96 -0
  260. package/src/plugin.ts +222 -0
  261. package/src/pulumi-urn-node.test.ts +94 -0
  262. package/src/run.test.ts +327 -0
  263. package/src/run.ts +542 -0
  264. package/src/serializer.test.ts +9 -0
  265. package/src/serializer.ts +15 -0
  266. package/src/skills/chant-pulumi-plunge.md +51 -0
  267. package/src/skills/chant-pulumi-stack-export.md +54 -0
  268. package/src/skills/chant-pulumi.md +83 -0
  269. package/src/stack-outputs.ts +66 -0
  270. package/src/testdata/plunge-drift/README.md +10 -0
  271. package/src/testdata/plunge-drift/assets-drifted.ndjson +3 -0
  272. package/src/testdata/plunge-drift/component-unsupported.ndjson +3 -0
  273. package/src/testdata/plunge-drift/role-in-sync.ndjson +3 -0
  274. package/src/testdata/plunge-drift/settled-empty.ndjson +2 -0
  275. package/src/testdata/plunge-graph/Pulumi.yaml +4 -0
  276. package/src/testdata/plunge-graph/README.md +12 -0
  277. package/src/testdata/plunge-graph/engine-graph.json +158 -0
  278. package/src/testdata/plunge-graph/stack-export.json +49 -0
  279. package/src/testdata/plunge-member/Pulumi.yaml +4 -0
  280. package/src/testdata/plunge-member/README.md +3 -0
  281. package/src/testdata/plunge-member/stack-export.json +480 -0
  282. package/src/testdata/plunge-outputs/Pulumi.yaml +9 -0
  283. package/src/testdata/plunge-outputs/README.md +7 -0
  284. package/src/testdata/plunge-outputs/stack-export.json +2003 -0
  285. package/src/testdata/plunge-outputs/stack-output.json +19 -0
  286. package/src/testdata/pulumi-member/Pulumi.yaml +2 -0
  287. package/src/testdata/pulumi-member/README.md +50 -0
  288. package/src/testdata/pulumi-member/recording/Pulumi.dev.yaml +19 -0
  289. package/src/testdata/pulumi-member/recording/Pulumi.yaml +7 -0
  290. package/src/testdata/pulumi-member/recording/index.js +47 -0
  291. package/src/testdata/pulumi-member/recording/package-lock.json +2707 -0
  292. package/src/testdata/pulumi-member/recording/package.json +9 -0
  293. package/src/testdata/pulumi-member/stack-export.json +746 -0
  294. package/src/testdata/pulumi-outputs/Pulumi.yaml +7 -0
  295. package/src/testdata/pulumi-outputs/README.md +9 -0
  296. package/src/testdata/pulumi-outputs/preview-replaced.json +2894 -0
  297. package/src/testdata/pulumi-outputs/preview-settled.json +2894 -0
  298. package/src/testdata/pulumi-outputs/stack-export.json +1919 -0
  299. package/src/testdata/pulumi-outputs/stack-output.json +19 -0
  300. package/src/testdata/pulumi-preview/Pulumi.yaml +7 -0
  301. package/src/testdata/pulumi-preview/README.md +9 -0
  302. package/src/testdata/pulumi-preview/preview-create.json +992 -0
  303. package/src/testdata/pulumi-preview/preview.json +2894 -0
  304. package/src/testdata/pulumi-preview/stack-export.json +1919 -0
  305. package/src/testdata/pulumi-refresh/Pulumi.yaml +7 -0
  306. package/src/testdata/pulumi-refresh/README.md +14 -0
  307. package/src/testdata/pulumi-refresh/all.json +3742 -0
  308. package/src/testdata/pulumi-refresh/bucket-edited.json +468 -0
  309. package/src/testdata/pulumi-refresh/policy-deleted.json +95 -0
  310. package/src/testdata/pulumi-refresh/queue-edited.json +250 -0
  311. package/src/testdata/pulumi-refresh/role-same.json +242 -0
  312. package/src/testdata/pulumi-refresh/secret-edited.json +247 -0
  313. package/src/testdata/pulumi-refresh/stack-export.json +1907 -0
  314. package/src/testdata/pulumi-unexported/Pulumi.yaml +2 -0
  315. package/src/testdata/pulumi-urn-node/Pulumi.yaml +7 -0
  316. package/src/testdata/pulumi-urn-node/README.md +9 -0
  317. package/src/testdata/pulumi-urn-node/preview.json +2894 -0
  318. package/src/testdata/pulumi-urn-node/stack-export.json +1919 -0
  319. package/src/values.ts +147 -0
  320. package/src/workspace-kinds.test.ts +47 -0
  321. package/src/workspace-member.test.ts +126 -0
  322. package/src/workspace-member.ts +286 -0
  323. package/workspace-kinds.json +29 -0
package/README.md CHANGED
@@ -1,3 +1,61 @@
1
- # Temporary Holding Version
1
+ # @intentius/chant-lexicon-pulumi
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Pulumi lexicon for [chant](https://intentius.io/chant/). It declares no resource types. It supplies the `pulumi` workspace member kind and reads a Pulumi program four ways:
4
+
5
+ | Read | Source | Module |
6
+ |---|---|---|
7
+ | the member's graph | the `pulumi stack export` checked in as `stack-export.json` | `src/workspace-member.ts` |
8
+ | its change-set part | `pulumi preview --json` | `src/change-set.ts` |
9
+ | its drift records | `pulumi refresh --preview-only --json --target <urn>`, one resource at a time | `src/drift-record.ts`, `src/drift-read.ts` |
10
+ | its stack outputs, for another member's parameters | `pulumi stack output --json --show-secrets=false` (applied) and `pulumi preview --json` (planned) | `src/stack-outputs.ts`, `src/member-outputs.ts` |
11
+ | engine facts, for a member on plunge | `plunge graph --json --stack <stack>` (`describeResources`), or the checked-in `engine-graph.json` (the graph read) | `src/describe-resources.ts`, `src/engine-graph.ts` |
12
+
13
+ The graph read never runs `pulumi`. The change set and drift run `preview` and `refresh --preview-only`, and the outputs read adds `stack output --json --show-secrets=false`. A member on plunge runs `plunge preview`, `plunge stack output --json --show-secrets=false` and `plunge drift --resource <urn> --stream`. For its engine facts it runs one of exactly four argv: `plunge graph --json`, `plunge graph --json --stack <stack>`, `plunge graph --json --versions` and `plunge graph --json --stack <stack> --versions` ([#4529](https://github.com/INTENTIUS/chant/issues/4529)). An outputs or secrets flag on `plunge graph` is refused. That is the whole list, as ruled on [#4476](https://github.com/INTENTIUS/chant/issues/4476) (2026-10-25), which widened the [#4450](https://github.com/INTENTIUS/chant/issues/4450) ruling's `preview` and `refresh --preview-only` to keep the outputs read and the plunge commands. Nothing else runs (`runAllowedPulumi` and `runAllowedPlunge` refuse any other argv), so chant never changes a stack. With `CHANT_PULUMI_APPLIED_OUTPUTS=export`, the outputs read runs nothing either.
14
+
15
+ ## Drift: `chant workspace drift`
16
+
17
+ `chant workspace drift --member <pulumi member> [--resource <urn>] [--stream]` runs `chant lifecycle drift` in the member's reader project, which calls this lexicon's `readDrift`. A stock member is read with one `pulumi refresh --preview-only --json --target <urn>` per resource in its checked-in `stack-export.json`. A member on plunge is read with `plunge drift --resource <urn> --stream` per resource. `--resource` reads one URN. The only read is `refresh`.
18
+
19
+ A member runs on plunge when its config says `engine: "plunge"`, or when `Pulumi.yaml` names a backend URL starting with `plunge` (`plunge+file://...`, `plunge://...`). Only `Pulumi.yaml` is read, never `PULUMI_BACKEND_URL` or login state.
20
+
21
+ ## Engine facts for a member on plunge
22
+
23
+ plunge keeps a record per resource, and `plunge graph --json` prints the stack's graph from those records in the engine graph document chant#4520 designed. It makes no provider call and prints no output value. chant reads it two ways ([#4529](https://github.com/INTENTIUS/chant/issues/4529)):
24
+
25
+ - `describeResources` runs `plunge graph --json --stack <stack>` once per member, with the stack the other reads use. Each node becomes a resource keyed like the member graph's node, with plunge's facts on `ResourceMetadata.facts`. Every resource has `ownership: "unknown"` and no marker, so no change set or teardown decides from it.
26
+ - The graph read takes a checked-in `engine-graph.json` beside `stack-export.json`. Its facts go on the nodes (`nodes[].facts`) and its `property` edges join the graph with `grain: "property"`. The export's `dependencies` and `parent` edges carry `grain: "instance"`.
27
+
28
+ plunge's markers say `source: "record"`: what its record says it wrote, not a read of the object. A stock member gets neither read, and chant runs nothing new for it. Record versions (`--versions`) cost one listing per record, so `describeResources` leaves them off.
29
+
30
+ ## Outputs into another member's parameters
31
+
32
+ A chant member reads a Pulumi member's outputs with core's `member-outputs` verb (chant#4455):
33
+
34
+ ```ts
35
+ import { memberOutputsComponent } from "@intentius/chant/components/verbs/member-outputs";
36
+
37
+ export const aws = memberOutputsComponent("aws");
38
+ export const records: Component = {
39
+ name: "records",
40
+ dependsOn: ["aws"],
41
+ deploy: [phase("Apply", [cfnDeploy({ template: "dist/dns.json", inputs: { awsEndpoint: stackOutput("aws", "awsEndpoint") } })])],
42
+ };
43
+ ```
44
+
45
+ The consumer lists `pulumi` among its lexicons, which brings `pulumiCapabilityPlugin` and its source, `pulumiOutputSource`, for members of kind `pulumi`.
46
+
47
+ - Applied values come from `pulumi stack output --json --show-secrets=false` in the member's directory. With `CHANT_PULUMI_APPLIED_OUTPUTS=export`, chant runs nothing and reads them from the checked-in `stack-export.json`.
48
+ - Planned values come from `pulumi preview --json --show-sames`. A real preview carries no outputs on the stack's `pulumi:pulumi:Stack` step (recorded, #4475), so a preview with nothing to apply gives the checked-in export's outputs and one with changes leaves every output unknown. An output a stack step does carry is read, and one holding Pulumi's unknown sentinel is unknown. The consumer is planned without an unknown output, gets a hole on `aws#outputs` naming it, and is held back on merge until the member applied, then planned again.
49
+ - The plan digest is the member part's `pulumi-preview` digest, so a preview that moves after review moves the consumer's digest.
50
+ - While the preview still has changes, `run` refuses and the consumer is blocked behind the member.
51
+ - Secret outputs are left out of both reads. chant never carries or prints their values.
52
+ - A member on plunge runs the same commands under `plunge`.
53
+ - Both commands run against the member's selected stack.
54
+
55
+ ```bash
56
+ npm install --save-dev @intentius/chant @intentius/chant-lexicon-pulumi
57
+ ```
58
+
59
+ ## License
60
+
61
+ See the main project LICENSE file.
@@ -0,0 +1,3 @@
1
+ import { type CapabilityPlugin } from "@intentius/chant/components/capability-plugin";
2
+ export declare const pulumiCapabilityPlugin: CapabilityPlugin;
3
+ //# sourceMappingURL=capability-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../src/capability-plugin.ts"],"names":[],"mappings":"AASA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAIzG,eAAO,MAAM,sBAAsB,EAAE,gBAWpC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { ownPackageVersion } from "@intentius/chant/components/capability-plugin";
2
+ import { pulumiStackOutputSource } from "./member-outputs.js";
3
+ export const pulumiCapabilityPlugin = {
4
+ name: "pulumi",
5
+ get version() {
6
+ return ownPackageVersion(import.meta.url);
7
+ },
8
+ capabilities() {
9
+ return [];
10
+ },
11
+ engineOutputSources() {
12
+ return [pulumiStackOutputSource];
13
+ },
14
+ };
@@ -0,0 +1,159 @@
1
+ /**
2
+ * The change-set adapter for a Pulumi member (#4453): `pulumi preview --json`
3
+ * into an `@intentius/chant/change-set` part, planner `pulumi`.
4
+ *
5
+ * ## Steps to entries
6
+ *
7
+ * The preview prints one step per resource the program registered, `same`
8
+ * included, and a replace as two or three steps on one URN
9
+ * (`create-replacement`, `replace`, `delete-replaced`). The adapter keeps one
10
+ * entry per URN, at the URN, so `node` comes from the one URN rule
11
+ * (`@intentius/chant/pulumi-urn`, #4456):
12
+ *
13
+ * | step op | action | disruption |
14
+ * |---|---|---|
15
+ * | `create` | create | |
16
+ * | `update` | update | in-place |
17
+ * | `delete` | delete | destroy |
18
+ * | `replace`, `create-replacement`, `delete-replaced` | replace | replace, or destroy when the delete comes first (`deleteBeforeReplace`) |
19
+ * | `same` | no-op | |
20
+ * | `read`, `read-replacement`, `refresh` | read | |
21
+ * | `import` | no-op, importing | |
22
+ * | `import-replacement` | replace, importing | replace |
23
+ * | `discard`, `remove-pending-replace` | forget | |
24
+ *
25
+ * An op the table does not hold is a hole on the member, never a guess.
26
+ *
27
+ * Attributes are top-level inputs, as the change set wants them. A create
28
+ * writes every input. An update or replace writes the keys `detailedDiff`
29
+ * and `diffReasons` name, and every input whose new value holds an unknown.
30
+ * `replaceReasons` and a `detailedDiff` kind ending in `-replace` mark
31
+ * `forcesReplacement`. An input that holds Pulumi's unknown sentinel is
32
+ * `unknown: true` with no `after`: a resource that reads an output of one
33
+ * being created shows its dependent input as unknown. A value that holds a
34
+ * secret is `sensitive: true` with neither side.
35
+ *
36
+ * ## What preview cannot list: `mayAppear`
37
+ *
38
+ * A program may register resources inside an `apply()`. At preview an
39
+ * `apply()` whose input is unknown does not run, so what it would register
40
+ * is never in the steps. Dropping it would make the set look smaller than
41
+ * the apply, so the adapter marks it `mayAppear` instead, on two signals:
42
+ *
43
+ * 1. A component (a step whose state is `custom: false`, not the root stack)
44
+ * whose subtree in the preview holds an unknown, in any input or output,
45
+ * or a create or replace, whose outputs are unknown until apply. Its code
46
+ * may be waiting on that value to register children. It gets one entry
47
+ * at `pulumiMayAppearAddress(<component urn>)`, action `create`, type
48
+ * `unknown`, no attributes, on the component's node.
49
+ * 2. With the last deployment's `pulumi stack export` (`prior`): a resource
50
+ * the export holds and the preview has no step for gets an `update`
51
+ * entry with disruption `unknown`, since a full preview lists every
52
+ * registered resource and only an `apply()` that did not run leaves one
53
+ * out. A `delete` step for a resource under a component signal 1 marks
54
+ * keeps its `delete` and gets `mayAppear`, since the `apply()` may
55
+ * register it again. A preview narrowed with `--target` (`targeted`)
56
+ * lists only its targets, and a failed one stops part way, so signal 2's
57
+ * first half is off for both.
58
+ *
59
+ * A resource registered inside an `apply()` directly under the stack, with
60
+ * no export that holds it, has no component to stand under and is not
61
+ * detected. When the export does hold it and its input is unknown, the
62
+ * preview prints a `delete` for it, which reads as a plain delete. Those are
63
+ * the two cases left out.
64
+ *
65
+ * ## The digest
66
+ *
67
+ * {@link pulumiPreviewDigest}: `computePlanDigest("pulumi-preview", …)` over
68
+ * each step's op, URN, provider, id, inputs before and after, `diffReasons`,
69
+ * `replaceReasons` and `detailedDiff`, sorted by URN and op. It leaves out
70
+ * `config`, `duration`, `diagnostics` and `changeSummary`, and the states'
71
+ * outputs, which at preview are the last deployment's or unknown.
72
+ *
73
+ * The fixtures under `testdata/pulumi-preview` are recorded from pulumi
74
+ * 3.272.0 against the plunge corpus's aws-ts program on floci (#4475). What
75
+ * the recording showed: `preview --json` lists no unchanged resource unless
76
+ * `--show-sames` is passed, which chant's argv does, since signal 2 reads a
77
+ * missing resource as one an `apply()` may register; a replace is one
78
+ * `replace` step at preview, not three; the stack's step carries no planned
79
+ * outputs; a secret is the blinded string `"[secret]"`; and a resource
80
+ * registered inside an `apply()` directly under the stack whose input is
81
+ * unknown (the corpus's `vpc-id` parameter, named after a VPC being
82
+ * replaced) is printed as a `delete`, which this adapter keeps as a plain
83
+ * delete since nothing tells it apart from a removed resource.
84
+ *
85
+ * ## The import graph
86
+ *
87
+ * Like the terraform lexicon's `change-set`, this imports chant's
88
+ * `change-set` types, `lifecycle/plan-digest`, `pulumi-urn` and `./values`,
89
+ * so it bundles without TypeScript, node's process modules or zod (#3421).
90
+ */
91
+ import type { ChangeSetPart } from "@intentius/chant/change-set";
92
+ import { type Json } from "./values.js";
93
+ /** One resource state on a preview step, `apitype.ResourceV3`, as far as the adapter reads it. */
94
+ export interface PulumiStepState {
95
+ urn?: string;
96
+ custom?: boolean;
97
+ delete?: boolean;
98
+ id?: string;
99
+ type?: string;
100
+ parent?: string;
101
+ inputs?: Json;
102
+ outputs?: Json;
103
+ }
104
+ /** One step of `pulumi preview --json` or `pulumi refresh --preview-only --json`. */
105
+ export interface PulumiStep {
106
+ op?: string;
107
+ urn?: string;
108
+ provider?: string;
109
+ oldState?: PulumiStepState;
110
+ newState?: PulumiStepState;
111
+ diffReasons?: string[];
112
+ replaceReasons?: string[];
113
+ detailedDiff?: Record<string, {
114
+ kind?: string;
115
+ inputDiff?: boolean;
116
+ }> | null;
117
+ }
118
+ /** The steps of a preview or refresh document, or undefined when it has none. */
119
+ export declare function pulumiSteps(doc: unknown): PulumiStep[] | undefined;
120
+ /** One resource of a `pulumi stack export`, as far as the adapter reads it. */
121
+ export interface PulumiExportedResource {
122
+ urn: string;
123
+ type: string;
124
+ custom?: boolean;
125
+ id?: string;
126
+ parent?: string;
127
+ }
128
+ /** The resources of a `pulumi stack export` document (`deployment.resources`). Not one: an empty list. */
129
+ export declare function pulumiExportResources(doc: unknown): PulumiExportedResource[];
130
+ /**
131
+ * The member's plan digest: `computePlanDigest("pulumi-preview", …)` over
132
+ * what each step proposes, sorted by URN and op, so two renderings of one
133
+ * preview agree. See the module comment for what it leaves out.
134
+ */
135
+ export declare function pulumiPreviewDigest(preview: unknown): string;
136
+ export interface PulumiPreviewPartInput {
137
+ /** The workspace member's name, which names its graph nodes (`<member>/<key>`). */
138
+ member: string;
139
+ /** `pulumi preview --json`, parsed. */
140
+ preview: unknown;
141
+ /** The stack the preview ran against, recorded as `scope`. */
142
+ stack?: string;
143
+ /**
144
+ * The last deployment, as `pulumi stack export` prints it: the member's
145
+ * checked-in `stack-export.json`. With it, a resource the preview leaves
146
+ * out is a `mayAppear` entry rather than silence.
147
+ */
148
+ prior?: unknown;
149
+ /** The preview was narrowed with `--target`, so it lists only its targets. */
150
+ targeted?: boolean;
151
+ /** The preview failed: the member is failed with this error, and keeps whatever steps it printed. */
152
+ error?: string;
153
+ }
154
+ /**
155
+ * A Pulumi member's part, from its `pulumi preview --json`. Throws when the
156
+ * document has no `steps` and no `error` says why.
157
+ */
158
+ export declare function pulumiPreviewPart(input: PulumiPreviewPartInput): ChangeSetPart;
159
+ //# sourceMappingURL=change-set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"change-set.d.ts","sourceRoot":"","sources":["../src/change-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AAEH,OAAO,KAAK,EAMV,aAAa,EACd,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAA6E,KAAK,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhH,kGAAkG;AAClG,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB;AAED,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CAC9E;AAED,iFAAiF;AACjF,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,EAAE,GAAG,SAAS,CAGlE;AAED,+EAA+E;AAC/E,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,EAAE,CAI5E;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAe5D;AAyFD,MAAM,WAAW,sBAAsB;IACrC,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qGAAqG;IACrG,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,aAAa,CAyH9E"}
@@ -0,0 +1,347 @@
1
+ /**
2
+ * The change-set adapter for a Pulumi member (#4453): `pulumi preview --json`
3
+ * into an `@intentius/chant/change-set` part, planner `pulumi`.
4
+ *
5
+ * ## Steps to entries
6
+ *
7
+ * The preview prints one step per resource the program registered, `same`
8
+ * included, and a replace as two or three steps on one URN
9
+ * (`create-replacement`, `replace`, `delete-replaced`). The adapter keeps one
10
+ * entry per URN, at the URN, so `node` comes from the one URN rule
11
+ * (`@intentius/chant/pulumi-urn`, #4456):
12
+ *
13
+ * | step op | action | disruption |
14
+ * |---|---|---|
15
+ * | `create` | create | |
16
+ * | `update` | update | in-place |
17
+ * | `delete` | delete | destroy |
18
+ * | `replace`, `create-replacement`, `delete-replaced` | replace | replace, or destroy when the delete comes first (`deleteBeforeReplace`) |
19
+ * | `same` | no-op | |
20
+ * | `read`, `read-replacement`, `refresh` | read | |
21
+ * | `import` | no-op, importing | |
22
+ * | `import-replacement` | replace, importing | replace |
23
+ * | `discard`, `remove-pending-replace` | forget | |
24
+ *
25
+ * An op the table does not hold is a hole on the member, never a guess.
26
+ *
27
+ * Attributes are top-level inputs, as the change set wants them. A create
28
+ * writes every input. An update or replace writes the keys `detailedDiff`
29
+ * and `diffReasons` name, and every input whose new value holds an unknown.
30
+ * `replaceReasons` and a `detailedDiff` kind ending in `-replace` mark
31
+ * `forcesReplacement`. An input that holds Pulumi's unknown sentinel is
32
+ * `unknown: true` with no `after`: a resource that reads an output of one
33
+ * being created shows its dependent input as unknown. A value that holds a
34
+ * secret is `sensitive: true` with neither side.
35
+ *
36
+ * ## What preview cannot list: `mayAppear`
37
+ *
38
+ * A program may register resources inside an `apply()`. At preview an
39
+ * `apply()` whose input is unknown does not run, so what it would register
40
+ * is never in the steps. Dropping it would make the set look smaller than
41
+ * the apply, so the adapter marks it `mayAppear` instead, on two signals:
42
+ *
43
+ * 1. A component (a step whose state is `custom: false`, not the root stack)
44
+ * whose subtree in the preview holds an unknown, in any input or output,
45
+ * or a create or replace, whose outputs are unknown until apply. Its code
46
+ * may be waiting on that value to register children. It gets one entry
47
+ * at `pulumiMayAppearAddress(<component urn>)`, action `create`, type
48
+ * `unknown`, no attributes, on the component's node.
49
+ * 2. With the last deployment's `pulumi stack export` (`prior`): a resource
50
+ * the export holds and the preview has no step for gets an `update`
51
+ * entry with disruption `unknown`, since a full preview lists every
52
+ * registered resource and only an `apply()` that did not run leaves one
53
+ * out. A `delete` step for a resource under a component signal 1 marks
54
+ * keeps its `delete` and gets `mayAppear`, since the `apply()` may
55
+ * register it again. A preview narrowed with `--target` (`targeted`)
56
+ * lists only its targets, and a failed one stops part way, so signal 2's
57
+ * first half is off for both.
58
+ *
59
+ * A resource registered inside an `apply()` directly under the stack, with
60
+ * no export that holds it, has no component to stand under and is not
61
+ * detected. When the export does hold it and its input is unknown, the
62
+ * preview prints a `delete` for it, which reads as a plain delete. Those are
63
+ * the two cases left out.
64
+ *
65
+ * ## The digest
66
+ *
67
+ * {@link pulumiPreviewDigest}: `computePlanDigest("pulumi-preview", …)` over
68
+ * each step's op, URN, provider, id, inputs before and after, `diffReasons`,
69
+ * `replaceReasons` and `detailedDiff`, sorted by URN and op. It leaves out
70
+ * `config`, `duration`, `diagnostics` and `changeSummary`, and the states'
71
+ * outputs, which at preview are the last deployment's or unknown.
72
+ *
73
+ * The fixtures under `testdata/pulumi-preview` are recorded from pulumi
74
+ * 3.272.0 against the plunge corpus's aws-ts program on floci (#4475). What
75
+ * the recording showed: `preview --json` lists no unchanged resource unless
76
+ * `--show-sames` is passed, which chant's argv does, since signal 2 reads a
77
+ * missing resource as one an `apply()` may register; a replace is one
78
+ * `replace` step at preview, not three; the stack's step carries no planned
79
+ * outputs; a secret is the blinded string `"[secret]"`; and a resource
80
+ * registered inside an `apply()` directly under the stack whose input is
81
+ * unknown (the corpus's `vpc-id` parameter, named after a VPC being
82
+ * replaced) is printed as a `delete`, which this adapter keeps as a plain
83
+ * delete since nothing tells it apart from a removed resource.
84
+ *
85
+ * ## The import graph
86
+ *
87
+ * Like the terraform lexicon's `change-set`, this imports chant's
88
+ * `change-set` types, `lifecycle/plan-digest`, `pulumi-urn` and `./values`,
89
+ * so it bundles without TypeScript, node's process modules or zod (#3421).
90
+ */
91
+ import { computePlanDigest } from "@intentius/chant/lifecycle/plan-digest";
92
+ import { isPulumiNodeless, parsePulumiUrn, pulumiMayAppearAddress, PULUMI_STACK_TYPE } from "@intentius/chant/pulumi-urn";
93
+ import { holdsSecret, holdsUnknown, isObject, isUnknown, propertyKeys, topLevelKey } from "./values.js";
94
+ /** The steps of a preview or refresh document, or undefined when it has none. */
95
+ export function pulumiSteps(doc) {
96
+ if (!isObject(doc) || !Array.isArray(doc.steps))
97
+ return undefined;
98
+ return doc.steps.filter((s) => isObject(s) && typeof s.urn === "string");
99
+ }
100
+ /** The resources of a `pulumi stack export` document (`deployment.resources`). Not one: an empty list. */
101
+ export function pulumiExportResources(doc) {
102
+ const deployment = isObject(doc) && isObject(doc.deployment) ? doc.deployment : undefined;
103
+ const list = deployment && Array.isArray(deployment.resources) ? deployment.resources : [];
104
+ return list.filter((r) => isObject(r) && typeof r.urn === "string" && typeof r.type === "string");
105
+ }
106
+ const byString = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
107
+ /**
108
+ * The member's plan digest: `computePlanDigest("pulumi-preview", …)` over
109
+ * what each step proposes, sorted by URN and op, so two renderings of one
110
+ * preview agree. See the module comment for what it leaves out.
111
+ */
112
+ export function pulumiPreviewDigest(preview) {
113
+ const steps = (pulumiSteps(preview) ?? [])
114
+ .map((s) => ({
115
+ op: s.op ?? null,
116
+ urn: s.urn ?? null,
117
+ provider: s.provider ?? null,
118
+ id: s.newState?.id ?? s.oldState?.id ?? null,
119
+ before: s.oldState?.inputs ?? null,
120
+ after: s.newState?.inputs ?? null,
121
+ diffReasons: [...(s.diffReasons ?? [])].sort(),
122
+ replaceReasons: [...(s.replaceReasons ?? [])].sort(),
123
+ detailedDiff: s.detailedDiff ?? null,
124
+ }))
125
+ .sort((a, b) => byString(`${a.urn}\u0000${a.op}`, `${b.urn}\u0000${b.op}`));
126
+ return computePlanDigest("pulumi-preview", steps);
127
+ }
128
+ const REPLACE_OPS = new Set(["replace", "create-replacement", "delete-replaced"]);
129
+ /** The action and disruption one URN's steps mean, or undefined for an op the change set has no action for. */
130
+ function actionOf(steps) {
131
+ const ops = steps.map((s) => s.op ?? "");
132
+ if (ops.includes("import-replacement"))
133
+ return { action: "replace", disruption: "replace", importing: true };
134
+ if (ops.some((o) => REPLACE_OPS.has(o))) {
135
+ const del = ops.indexOf("delete-replaced");
136
+ const create = ops.indexOf("create-replacement");
137
+ return { action: "replace", disruption: del >= 0 && create >= 0 && del < create ? "destroy" : "replace" };
138
+ }
139
+ if (ops.length !== 1)
140
+ return undefined;
141
+ switch (ops[0]) {
142
+ case "create": return { action: "create" };
143
+ case "update": return { action: "update", disruption: "in-place" };
144
+ case "delete": return { action: "delete", disruption: "destroy" };
145
+ case "same": return { action: "no-op" };
146
+ case "read":
147
+ case "read-replacement":
148
+ case "refresh": return { action: "read" };
149
+ case "import": return { action: "no-op", importing: true };
150
+ case "discard":
151
+ case "remove-pending-replace": return { action: "forget" };
152
+ default: return undefined;
153
+ }
154
+ }
155
+ /** The state before and after across one URN's steps: the first old state and the last new one. */
156
+ function statesOf(steps) {
157
+ const before = steps.find((s) => isObject(s.oldState))?.oldState;
158
+ const after = [...steps].reverse().find((s) => isObject(s.newState) && s.op !== "delete-replaced" && s.op !== "delete")?.newState;
159
+ return { ...(before ? { before } : {}), ...(after ? { after } : {}) };
160
+ }
161
+ function attributesOf(steps, action, states) {
162
+ if (action !== "create" && action !== "update" && action !== "replace")
163
+ return [];
164
+ const before = isObject(states.before?.inputs) ? states.before.inputs : {};
165
+ const after = isObject(states.after?.inputs) ? states.after.inputs : {};
166
+ const forcing = new Set();
167
+ const named = new Set();
168
+ for (const s of steps) {
169
+ for (const k of s.replaceReasons ?? [])
170
+ forcing.add(topLevelKey(k));
171
+ for (const k of s.diffReasons ?? [])
172
+ named.add(topLevelKey(k));
173
+ for (const [path, d] of Object.entries(s.detailedDiff ?? {})) {
174
+ named.add(topLevelKey(path));
175
+ if (typeof d?.kind === "string" && d.kind.endsWith("-replace"))
176
+ forcing.add(topLevelKey(path));
177
+ }
178
+ }
179
+ const keys = action === "create"
180
+ ? propertyKeys(after)
181
+ : [...new Set([...named, ...propertyKeys(after).filter((k) => holdsUnknown(after[k]))])].filter((k) => !k.startsWith("__"));
182
+ const beforeOut = isObject(states.before?.outputs) ? states.before.outputs : {};
183
+ const afterOut = isObject(states.after?.outputs) ? states.after.outputs : {};
184
+ const present = (v) => v !== undefined && v !== null;
185
+ const out = [];
186
+ for (const k of keys.sort()) {
187
+ let b = before[k];
188
+ let a = after[k];
189
+ let unknown = holdsUnknown(a);
190
+ // On an update a key the diff names is listed even when both sides read the same: the provider said it changes.
191
+ if (action === "create" && !present(a) && !unknown)
192
+ continue;
193
+ // A key the diff names with no input on either side is an output the provider computes (an SSM parameter's
194
+ // `version`, recorded, #4475): before is the last deployment's output, after the planned output, which a
195
+ // preview leaves empty when the value is known only after apply.
196
+ if (action !== "create" && !present(b) && !present(a) && !unknown && named.has(k)) {
197
+ b = beforeOut[k];
198
+ a = afterOut[k];
199
+ unknown = !present(a) || holdsUnknown(a);
200
+ }
201
+ const hasBefore = action !== "create" && present(b);
202
+ const hasAfter = present(a);
203
+ const sensitive = holdsSecret(b) || holdsSecret(a);
204
+ out.push({
205
+ path: k,
206
+ ...(sensitive
207
+ ? { sensitive: true }
208
+ : {
209
+ ...(hasBefore ? { before: b } : {}),
210
+ ...(hasAfter && !unknown ? { after: a } : {}),
211
+ }),
212
+ ...(unknown ? { unknown: true } : {}),
213
+ ...(forcing.has(k) ? { forcesReplacement: true } : {}),
214
+ });
215
+ }
216
+ return out;
217
+ }
218
+ const knownId = (id) => (typeof id === "string" && id !== "" && !isUnknown(id) ? id : undefined);
219
+ /**
220
+ * A Pulumi member's part, from its `pulumi preview --json`. Throws when the
221
+ * document has no `steps` and no `error` says why.
222
+ */
223
+ export function pulumiPreviewPart(input) {
224
+ const steps = pulumiSteps(input.preview);
225
+ if (steps === undefined && input.error === undefined)
226
+ throw new Error('not a pulumi preview --json document: no top-level "steps"');
227
+ const scope = input.stack ? { scope: input.stack } : {};
228
+ const base = { member: input.member, lexicon: "pulumi", planner: "pulumi" };
229
+ // One URN's steps, in the order the preview printed them.
230
+ const byUrn = new Map();
231
+ for (const s of steps ?? []) {
232
+ const list = byUrn.get(s.urn) ?? [];
233
+ list.push(s);
234
+ byUrn.set(s.urn, list);
235
+ }
236
+ const entries = [];
237
+ const holes = [];
238
+ const actions = new Map();
239
+ const states = new Map();
240
+ for (const [urn, list] of byUrn) {
241
+ const parsed = parsePulumiUrn(urn);
242
+ const st = statesOf(list);
243
+ states.set(urn, st);
244
+ const type = st.after?.type ?? st.before?.type ?? parsed?.type ?? "unknown";
245
+ const mapped = actionOf(list);
246
+ if (!mapped) {
247
+ holes.push({ address: urn, type, reason: `pulumi printed ${list.map((s) => s.op ?? "no op").join(", ")} for the URN, which the change set has no action for` });
248
+ continue;
249
+ }
250
+ actions.set(urn, mapped.action);
251
+ const id = knownId(st.after?.id) ?? knownId(st.before?.id);
252
+ entries.push({
253
+ ...base,
254
+ address: urn,
255
+ type,
256
+ ...(parsed ? { name: parsed.name } : {}),
257
+ ...(id ? { id } : {}),
258
+ action: mapped.action,
259
+ ...(mapped.importing ? { importing: true } : {}),
260
+ ...(mapped.disruption ? { disruption: mapped.disruption } : {}),
261
+ ...scope,
262
+ attributes: attributesOf(list, mapped.action, st),
263
+ });
264
+ }
265
+ // Signal 1: components whose subtree waits on a value preview does not know.
266
+ const parentOf = new Map();
267
+ for (const [urn, st] of states) {
268
+ const parent = st.after?.parent ?? st.before?.parent;
269
+ if (typeof parent === "string")
270
+ parentOf.set(urn, parent);
271
+ }
272
+ const isComponent = (urn) => {
273
+ const st = states.get(urn);
274
+ const state = st?.after ?? st?.before;
275
+ const type = state?.type ?? parsePulumiUrn(urn)?.type ?? "";
276
+ return state?.custom === false && type !== PULUMI_STACK_TYPE && !isPulumiNodeless(type);
277
+ };
278
+ const waits = (urn) => {
279
+ const action = actions.get(urn);
280
+ if (action === "create" || action === "replace")
281
+ return true;
282
+ const st = states.get(urn);
283
+ return holdsUnknown(st?.after?.inputs) || holdsUnknown(st?.after?.outputs);
284
+ };
285
+ const flagged = new Set();
286
+ for (const urn of byUrn.keys()) {
287
+ if (actions.get(urn) === "delete" || !waits(urn))
288
+ continue;
289
+ // The resource and every component above it, up to the stack.
290
+ const seen = new Set();
291
+ for (let at = urn; at !== undefined && !seen.has(at); at = parentOf.get(at)) {
292
+ seen.add(at);
293
+ if (isComponent(at) && actions.get(at) !== "delete")
294
+ flagged.add(at);
295
+ }
296
+ }
297
+ for (const component of [...flagged].sort()) {
298
+ entries.push({ ...base, address: pulumiMayAppearAddress(component), type: "unknown", action: "create", mayAppear: true, ...scope, attributes: [] });
299
+ }
300
+ const underFlagged = (urn) => {
301
+ const seen = new Set();
302
+ for (let at = parentOf.get(urn); at !== undefined && !seen.has(at); at = parentOf.get(at)) {
303
+ seen.add(at);
304
+ if (flagged.has(at))
305
+ return true;
306
+ }
307
+ return false;
308
+ };
309
+ for (const e of entries) {
310
+ if (e.action === "delete" && e.mayAppear !== true && underFlagged(e.address))
311
+ e.mayAppear = true;
312
+ }
313
+ // Signal 2: what the last deployment holds and the preview never listed.
314
+ // A failed preview stopped part way, so what it did not list says nothing.
315
+ if (input.prior !== undefined && !input.targeted && input.error === undefined) {
316
+ for (const r of pulumiExportResources(input.prior)) {
317
+ if (byUrn.has(r.urn) || isPulumiNodeless(r.type))
318
+ continue;
319
+ const parsed = parsePulumiUrn(r.urn);
320
+ const id = knownId(r.id);
321
+ entries.push({
322
+ ...base,
323
+ address: r.urn,
324
+ type: r.type,
325
+ ...(parsed ? { name: parsed.name } : {}),
326
+ ...(id ? { id } : {}),
327
+ action: "update",
328
+ disruption: "unknown",
329
+ mayAppear: true,
330
+ ...scope,
331
+ attributes: [],
332
+ });
333
+ }
334
+ }
335
+ const failed = input.error !== undefined;
336
+ return {
337
+ member: {
338
+ ...base,
339
+ ...scope,
340
+ status: failed ? "failed" : "planned",
341
+ ...(failed ? { error: input.error } : {}),
342
+ planDigest: failed ? null : pulumiPreviewDigest(input.preview),
343
+ holes,
344
+ },
345
+ entries,
346
+ };
347
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env tsx
2
+ export {};
3
+ //# sourceMappingURL=docs-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-cli.d.ts","sourceRoot":"","sources":["../../src/codegen/docs-cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env tsx
2
+ import { generateDocs } from "./docs.js";
3
+ await generateDocs({ verbose: true });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generate the docs section for the pulumi lexicon (#4468). Authored pages
3
+ * come from `docs/pages/`; the overview, the rules page and the sidebar are
4
+ * the pipeline's.
5
+ */
6
+ export declare function generateDocs(options?: {
7
+ verbose?: boolean;
8
+ }): Promise<void>;
9
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBjF"}