@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.
- package/CHANGELOG.md +106 -0
- package/bin/add.js +7 -23
- package/bin/bind.js +14 -0
- package/bin/build.js +21 -34
- package/bin/cds.js +1 -1
- package/bin/compile/index.js +16 -41
- package/bin/completion/completionFs.js +11 -8
- package/bin/completion/index.js +603 -80
- package/bin/completion/scripts/cds.fish +620 -0
- package/bin/completion/scripts/cds.ps1 +403 -0
- package/bin/completion/scripts/cds.sh +327 -0
- package/bin/completion/scripts/cds.zsh +296 -0
- package/bin/completion/templates/cds-tmpl.fish +65 -0
- package/bin/completion/templates/cds-tmpl.ps1 +217 -0
- package/bin/completion/templates/cds-tmpl.sh +93 -0
- package/bin/completion/templates/cds-tmpl.zsh +74 -0
- package/bin/deploy/index.js +11 -1
- package/bin/deploy/options.js +25 -0
- package/{lib → bin}/deploy/to-hana/hana.js +8 -8
- package/{lib → bin}/deploy/to-hana/hdiDeployUtil.js +1 -1
- package/bin/deploy/{to-hana.js → to-hana/index.js} +1 -1
- package/{lib → bin}/deploy/to-hana/mtaUtil.js +1 -1
- package/bin/deploy/to-sql.js +0 -2
- package/bin/env.js +4 -1
- package/bin/export.js +44 -6
- package/bin/help/export.md +3 -0
- package/bin/help.js +1 -5
- package/bin/import.js +9 -0
- package/bin/init.js +6 -24
- package/bin/inspect.js +8 -0
- package/bin/lint.js +5 -3
- package/bin/login.js +26 -20
- package/bin/minify.js +6 -1
- package/bin/pull.js +19 -6
- package/bin/push.js +19 -6
- package/bin/repl.js +11 -2
- package/bin/run.js +12 -1
- package/bin/serve.js +13 -2
- package/bin/up.js +17 -11
- package/{lib → bin}/upgrade/constants.js +1 -1
- package/bin/{upgrade.js → upgrade/index.js} +2 -2
- package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
- package/{lib → bin}/upgrade/preflight/index.js +1 -1
- package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
- package/{lib → bin}/upgrade/steps/install.js +1 -1
- package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/removals.js +1 -1
- package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/verify.js +1 -1
- package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
- package/{lib → bin}/upgrade/util/pom.js +2 -2
- package/{lib → bin}/upgrade/util/prompt.js +1 -1
- package/bin/util/containerize.js +10 -4
- package/bin/version.js +10 -1
- package/{lib → bin}/watch/hot-reload.js +1 -1
- package/bin/{watch.js → watch/index.js} +24 -9
- package/{lib → bin}/watch/livereload-connect.js +1 -1
- package/{lib → bin}/watch/vite-watch.js +1 -1
- package/{lib → bin}/watch/watched.js +2 -2
- package/lib/build/constants.js +1 -1
- package/lib/build/plugins/fiori/index.js +31 -2
- package/lib/build/plugins/internal.js +4 -2
- package/lib/build/plugins/mtx-sidecar/index.js +7 -8
- package/lib/build/plugins/nodejs/index.js +64 -7
- package/lib/build/util.js +2 -4
- package/lib/compile/to_asyncapi.js +1 -1
- package/lib/env/schema.js +16 -0
- package/lib/env/schemas/cds-rc.js +1 -76
- package/lib/import/importapi.js +2 -3
- package/lib/import/message.js +0 -2
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +2 -2
- package/lib/init/merge.js +123 -280
- package/lib/init/plugin.js +3 -1
- package/lib/init/projectReader.js +22 -6
- package/lib/init/registries/xs-app.js +3 -5
- package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ai/index.js +14 -2
- package/lib/init/template/ams/index.js +2 -2
- package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/app-frontend/index.js +4 -4
- package/lib/init/template/application-logging/index.js +2 -2
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/index.js +8 -3
- package/lib/init/template/attachments/files/package.json.hbs +1 -1
- package/lib/init/template/attachments/index.js +2 -2
- package/lib/init/template/audit-logging/index.js +2 -2
- package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
- package/lib/init/template/cloud-logging/index.js +2 -2
- package/lib/init/template/completion/completionSetup.js +36 -39
- package/lib/init/template/connectivity/index.js +2 -2
- package/lib/init/template/data/as-csv.js +15 -5
- package/lib/init/template/data/as-json.js +117 -42
- package/lib/init/template/data/index.js +16 -2
- package/lib/init/template/destination/index.js +2 -2
- package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
- package/lib/init/template/dynatrace/index.js +2 -2
- package/lib/init/template/enterprise-messaging/index.js +2 -2
- package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
- package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
- package/lib/init/template/extensibility/index.js +3 -3
- package/lib/init/template/github-actions/index.js +2 -2
- package/lib/init/template/hana/index.js +3 -2
- package/lib/init/template/hana-serverless/files/db/package.json +14 -0
- package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
- package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
- package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
- package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
- package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
- package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
- package/lib/init/template/hana-serverless/index.js +184 -0
- package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
- package/lib/init/template/html5-repo/index.js +18 -14
- package/lib/init/template/http/index.js +123 -26
- package/lib/init/template/ias/index.js +2 -2
- package/lib/init/template/kafka/index.js +2 -2
- package/lib/init/template/kyma/index.js +7 -5
- package/lib/init/template/malware-scanner/index.js +2 -2
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/multitenancy/index.js +18 -3
- package/lib/init/template/notifications/index.js +2 -2
- package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
- package/lib/init/template/portal/index.js +13 -8
- package/lib/init/template/postgres/index.js +2 -2
- package/lib/init/template/redis/index.js +2 -2
- package/lib/init/template/sample/files/db/currencies.cds +2 -0
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
- package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
- package/lib/init/template/workzone-standard/index.js +5 -5
- package/lib/init/template/xsuaa/index.js +20 -2
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/mtx/auth_manager.js +103 -37
- package/lib/mtx/params.js +3 -2
- package/lib/mtx/settings_manager.js +45 -28
- package/lib/mtx/tenant_action.js +0 -1
- package/lib/mtx/util/credentials.js +62 -0
- package/node_modules/@cap-js/db-service/CHANGELOG.md +17 -0
- package/node_modules/@cap-js/db-service/lib/common/generic-pool.js +4 -7
- package/node_modules/@cap-js/db-service/lib/cqn2pql.js +1 -1
- package/node_modules/@cap-js/db-service/lib/cqn2sql.js +15 -11
- package/node_modules/@cap-js/db-service/lib/cqn4sql.js +119 -19
- package/node_modules/@cap-js/db-service/lib/infer/index.js +27 -16
- package/node_modules/@cap-js/db-service/lib/recursion-guard.js +40 -0
- package/node_modules/@cap-js/db-service/lib/search.js +1 -1
- package/node_modules/@cap-js/db-service/package.json +1 -1
- package/node_modules/@cap-js/sqlite/CHANGELOG.md +19 -0
- package/node_modules/@cap-js/sqlite/lib/SQLiteService.js +110 -14
- package/node_modules/@cap-js/sqlite/package.json +3 -3
- package/node_modules/@sap/cds/CHANGELOG.md +57 -0
- package/node_modules/@sap/cds/app/index.js +5 -4
- package/node_modules/@sap/cds/eslint.config.mjs +1 -0
- package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
- package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
- package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
- package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
- package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
- package/node_modules/@sap/cds/lib/plugins.js +9 -5
- package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
- package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
- package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
- package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
- package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
- package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
- package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
- package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
- package/node_modules/@sap/cds/libx/http/location.js +3 -3
- package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
- package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
- package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
- package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
- package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
- package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
- package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
- package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
- package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
- package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds-compiler/CHANGELOG.md +75 -8
- package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
- package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
- package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
- package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
- package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
- package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
- package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
- package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
- package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
- package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
- package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
- package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +48 -18
- package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
- package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
- package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
- package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
- package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
- package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
- package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
- package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
- package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
- package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
- package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +4 -0
- package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
- package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
- package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
- package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
- package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
- package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
- package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +15 -0
- package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +10 -2
- package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
- package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
- package/node_modules/@sap/cds-compiler/lib/transform/db/flattening.js +4 -3
- package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
- package/node_modules/@sap/cds-compiler/lib/transform/effective/flattening.js +17 -1
- package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +20 -0
- package/node_modules/@sap/cds-compiler/lib/transform/fioriTreeViews.js +12 -1
- package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +7 -2
- package/node_modules/@sap/cds-compiler/lib/transform/odata/adaptAnnotationRefs.js +11 -5
- package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +48 -10
- package/node_modules/@sap/cds-compiler/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/CHANGELOG.md +49 -0
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +26 -5
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +37 -16
- package/node_modules/@sap/cds-mtxs/lib/utils.js +23 -7
- package/node_modules/@sap/cds-mtxs/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +63 -8
- package/node_modules/@sap/cds-mtxs/srv/cf/saas-provisioning-service.js +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/sms-provisioning-service.js +23 -3
- package/node_modules/@sap/cds-mtxs/srv/extensibility/compat/update.js +15 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +2 -2
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/config.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/protected-namespace.js +45 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +30 -16
- package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +49 -10
- package/node_modules/@sap/cds-mtxs/srv/model-provider.js +28 -4
- package/node_modules/@sap/cds-mtxs/srv/plugins/common.js +19 -12
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr.js +6 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/serverless.js +271 -0
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +7 -10
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker-pool.js +212 -0
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker.js +61 -0
- package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
- package/node_modules/@sap/xsenv/package.json +10 -7
- package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
- package/node_modules/hdb/cfg/VERSION +1 -1
- package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
- package/node_modules/hdb/lib/protocol/Connection.js +1 -0
- package/node_modules/hdb/package.json +3 -2
- package/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/negotiator/package.json +16 -10
- package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/qs/CHANGELOG.md +15 -0
- package/node_modules/qs/README.md +19 -1
- package/node_modules/qs/dist/qs.js +21 -21
- package/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/qs/lib/parse.js +3 -4
- package/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/qs/lib/utils.js +10 -3
- package/node_modules/qs/package.json +4 -4
- package/node_modules/qs/test/parse.js +192 -3
- package/node_modules/qs/test/stringify.js +317 -0
- package/node_modules/qs/test/utils.js +12 -0
- package/node_modules/type-is/node_modules/content-type/README.md +2 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/type-is/node_modules/content-type/package.json +1 -1
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/package.json +2 -2
- package/bin/completion/scripts/cds-bash.sh +0 -20
- package/bin/completion/scripts/cds-fish.fish +0 -13
- package/bin/completion/scripts/cds-ps.ps1 +0 -19
- package/bin/completion/scripts/cds-zsh.sh +0 -13
- package/lib/deploy/index.js +0 -25
- package/lib/import/asyncapi/importAsyncAPI.js +0 -33
- package/lib/import/asyncapi/index.js +0 -18
- package/lib/import/asyncapi/parserContext.js +0 -454
- package/lib/import/asyncapi/utils.js +0 -49
- package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
- package/node_modules/negotiator/HISTORY.md +0 -114
- /package/{lib → bin}/upgrade/context.js +0 -0
- /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
- /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
- /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
- /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
- /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
- /package/{lib → bin}/watch/livereload-server.js +0 -0
- /package/{lib → bin}/watch/node-watch.js +0 -0
- /package/{lib → bin}/watch/open.js +0 -0
- /package/{lib → bin}/watch/watcher.js +0 -0
- /package/node_modules/@sap/cds-mtxs/srv/worker/{pool.js → model-worker-pool.js} +0 -0
- /package/node_modules/@sap/cds-mtxs/srv/worker/{load.js → model-worker.js} +0 -0
package/bin/completion/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
70
|
-
case '
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
|
147
|
+
const currentWord = localOptions.curr?.trim().replace(/^'|'$/g, '');
|
|
117
148
|
const previousWord = localOptions.prev?.trim().replace(/^'|'$/g, '');
|
|
118
|
-
const line
|
|
119
|
-
const segments
|
|
120
|
-
const cdsCmd
|
|
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
|
|
127
|
-
const
|
|
128
|
-
|
|
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
|
-
|
|
131
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
|
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 =>
|
|
148
|
-
values = [...new Set(values)];
|
|
606
|
+
values = [...new Set(values.filter(e => typeof e === 'string' && e.trim()))];
|
|
149
607
|
values.sort((a, b) => {
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
214
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
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
|
|
231
|
-
if (currentWord) {
|
|
232
|
-
completions =
|
|
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
|
}
|