@sap/cds-dk 10.0.7 → 10.1.1

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 (341) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/bin/add.js +7 -23
  3. package/bin/bind.js +14 -0
  4. package/bin/build.js +21 -34
  5. package/bin/cds.js +1 -1
  6. package/bin/compile/index.js +16 -41
  7. package/bin/completion/completionFs.js +11 -8
  8. package/bin/completion/index.js +603 -80
  9. package/bin/completion/scripts/cds.fish +620 -0
  10. package/bin/completion/scripts/cds.ps1 +403 -0
  11. package/bin/completion/scripts/cds.sh +327 -0
  12. package/bin/completion/scripts/cds.zsh +296 -0
  13. package/bin/completion/templates/cds-tmpl.fish +65 -0
  14. package/bin/completion/templates/cds-tmpl.ps1 +217 -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 +11 -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/env.js +4 -1
  25. package/bin/export.js +44 -6
  26. package/bin/help/export.md +3 -0
  27. package/bin/help.js +1 -5
  28. package/bin/import.js +9 -0
  29. package/bin/init.js +6 -24
  30. package/bin/inspect.js +8 -0
  31. package/bin/lint.js +5 -3
  32. package/bin/login.js +26 -20
  33. package/bin/minify.js +6 -1
  34. package/bin/pull.js +19 -6
  35. package/bin/push.js +19 -6
  36. package/bin/repl.js +11 -2
  37. package/bin/run.js +12 -1
  38. package/bin/serve.js +13 -2
  39. package/bin/up.js +17 -11
  40. package/{lib → bin}/upgrade/constants.js +1 -1
  41. package/bin/{upgrade.js → upgrade/index.js} +2 -2
  42. package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
  43. package/{lib → bin}/upgrade/preflight/index.js +1 -1
  44. package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
  45. package/{lib → bin}/upgrade/steps/install.js +1 -1
  46. package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
  47. package/{lib → bin}/upgrade/steps/removals.js +1 -1
  48. package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
  49. package/{lib → bin}/upgrade/steps/verify.js +1 -1
  50. package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
  51. package/{lib → bin}/upgrade/util/pom.js +2 -2
  52. package/{lib → bin}/upgrade/util/prompt.js +1 -1
  53. package/bin/util/containerize.js +10 -4
  54. package/bin/version.js +10 -1
  55. package/{lib → bin}/watch/hot-reload.js +1 -1
  56. package/bin/{watch.js → watch/index.js} +24 -9
  57. package/{lib → bin}/watch/livereload-connect.js +1 -1
  58. package/{lib → bin}/watch/vite-watch.js +1 -1
  59. package/{lib → bin}/watch/watched.js +2 -2
  60. package/lib/build/constants.js +1 -1
  61. package/lib/build/plugins/fiori/index.js +31 -2
  62. package/lib/build/plugins/internal.js +4 -2
  63. package/lib/build/plugins/mtx-sidecar/index.js +7 -8
  64. package/lib/build/plugins/nodejs/index.js +64 -7
  65. package/lib/build/util.js +2 -4
  66. package/lib/compile/to_asyncapi.js +1 -1
  67. package/lib/env/schema.js +16 -0
  68. package/lib/env/schemas/cds-rc.js +1 -76
  69. package/lib/import/importapi.js +2 -3
  70. package/lib/import/message.js +0 -2
  71. package/lib/init/constants.js +2 -1
  72. package/lib/init/index.js +2 -2
  73. package/lib/init/merge.js +123 -280
  74. package/lib/init/plugin.js +3 -1
  75. package/lib/init/projectReader.js +22 -6
  76. package/lib/init/registries/xs-app.js +3 -5
  77. package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
  78. package/lib/init/template/ai/index.js +14 -2
  79. package/lib/init/template/ams/index.js +2 -2
  80. package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
  81. package/lib/init/template/app-frontend/index.js +4 -4
  82. package/lib/init/template/application-logging/index.js +2 -2
  83. package/lib/init/template/approuter/files/package.json +1 -1
  84. package/lib/init/template/approuter/index.js +8 -3
  85. package/lib/init/template/attachments/files/package.json.hbs +1 -1
  86. package/lib/init/template/attachments/index.js +2 -2
  87. package/lib/init/template/audit-logging/index.js +2 -2
  88. package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
  89. package/lib/init/template/cloud-logging/index.js +2 -2
  90. package/lib/init/template/completion/completionSetup.js +36 -39
  91. package/lib/init/template/connectivity/index.js +2 -2
  92. package/lib/init/template/data/as-csv.js +15 -5
  93. package/lib/init/template/data/as-json.js +117 -42
  94. package/lib/init/template/data/index.js +16 -2
  95. package/lib/init/template/destination/index.js +2 -2
  96. package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
  97. package/lib/init/template/dynatrace/index.js +2 -2
  98. package/lib/init/template/enterprise-messaging/index.js +2 -2
  99. package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
  100. package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
  101. package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
  102. package/lib/init/template/extensibility/index.js +3 -3
  103. package/lib/init/template/github-actions/index.js +2 -2
  104. package/lib/init/template/hana/index.js +3 -2
  105. package/lib/init/template/hana-serverless/files/db/package.json +14 -0
  106. package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
  107. package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
  108. package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
  109. package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
  110. package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
  111. package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
  112. package/lib/init/template/hana-serverless/index.js +184 -0
  113. package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
  114. package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
  115. package/lib/init/template/html5-repo/index.js +18 -14
  116. package/lib/init/template/http/index.js +123 -26
  117. package/lib/init/template/ias/index.js +2 -2
  118. package/lib/init/template/kafka/index.js +2 -2
  119. package/lib/init/template/kyma/index.js +7 -5
  120. package/lib/init/template/malware-scanner/index.js +2 -2
  121. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  122. package/lib/init/template/multitenancy/index.js +18 -3
  123. package/lib/init/template/notifications/index.js +2 -2
  124. package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
  125. package/lib/init/template/portal/index.js +13 -8
  126. package/lib/init/template/postgres/index.js +2 -2
  127. package/lib/init/template/redis/index.js +2 -2
  128. package/lib/init/template/sample/files/db/currencies.cds +2 -0
  129. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
  130. package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
  131. package/lib/init/template/workzone-standard/index.js +5 -5
  132. package/lib/init/template/xsuaa/index.js +20 -2
  133. package/lib/lint/eslintHelp.json +1 -1
  134. package/lib/mtx/auth_manager.js +103 -37
  135. package/lib/mtx/params.js +3 -2
  136. package/lib/mtx/settings_manager.js +45 -28
  137. package/lib/mtx/tenant_action.js +0 -1
  138. package/lib/mtx/util/credentials.js +62 -0
  139. package/node_modules/@cap-js/db-service/CHANGELOG.md +17 -0
  140. package/node_modules/@cap-js/db-service/lib/common/generic-pool.js +4 -7
  141. package/node_modules/@cap-js/db-service/lib/cqn2pql.js +1 -1
  142. package/node_modules/@cap-js/db-service/lib/cqn2sql.js +15 -11
  143. package/node_modules/@cap-js/db-service/lib/cqn4sql.js +119 -19
  144. package/node_modules/@cap-js/db-service/lib/infer/index.js +27 -16
  145. package/node_modules/@cap-js/db-service/lib/recursion-guard.js +40 -0
  146. package/node_modules/@cap-js/db-service/lib/search.js +1 -1
  147. package/node_modules/@cap-js/db-service/package.json +1 -1
  148. package/node_modules/@cap-js/sqlite/CHANGELOG.md +19 -0
  149. package/node_modules/@cap-js/sqlite/lib/SQLiteService.js +110 -14
  150. package/node_modules/@cap-js/sqlite/package.json +3 -3
  151. package/node_modules/@sap/cds/CHANGELOG.md +57 -0
  152. package/node_modules/@sap/cds/app/index.js +5 -4
  153. package/node_modules/@sap/cds/eslint.config.mjs +1 -0
  154. package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
  155. package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
  156. package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
  157. package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
  158. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
  159. package/node_modules/@sap/cds/lib/plugins.js +9 -5
  160. package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
  161. package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
  162. package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
  163. package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
  164. package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
  165. package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
  166. package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
  167. package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
  168. package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
  169. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
  170. package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
  171. package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
  172. package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
  173. package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
  174. package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
  175. package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
  176. package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
  177. package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
  178. package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
  179. package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
  180. package/node_modules/@sap/cds/libx/http/location.js +3 -3
  181. package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
  182. package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
  183. package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
  184. package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
  185. package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
  186. package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
  187. package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
  188. package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
  189. package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
  190. package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
  191. package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
  192. package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
  193. package/node_modules/@sap/cds/package.json +1 -1
  194. package/node_modules/@sap/cds-compiler/CHANGELOG.md +75 -8
  195. package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
  196. package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
  197. package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
  198. package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
  199. package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
  200. package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
  201. package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
  202. package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
  203. package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
  204. package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
  205. package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
  206. package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
  207. package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
  208. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
  209. package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
  210. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +48 -18
  211. package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
  212. package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
  213. package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
  214. package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
  215. package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
  216. package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
  217. package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
  218. package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
  219. package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
  220. package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
  221. package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
  222. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +4 -0
  223. package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
  224. package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
  225. package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
  226. package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
  227. package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
  228. package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
  229. package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
  230. package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
  231. package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +15 -0
  232. package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +10 -2
  233. package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
  234. package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
  235. package/node_modules/@sap/cds-compiler/lib/transform/db/flattening.js +4 -3
  236. package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
  237. package/node_modules/@sap/cds-compiler/lib/transform/effective/flattening.js +17 -1
  238. package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +20 -0
  239. package/node_modules/@sap/cds-compiler/lib/transform/fioriTreeViews.js +12 -1
  240. package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +7 -2
  241. package/node_modules/@sap/cds-compiler/lib/transform/odata/adaptAnnotationRefs.js +11 -5
  242. package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +48 -10
  243. package/node_modules/@sap/cds-compiler/package.json +1 -1
  244. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +49 -0
  245. package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +26 -5
  246. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +37 -16
  247. package/node_modules/@sap/cds-mtxs/lib/utils.js +23 -7
  248. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  249. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +63 -8
  250. package/node_modules/@sap/cds-mtxs/srv/cf/saas-provisioning-service.js +1 -1
  251. package/node_modules/@sap/cds-mtxs/srv/cf/sms-provisioning-service.js +23 -3
  252. package/node_modules/@sap/cds-mtxs/srv/extensibility/compat/update.js +15 -0
  253. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +2 -2
  254. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/config.js +2 -0
  255. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +2 -0
  256. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/protected-namespace.js +45 -0
  257. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +30 -16
  258. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +49 -10
  259. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +28 -4
  260. package/node_modules/@sap/cds-mtxs/srv/plugins/common.js +19 -12
  261. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
  262. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr.js +6 -3
  263. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/serverless.js +271 -0
  264. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +7 -10
  265. package/node_modules/@sap/cds-mtxs/srv/worker/job-worker-pool.js +212 -0
  266. package/node_modules/@sap/cds-mtxs/srv/worker/job-worker.js +61 -0
  267. package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
  268. package/node_modules/@sap/xsenv/package.json +10 -7
  269. package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  270. package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  271. package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  272. package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  273. package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  274. package/node_modules/hdb/cfg/VERSION +1 -1
  275. package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
  276. package/node_modules/hdb/lib/protocol/Connection.js +1 -0
  277. package/node_modules/hdb/package.json +3 -2
  278. package/node_modules/negotiator/lib/accept.js +54 -0
  279. package/node_modules/negotiator/lib/charset.js +10 -34
  280. package/node_modules/negotiator/lib/encoding.js +9 -30
  281. package/node_modules/negotiator/lib/language.js +15 -36
  282. package/node_modules/negotiator/lib/mediaType.js +16 -134
  283. package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  284. package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  285. package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  286. package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  287. package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  288. package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  289. package/node_modules/negotiator/package.json +16 -10
  290. package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
  291. package/node_modules/qs/CHANGELOG.md +15 -0
  292. package/node_modules/qs/README.md +19 -1
  293. package/node_modules/qs/dist/qs.js +21 -21
  294. package/node_modules/qs/eslint.config.mjs +1 -1
  295. package/node_modules/qs/lib/parse.js +3 -4
  296. package/node_modules/qs/lib/stringify.js +23 -8
  297. package/node_modules/qs/lib/utils.js +10 -3
  298. package/node_modules/qs/package.json +4 -4
  299. package/node_modules/qs/test/parse.js +192 -3
  300. package/node_modules/qs/test/stringify.js +317 -0
  301. package/node_modules/qs/test/utils.js +12 -0
  302. package/node_modules/type-is/node_modules/content-type/README.md +2 -0
  303. package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  304. package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  305. package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  306. package/node_modules/type-is/node_modules/content-type/package.json +1 -1
  307. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  308. package/node_modules/ws/package.json +1 -1
  309. package/package.json +2 -2
  310. package/bin/completion/scripts/cds-bash.sh +0 -20
  311. package/bin/completion/scripts/cds-fish.fish +0 -13
  312. package/bin/completion/scripts/cds-ps.ps1 +0 -19
  313. package/bin/completion/scripts/cds-zsh.sh +0 -13
  314. package/lib/deploy/index.js +0 -25
  315. package/lib/import/asyncapi/importAsyncAPI.js +0 -33
  316. package/lib/import/asyncapi/index.js +0 -18
  317. package/lib/import/asyncapi/parserContext.js +0 -454
  318. package/lib/import/asyncapi/utils.js +0 -49
  319. package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
  320. package/node_modules/negotiator/HISTORY.md +0 -114
  321. /package/{lib → bin}/upgrade/context.js +0 -0
  322. /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
  323. /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
  324. /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
  325. /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
  326. /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
  327. /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
  328. /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
  329. /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
  330. /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
  331. /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
  332. /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
  333. /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
  334. /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
  335. /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
  336. /package/{lib → bin}/watch/livereload-server.js +0 -0
  337. /package/{lib → bin}/watch/node-watch.js +0 -0
  338. /package/{lib → bin}/watch/open.js +0 -0
  339. /package/{lib → bin}/watch/watcher.js +0 -0
  340. /package/node_modules/@sap/cds-mtxs/srv/worker/{pool.js → model-worker-pool.js} +0 -0
  341. /package/node_modules/@sap/cds-mtxs/srv/worker/{load.js → model-worker.js} +0 -0
@@ -1,15 +1,31 @@
1
+ const fs = require('node:fs');
1
2
  const path = require('node:path');
2
3
 
3
4
  const cds = require('../../bin/cds');
4
5
  const { bold } = require('../../lib/util/term');
6
+ const completionFs = require('./completionFs');
7
+ const completionSetup = require('../../lib/init/template/completion/completionSetup');
5
8
 
9
+ // Sentinel factories — returned by staticCompletions() to mark special argument types.
10
+ const FILE = (exts, { dirs } = {}) => exts ? { type: ':file', ext: exts.split(',').map(e => e.trim()), dirs: dirs ?? false } : ':file';
11
+ const DIR = () => ':dir';
12
+ const COMMA = (values) => ({ type: ':comma', values });
6
13
 
14
+ // The '_' key in a staticCompletions map marks the default positional argument.
15
+ const POSITIONAL_KEY = '_';
16
+
17
+ const isFileSentinel = s => s === ':file' || s === ':dir' || (s?.type === ':file' && Array.isArray(s.ext));
18
+ const fileRegex = s => s.ext ? new RegExp(`\\.(${s.ext.join('|')})$`) : null;
19
+ const filePs1 = s => s.ext ? (s.dirs ? `':file+dir:${s.ext.join(',')}'` : `':file:${s.ext.join(',')}'`) : `'${s}'`;
7
20
 
8
21
  module.exports = Object.assign(completion, {
9
- handleCompletion,
22
+ staticCompletions: () => ({ '--shell': completionSetup.supportedShells }),
23
+ FILE,
24
+ DIR,
25
+ COMMA,
10
26
  options: ['--shell', '--curr', '--line', '--prev'],
11
27
  shortcuts: ['-s'],
12
- flags: ['--add', '--profile', '--remove'],
28
+ flags: ['--add', '--profile', '--generate', '--remove'],
13
29
  help: `
14
30
  # SYNOPSIS
15
31
 
@@ -41,6 +57,13 @@ module.exports = Object.assign(completion, {
41
57
  *--remove*
42
58
  Remove shell completion for cds commands (see examples).
43
59
 
60
+ *--profile* _(deprecated)_
61
+ Print the path to the completion script for the given shell.
62
+
63
+ *--generate*
64
+ Generate a static completion script for the given shell and print it to stdout.
65
+ Used by 'npm run build:completion' to pre-build the bundled cache files.
66
+
44
67
  *--shell* <bash | fish | gitbash | ps | zsh>
45
68
  Force the shell completion code to be added to the correct shell profile file.
46
69
  bash: macOS, Linux, WSL
@@ -65,22 +88,13 @@ module.exports = Object.assign(completion, {
65
88
  function getScriptFile(shell) {
66
89
  switch (shell) {
67
90
  case 'bash':
68
- case 'gitbash':
69
- return 'cds-bash.sh';
70
- case 'fish':
71
- return 'cds-fish.fish';
72
- case 'ps':
73
- return 'cds-ps.ps1';
74
- case 'zsh':
75
- return 'cds-zsh.sh';
76
- case '':
77
- case undefined:
78
- case null:
79
- throw 'Internal error: option --shell is missing';
80
- default: {
81
- const completionSetup = require('../../lib/init/template/completion/completionSetup');
91
+ case 'gitbash': return 'cds.sh';
92
+ case 'fish': return 'cds.fish';
93
+ case 'ps': return 'cds.ps1';
94
+ case 'zsh': return 'cds.zsh';
95
+ default:
96
+ if (!shell) throw 'Internal error: option --shell is missing';
82
97
  throw `Internal error: unsupported shell: ${shell}, supported shells are ${completionSetup.supportedShells.join(', ')}`;
83
- }
84
98
  }
85
99
  }
86
100
 
@@ -90,7 +104,24 @@ async function completion(_argv, options) {
90
104
  return console.log(path.join(__dirname, 'scripts', scriptFile));
91
105
  }
92
106
 
93
- const completionSetup = require('../../lib/init/template/completion/completionSetup');
107
+ if (options.generate) {
108
+ if (options.shell) {
109
+ const content = await generateStaticScript(options.shell);
110
+ return content ? process.stdout.write(content) : undefined;
111
+ }
112
+ const shells = { sh: 'bash', zsh: 'zsh', fish: 'fish', ps1: 'ps' };
113
+ const scriptsDir = path.join(__dirname, 'scripts');
114
+ fs.mkdirSync(scriptsDir, { recursive: true });
115
+ for (const [ext, shell] of Object.entries(shells)) {
116
+ const content = await generateStaticScript(shell);
117
+ if (content) {
118
+ fs.writeFileSync(path.join(scriptsDir, `cds.${ext}`), content);
119
+ console.log(`Generated cds.${ext}`);
120
+ }
121
+ }
122
+ return;
123
+ }
124
+
94
125
  if (options.add || options.remove) {
95
126
  await completionSetup.setup(options.add, options);
96
127
  return;
@@ -113,124 +144,616 @@ async function completion(_argv, options) {
113
144
  throw `internal Error: no completion handler found for shell type: ${shell}, supported shells are ${completionSetup.supportedShells.join(', ')}`;
114
145
  }
115
146
 
116
- const currentWord = localOptions.curr?.trim().replace(/^'|'$/g, '');
147
+ const currentWord = localOptions.curr?.trim().replace(/^'|'$/g, '');
117
148
  const previousWord = localOptions.prev?.trim().replace(/^'|'$/g, '');
118
- const line = localOptions.line?.trim().replace(/^'|'$/g, '');
119
- const segments = getSegments(line);
120
- const cdsCmd = segments[1] || '';
149
+ const line = localOptions.line?.trim().replace(/^'|'$/g, '');
150
+ const segments = getSegments(line);
151
+ const cdsCmd = segments[1] || '';
121
152
 
122
153
  const completions = await getCompletions(cdsCmd, previousWord, currentWord, segments);
123
154
  reply(completions);
124
155
  }
125
156
 
126
- async function handleCompletion(currentWord, previousWord, argv) {
127
- const allOptionsFlags = ['--add', '--remove', '--shell']
128
- .filter(e => !argv.includes(e));
157
+ async function buildCompletionMap() {
158
+ const commands = cds.cmds ?? [];
159
+ const commandMap = {};
160
+ for (const cmd of commands) {
161
+ try {
162
+ const obj = cds.load(cmd);
163
+ const raw = await obj.staticCompletions?.() ?? [];
164
+ let positionals = [], optionValues = {}, fileCases = {}, commaCases = {};
165
+ if (Array.isArray(raw)) {
166
+ positionals = raw;
167
+ } else {
168
+ for (const [key, val] of Object.entries(raw)) {
169
+ const resolved = await val;
170
+ if (resolved?.type === ':comma') {
171
+ commaCases[key] = await resolved.values;
172
+ } else if (isFileSentinel(resolved)) {
173
+ fileCases[key] = resolved;
174
+ } else {
175
+ optionValues[key] = resolved;
176
+ }
177
+ }
178
+ }
179
+ commandMap[cmd] = {
180
+ options: (obj.options ?? []).filter(Boolean),
181
+ flags: (obj.flags ?? []).filter(Boolean),
182
+ shortcuts: (obj.shortcuts ?? []).filter(Boolean),
183
+ positionals,
184
+ optionValues,
185
+ fileCases,
186
+ commaCases,
187
+ };
188
+ } catch (e) { cds.debug?.('completion')?.(`skipping command '${cmd}': ${e?.message ?? e}`); }
189
+ }
190
+ return { commands, shortcuts: cds.Shortcuts, commandMap };
191
+ }
129
192
 
130
- if (currentWord?.startsWith('-')) {
131
- return allOptionsFlags;
193
+ async function generateStaticScript(shell) {
194
+ const map = await buildCompletionMap();
195
+ switch (shell) {
196
+ case 'bash':
197
+ case 'gitbash': return generateBash(map);
198
+ case 'zsh': return generateZsh(map);
199
+ case 'fish': return generateFish(map);
200
+ case 'ps': return generatePs(map);
201
+ default:
202
+ throw `Internal error: unsupported shell: ${shell}`;
132
203
  }
204
+ }
205
+
206
+ // --- Code generation helpers ---
207
+
208
+ // Serialises an array of strings for embedding in a shell word-list (e.g. compgen -W "...").
209
+ function shellQuoteList(arr) {
210
+ return arr.map(s => JSON.stringify(s)).join(' ');
211
+ }
212
+
213
+ // Returns the single-char shortcuts from the global shortcuts map.
214
+ function singleCharShortcuts(shortcuts) {
215
+ return Object.entries(shortcuts).filter(([k]) => /^[a-z]$/.test(k));
216
+ }
217
+
218
+ // Returns the merged, deduplicated, sorted list of all flags/options for a command.
219
+ function sortedFlags(e) {
220
+ return [...new Set([...e.options, ...e.flags])].sort();
221
+ }
222
+
223
+ // Generates the bash/zsh case block that resolves single-char shortcuts to canonical names.
224
+ function shortcutCaseBlock(shortcuts, indent = ' ') {
225
+ const entries = singleCharShortcuts(shortcuts)
226
+ .map(([k, v]) => `${indent} ${k}) cmd=${v} ;;`)
227
+ .join('\n');
228
+ if (!entries) return '';
229
+ return `${indent}case "$cmd" in\n${entries}\n${indent}esac\n`;
230
+ }
231
+
232
+ // Bash: expression that completes to files matching a sentinel's extensions.
233
+ function bashFileExpr(sentinel) {
234
+ if (!sentinel.ext) return 'compgen -f -- "$current"';
235
+ const files = `compgen -f -- "$current" | grep -E '\\.(${sentinel.ext.join('|')})$'`;
236
+ if (!sentinel.dirs) return files;
237
+ return `{ ${files}; compgen -d -- "$current"; }`;
238
+ }
239
+
240
+ // Zsh: compadd call that completes to files matching a sentinel's extensions.
241
+ // _path_files is used instead of _files to avoid the '*:all-files' fallback tier
242
+ // that _files always appends, which would show every file type regardless of the glob.
243
+ // Multiple extensions are passed as space-separated patterns in one -g argument
244
+ // (e.g. '*.cds *.json') — _path_files word-splits the value, no extendedglob needed.
245
+ function zshFileComp(sentinel) {
246
+ if (!sentinel.ext) return '_path_files';
247
+ const glob = sentinel.ext.map(e => `*.${e}`).join(' ');
248
+ if (!sentinel.dirs) return `_path_files -g '${glob}'`;
249
+ return `_path_files -g '${glob}' -/`;
250
+ }
251
+
252
+ // Fish: expression that completes to files matching a sentinel's extensions.
253
+ function fishFileComp(sentinel) {
254
+ if (!sentinel.ext) return '__fish_complete_path';
255
+ const files = `string match -r '\\.(${sentinel.ext.join('|')})\\$' -- (__fish_complete_path)`;
256
+ if (!sentinel.dirs) return files;
257
+ return `${files}; __fish_complete_directories`;
258
+ }
259
+
260
+ // Reads a shell template and substitutes {{PLACEHOLDER}} tokens.
261
+ // Note: replacement strings go through String.replaceAll, so '$' must be doubled
262
+ // ('$$$$' → '$$' → '$') to prevent JS from interpreting '$1' etc. as back-references.
263
+ async function applyTemplate(templateFile, replacements) {
264
+ const tmpl = await fs.promises.readFile(path.join(__dirname, 'templates', templateFile), 'utf8');
265
+ return Object.entries(replacements).reduce(
266
+ (s, [k, v]) => s.replaceAll(`{{${k}}}`, v.replaceAll('$', '$$$$')),
267
+ tmpl
268
+ );
269
+ }
270
+
271
+ // --- Per-shell case-block generators ---
272
+
273
+ // Bash/zsh: option-value completions (previous word is a known flag → offer its values).
274
+ function optionValueCases(commandMap, emitLine) {
275
+ return Object.entries(commandMap)
276
+ .map(([cmd, e]) => {
277
+ const innerLines = [];
278
+ for (const [flag, val] of Object.entries(e.optionValues ?? {})) {
279
+ innerLines.push(emitLine(flag, val, null));
280
+ }
281
+ for (const [flag, sentinel] of Object.entries(e.fileCases ?? {})) {
282
+ if (flag === POSITIONAL_KEY) continue;
283
+ innerLines.push(emitLine(flag, null, sentinel));
284
+ }
285
+ if (!innerLines.length) return '';
286
+ return ` ${cmd})\n case "$previous" in\n${innerLines.join('\n')}\n esac ;;\n`;
287
+ })
288
+ .filter(Boolean)
289
+ .join('');
290
+ }
291
+
292
+ function bashOptionValueCases(commandMap) {
293
+ return optionValueCases(commandMap, (flag, val, sentinel) => {
294
+ const expr = sentinel
295
+ ? (sentinel === DIR() ? 'compgen -d -- "$current"' : bashFileExpr(sentinel))
296
+ : `compgen -W "${shellQuoteList(val)}" -- "$current"`;
297
+ return ` ${flag}) COMPREPLY=( $(${expr}) ) ; return 0 ;;`;
298
+ });
299
+ }
300
+
301
+ function zshOptionValueCases(commandMap) {
302
+ return optionValueCases(commandMap, (flag, val, sentinel) => {
303
+ const comp = sentinel
304
+ ? (sentinel === DIR() ? '_files -/' : zshFileComp(sentinel))
305
+ : `compadd -S '' -- ${shellQuoteList([...val].sort())}`;
306
+ const prefix = sentinel ? `compstate[nomatches]='' ; ` : '';
307
+ return ` ${flag}) ${prefix}${comp} ; return ;;`;
308
+ });
309
+ }
310
+
311
+ // Bash/zsh: comma-separated option completions.
312
+ // Entries keyed by POSITIONAL_KEY match any previous word (when user didn't type a flag);
313
+ // a guard skips them if the previous word is itself a flag (consuming an option value).
314
+ function bashCommaCases(commandMap) {
315
+ const S = '$'; // prevent JS template literal from interpolating shell variables
316
+ return Object.entries(commandMap)
317
+ .map(([cmd, e]) => {
318
+ // Sort so POSITIONAL_KEY ('_') entries come last — they use a catch-all pattern.
319
+ const entries = Object.entries(e.commaCases ?? {}).sort(([a], [b]) =>
320
+ a === POSITIONAL_KEY ? 1 : b === POSITIONAL_KEY ? -1 : 0
321
+ );
322
+ if (!entries.length) return '';
323
+ const innerLines = entries.map(([flag, val]) => {
324
+ const list = shellQuoteList(val);
325
+ const pattern = flag === POSITIONAL_KEY ? '*' : flag;
326
+ // For positional entries: skip if previous word looks like a flag (it's consuming a value).
327
+ const guard = flag === POSITIONAL_KEY
328
+ ? ` [[ "$previous" == -* ]] && return 0\n`
329
+ : '';
330
+ const body = [
331
+ guard + ` local prefix="" partial="" IFS=,`,
332
+ ` if [[ "$current" == *,* ]]; then`,
333
+ ` prefix="` + S + `{current%,*},"`,
334
+ ` partial="` + S + `{current##*,}"`,
335
+ ` else`,
336
+ ` partial="$current"`,
337
+ ` fi`,
338
+ ` local -a _used`,
339
+ ` read -ra _used <<< "` + S + `{prefix%,}"`,
340
+ ` local _all=(${list})`,
341
+ ` for v in "` + S + `{_all[@]}"; do`,
342
+ ` [[ " ` + S + `{_used[*]} " == *" $v "* ]] && continue`,
343
+ ` [[ "$v" == "$partial"* ]] && COMPREPLY+=("$prefix$v")`,
344
+ ` done`,
345
+ ` [[ ` + S + `{#COMPREPLY[@]} -gt 0 ]] && { compopt -o nospace; return 0; } ;;`,
346
+ ].join('\n');
347
+ return ` ${pattern})\n${body}`;
348
+ });
349
+ return ` ${cmd})\n case "$previous" in\n${innerLines.join('\n')}\n esac ;;\n`;
350
+ })
351
+ .filter(Boolean)
352
+ .join('');
353
+ }
354
+
355
+ function zshCommaCases(commandMap) {
356
+ const S = '$'; // prevent JS template literal from interpolating shell variables
357
+ return Object.entries(commandMap)
358
+ .map(([cmd, e]) => {
359
+ const entries = Object.entries(e.commaCases ?? {}).sort(([a], [b]) =>
360
+ a === POSITIONAL_KEY ? 1 : b === POSITIONAL_KEY ? -1 : 0
361
+ );
362
+ if (!entries.length) return '';
363
+ const innerLines = entries.map(([flag, val]) => {
364
+ const list = shellQuoteList(val);
365
+ const pattern = flag === POSITIONAL_KEY ? `*)` : `${flag})`;
366
+ // For positional entries: skip if previous word looks like a flag (it's consuming a value).
367
+ const guard = flag === POSITIONAL_KEY
368
+ ? ` [[ "$previous" == -* ]] && return\n`
369
+ : '';
370
+ const body = [
371
+ guard + ` local -a _used=("` + S + `{(s:,:)current}")`,
372
+ ` local prefix="` + S + `{(j:,:)_used[1,-2]}" partial="` + S + `{_used[-1]}"`,
373
+ ` [[ -n "$prefix" ]] && prefix="$prefix,"`,
374
+ ` local -a _all=(${list}) _result=()`,
375
+ ` for v in "` + S + `{_all[@]}"; do`,
376
+ ` (( ` + S + `{_used[(Ie)$v]} )) && continue`,
377
+ ` [[ "$v" == "$partial"* ]] && _result+=("$v")`,
378
+ ` done`,
379
+ ` compadd -p "$prefix" -S '' -- "` + S + `{_result[@]}" ; return ;;`,
380
+ ].join('\n');
381
+ return ` ${pattern}\n${body}`;
382
+ });
383
+ return ` ${cmd})\n case "$previous" in\n${innerLines.join('\n')}\n esac ;;\n`;
384
+ })
385
+ .filter(Boolean)
386
+ .join('');
387
+ }
133
388
 
134
- if (previousWord === '--shell') {
135
- const { supportedShells } = require('../../lib/init/template/completion/completionSetup');
136
- return supportedShells;
389
+ // --- Static script generators ---
390
+
391
+ async function generateBash(map) {
392
+ const { commands, shortcuts, commandMap } = map;
393
+
394
+ const flagCases = Object.entries(commandMap)
395
+ .map(([cmd, e]) => {
396
+ const flags = sortedFlags(e);
397
+ if (!flags.length) return '';
398
+ return ` ${cmd}) COMPREPLY=( $(compgen -W "${shellQuoteList(flags)}" -- "$current") ) ;;`;
399
+ })
400
+ .filter(Boolean)
401
+ .join('\n');
402
+
403
+ const fileCases = Object.entries(commandMap)
404
+ .map(([cmd, e]) => {
405
+ const sentinel = e.fileCases?.[POSITIONAL_KEY];
406
+ if (!sentinel) return '';
407
+ const expr = sentinel === DIR() ? 'compgen -d -- "$current"' : bashFileExpr(sentinel);
408
+ return ` ${cmd}) COMPREPLY=( $(${expr}) ) ;;`;
409
+ })
410
+ .filter(Boolean)
411
+ .join('\n');
412
+
413
+ const stringPositionalCases = Object.entries(commandMap)
414
+ .map(([cmd, e]) => {
415
+ if (e.fileCases?.[POSITIONAL_KEY] || !e.positionals?.length) return '';
416
+ return ` ${cmd}) COMPREPLY=( $(compgen -W "${shellQuoteList([...e.positionals].sort())}" -- "$current") ) ;;`;
417
+ })
418
+ .filter(Boolean)
419
+ .join('\n');
420
+
421
+ return applyTemplate('cds-tmpl.sh', {
422
+ SHORTCUT_CASE: shortcutCaseBlock(shortcuts),
423
+ COMMANDS: shellQuoteList(commands),
424
+ FLAG_CASES: flagCases,
425
+ OPTION_VALUE_CASES: bashOptionValueCases(commandMap),
426
+ COMMA_CASES: bashCommaCases(commandMap),
427
+ FILE_CASES: fileCases,
428
+ STRING_POSITIONAL_CASES: stringPositionalCases,
429
+ });
430
+ }
431
+
432
+ async function generateZsh(map) {
433
+ const { commands, shortcuts, commandMap } = map;
434
+
435
+ const flagCases = Object.entries(commandMap)
436
+ .map(([cmd, e]) => {
437
+ const flags = sortedFlags(e);
438
+ if (!flags.length) return '';
439
+ return ` ${cmd}) compadd -S '' -- ${shellQuoteList(flags)} ;;`;
440
+ })
441
+ .filter(Boolean)
442
+ .join('\n');
443
+
444
+ const fileCases = Object.entries(commandMap)
445
+ .map(([cmd, e]) => {
446
+ const sentinel = e.fileCases?.[POSITIONAL_KEY];
447
+ if (!sentinel) return '';
448
+ const comp = sentinel === DIR() ? '_files -/' : zshFileComp(sentinel);
449
+ return ` ${cmd}) compstate[nomatches]='' ; ${comp} ; return ;;`;
450
+ })
451
+ .filter(Boolean)
452
+ .join('\n');
453
+
454
+ const stringPositionalCases = Object.entries(commandMap)
455
+ .map(([cmd, e]) => {
456
+ if (e.fileCases?.[POSITIONAL_KEY] || !e.positionals?.length) return '';
457
+ return ` ${cmd}) compadd -S '' -- ${shellQuoteList([...e.positionals].sort())} ; return ;;`;
458
+ })
459
+ .filter(Boolean)
460
+ .join('\n');
461
+
462
+ return applyTemplate('cds-tmpl.zsh', {
463
+ SHORTCUT_CASE: shortcutCaseBlock(shortcuts),
464
+ COMMANDS: shellQuoteList(commands),
465
+ FLAG_CASES: flagCases,
466
+ OPTION_VALUE_CASES: zshOptionValueCases(commandMap),
467
+ COMMA_CASES: zshCommaCases(commandMap),
468
+ FILE_CASES: fileCases,
469
+ STRING_POSITIONAL_CASES: stringPositionalCases,
470
+ });
471
+ }
472
+
473
+ async function generateFish(map) {
474
+ const { commands, shortcuts, commandMap } = map;
475
+
476
+ // Reverse map: canonical command name → its single-char shortcut(s).
477
+ const cmdShortcuts = {};
478
+ for (const [shortcut, cmd] of singleCharShortcuts(shortcuts)) {
479
+ (cmdShortcuts[cmd] ??= []).push(shortcut);
480
+ }
481
+
482
+ // Fish condition: fires when the subcommand (or one of its shortcuts) is already on the line.
483
+ const seenCmd = (cmd) =>
484
+ `__fish_seen_subcommand_from ${[cmd, ...(cmdShortcuts[cmd] ?? [])].join(' ')}`;
485
+
486
+ const allCmdsAndShortcuts = [
487
+ ...commands,
488
+ ...singleCharShortcuts(shortcuts).map(([k]) => k),
489
+ ].join(' ');
490
+
491
+ const lines = [];
492
+
493
+ // Top-level commands — only shown before any subcommand is committed.
494
+ for (const cmd of commands) {
495
+ lines.push(`complete -c cds -f -n '__fish_use_subcommand' -a '${cmd}'`);
496
+ }
497
+
498
+ for (const [cmd, e] of Object.entries(commandMap)) {
499
+ const hasFileSentinel = !!e.fileCases?.[POSITIONAL_KEY];
500
+
501
+ // File-sentinel positionals (e.g. *.cds, *.json for compile).
502
+ for (const [flag, sentinel] of Object.entries(e.fileCases ?? {})) {
503
+ const fishComp = sentinel === DIR() ? '__fish_complete_directories' : fishFileComp(sentinel);
504
+ const cond = flag === POSITIONAL_KEY
505
+ ? seenCmd(cmd)
506
+ : `${seenCmd(cmd)} && __fish_prev_arg_in ${flag}`;
507
+ lines.push(`complete -c cds -f -n '${cond}' -a "(${fishComp})"`);
508
+ }
509
+
510
+ // String positionals (e.g. command names for `cds help`).
511
+ for (const pos of [...(e.positionals ?? [])].sort()) {
512
+ lines.push(`complete -c cds -f -n '${seenCmd(cmd)}' -a '${pos}'`);
513
+ }
514
+
515
+ // Flags — gated on current token starting with '-' when a file sentinel is present,
516
+ // so that `cds compile <tab>` shows files only and `cds compile --<tab>` shows flags.
517
+ const flagCond = hasFileSentinel
518
+ ? `${seenCmd(cmd)} && string match -q -- "-*" (commandline -ct)`
519
+ : seenCmd(cmd);
520
+ for (const token of sortedFlags(e)) {
521
+ lines.push(`complete -c cds -f -n '${flagCond}' -a '${token}'`);
522
+ }
523
+
524
+ // Option values (previous word is a known flag → offer its static values).
525
+ for (const [flag, val] of Object.entries(e.optionValues ?? {})) {
526
+ lines.push(`complete -c cds -f -n '${seenCmd(cmd)} && __fish_prev_arg_in ${flag}' -a '${[...val].sort().join(' ')}'`);
527
+ }
528
+
529
+ // Comma-separated values — delegated to the _cdsCommaComplete helper in the template.
530
+ for (const [flag, val] of Object.entries(e.commaCases ?? {})) {
531
+ const values = [...val].sort().join(' ');
532
+ const cond = flag === POSITIONAL_KEY
533
+ ? seenCmd(cmd)
534
+ : `${seenCmd(cmd)} && __fish_prev_arg_in ${flag}`;
535
+ lines.push(`complete -c cds -f -n '${cond}' -a "(_cdsCommaComplete ${values})"`);
536
+ }
137
537
  }
138
538
 
139
- return allOptionsFlags;
539
+ return applyTemplate('cds-tmpl.fish', {
540
+ COMMAND_COMPLETIONS: lines.join('\n'),
541
+ CMD_LIST: commands.join(' '),
542
+ CMD_LIST_WITH_SHORTCUTS: allCmdsAndShortcuts,
543
+ });
140
544
  }
141
545
 
546
+ async function generatePs(map) {
547
+ const { commands, shortcuts, commandMap } = map;
548
+
549
+ const cmdArray = commands.map(c => `'${c}'`).join(', ');
550
+
551
+ const shortcutEntries = singleCharShortcuts(shortcuts)
552
+ .map(([k, v]) => ` '${k}' = '${v}'`)
553
+ .join(";\n");
554
+
555
+ const cmdEntries = Object.entries(commandMap)
556
+ .map(([cmd, e]) => {
557
+ const flags = sortedFlags(e).map(t => `'${t}'`).join(', ');
558
+ return ` '${cmd}' = @(${flags})`;
559
+ })
560
+ .join(";\n");
561
+
562
+ const positionalEntries = Object.entries(commandMap)
563
+ .filter(([, e]) => e.positionals?.length)
564
+ .map(([cmd, e]) => ` '${cmd}' = @(${[...e.positionals].sort().map(p => `'${p}'`).join(', ')})`)
565
+ .join(";\n");
566
+
567
+ const optionValueEntries = Object.entries(commandMap)
568
+ .filter(([, e]) => Object.keys(e.optionValues ?? {}).length || Object.keys(e.fileCases ?? {}).length)
569
+ .map(([cmd, e]) => {
570
+ const inner = [];
571
+ for (const [flag, val] of Object.entries(e.optionValues ?? {})) {
572
+ inner.push(` '${flag}' = @(${[...val].sort().map(v => `'${v}'`).join(', ')})`);
573
+ }
574
+ for (const [flag, sentinel] of Object.entries(e.fileCases ?? {})) {
575
+ inner.push(` '${flag}' = ${filePs1(sentinel)}`);
576
+ }
577
+ return ` '${cmd}' = @{\n${inner.join(";\n")}\n }`;
578
+ })
579
+ .join(";\n");
580
+
581
+ const commaEntries = Object.entries(commandMap)
582
+ .filter(([, e]) => Object.keys(e.commaCases ?? {}).length)
583
+ .map(([cmd, e]) => {
584
+ const inner = Object.entries(e.commaCases).map(([flag, val]) =>
585
+ ` '${flag}' = @(${[...val].sort().map(v => `'${v}'`).join(', ')})`
586
+ );
587
+ return ` '${cmd}' = @{\n${inner.join(";\n")}\n }`;
588
+ })
589
+ .join(";\n");
590
+
591
+ return applyTemplate('cds-tmpl.ps1', {
592
+ CMD_ARRAY: cmdArray,
593
+ SHORTCUT_ENTRIES: shortcutEntries,
594
+ POSITIONAL_ENTRIES: positionalEntries,
595
+ OPTION_VALUE_ENTRIES: optionValueEntries,
596
+ COMMA_ENTRIES: commaEntries,
597
+ CMD_ENTRIES: cmdEntries,
598
+ });
599
+ }
600
+
601
+ // --- Completion engine ---
602
+
142
603
  function reply(values) {
143
- if (!Array.isArray(values) || values.length === 0) {
144
- return;
145
- }
604
+ if (!Array.isArray(values) || values.length === 0) return;
146
605
 
147
- values = values.filter(e => !!(typeof e === 'string' && e.trim()));
148
- values = [...new Set(values)];
606
+ values = [...new Set(values.filter(e => typeof e === 'string' && e.trim()))];
149
607
  values.sort((a, b) => {
150
- if (a.startsWith('-') && !b.startsWith('-')) { return 1; }
151
- if (!a.startsWith('-') && b.startsWith('-')) { return -1; }
608
+ // Files / positionals before flags, then alphabetical within each group.
609
+ const aIsFlag = a.startsWith('-');
610
+ const bIsFlag = b.startsWith('-');
611
+ if (aIsFlag !== bIsFlag) return aIsFlag ? 1 : -1;
152
612
  return a.localeCompare(b);
153
613
  });
154
614
 
155
615
  console.log(values.join('\n'));
156
616
  }
157
617
 
618
+ // Splits a shell command line into tokens, respecting quoted strings and escaped spaces.
158
619
  function getSegments(line) {
159
620
  const cliSplit = /'(.*?)'|"(.*?)"|(\\,|\\ |[^, ])+/gs;
160
- const result = line.match(cliSplit);
161
- return result.map(s =>
621
+ return line.match(cliSplit).map(s =>
162
622
  s.trim()
163
623
  .replace(/(\\ )/g, ' ')
164
624
  .replace(/^["']|["']$/g, '')
165
625
  );
166
626
  }
167
627
 
628
+ // Loads the cds command object for the given name, resolving single-char shortcuts first.
168
629
  function getCdsCmd(cdsCmd) {
169
630
  cdsCmd = cds.Shortcuts?.[cdsCmd] ?? cdsCmd;
170
631
  return cds.load(cdsCmd);
171
632
  }
172
633
 
634
+ // Returns all completable flags/options for a command, excluding flags already used on the line.
173
635
  function getAllOptions(cdsCmdObj, segments) {
174
636
  return [
175
637
  ...cdsCmdObj.options ?? [],
176
- ...cdsCmdObj.flags?.filter(o => !segments.includes(o)) ?? []
638
+ ...cdsCmdObj.flags?.filter(o => !segments.includes(o)) ?? [],
177
639
  ];
178
640
  }
179
641
 
180
- function getUtil() {
181
- const completionFs = require('./completionFs');
182
- return {
183
- cds,
184
- completionFs
185
- }
186
- }
187
-
188
642
  async function getCompletions(cdsCmd, previousWord, currentWord, segments) {
189
- const _filter = (completions, currentWord) => {
190
- return completions.filter(token => token?.startsWith(currentWord));
191
- }
192
-
193
- const _getCompletions = async () => {
643
+ // Returns completions filtered by currentWord prefix, unless commaFiltered is set
644
+ // (comma logic pre-filters its own results to avoid double-filtering).
645
+ let commaFiltered = false;
646
+
647
+ const resolveComma = (values, commaStr, partial) => {
648
+ commaFiltered = true;
649
+ const parts = commaStr.split(',');
650
+ const alreadyUsed = new Set(parts.slice(0, -1).map(s => s.trim()).filter(Boolean));
651
+ const prefix = parts.slice(0, -1).join(',') + (parts.length > 1 ? ',' : '');
652
+ return values.filter(v => !alreadyUsed.has(v) && v.startsWith(partial)).map(v => prefix + v);
653
+ };
654
+
655
+ // Reads the file/dir sentinel for a resolved entry and returns matching paths.
656
+ const resolveSentinel = (sentinel, word) => {
657
+ if (sentinel === DIR()) return completionFs.readdir(word, { files: false });
658
+ if (isFileSentinel(sentinel)) return completionFs.readdir(word, fileRegex(sentinel) ? { fileRegex: fileRegex(sentinel), folders: sentinel.dirs ?? false } : {});
659
+ return null;
660
+ };
661
+
662
+ const computeCompletions = async () => {
663
+ // If the cursor is right after 'cds', offer top-level command names.
194
664
  if (previousWord === 'cds') {
195
- if (!currentWord) {
196
- return cds.cmds;
197
- } else {
198
- const completions = _filter(cds.cmds, currentWord);
199
- if (completions.length > 0) {
200
- return completions;
201
- }
202
- cdsCmd = 'compile';
203
- previousWord = 'compile';
204
- }
665
+ if (!currentWord) return cds.cmds;
666
+ const matching = cds.cmds.filter(c => c.startsWith(currentWord));
667
+ if (matching.length) return matching;
668
+ // No command matched the typed prefix — fall through as if typing a compile file arg.
669
+ cdsCmd = 'compile';
670
+ previousWord = 'compile';
205
671
  }
206
672
 
207
673
  try {
208
674
  const cdsCmdObj = getCdsCmd(cdsCmd);
209
- if (typeof cdsCmdObj.handleCompletion === 'function') {
210
- return await cdsCmdObj.handleCompletion(currentWord, previousWord, segments, getUtil());
211
- }
212
675
 
213
- if (currentWord?.startsWith('-')) {
214
- return getAllOptions(cdsCmdObj, segments);
676
+ // Current token starts with '-' → offer flags/options.
677
+ if (currentWord?.startsWith('-')) return getAllOptions(cdsCmdObj, segments);
678
+
679
+ const raw = await cdsCmdObj.staticCompletions?.();
680
+ if (raw && !Array.isArray(raw)) {
681
+ // Resolve single-char option shortcuts (e.g. -4 → --for) so we can look up
682
+ // the right key in the staticCompletions map.
683
+ const cmdOptions = cdsCmdObj.options ?? [];
684
+ const cmdShortcuts = cdsCmdObj.shortcuts ?? [];
685
+ const shortcutIdx = cmdShortcuts.indexOf(previousWord);
686
+ const lookupKey = shortcutIdx !== -1 ? (cmdOptions[shortcutIdx] ?? previousWord) : previousWord;
687
+
688
+ // Comma-separated values come in two forms:
689
+ // inline: "--add approuter,m" → prev="--add" curr="approuter,m"
690
+ // space-separated: "--add approuter, m" → prev="approuter," curr="m"
691
+ const isSpaceSeparated = lookupKey.endsWith(',');
692
+ const isInlineComma = !isSpaceSeparated && currentWord?.includes(',');
693
+ if (isSpaceSeparated || isInlineComma) {
694
+ // For space-separated form, find the originating option flag in the segments.
695
+ const optKey = isSpaceSeparated
696
+ ? cmdOptions.find(o =>
697
+ segments.includes(o) ||
698
+ cmdShortcuts.some((s, i) => segments.includes(s) && cmdOptions[i] === o)
699
+ )
700
+ : lookupKey;
701
+ const resolved = optKey ? await raw[optKey] : undefined;
702
+ if (resolved?.type === ':comma') {
703
+ const values = await resolved.values;
704
+ const commaStr = isSpaceSeparated ? previousWord : currentWord;
705
+ const partial = isSpaceSeparated ? (currentWord ?? '') : commaStr.split(',').at(-1);
706
+ return resolveComma(values, commaStr, partial);
707
+ }
708
+ }
709
+
710
+ // Previous word is a known option → offer its static values or file completions.
711
+ const entry = raw[lookupKey];
712
+ if (entry !== undefined) {
713
+ const resolved = await entry;
714
+ if (resolved?.type === ':comma') {
715
+ const values = await resolved.values;
716
+ return resolveComma(values, currentWord ?? '', (currentWord ?? '').split(',').at(-1));
717
+ }
718
+ return resolveSentinel(resolved, currentWord) ?? resolved;
719
+ }
720
+
721
+ // No option matched — check the default positional sentinel.
722
+ const defaultPositional = raw[POSITIONAL_KEY] !== undefined ? await raw[POSITIONAL_KEY] : undefined;
723
+ if (defaultPositional !== undefined) {
724
+ if (defaultPositional?.type === ':comma') {
725
+ const values = await defaultPositional.values;
726
+ return resolveComma(values, currentWord ?? '', (currentWord ?? '').split(',').at(-1));
727
+ }
728
+ return resolveSentinel(defaultPositional, currentWord) ?? [];
729
+ }
730
+
731
+ // Previous word is a consumed option value (e.g. "approuter" after "--add").
732
+ // Don't offer more positionals — the user has already provided one.
733
+ const allOpts = [...cmdOptions, ...cmdShortcuts, ...(cdsCmdObj.flags ?? [])];
734
+ if (previousWord !== cdsCmd && !allOpts.includes(previousWord)) return [];
215
735
  }
216
736
 
217
- const completionFs = require('./completionFs');
218
- const all = await completionFs.readdir(currentWord);
219
- if (!(cdsCmdObj.options?.includes(previousWord) || cdsCmdObj.shortcuts?.includes(previousWord))) {
220
- const allOptions = getAllOptions(cdsCmdObj, segments);
221
- all.push(...allOptions);
737
+ // Array form of staticCompletions → fixed positional list (e.g. cds help <tab>).
738
+ if (Array.isArray(raw) && raw.length) {
739
+ const prevIsOption = cdsCmdObj.options?.includes(previousWord) || cdsCmdObj.shortcuts?.includes(previousWord);
740
+ return prevIsOption ? [] : raw;
222
741
  }
223
742
 
224
- return all;
743
+ // No staticCompletions — fall back to files + available flags.
744
+ const files = await completionFs.readdir(currentWord);
745
+ const prevIsOption = cdsCmdObj.options?.includes(previousWord) || cdsCmdObj.shortcuts?.includes(previousWord);
746
+ if (!prevIsOption) files.push(...getAllOptions(cdsCmdObj, segments));
747
+ return files;
748
+
225
749
  } catch {
226
750
  return [];
227
751
  }
228
- }
752
+ };
229
753
 
230
- let completions = await _getCompletions();
231
- if (currentWord) {
232
- completions = _filter(completions, currentWord);
754
+ let completions = await computeCompletions();
755
+ if (currentWord && !commaFiltered) {
756
+ completions = completions.filter(c => c?.startsWith(currentWord));
233
757
  }
234
-
235
758
  return completions;
236
759
  }