@sap/cds-dk 10.0.7 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/bin/add.js +7 -23
  3. package/bin/bind.js +10 -0
  4. package/bin/build.js +20 -34
  5. package/bin/cds.js +1 -1
  6. package/bin/compile/index.js +15 -41
  7. package/bin/completion/completionFs.js +11 -8
  8. package/bin/completion/index.js +592 -80
  9. package/bin/completion/scripts/cds.fish +568 -0
  10. package/bin/completion/scripts/cds.ps1 +329 -0
  11. package/bin/completion/scripts/cds.sh +261 -0
  12. package/bin/completion/scripts/cds.zsh +230 -0
  13. package/bin/completion/templates/cds-tmpl.fish +65 -0
  14. package/bin/completion/templates/cds-tmpl.ps1 +208 -0
  15. package/bin/completion/templates/cds-tmpl.sh +93 -0
  16. package/bin/completion/templates/cds-tmpl.zsh +74 -0
  17. package/bin/deploy/index.js +7 -1
  18. package/bin/deploy/options.js +25 -0
  19. package/{lib → bin}/deploy/to-hana/hana.js +8 -8
  20. package/{lib → bin}/deploy/to-hana/hdiDeployUtil.js +1 -1
  21. package/bin/deploy/{to-hana.js → to-hana/index.js} +1 -1
  22. package/{lib → bin}/deploy/to-hana/mtaUtil.js +1 -1
  23. package/bin/deploy/to-sql.js +0 -2
  24. package/bin/export.js +35 -5
  25. package/bin/help/export.md +3 -0
  26. package/bin/help.js +1 -5
  27. package/bin/import.js +6 -0
  28. package/bin/init.js +5 -24
  29. package/bin/inspect.js +6 -0
  30. package/bin/login.js +26 -20
  31. package/bin/pull.js +19 -6
  32. package/bin/push.js +19 -6
  33. package/bin/up.js +14 -11
  34. package/{lib → bin}/upgrade/constants.js +1 -1
  35. package/bin/{upgrade.js → upgrade/index.js} +2 -2
  36. package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
  37. package/{lib → bin}/upgrade/preflight/index.js +1 -1
  38. package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
  39. package/{lib → bin}/upgrade/steps/install.js +1 -1
  40. package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
  41. package/{lib → bin}/upgrade/steps/removals.js +1 -1
  42. package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
  43. package/{lib → bin}/upgrade/steps/verify.js +1 -1
  44. package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
  45. package/{lib → bin}/upgrade/util/pom.js +2 -2
  46. package/{lib → bin}/upgrade/util/prompt.js +1 -1
  47. package/bin/util/containerize.js +8 -4
  48. package/bin/version.js +10 -1
  49. package/{lib → bin}/watch/hot-reload.js +1 -1
  50. package/bin/{watch.js → watch/index.js} +17 -9
  51. package/{lib → bin}/watch/livereload-connect.js +1 -1
  52. package/{lib → bin}/watch/vite-watch.js +1 -1
  53. package/{lib → bin}/watch/watched.js +2 -2
  54. package/lib/build/constants.js +1 -1
  55. package/lib/build/plugins/fiori/index.js +31 -2
  56. package/lib/build/plugins/internal.js +4 -2
  57. package/lib/build/plugins/mtx-sidecar/index.js +7 -8
  58. package/lib/build/plugins/nodejs/index.js +64 -7
  59. package/lib/compile/to_asyncapi.js +1 -1
  60. package/lib/env/schema.js +16 -0
  61. package/lib/env/schemas/cds-rc.js +1 -76
  62. package/lib/import/importapi.js +2 -3
  63. package/lib/import/message.js +0 -2
  64. package/lib/init/constants.js +2 -1
  65. package/lib/init/index.js +2 -2
  66. package/lib/init/merge.js +123 -280
  67. package/lib/init/plugin.js +3 -1
  68. package/lib/init/projectReader.js +22 -6
  69. package/lib/init/registries/xs-app.js +3 -5
  70. package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
  71. package/lib/init/template/ai/index.js +14 -2
  72. package/lib/init/template/ams/index.js +2 -2
  73. package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
  74. package/lib/init/template/app-frontend/index.js +4 -4
  75. package/lib/init/template/application-logging/index.js +2 -2
  76. package/lib/init/template/approuter/files/package.json +1 -1
  77. package/lib/init/template/approuter/index.js +8 -3
  78. package/lib/init/template/attachments/files/package.json.hbs +1 -1
  79. package/lib/init/template/attachments/index.js +2 -2
  80. package/lib/init/template/audit-logging/index.js +2 -2
  81. package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
  82. package/lib/init/template/cloud-logging/index.js +2 -2
  83. package/lib/init/template/completion/completionSetup.js +36 -39
  84. package/lib/init/template/connectivity/index.js +2 -2
  85. package/lib/init/template/data/as-csv.js +15 -5
  86. package/lib/init/template/data/as-json.js +114 -42
  87. package/lib/init/template/data/index.js +16 -2
  88. package/lib/init/template/destination/index.js +2 -2
  89. package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
  90. package/lib/init/template/dynatrace/index.js +2 -2
  91. package/lib/init/template/enterprise-messaging/index.js +2 -2
  92. package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
  93. package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
  94. package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
  95. package/lib/init/template/extensibility/index.js +3 -3
  96. package/lib/init/template/github-actions/index.js +2 -2
  97. package/lib/init/template/hana/index.js +3 -2
  98. package/lib/init/template/hana-serverless/files/db/package.json +14 -0
  99. package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
  100. package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
  101. package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
  102. package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
  103. package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
  104. package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
  105. package/lib/init/template/hana-serverless/index.js +184 -0
  106. package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
  107. package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
  108. package/lib/init/template/html5-repo/index.js +18 -14
  109. package/lib/init/template/http/index.js +123 -26
  110. package/lib/init/template/ias/index.js +2 -2
  111. package/lib/init/template/kafka/index.js +2 -2
  112. package/lib/init/template/kyma/index.js +7 -5
  113. package/lib/init/template/malware-scanner/index.js +2 -2
  114. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  115. package/lib/init/template/multitenancy/index.js +18 -3
  116. package/lib/init/template/notifications/index.js +2 -2
  117. package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
  118. package/lib/init/template/portal/index.js +13 -8
  119. package/lib/init/template/postgres/index.js +2 -2
  120. package/lib/init/template/redis/index.js +2 -2
  121. package/lib/init/template/sample/files/db/currencies.cds +2 -0
  122. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
  123. package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
  124. package/lib/init/template/workzone-standard/index.js +5 -5
  125. package/lib/init/template/xsuaa/index.js +20 -2
  126. package/lib/lint/eslintHelp.json +1 -1
  127. package/lib/mtx/auth_manager.js +103 -37
  128. package/lib/mtx/params.js +3 -2
  129. package/lib/mtx/settings_manager.js +45 -28
  130. package/lib/mtx/tenant_action.js +0 -1
  131. package/lib/mtx/util/credentials.js +62 -0
  132. package/node_modules/@sap/cds/CHANGELOG.md +57 -0
  133. package/node_modules/@sap/cds/app/index.js +5 -4
  134. package/node_modules/@sap/cds/eslint.config.mjs +1 -0
  135. package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
  136. package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
  137. package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
  138. package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
  139. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
  140. package/node_modules/@sap/cds/lib/plugins.js +9 -5
  141. package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
  142. package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
  143. package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
  144. package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
  145. package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
  146. package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
  147. package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
  148. package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
  149. package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
  150. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
  151. package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
  152. package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
  153. package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
  154. package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
  155. package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
  156. package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
  157. package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
  158. package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
  159. package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
  160. package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
  161. package/node_modules/@sap/cds/libx/http/location.js +3 -3
  162. package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
  163. package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
  164. package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
  165. package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
  166. package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
  167. package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
  168. package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
  169. package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
  170. package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
  171. package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
  172. package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
  173. package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
  174. package/node_modules/@sap/cds/package.json +1 -1
  175. package/node_modules/@sap/cds-compiler/CHANGELOG.md +60 -8
  176. package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
  177. package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
  178. package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
  179. package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
  180. package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
  181. package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
  182. package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
  183. package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
  184. package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
  185. package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
  186. package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
  187. package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
  188. package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
  189. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
  190. package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
  191. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +41 -15
  192. package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
  193. package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
  194. package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
  195. package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
  196. package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
  197. package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
  198. package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
  199. package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
  200. package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
  201. package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
  202. package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
  203. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +2 -0
  204. package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
  205. package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
  206. package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
  207. package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
  208. package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
  209. package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
  210. package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
  211. package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
  212. package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +3 -0
  213. package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +8 -2
  214. package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
  215. package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
  216. package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
  217. package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +1 -0
  218. package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +6 -1
  219. package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +19 -8
  220. package/node_modules/@sap/cds-compiler/package.json +1 -1
  221. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +15 -0
  222. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +34 -16
  223. package/node_modules/@sap/cds-mtxs/lib/utils.js +19 -4
  224. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  225. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +1 -1
  226. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +22 -13
  227. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +17 -2
  228. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
  229. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +4 -8
  230. package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
  231. package/node_modules/@sap/xsenv/package.json +10 -7
  232. package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  233. package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  234. package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  235. package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  236. package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  237. package/node_modules/hdb/cfg/VERSION +1 -1
  238. package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
  239. package/node_modules/hdb/lib/protocol/Connection.js +1 -0
  240. package/node_modules/hdb/package.json +3 -2
  241. package/node_modules/negotiator/lib/accept.js +54 -0
  242. package/node_modules/negotiator/lib/charset.js +10 -34
  243. package/node_modules/negotiator/lib/encoding.js +9 -30
  244. package/node_modules/negotiator/lib/language.js +15 -36
  245. package/node_modules/negotiator/lib/mediaType.js +16 -134
  246. package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  247. package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  248. package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  249. package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  250. package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  251. package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  252. package/node_modules/negotiator/package.json +16 -10
  253. package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
  254. package/node_modules/qs/CHANGELOG.md +15 -0
  255. package/node_modules/qs/README.md +19 -1
  256. package/node_modules/qs/dist/qs.js +21 -21
  257. package/node_modules/qs/eslint.config.mjs +1 -1
  258. package/node_modules/qs/lib/parse.js +3 -4
  259. package/node_modules/qs/lib/stringify.js +23 -8
  260. package/node_modules/qs/lib/utils.js +10 -3
  261. package/node_modules/qs/package.json +4 -4
  262. package/node_modules/qs/test/parse.js +192 -3
  263. package/node_modules/qs/test/stringify.js +317 -0
  264. package/node_modules/qs/test/utils.js +12 -0
  265. package/node_modules/type-is/node_modules/content-type/README.md +2 -0
  266. package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  267. package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  268. package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  269. package/node_modules/type-is/node_modules/content-type/package.json +1 -1
  270. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  271. package/node_modules/ws/package.json +1 -1
  272. package/package.json +3 -3
  273. package/bin/completion/scripts/cds-bash.sh +0 -20
  274. package/bin/completion/scripts/cds-fish.fish +0 -13
  275. package/bin/completion/scripts/cds-ps.ps1 +0 -19
  276. package/bin/completion/scripts/cds-zsh.sh +0 -13
  277. package/lib/deploy/index.js +0 -25
  278. package/lib/import/asyncapi/importAsyncAPI.js +0 -33
  279. package/lib/import/asyncapi/index.js +0 -18
  280. package/lib/import/asyncapi/parserContext.js +0 -454
  281. package/lib/import/asyncapi/utils.js +0 -49
  282. package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
  283. package/node_modules/negotiator/HISTORY.md +0 -114
  284. /package/{lib → bin}/upgrade/context.js +0 -0
  285. /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
  286. /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
  287. /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
  288. /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
  289. /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
  290. /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
  291. /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
  292. /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
  293. /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
  294. /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
  295. /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
  296. /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
  297. /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
  298. /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
  299. /package/{lib → bin}/watch/livereload-server.js +0 -0
  300. /package/{lib → bin}/watch/node-watch.js +0 -0
  301. /package/{lib → bin}/watch/open.js +0 -0
  302. /package/{lib → bin}/watch/watcher.js +0 -0
@@ -178,79 +178,8 @@ module.exports = {
178
178
  type: "object",
179
179
  description: "Customize cds compile settings",
180
180
  additionalProperties: false,
181
+ // export format settings (e.g. `asyncapi`) are contributed by plugins via their package.json `cds.schema.export`
181
182
  properties: {
182
- asyncapi: {
183
- type: "object",
184
- description: "AsyncAPI settings for cds compile",
185
- additionalProperties: false,
186
- properties: {
187
- application_namespace: {
188
- type: "string",
189
- description: "The registered namespace of the application"
190
- },
191
- merged: {
192
- type: "object",
193
- description: "properties that needs to be there when merged option is used",
194
- additionalProperties: false,
195
- properties: {
196
- title: {
197
- type: "string",
198
- description: "Title to be used for merged doc"
199
- },
200
- version: {
201
- type: "string",
202
- description: "Version to be used for merged doc"
203
- },
204
- short_text: {
205
- type: "string",
206
- description: "Short decription of the AsyncAPIs"
207
- },
208
- description: {
209
- type: "string",
210
- description: "Description to be used for the merged doc"
211
- }
212
- }
213
- },
214
- event_spec_version: {
215
- type: "string",
216
- description: "Mentions the version of AsyncAPI spec"
217
- },
218
- event_source: {
219
- type: "string",
220
- description: "Event source information",
221
- default: "{region}/{applicationNamespace}/{instanceId}",
222
- },
223
- event_source_params: {
224
- type: "object",
225
- description: "Parameters related to the source of event",
226
- default: {
227
- region: "the region",
228
- applicationNamespace: "the namespace",
229
- instanceId: "the instance id"
230
- },
231
- additionalProperties: false,
232
- properties: {
233
- region: {
234
- type: "string",
235
- description: "The regional context of the application"
236
- },
237
- applicationNamespace: {
238
- type: "string",
239
- description: "The registered namespace of the application"
240
- },
241
- instanceId: {
242
- type: "string",
243
- description: "The instance id (tenant, installation, ...) of the application."
244
- }
245
- }
246
- },
247
- event_characteristics: {
248
- type: "object",
249
- description: "The characteristics defined for events",
250
- additionalProperties: true
251
- }
252
- }
253
- }
254
183
  }
255
184
  },
256
185
  // deploy specific schema
@@ -318,10 +247,6 @@ module.exports = {
318
247
  importOptions: {
319
248
  from: {
320
249
  oneOf: [
321
- {
322
- const: "asyncapi",
323
- description: "AsyncAPI specification"
324
- },
325
250
  {
326
251
  const: "edmx",
327
252
  description: "OData specification"
@@ -3,7 +3,6 @@ let { path } = cds.utils;
3
3
  let common = require('./common');
4
4
  let odata = require('./odata');
5
5
  let openapi = require('./openapi');
6
- let asyncapi = require('./asyncapi');
7
6
  let messages = require('./message').getMessages();
8
7
 
9
8
  module.exports = Object.assign(cds_import, {
@@ -97,15 +96,15 @@ async function cds_import_from_openapi(filepath, options = {}) {
97
96
 
98
97
  /**
99
98
  * This is the import API function to generate CSN from asyncapi files.
99
+ * cds11: remove once @cap-js/asyncapi is a required project dependency
100
100
  * @param {string} filepath
101
101
  * - a single valid filepath
102
102
  * @returns {object} CSN
103
103
  */
104
104
  async function cds_import_from_asyncapi(filepath, options = {}) {
105
- // validates the input file
106
105
  filepath = await common.isValidInputFile(path.resolve(process.cwd(), filepath));
107
106
  const src = await common.getContentFromFile(filepath);
108
- let csn = asyncapi.asyncapi2csn(src);
107
+ let csn = require('@cap-js/asyncapi').import.asyncapi2csn(src);
109
108
  options.inputFileKind = 'odata';
110
109
  return csn;
111
110
  }
@@ -18,8 +18,6 @@ const messages = {
18
18
  MISSING_ASSOCIATION: 'Association is missing in the input file provided. Please check the edmx file.',
19
19
  COLLECTION_IN_KEY: 'Key Property of an Entity cannot be of the type Collection.',
20
20
  INVALID_OPENAPI_FILE: 'The OpenAPI file is not valid. Specify the correct OpenAPI file.',
21
- INVALID_ASYNCAPI_FILE: 'The AsyncAPI file is not valid. Specify the correct AsyncAPI file.',
22
- INVALID_MESSAGE_NAME: 'The message name is not valid.',
23
21
  UNRESOLVED_TYPE: 'Could not resolve the type: ',
24
22
  NO_RETURN_TYPE: 'No ReturnType found in Function: ',
25
23
  INVALID_ENUM_TYPE: 'The Underlying type provided is not supported for the EnumType: ',
@@ -5,7 +5,7 @@ module.exports = {
5
5
  COMMAND_ADD: 'add',
6
6
 
7
7
  JAVA_LTS_VERSIONS: [25],
8
- MAVEN_ARCHETYPE_VERSION: '5.0.0',
8
+ MAVEN_ARCHETYPE_VERSION: '5.0.1',
9
9
 
10
10
  OPTIONS: Object.freeze({
11
11
  COMPLETION: 'completion',
@@ -29,6 +29,7 @@ module.exports = {
29
29
  IAS: 'ias',
30
30
  AMS: 'ams',
31
31
  HANA: 'hana',
32
+ HANA_SERVERLESS: 'hana-serverless',
32
33
  POSTGRES: 'postgres',
33
34
  SQLITE: 'sqlite',
34
35
  LIQUIBASE: 'liquibase',
package/lib/init/index.js CHANGED
@@ -165,7 +165,7 @@ module.exports = class CDSGenerator {
165
165
  const added = cds.cli.command === 'add' && cds.cli.argv[0]?.split(',').includes(plugin) || cds.cli.options.add?.has(plugin)
166
166
  const inProduction = Plugin.hasInProduction(env4('production')) || added
167
167
  DEBUG && console.log(inProduction ? '✅' : '❌', plugin)
168
- if (inProduction) await template.combine()
168
+ if (inProduction) await template.combine(plugin)
169
169
  }
170
170
  }
171
171
 
@@ -237,7 +237,7 @@ module.exports = class CDSGenerator {
237
237
  const creating = ['java', 'nodejs', 'typescript', 'cjs', 'extension']
238
238
  const { command, options, argv } = cds.cli
239
239
  const inOptions = option => command === 'init' && options.add.has(option) ||
240
- command === 'add' && argv[0]?.split(',').includes(option)
240
+ command === 'add' && argv.flatMap(a => a.split(',')).includes(option)
241
241
  if (!exists('pom.xml') && !exists('package.json') && !creating.some(inOptions)) {
242
242
  if (command === 'init') {
243
243
  const project = argv[0] ? argv[0]+' ' : ''
package/lib/init/merge.js CHANGED
@@ -1,11 +1,9 @@
1
1
  const { EOL } = require('node:os')
2
- const { inspect } = require('node:util')
3
2
  const cds = require('../cds')
4
3
  const YAML = require('yaml')
5
4
  const { copy, read, write, exists, path: {resolve, join} } = cds.utils
6
5
  const { readYAML, writeYAML, readJSON } = require('../util/fs')
7
6
  const { detectIndent } = require('./indent')
8
- const { colors } = require('../util/term')
9
7
 
10
8
  function _mergeObject(target, source) {
11
9
  const _isObject = item => item && typeof item === 'object' && !Array.isArray(item)
@@ -113,288 +111,119 @@ async function _mergeYAML(into, from, project, semantics = {}) {
113
111
  throw new Error(`Target YAML doesn't exist`)
114
112
  }
115
113
 
116
- const entryMap = new Map, templateEntryMap = new Map
114
+ const { forceOverwrite, additions = [], overwrites = [], deletions = [], relationships = [] } = semantics
115
+ const path = keyPath => keyPath.split('.').filter(k => k)
117
116
 
118
- const { additions, overwrites, deletions, relationships } = semantics
119
- if (relationships && Array.isArray(relationships)) {
120
- semantics.additions ??= []
121
- const add = semantics.additions
122
-
123
- for (const rel of relationships) {
124
- for (const ins of (Array.isArray(rel.insert) ? rel.insert : [rel.insert])) {
125
- if (!add.includes(ins)) add.push(ins)
126
- }
127
- const base = rel.into?.[0]
128
- if (base && !add.includes(base)) add.push(base)
129
- }
130
- }
131
-
132
- for (const entry of additions ?? []) {
133
- entryMap.set(entry, undefined)
134
- templateEntryMap.set(entry, undefined)
117
+ // Seq members correspond unless a shared top-level key holds a different scalar.
118
+ // {name:x} enriches {name:x,...}; {name:x,alias:a} and {name:x,alias:b} stay distinct.
119
+ const conflict = (a, b) => Object.keys(a).some(k =>
120
+ k in b && (typeof a[k] !== 'object' || typeof b[k] !== 'object') && JSON.stringify(a[k]) !== JSON.stringify(b[k]))
121
+ const same = (a, b) => {
122
+ if (YAML.isMap(a) && YAML.isMap(b)) { const x = a.toJSON(), y = b.toJSON(); return !conflict(x, y) && !conflict(y, x) }
123
+ return JSON.stringify(a.toJSON?.() ?? a.value) === JSON.stringify(b.toJSON?.() ?? b.value)
135
124
  }
136
- for (const deletion of deletions ?? []) {
137
- entryMap.set(deletion.item, undefined)
125
+ const has = (seq, node) => YAML.isSeq(seq) && seq.items.some(x => same(x, node))
126
+
127
+ // `where` matches a node iff every constraint holds on its JSON projection.
128
+ const matches = (node, where) => {
129
+ const json = node.toJSON?.() ?? {}
130
+ const at = (o, k) => path(k).reduce((p, s) => p?.[s], o)
131
+ return Object.entries(where).every(([k, v]) =>
132
+ Array.isArray(v) ? v.every(x => at(json, k) === x) : at(json, k) === v)
138
133
  }
139
- for (const relationship of relationships ?? []) {
140
- const [entry] = relationship.into
141
- const [insertEntry] = relationship.insert
142
- const hash = JSON.stringify(insertEntry) + ' -> ' + JSON.stringify(entry)
143
- entryMap.set(hash, undefined)
144
- }
145
-
146
- let collectionStack = [target.contents]
147
-
148
- const _getProperty = (object, keyPath) => keyPath.split('.').filter(k => k).reduce((p, k) => p && p[k], object)
149
- const _getYAMLProperty = (object, keyPath) => keyPath.split('.').filter(k => k).reduce((p, k) => p && p.get(k), object)
150
134
 
151
- const _validateWhere = (node, dict, index) => {
152
- const _addToMap = entries => entries?.filter(entry => {
153
- if (typeof entry.in === 'string') return true
154
- if (typeof entry === 'string' && !entry.where) return false // no random access caching needed for pure key paths
155
- if (Array.isArray(entry)) entry = entry[0]
156
- const neededParent = dict.get(entry.in[0])?.node
157
- return collectionStack.includes(neededParent) // lookbehind in parent collection stack
158
- }).forEach(item => {
159
- if (Array.isArray(item)) item = item[0]
160
- const json = JSON.parse(String(node))
161
- const whereFulfilled = Object.entries(item.where).every(([key, value]) => {
162
- if (Array.isArray(value)) {
163
- return value.every(v => _getProperty(json, key) === v)
164
- } else {
165
- return _getProperty(json, key) === value
166
- }
167
- })
168
- if (whereFulfilled) {
169
- const [collection] = collectionStack
170
- dict.set(item, { json, node, index, collection })
171
- }
172
- })
173
- if (additions) _addToMap(additions)
174
- if (deletions) _addToMap(deletions.map(deletion => deletion.item))
175
- if (relationships) _addToMap(relationships?.map(({into: [entry]}) => entry).filter(e => e))
176
- if (overwrites) _addToMap(overwrites.map(overwrite => overwrite.item))
135
+ // Resolve a descriptor to a live node:
136
+ // 'a.b.c' -> getIn; {in,where} -> matching seq member; [entry,'rel'] -> getIn on entry.
137
+ const locate = (doc, d) => {
138
+ if (d == null) return undefined
139
+ if (typeof d === 'string') return doc.getIn(path(d))
140
+ if (Array.isArray(d)) {
141
+ const [base, keyPath] = d
142
+ const node = locate(doc, base)
143
+ return keyPath ? node?.getIn(path(keyPath)) : node
144
+ }
145
+ const seq = locate(doc, d.in)
146
+ return YAML.isSeq(seq) ? seq.items.find(n => matches(n, d.where)) : undefined
177
147
  }
178
148
 
179
- function _traverseYAMLNode(node, index, actions, templateNode) {
180
- let shifted = false
181
- if (YAML.isMap(node)) {
182
- actions.visitMap?.(node, index)
183
- const [collection] = collectionStack
184
- if (YAML.isSeq(collection)) {
185
- collectionStack.unshift(node)
186
- shifted = true
149
+ // Generic deep-merge: recurse maps, enrich matching seq members, union scalars.
150
+ // Unmatched map members are placed by the passes below. Target scalars win unless forced.
151
+ const mergeNode = (t, s) => {
152
+ if (YAML.isMap(t) && YAML.isMap(s)) {
153
+ for (const pair of s.items) {
154
+ const tv = t.get(pair.key.value, true)
155
+ if (tv === undefined) t.add(pair)
156
+ else mergeNode(tv, pair.value)
187
157
  }
188
- } else if (YAML.isPair(node) && node.value?.items) {
189
- collectionStack.unshift(node.value)
190
- } else if (YAML.isScalar(node) && semantics.forceOverwrite && templateNode && node.comment != 'cds.noOverwrite') {
191
- node.value = templateNode.value ?? templateNode.items?.[0]?.value?.value
192
- }
193
-
194
- if (node.items) {
195
- if (YAML.isSeq(node) && templateNode?.items) {
196
- actions.mergeCollection?.(node, templateNode)
197
- _traverseYAMLCollection(node, actions, templateNode)
198
- } else {
199
- _traverseYAMLCollection(node, actions, templateNode)
158
+ } else if (YAML.isSeq(t) && YAML.isSeq(s)) {
159
+ for (const item of s.items) {
160
+ const match = t.items.find(x => same(x, item))
161
+ if (match) mergeNode(match, item)
162
+ else if (YAML.isScalar(item)) t.add(item)
200
163
  }
201
- } else if(node.value?.source === '' && YAML.isSeq(templateNode?.value)) {
202
- node.value = new YAML.YAMLSeq()
203
- collectionStack.unshift(node.value)
204
- _traverseYAMLNode(node.value, index, actions, templateNode?.value)
205
- } else if (node.value?.items || node.value && semantics.forceOverwrite) {
206
- _traverseYAMLNode(node.value, index, actions, templateNode?.value)
164
+ } else if (forceOverwrite && YAML.isScalar(t) && YAML.isScalar(s) && t.comment !== 'cds.noOverwrite') {
165
+ t.value = s.value
207
166
  }
208
-
209
- if (node.value?.items || shifted) {
210
- collectionStack.shift()
167
+ }
168
+ mergeNode(target.contents, source.contents)
169
+
170
+ // Placement: add matched (and relationship-referenced) template entries not already present.
171
+ const isEntry = e => e && typeof e === 'object' && !Array.isArray(e) && e.in !== undefined
172
+ const insertNode = ins => Array.isArray(ins) ? (ins.length === 1 ? ins[0] : undefined) : ins
173
+ const relEntries = relationships.flatMap(r => [r.into?.[0], ...[].concat(r.insert).map(insertNode)])
174
+ for (const entry of [...additions, ...relEntries].filter(isEntry)) {
175
+ const seq = locate(target, entry.in)
176
+ if (!YAML.isSeq(seq)) continue
177
+ const clone = locate(source, entry)
178
+ if (clone && !has(seq, clone)) {
179
+ entry.at !== undefined ? seq.items.splice(entry.at, 0, clone) : seq.add(clone)
211
180
  }
212
181
  }
213
- _traverseYAMLNode.bind(this)
214
-
215
- function _traverseYAMLCollection (collection, actions, templateCollection) {
216
- if (!collection) return
217
-
218
- const keyToIndex = new Map, templateIndexToIndex = new Map
219
-
220
- // Map collection items to their semantic counterpart(s)
221
- collection.items.forEach((node, i) => {
222
- if (node.key) keyToIndex.set(node.key.value, i)
223
- const entry = [...entryMap.entries()].find(([,value]) => value?.node === node)
224
- if (entry) {
225
- const [entryKey] = entry
226
- const templateEntry = entryKey && templateEntryMap.get(entryKey)
227
- const templateIndex = templateEntry?.index
228
- if (templateIndex !== undefined) templateIndexToIndex.set(templateIndex, i)
229
- }
230
- if (!templateCollection) _traverseYAMLNode(node, i, actions)
231
- })
232
-
233
- if (!templateCollection?.items) return
234
182
 
235
- templateCollection.items?.forEach((templateNode, templateIndex) => {
236
- if (YAML.isScalar(templateNode)) {
237
- if (!collection.items.map(item => item.value).includes(templateNode.value)) {
238
- collection.add(templateNode)
239
- }
240
- } else if (YAML.isPair(templateNode)) {
241
- const i = keyToIndex.get(templateNode.key.value)
242
- const [collection] = collectionStack
243
- const targetNode = collection.items?.[i]
244
- if (targetNode) {
245
- _traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
246
- } else {
247
- actions.mergePair?.(collection, templateNode)
248
- }
249
- } else if (YAML.isMap(templateNode)) {
250
- const targetNode = collection.items[templateIndexToIndex.get(templateIndex)]
251
- actions.mergeCollection?.(targetNode, templateNode)
252
- if (targetNode) {
253
- _traverseYAMLNode(targetNode, templateIndex, actions, templateNode)
254
- }
255
- }
256
- })
183
+ // Relationships: wire a value into a target seq. [entry,'k'] -> {k: value}; [entry] -> the node.
184
+ for (const { insert, into } of relationships) {
185
+ const [baseEntry, seqPath, prop] = into
186
+ const seq = locate(target, seqPath ? [baseEntry, seqPath] : baseEntry)
187
+ if (!YAML.isSeq(seq)) continue
188
+ for (const ins of Array.isArray(insert) && typeof insert[0] === 'object' ? [insert] : [].concat(insert)) {
189
+ const [srcEntry, valueKey] = Array.isArray(ins) ? ins : [ins]
190
+ const srcNode = locate(target, srcEntry)
191
+ if (!srcNode) continue
192
+ const ref = prop || valueKey
193
+ const node = ref ? target.createNode({ [ref]: (valueKey ? srcNode.get(valueKey) : srcNode.get(ref)) }) : srcNode
194
+ if (!has(seq, node)) seq.add(node)
195
+ }
257
196
  }
258
- _traverseYAMLCollection.bind(this)
259
-
260
- // 1. Register the entries in the template
261
- _traverseYAMLNode(source.contents, null, {
262
- visitMap: (node, index) => _validateWhere(node, templateEntryMap, index)
263
- })
264
197
 
265
- // 2. Register the entries in the project
266
- _traverseYAMLNode(target.contents, null, {
267
- visitMap: (node, index) => _validateWhere(node, entryMap, index)
268
- })
269
-
270
- // 3. Apply overwrites to already found entries
271
- overwrites?.forEach(({ item, withValue }) => {
272
- const keyPath = Array.isArray(item) && typeof item[0] === 'string' ? item[0] : typeof item === 'string' ? item : item[1]
273
- const inEntry = Array.isArray(item) && typeof item[0] === 'object' ? item[0] : typeof item === 'object' ? item : item[1]
274
- let node
275
- if (inEntry && entryMap.get(inEntry)) {
276
- node = entryMap.get(inEntry).node // starting from item found in nested array cache
277
- } else if (typeof inEntry === 'string') {
278
- node = collectionStack[collectionStack.length - 1] // starting from root
279
- } else {
280
- return
281
- }
198
+ // Fill the bare nodes relationships just added from their full source counterparts.
199
+ if (relationships.length) mergeNode(target.contents, source.contents)
282
200
 
283
- const keys = keyPath.split('.')
284
- for (const key of keys.slice(0, -1)) {
285
- if (!node?.get(key) && typeof inEntry === 'string') return // node doesn't exist, will be added by template
286
- node = node?.get(key) ?? node
201
+ // Overwrites: set a (possibly nested) key on a located node.
202
+ for (const { item, withValue } of overwrites) {
203
+ const [base, keyPath] = Array.isArray(item) ? item : [undefined, item]
204
+ const node = base ? locate(target, base) : target.contents
205
+ const keys = path(typeof base === 'string' ? base : keyPath)
206
+ if (node?.getIn(keys.slice(0, -1)) !== undefined || base && typeof base !== 'string') {
207
+ (node.getIn(keys.slice(0, -1)) ?? node).set(keys.at(-1), withValue)
287
208
  }
288
- const tail = keys.pop()
289
- if (!node.get(tail)) {
290
- node.add({ key: tail, value: withValue })
291
- } else {
292
- node.set(tail, withValue)
293
- }
294
- })
295
-
296
- // 4. Delete entries from the project (e.g. separate deployer module when adding mtx)
297
- deletions?.forEach(({ item, relationships, key }) => {
298
- const entry = entryMap.get(item)
299
- if (!entry) return
300
- if (key) entry.collection.deleteIn([entry.index, ...key.split('.')])
301
- else entry.collection.delete(entry.index)
302
-
303
- relationships?.forEach(relationship => {
304
- const [allWithinKeyPath, inKeyPath, into] = relationship.allWithin
305
- const parent = _getYAMLProperty(target, allWithinKeyPath)
306
- for (const child of parent.items) {
307
- const grandchild = _getYAMLProperty(child, inKeyPath)
308
- const i = grandchild?.items?.findIndex(node =>
309
- node.get(into) === _getProperty(entry.json, relationship.removeProperty)
310
- ) ?? - 1
311
- if (i > -1) grandchild.delete(i)
312
- }
313
- })
314
- })
315
-
316
- // 5. Create missing entries and pairs
317
- _traverseYAMLNode(target.contents, null, {
318
- mergePair: (collection, templateNode) => {
319
- if (YAML.isMap(collection)) {
320
- collection.add(templateNode)
321
- }
322
- },
323
- mergeCollection: (targetNode, templateNode) => {
324
- if (YAML.isSeq(templateNode)) {
325
- let [,parent] = collectionStack
326
- additions?.filter(addition => {
327
- if (typeof addition.in === 'string' || Array.isArray(addition.in) && typeof addition.in[0] === 'string') return true
328
- const base = Array.isArray(addition.in) ? addition.in[0] : addition.in
329
- const keyPath = Array.isArray(addition.in) ? addition.in[1] : ''
330
- const inEntry = entryMap.get(base)
331
- if (!inEntry) return false
332
- const depth = String(keyPath).split('.').filter(Boolean).length
333
- const expectedParent = depth > 1 ? collectionStack[depth] : parent
334
- return inEntry.node === expectedParent
335
- })
336
- .filter(addition => {
337
- const keyPath = typeof addition.in === 'string' ? addition.in : Array.isArray(addition.in) && typeof addition.in[0] === 'string' ? addition.in[0] : addition.in[1]
338
- const keys = keyPath.split('.')
339
- if (keys.length > collectionStack.length + 1) return false
340
- if (keys.length > 1) parent = collectionStack[keys.length]
341
- return _getYAMLProperty(parent, keyPath) === targetNode
342
- })
343
- .filter(item => !entryMap.get(item))
344
- .forEach(item => {
345
- if (!templateEntryMap.get(item)) throw 'Error: did not find entry in template for ' + inspect(item, { colors, depth:11 }) + ' in \n' + from
346
- const templateNode = templateEntryMap.get(item).node
347
- item.at !== undefined ? targetNode.items.splice(item.at, 0, templateNode) : targetNode.add(templateNode)
348
- })
349
-
350
- }
351
- },
352
- }, source.contents)
353
-
354
- // 6. Re-register the entries in the project
355
- _traverseYAMLNode(target.contents, null, {
356
- visitMap: (node, index) => _validateWhere(node, entryMap, index)
357
- })
209
+ }
358
210
 
359
- // 7. Create missing relationships
360
- _traverseYAMLNode(target.contents, null, {
361
- mergeCollection: (targetNode, templateNode) => {
362
- if (!YAML.isSeq(templateNode)) return
363
- const targetJSON = YAML.parse(String(targetNode))
364
- for (const { insert, into } of semantics.relationships ?? []) {
365
- const [first, ...rest] = into
366
- const seqPath = rest.find(x => typeof x === 'string') || ''
367
- const keyPath = rest.length > 1 ? rest.at(-1) : null
368
- const base = entryMap.get(first)
369
- if (!base) continue
370
- const seqNode = seqPath ? _getYAMLProperty(base.node, seqPath) : base.node
371
- if (seqNode !== targetNode) continue
372
- const inserts = Array.isArray(insert) ? insert : [insert]
373
- for (const ins of inserts) {
374
- const insEntry = entryMap.get(ins)
375
- if (!insEntry) continue
376
- const srcNode = insEntry.node, srcJson = insEntry.json
377
- let key = keyPath
378
- if (!key && srcNode.get && srcNode.get('name')) key = 'name'
379
- let cand, duplicate
380
- if (key) {
381
- const val = _getProperty(srcJson, key)
382
- cand = templateNode.items.find(i => YAML.isMap(i) && i.get(key) === val) || { [key]: val }
383
- duplicate = targetJSON.some(t => t?.[key] === val)
384
- } else {
385
- cand = templateNode.items.find(i => JSON.stringify(YAML.parse(String(i))) === JSON.stringify(YAML.parse(String(srcNode)))) || srcNode
386
- const srcObj = YAML.parse(String(cand))
387
- duplicate = targetJSON.some(t => JSON.stringify(t) === JSON.stringify(srcObj))
388
- }
389
- if (!duplicate) {
390
- const clone = YAML.parse(YAML.stringify(cand))
391
- targetNode.add(clone)
392
- targetJSON.push(clone)
393
- }
394
- }
211
+ // Deletions: remove the matched node (or a sub-key), then cascade-remove references to it.
212
+ for (const { item, key, relationships: refs } of deletions) {
213
+ const seq = locate(target, item.in)
214
+ const node = locate(target, item)
215
+ if (!YAML.isSeq(seq) || !node) continue
216
+ const removed = node.toJSON()
217
+ key ? node.deleteIn(path(key)) : seq.delete(seq.items.indexOf(node))
218
+ for (const { removeProperty, allWithin } of refs ?? []) {
219
+ const [parentPath, childPath, prop] = allWithin
220
+ for (const parent of locate(target, parentPath)?.items ?? []) {
221
+ const list = parent.getIn(path(childPath))
222
+ const i = list?.items?.findIndex(n => n.get?.(prop) === removed[removeProperty]) ?? -1
223
+ if (i > -1) list.delete(i)
395
224
  }
396
225
  }
397
- }, source.contents)
226
+ }
398
227
 
399
228
  typeof into === 'string' && await writeYAML(into, target)
400
229
  return target
@@ -471,39 +300,53 @@ module.exports.merge = (...src) => {
471
300
  }
472
301
 
473
302
 
303
+ /**
304
+ * A location in a document. One of:
305
+ * - a dotted key path from the root, e.g. `'modules'` or `'a.b.c'`;
306
+ * - a {@link MatchedNode}, i.e. the member of a collection satisfying a `where` predicate;
307
+ * - a based path `[base, keyPath?]` resolving `keyPath` relative to the node `base` denotes
308
+ * (with `keyPath` omitted, the pair denotes `base` itself).
309
+ * @typedef {string | MatchedNode | [Descriptor, string?]} Descriptor
310
+ */
311
+
474
312
  /**
475
313
  * @typedef {Object} MatchedNode
476
- * @property {string | MatchedNode} in - key path or matched node to start search from
477
- * @property {Object} where - list of constraints
314
+ * @property {Descriptor} in - the collection to search
315
+ * @property {Object.<string, (string | number | boolean | Array)>} where - constraints on the
316
+ * node's JSON projection; an array value requires each of its entries to be present
317
+ * @property {number} [at] - insertion index for additions (appended when omitted)
478
318
  */
479
319
 
480
320
  /**
481
321
  * @typedef {Object} Overwrites
482
- * @property {(string | MatchedNode)[]} item - path to item to be overwritten
483
- * @property {string} withValue - replacement string
322
+ * @property {Descriptor} item - location of the value to overwrite
323
+ * @property {string | number | boolean} withValue - replacement value
484
324
  */
485
325
 
486
326
  /**
487
327
  * @typedef {Object} Deletion
488
328
  * @property {MatchedNode} item - matched node to delete
489
- * @property {MatchedNode} [key] - key path to property to delete in node (optional)
490
- * @property {Object[]} [relationships] - list of relationships to delete
491
- * @property {string} relationships[].removeProperty - key path to to-be-removed property
492
- * @property {string[]} relationships[].allWithin - key path to relationship
329
+ * @property {string} [key] - dotted key path of a sub-property to delete instead of the whole node
330
+ * @property {Object[]} [relationships] - references to cascade-remove after deletion
331
+ * @property {string} relationships[].removeProperty - property of the removed node to match on
332
+ * @property {string[]} relationships[].allWithin - `[parentPath, childPath, prop]` naming the
333
+ * sibling collections and the referencing property to strip
493
334
  */
494
335
 
495
336
  /**
496
337
  * @typedef {Object} Relationship
497
- * @property {(string | MatchedNode)[]} insert - source path to matched node
498
- * @property {(string | MatchedNode)[]} into - target path for inserted relationship
338
+ * @property {Descriptor | Descriptor[] | [Descriptor, string]} insert - source node(s), or a
339
+ * `[entry, key]` pair whose `key` value is wired in
340
+ * @property {[Descriptor, string?, string?]} into - `[baseEntry, seqPath?, prop?]` naming the
341
+ * target sequence and, optionally, the property key the wired value is written under
499
342
  */
500
343
 
501
344
  /**
502
345
  * @typedef {Object} MergingSemantics
503
- * @property {boolean} [forceOverwrite] - overwrite values for existing keys
504
- * @property {MatchedNode[]} [additions] - matched nodes to be added from source template
505
- * @property {Overwrites[]} [overwrites] - matched keys to be overwritten with given string
506
- * @property {Deletion[]} [deletions] - matched nodes to be deleted
507
- * @property {Relationship[]} [relationships] - relationships to be inserted
346
+ * @property {boolean} [forceOverwrite] - overwrite existing scalar values from the template
347
+ * @property {MatchedNode[]} [additions] - matched nodes to add from the source template
348
+ * @property {Overwrites[]} [overwrites] - values to overwrite at the given locations
349
+ * @property {Deletion[]} [deletions] - matched nodes (or sub-keys) to delete
350
+ * @property {Relationship[]} [relationships] - relationships to wire into target sequences
508
351
  */
509
352