@sap/cds-dk 7.4.1 → 7.5.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/bin/activate.js +1 -1
- package/bin/add.js +6 -4
- package/bin/build.js +4 -6
- package/bin/cds.js +4 -1
- package/bin/deploy/index.js +5 -2
- package/bin/eval.js +1 -1
- package/bin/extend.js +3 -3
- package/bin/login.js +2 -2
- package/bin/logout.js +1 -1
- package/bin/pull.js +1 -1
- package/bin/push.js +2 -2
- package/bin/subscribe.js +2 -2
- package/bin/unsubscribe.js +2 -2
- package/bin/upgrade.js +2 -2
- package/bin/version.js +2 -2
- package/bin/watch.js +1 -1
- package/lib/bind/bindingUtil.js +2 -1
- package/lib/bind/cfKeyProvider.js +2 -2
- package/lib/bind/userCdsrcJsonStorageProvider.js +1 -1
- package/lib/build/buildPlugin.js +6 -12
- package/lib/build/buildTaskEngine.js +24 -19
- package/lib/build/buildTaskFactory.js +27 -33
- package/lib/build/buildTaskProvider.js +1 -1
- package/lib/build/buildTaskProviderFactory.js +26 -41
- package/lib/build/constants.js +0 -1
- package/lib/build/index.js +3 -3
- package/lib/build/plugins.js +15 -15
- package/lib/build/provider/edmxBuildPlugin.js +6 -7
- package/lib/build/provider/fiori/index.js +8 -8
- package/lib/build/provider/hana/2migration.js +12 -16
- package/lib/build/provider/hana/index.js +5 -7
- package/lib/build/provider/hana/template/package.json +1 -1
- package/lib/build/provider/internalBuildPlugin.js +0 -8
- package/lib/build/provider/internalBuildTaskProvider.js +17 -21
- package/lib/build/provider/java/index.js +2 -1
- package/lib/build/provider/mtx-extension/index.js +5 -4
- package/lib/build/provider/mtx-sidecar/index.js +2 -1
- package/lib/build/provider/nodejs/index.js +6 -5
- package/lib/compile/openapi/csdl2openapi.js +28 -14
- package/lib/compile/openapi/index.js +6 -6
- package/lib/deploy/to-hana/hana.js +2 -2
- package/lib/env/schema.js +2 -3
- package/lib/index.js +68 -28
- package/lib/init/add.js +17 -0
- package/lib/init/constants.js +5 -3
- package/lib/init/index.js +39 -25
- package/lib/init/{util/merge.js → merge.js} +32 -20
- package/lib/init/{util/mvn.js → mvn.js} +5 -5
- package/lib/init/plugin.js +85 -0
- package/lib/init/projectReader.js +145 -0
- package/lib/init/registries/mta.js +151 -0
- package/lib/init/template/{kibana → application-logging}/files/mta.yaml.hbs +3 -3
- package/lib/init/template/application-logging/index.js +49 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +11 -11
- package/lib/init/template/approuter/files/xs-app.json.hbs +2 -2
- package/lib/init/template/approuter/index.js +36 -81
- package/lib/init/template/cf-manifest/files/manifest.yml.hbs +3 -3
- package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +4 -4
- package/lib/init/template/cf-manifest/index.js +4 -4
- package/lib/init/template/connectivity/index.js +22 -35
- package/lib/init/template/data/index.js +3 -2
- package/lib/init/template/destination/files/values.yaml +9 -0
- package/lib/init/template/destination/index.js +15 -47
- package/lib/init/template/enterprise-messaging/index.js +26 -58
- package/lib/init/template/enterprise-messaging-shared/index.js +23 -39
- package/lib/init/template/extensibility/index.js +16 -30
- package/lib/init/template/file-based-messaging/index.js +7 -8
- package/lib/init/template/h2/index.js +4 -4
- package/lib/init/template/hana/files/mta.yaml.hbs +8 -8
- package/lib/init/template/hana/index.js +29 -115
- package/lib/init/template/helm/files/chart/templates/NOTES.txt +12 -0
- package/lib/init/template/helm/files/chart/templates/_deployment_helpers.tpl +82 -0
- package/lib/init/template/helm/files/chart/templates/_helpers.tpl +28 -0
- package/lib/init/template/helm/files/chart/values.root.schema.json +61 -0
- package/lib/init/template/helm/files/chart/values.schema.json +366 -0
- package/lib/init/template/helm/{subcharts → files}/web-application/Chart.yaml +1 -1
- package/lib/init/template/helm/{subcharts → files}/web-application/templates/_api.tpl +1 -1
- package/lib/init/template/helm/{subcharts → files}/web-application/values.yaml +1 -1
- package/lib/init/template/helm/index.js +84 -85
- package/lib/init/template/helm-unified-runtime/files/Chart.yaml.hbs +10 -0
- package/lib/init/template/helm-unified-runtime/files/values.yaml.hbs +26 -0
- package/lib/init/template/helm-unified-runtime/index.js +91 -0
- package/lib/init/template/helm-unified-runtime/lib/build.js +0 -0
- package/lib/init/template/helm-unified-runtime/package.json +4 -0
- package/lib/init/template/html5-repo/files/values.yaml.hbs +28 -0
- package/lib/init/template/html5-repo/index.js +23 -97
- package/lib/init/template/java/index.js +3 -3
- package/lib/init/template/lint/index.js +2 -2
- package/lib/init/template/liquibase/index.js +16 -0
- package/lib/init/template/local-messaging/index.js +7 -8
- package/lib/init/template/mta/index.js +7 -19
- package/lib/init/template/mtx/index.js +2 -2
- package/lib/init/template/multitenancy/index.js +38 -89
- package/lib/init/template/nodejs/index.js +5 -4
- package/lib/init/template/notebook/index.js +1 -1
- package/lib/init/template/notifications/index.js +16 -19
- package/lib/init/template/pipeline/index.js +1 -1
- package/lib/init/template/postgres/index.js +25 -31
- package/lib/init/template/redis-messaging/index.js +23 -27
- package/lib/init/template/sample/index.js +4 -4
- package/lib/init/template/samples/index.js +2 -2
- package/lib/init/template/sqlite/files/{package.json.hbs → package.json} +0 -2
- package/lib/init/template/sqlite/index.js +6 -10
- package/lib/init/template/tiny-sample/index.js +6 -6
- package/lib/init/template/toggles/index.js +7 -8
- package/lib/init/template/typer/index.js +6 -6
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +3 -3
- package/lib/init/template/xsuaa/files/values.yaml.hbs +3 -3
- package/lib/init/template/xsuaa/index.js +27 -52
- package/lib/init/{util/template.js → template.js} +1 -1
- package/lib/{client → mtx}/activate.js +15 -11
- package/lib/{client → mtx}/auth_manager.js +5 -4
- package/lib/{client → mtx}/download_legacy.js +6 -4
- package/lib/{client → mtx}/extend.js +14 -9
- package/lib/{client → mtx}/index.js +1 -1
- package/lib/{client → mtx}/params.js +3 -1
- package/lib/{client → mtx}/pull.js +6 -4
- package/lib/{client → mtx}/push.js +10 -9
- package/lib/{client → mtx}/settings_manager.js +8 -6
- package/lib/{client → mtx}/tenant_action.js +9 -8
- package/lib/{client/helper/cf_helper.js → mtx/util/cf.js} +4 -3
- package/lib/{client/helper/dependency_helper.js → mtx/util/dependencies.js} +1 -0
- package/lib/mtx/util/errors.js +27 -0
- package/lib/mtx/util/legacy_ext.js +16 -0
- package/lib/{client/helper/url_helper.js → mtx/util/urls.js} +12 -1
- package/lib/util/axios.js +84 -0
- package/lib/util/fs.js +5 -1
- package/lib/util/write.js +1 -1
- package/npm-shrinkwrap.json +363 -157
- package/package.json +1 -1
- package/lib/client/base_command.js +0 -54
- package/lib/init/template/_merging/registry-mta.js +0 -304
- package/lib/init/template/helm/Model.d.ts +0 -53
- package/lib/init/template/kibana/files/package.json.hbs +0 -17
- package/lib/init/template/kibana/index.js +0 -54
- package/lib/init/template/templateBase.js +0 -100
- package/lib/init/util/md5.js +0 -86
- package/lib/init/util/projectReader.js +0 -94
- package/lib/util/pruneAxiosErrors.js +0 -39
- /package/lib/init/{util/indent.js → indent.js} +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/Chart.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/_helpers.tpl +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/job.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/secret.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/service-account.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/templates/service-binding.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/values.schema.json +0 -0
- /package/lib/init/template/helm/{subcharts → files}/content-deployment/values.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/service-instance/Chart.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/service-instance/templates/_helpers.tpl +0 -0
- /package/lib/init/template/helm/{subcharts → files}/service-instance/templates/serviceinstance.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/service-instance/values.schema.json +0 -0
- /package/lib/init/template/helm/{subcharts → files}/service-instance/values.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/NOTES.txt +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/_helpers.tpl +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/api-rule.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/deployment.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/network-policy.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/pod-disruption-budget.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/rbac.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/secret.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service-account.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service-binding.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/service.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/templates/virtual-service.yaml +0 -0
- /package/lib/init/template/helm/{subcharts → files}/web-application/values.schema.json +0 -0
- /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/NOTES.txt +0 -0
- /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/_deployment_helpers.tpl +0 -0
- /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/templates/_helpers.tpl +0 -0
- /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/values.root.schema.json +0 -0
- /package/lib/init/template/{helm/chart → helm-unified-runtime/files}/values.schema.json +0 -0
- /package/lib/init/template/postgres/files/{mta.yaml.hbs → mta.yml.hbs} +0 -0
- /package/lib/init/{util/xml.js → xml.js} +0 -0
- /package/lib/{client/helper/env_helper.js → mtx/util/env.js} +0 -0
- /package/lib/{client/helper/fs_helper.js → mtx/util/fs.js} +0 -0
- /package/lib/{client/helper → mtx/util}/logging.js +0 -0
- /package/lib/{client/helper → mtx/util}/question.js +0 -0
- /package/lib/{client/helper/string_helper.js → mtx/util/strings.js} +0 -0
- /package/lib/util/{cfUtil.js → cf.js} +0 -0
- /package/lib/util/{gitUtil.js → git.js} +0 -0
|
@@ -6,6 +6,7 @@ const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES,
|
|
|
6
6
|
OUTPUT_MODE_FILESYSTEM, FLAVOR_LOCALIZED_EDMX, CONTENT_EDMX, CONTENT_LOCALIZED_EDMX } = require('../../constants')
|
|
7
7
|
const { getI18nDefaultFolder } = require('../../util')
|
|
8
8
|
const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
|
|
9
|
+
const DEBUG = cds.debug('cli|build')
|
|
9
10
|
|
|
10
11
|
class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
11
12
|
init() {
|
|
@@ -49,7 +50,7 @@ class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
|
49
50
|
if (this.isStagingBuild()) {
|
|
50
51
|
return super.clean()
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
DEBUG?.(`Deleting build target folder ${this.task.options.compileDest}`)
|
|
53
54
|
await fs.promises.rm(this.task.options.compileDest, { force: true, recursive: true })
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const fs = require('fs')
|
|
3
3
|
const cds = require('../../../cds')
|
|
4
|
-
|
|
5
4
|
const InternalBuildPlugin = require('../internalBuildPlugin')
|
|
6
5
|
const { FOLDER_GEN, EXTENSION_POINT_VALIDATION } = require('../../constants')
|
|
7
6
|
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder')
|
|
8
7
|
const { BuildError, BuildMessage } = require('../../util')
|
|
8
|
+
const DEBUG = cds.debug('cli|build')
|
|
9
9
|
|
|
10
10
|
class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
11
11
|
init() {
|
|
@@ -43,7 +43,8 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
43
43
|
await this.collectLanguageBundles(extModel, path.join(destExt, 'i18n'))
|
|
44
44
|
|
|
45
45
|
// perform SQL backend validation to prevent extension deployment problems later on
|
|
46
|
-
|
|
46
|
+
// REVISIT: disabled - causing stack overflow errors in LinkedCSN for some scenarios
|
|
47
|
+
// cds.compile.to.sql(model)
|
|
47
48
|
|
|
48
49
|
const files = Object.keys(await cds.deploy.resources(model))
|
|
49
50
|
if (files.length > 0) {
|
|
@@ -61,7 +62,7 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
61
62
|
try {
|
|
62
63
|
// throws error in case of linting errors
|
|
63
64
|
this._lintExtModel(extModel, model)
|
|
64
|
-
} catch(error) {
|
|
65
|
+
} catch (error) {
|
|
65
66
|
// cleanup existing files in case of an error
|
|
66
67
|
await fs.promises.rm(this.task.dest, { recursive: true })
|
|
67
68
|
throw error
|
|
@@ -108,7 +109,7 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
108
109
|
return
|
|
109
110
|
}
|
|
110
111
|
const env = cds.env.for('cds', path.join(this.task.src, this._getAppPackageFolder()))
|
|
111
|
-
|
|
112
|
+
DEBUG?.(`Saas extension point restrictions:\n${env.requires?.['cds.xt.ExtensibilityService']}`)
|
|
112
113
|
|
|
113
114
|
const messages = linter.lint(extModel, model, env)
|
|
114
115
|
if (messages.length) {
|
|
@@ -6,6 +6,7 @@ const NodejsBuildPlugin = require('../nodejs')
|
|
|
6
6
|
const ResourcesTarProvider = require('../mtx/resourcesTarBuilder')
|
|
7
7
|
const { ERROR } = NodejsBuildPlugin
|
|
8
8
|
const { relativePaths, BuildError, resolveRequiredSapModels, getI18nDefaultFolder } = require('../../util')
|
|
9
|
+
const DEBUG = cds.debug('cli|build')
|
|
9
10
|
|
|
10
11
|
const DEFAULT_MAIN_FOLDER = "_main"
|
|
11
12
|
|
|
@@ -114,7 +115,7 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
114
115
|
if (!modelFilePaths || modelFilePaths.length === 0) {
|
|
115
116
|
throw new BuildError("No CDS models found in MTX sidecar. Make sure up-to-date versions of the required npm modules are installed.")
|
|
116
117
|
}
|
|
117
|
-
|
|
118
|
+
DEBUG?.(`sidecar model: ${relativePaths(cds.root, modelFilePaths).join(", ")}`)
|
|
118
119
|
|
|
119
120
|
// check whether all models belonging to the @sap namespace can be resolved
|
|
120
121
|
const unresolved = resolveRequiredSapModels(modelPaths)
|
|
@@ -7,6 +7,7 @@ const { BuildError } = require('../../util')
|
|
|
7
7
|
const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, ODATA_VERSION_V2, FOLDER_GEN, CONTENT_EDMX, CONTENT_PACKAGELOCK_JSON,
|
|
8
8
|
CONTENT_NPMRC, CONTENT_CDSRC_JSON, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
|
|
9
9
|
const { WARNING } = EdmxBuildPlugin
|
|
10
|
+
const DEBUG = cds.debug('cli|build')
|
|
10
11
|
|
|
11
12
|
class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
12
13
|
init() {
|
|
@@ -67,7 +68,7 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
67
68
|
if (cds.env.build.target === '.') {
|
|
68
69
|
// delete the entire 'task.dest' folder otherwise, for details see #constructor
|
|
69
70
|
// - the value of the folder 'src' has been appended to the origin 'task.dest' dir
|
|
70
|
-
|
|
71
|
+
DEBUG?.(`Deleting build target folder ${this.destSrv}`)
|
|
71
72
|
await fs.promises.rm(this.isStagingBuild() ? this.task.dest : this.destSrv, { force: true, recursive: true })
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -186,7 +187,7 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
186
187
|
try {
|
|
187
188
|
pkgDescriptors = await this._execNpmPack(dest, wsRoot, workspaces)
|
|
188
189
|
} catch (e) {
|
|
189
|
-
|
|
190
|
+
DEBUG?.(e)
|
|
190
191
|
throw new BuildError(`Failed to package npm workspace dependencies\n${e.message}`)
|
|
191
192
|
}
|
|
192
193
|
if (pkgDescriptors?.length) {
|
|
@@ -229,9 +230,9 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
229
230
|
const args = ['pack', '-ws', '--json', `--pack-destination=${dest}`]
|
|
230
231
|
workspaces.forEach(w => args.push(`-w=${w}`))
|
|
231
232
|
|
|
232
|
-
|
|
233
|
-
const result = await cmd.spawnCommand( 'npm', args, { cwd: wsRoot }, true, !!
|
|
234
|
-
|
|
233
|
+
DEBUG?.(`execute command: npm ${args}`)
|
|
234
|
+
const result = await cmd.spawnCommand( 'npm', args, { cwd: wsRoot }, true, !!DEBUG)
|
|
235
|
+
DEBUG?.(result)
|
|
235
236
|
return JSON.parse(result)
|
|
236
237
|
}
|
|
237
238
|
}
|
|
@@ -77,8 +77,18 @@ module.exports.csdl2openapi = function (
|
|
|
77
77
|
preProcess(csdl, boundOverloads, derivedTypes, alias, namespace, namespaceUrl, voc);
|
|
78
78
|
|
|
79
79
|
const entityContainer = csdl.$EntityContainer ? modelElement(csdl.$EntityContainer) : {};
|
|
80
|
+
if (csdl.$EntityContainer) {
|
|
81
|
+
let serviceName = nameParts(csdl.$EntityContainer).qualifier;
|
|
82
|
+
Object.keys(entityContainer).forEach(element => {
|
|
83
|
+
if (entityContainer[element].$Type) {
|
|
84
|
+
let type = nameParts(entityContainer[element].$Type).name;
|
|
85
|
+
if (csdl[serviceName]?.[type]?.['@cds.autoexpose'] || csdl[serviceName]?.[type]?.['@cds.autoexposed'])
|
|
86
|
+
entityContainer[element]['$cds.autoexpose'] = true;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
const keyAsSegment = entityContainer ? entityContainer[voc.Capabilities.KeyAsSegmentSupported] : {};
|
|
81
|
-
const deepUpdate = entityContainer ? entityContainer[voc.Capabilities.DeepUpdateSupport] && entityContainer[voc.Capabilities.DeepUpdateSupport].Supported : {};
|
|
82
92
|
|
|
83
93
|
const openapi = {
|
|
84
94
|
openapi: '3.0.2',
|
|
@@ -534,7 +544,7 @@ module.exports.csdl2openapi = function (
|
|
|
534
544
|
if (prefixParameters.length > 0) pathItem.parameters = prefixParameters;
|
|
535
545
|
|
|
536
546
|
operationRead(pathItem, element, name, sourceName, targetName, target, level, restrictions, false, nonExpandable);
|
|
537
|
-
if (element.$Collection && (element.$ContainsTarget || level < 2 && target)) {
|
|
547
|
+
if (!root['$cds.autoexpose'] && element.$Collection && (element.$ContainsTarget || level < 2 && target)) {
|
|
538
548
|
operationCreate(pathItem, element, name, sourceName, targetName, target, level, restrictions);
|
|
539
549
|
}
|
|
540
550
|
pathItemsForBoundOperations(paths, prefix, prefixParameters, element, sourceName);
|
|
@@ -544,9 +554,11 @@ module.exports.csdl2openapi = function (
|
|
|
544
554
|
if (level < maxLevels)
|
|
545
555
|
pathItemsWithKey(paths, prefix, prefixParameters, element, root, sourceName, targetName, target, level, navigationPath, restrictions, nonExpandable);
|
|
546
556
|
} else {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
557
|
+
if (!root['$cds.autoexpose']) {
|
|
558
|
+
operationUpdate(pathItem, element, name, sourceName, target, level, restrictions);
|
|
559
|
+
if (element.$Nullable) {
|
|
560
|
+
operationDelete(pathItem, element, name, sourceName, target, level, restrictions);
|
|
561
|
+
}
|
|
550
562
|
}
|
|
551
563
|
pathItemsForBoundOperations(paths, prefix, prefixParameters, element, sourceName);
|
|
552
564
|
pathItemsWithNavigation(paths, prefix, prefixParameters, type, root, sourceName, level, navigationPath);
|
|
@@ -616,8 +628,10 @@ module.exports.csdl2openapi = function (
|
|
|
616
628
|
paths[path] = pathItem;
|
|
617
629
|
|
|
618
630
|
operationRead(pathItem, element, name, sourceName, targetName, target, level, restrictions, true, nonExpandable);
|
|
619
|
-
|
|
620
|
-
|
|
631
|
+
if (!root['$cds.autoexpose']) {
|
|
632
|
+
operationUpdate(pathItem, element, name, sourceName, target, level, restrictions, true);
|
|
633
|
+
operationDelete(pathItem, element, name, sourceName, target, level, restrictions, true);
|
|
634
|
+
}
|
|
621
635
|
if (Object.keys(pathItem).filter((i) => i !== "parameters").length === 0)
|
|
622
636
|
delete paths[path];
|
|
623
637
|
|
|
@@ -1773,7 +1787,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1773
1787
|
title: name,
|
|
1774
1788
|
enum: members
|
|
1775
1789
|
};
|
|
1776
|
-
const description = type[voc.Core.
|
|
1790
|
+
const description = type[voc.Core.LongDescription];
|
|
1777
1791
|
if (description) s.description = description;
|
|
1778
1792
|
schemas[qualifier + '.' + name] = s;
|
|
1779
1793
|
}
|
|
@@ -1789,7 +1803,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1789
1803
|
function schemaForTypeDefinition(schemas, qualifier, name, type) {
|
|
1790
1804
|
const s = getSchema(Object.assign({ $Type: type.$UnderlyingType }, type));
|
|
1791
1805
|
s.title = name;
|
|
1792
|
-
const description = type[voc.Core.
|
|
1806
|
+
const description = type[voc.Core.LongDescription];
|
|
1793
1807
|
if (description) s.description = description;
|
|
1794
1808
|
schemas[qualifier + '.' + name] = s;
|
|
1795
1809
|
}
|
|
@@ -1825,10 +1839,10 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1825
1839
|
if (property.$Collection && suffix === "" && isCount === true) {
|
|
1826
1840
|
schemaProperties[`${iName}@${csdl.$Version === '4.0' ? 'odata.' : ''}count`] = ref('count');
|
|
1827
1841
|
}
|
|
1828
|
-
if (property[voc.Core.Permissions] != "Read" && !property[voc.Core.Computed] && property.$ContainsTarget) {
|
|
1842
|
+
if (property[voc.Core.Permissions] != "Read" && !property[voc.Core.Computed] && ( property.$ContainsTarget || property.$OnDelete === 'Cascade') ) {
|
|
1829
1843
|
if (suffix === SUFFIX.create)
|
|
1830
1844
|
schemaProperties[iName] = getSchema(property, SUFFIX.create);
|
|
1831
|
-
if (suffix === SUFFIX.update
|
|
1845
|
+
if (suffix === SUFFIX.update)
|
|
1832
1846
|
schemaProperties[iName] = getSchema(property, SUFFIX.create);
|
|
1833
1847
|
}
|
|
1834
1848
|
} else {
|
|
@@ -1858,7 +1872,7 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
1858
1872
|
if (suffix === SUFFIX.create && required.length > 0)
|
|
1859
1873
|
schemas[schemaName].required = [...new Set(required)];
|
|
1860
1874
|
|
|
1861
|
-
const description = type[voc.Core.
|
|
1875
|
+
const description = type[voc.Core.LongDescription];
|
|
1862
1876
|
if (description) {
|
|
1863
1877
|
schemas[schemaName].description = description;
|
|
1864
1878
|
}
|
|
@@ -2248,9 +2262,9 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
|
|
|
2248
2262
|
};
|
|
2249
2263
|
}
|
|
2250
2264
|
|
|
2251
|
-
if (!forParameter && element[voc.Core.
|
|
2265
|
+
if (!forParameter && element[voc.Core.LongDescription]) {
|
|
2252
2266
|
if (s.$ref) s = { allOf: [s] };
|
|
2253
|
-
s.description = element[voc.Core.
|
|
2267
|
+
s.description = element[voc.Core.LongDescription];
|
|
2254
2268
|
}
|
|
2255
2269
|
|
|
2256
2270
|
return s;
|
|
@@ -2,9 +2,13 @@ const csdl2openapi = require('./csdl2openapi')
|
|
|
2
2
|
const cds = require('../../cds')
|
|
3
3
|
|
|
4
4
|
module.exports = function processor(csn, options = {}) {
|
|
5
|
+
const edmOptions = Object.assign({
|
|
6
|
+
odataOpenapiHints: true, // hint to compiler
|
|
7
|
+
to: 'openapi' // hint to cds.compile.to.edm (usually set by CLI, but also do this in programmatic usages)
|
|
8
|
+
}, options)
|
|
5
9
|
|
|
6
10
|
// must not be part of function* otherwise thrown errors are swallowed
|
|
7
|
-
const csdl = cds.compile.to.edm(csn,
|
|
11
|
+
const csdl = cds.compile.to.edm(csn, edmOptions);
|
|
8
12
|
|
|
9
13
|
if (csdl[Symbol.iterator]) { // generator function means multiple services
|
|
10
14
|
return _iterate(csdl, csn, options)
|
|
@@ -12,10 +16,6 @@ module.exports = function processor(csn, options = {}) {
|
|
|
12
16
|
const openApiOptions = toOpenApiOptions(csdl, csn, options)
|
|
13
17
|
return _getOpenApi(csdl, openApiOptions);
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
// const file = csdl.$EntityContainer.replace(/\.[^.]+$/, '');
|
|
17
|
-
// yield [openapi, { file }]; // add file to avoid relative path in filename
|
|
18
|
-
// return openapi;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function* _iterate(csdl, csn, options) {
|
|
@@ -57,6 +57,6 @@ function servicePath(csdl, csn) {
|
|
|
57
57
|
if (csdl.$EntityContainer) {
|
|
58
58
|
const serviceName = csdl.$EntityContainer.replace(/\.[^.]+$/, '')
|
|
59
59
|
const service = csn.definitions[serviceName]
|
|
60
|
-
return cds.service.path4
|
|
60
|
+
return cds.service.path4?.(service) || cds.serve.path4(service)
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -10,8 +10,8 @@ const { build } = require('../../build');
|
|
|
10
10
|
const buildConstants = require('../../build/constants');
|
|
11
11
|
|
|
12
12
|
const hdiDeployUtil = require('./hdiDeployUtil');
|
|
13
|
-
const cfUtil = require('../../util/
|
|
14
|
-
const gitUtil = require('../../util/
|
|
13
|
+
const cfUtil = require('../../util/cf');
|
|
14
|
+
const gitUtil = require('../../util/git');
|
|
15
15
|
const mtaUtil = require('./mtaUtil');
|
|
16
16
|
|
|
17
17
|
const { bold, info } = require('../../util/term');
|
package/lib/env/schema.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const { mergeJSON } = require('../init/util/merge')
|
|
1
|
+
const { merge } = require('../init/merge')
|
|
3
2
|
const { readJSON } = require('../util/fs')
|
|
4
3
|
|
|
5
4
|
module.exports = async function overlay4(schemaName, cwd = process.cwd()) {
|
|
@@ -26,7 +25,7 @@ module.exports = async function overlay4(schemaName, cwd = process.cwd()) {
|
|
|
26
25
|
|
|
27
26
|
// optional, don't throw if file not found
|
|
28
27
|
try {
|
|
29
|
-
await
|
|
28
|
+
await merge(__dirname, 'schemas', schemaName).into(result)
|
|
30
29
|
result.description = result.description + ' - overlaid'
|
|
31
30
|
} catch (err) {
|
|
32
31
|
if (err.code !== 'ENOENT') throw err
|
package/lib/index.js
CHANGED
|
@@ -1,33 +1,73 @@
|
|
|
1
|
+
/** @type { import('./cds') & CdsDk & CdsDkAdd & CdsDkBuild} */
|
|
1
2
|
const cds = module.exports = require('./cds')
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
get
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
3
|
+
|
|
4
|
+
class CdsDk {
|
|
5
|
+
|
|
6
|
+
get import() {
|
|
7
|
+
return super.import = require('./import/importapi')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get compile() {
|
|
11
|
+
let compile = require(_local('@sap/cds/lib/compile/cds-compile'))
|
|
12
|
+
cds.extend (compile.to.constructor) .with (class {
|
|
13
|
+
get asyncapi() { return super.asyncapi = require('./compile/asyncapi') }
|
|
14
|
+
get openapi() { return super.openapi = require('./compile/openapi') }
|
|
15
|
+
get xsuaa(){ return super.xsuaa = require('./compile/to-xsuaa') }
|
|
16
|
+
'edmx-v2'(csn,o) { return cds.compile.to.edmx(csn,{...o,flavor:'v2'}) }
|
|
17
|
+
'edmx-v4'(csn,o) { return cds.compile.to.edmx(csn,{...o,flavor:'v4'}) }
|
|
18
|
+
'edmx-w4'(csn,o) { return cds.compile.to.edmx(csn,{...o,flavor:'w4'}) }
|
|
19
|
+
'edmx-x4'(csn,o) { return cds.compile.to.edmx(csn,{...o,flavor:'x4'}) }
|
|
20
|
+
})
|
|
21
|
+
// Compat to cds <=6. Esp. BAS tools need it, see cap/issues#13918
|
|
22
|
+
// TODO remove compat w/ cds-dk 8
|
|
23
|
+
if (compile.to.constructor.name === 'Object') { // not a class as in cds 7
|
|
24
|
+
compile.to.xsuaa = require('./compile/to-xsuaa')
|
|
25
|
+
}
|
|
26
|
+
return super.compile = compile
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// add overlay4 method to cds.schema to retrieve schema with cds-dk features
|
|
30
|
+
// schema is cds version specific; add cds-dk parts not present in cds, e.g. build
|
|
31
|
+
// failsafe for legacy cds without schema.constructor
|
|
32
|
+
get schema() {
|
|
33
|
+
let schema = require(_local('@sap/cds/lib/env/schemas'))
|
|
34
|
+
cds.extend(schema.constructor) .with (class {
|
|
35
|
+
get overlay4() { return super.overlay4 = require('./env/schema') }
|
|
36
|
+
})
|
|
37
|
+
return super.schema = schema
|
|
38
|
+
}
|
|
20
39
|
}
|
|
21
40
|
|
|
22
|
-
|
|
23
|
-
// schema is cds version specific; add cds-dk parts not present in cds, e.g. build
|
|
24
|
-
// failsafe for legacy cds without schema.constructor
|
|
25
|
-
cds.extend(cds.schema?.constructor || {}).with(class {
|
|
26
|
-
get overlay4() { return super.overlay4 = require('./env/schema') }
|
|
27
|
-
})
|
|
41
|
+
cds.extend (cds.constructor) .with (CdsDk)
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
class CdsDkAdd {
|
|
44
|
+
get add() { return super.add = require('./init/add') }
|
|
45
|
+
}
|
|
46
|
+
class CdsDkBuild {
|
|
32
47
|
get build() { return super.build = require('./build') }
|
|
33
|
-
}
|
|
48
|
+
}
|
|
49
|
+
if (process.argv[2] in { 'add':1, 'init':1 }) {
|
|
50
|
+
cds.extend (cds.constructor) .with (CdsDkAdd)
|
|
51
|
+
} else if (process.argv[2] in { 'build':1, 'deploy':1, 'push':1 }) {
|
|
52
|
+
cds.extend (cds.constructor) .with (CdsDkBuild)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const MIN_SUPPORTED_CDS_VERSION = 6
|
|
56
|
+
const [cdsVersion] = cds.version.split('.')
|
|
57
|
+
if (parseInt(cdsVersion) < MIN_SUPPORTED_CDS_VERSION) {
|
|
58
|
+
const [dkVersion] = require('../package.json').version.split('.')
|
|
59
|
+
console.error(`
|
|
60
|
+
This application uses '@sap/cds' version ${cdsVersion}, which is not compatible with the installed '@sap/cds-dk' version ${dkVersion}.
|
|
61
|
+
You can either:
|
|
62
|
+
- update '@sap/cds' to the latest version (recommended)
|
|
63
|
+
- downgrade '@sap/cds-dk' to version ${MIN_SUPPORTED_CDS_VERSION}
|
|
64
|
+
`)
|
|
65
|
+
process.exit(1)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function _local (id) {
|
|
69
|
+
return require.resolve (id, {paths:[
|
|
70
|
+
process.cwd(), // project-local module is preferred
|
|
71
|
+
__dirname // otherwise from our own dependencies
|
|
72
|
+
]})
|
|
73
|
+
}
|
package/lib/init/add.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const registered = new Map
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
Plugin: require('./plugin'),
|
|
5
|
+
merge: require('./merge').merge, // fluent API
|
|
6
|
+
readProject: require('./projectReader').readProject,
|
|
7
|
+
mvn: {
|
|
8
|
+
add: require('./mvn').add
|
|
9
|
+
},
|
|
10
|
+
registries: {
|
|
11
|
+
mta: require('./registries/mta')
|
|
12
|
+
},
|
|
13
|
+
register: (name, plugin) => {
|
|
14
|
+
registered.set(name, plugin)
|
|
15
|
+
},
|
|
16
|
+
registered
|
|
17
|
+
}
|
package/lib/init/constants.js
CHANGED
|
@@ -4,7 +4,7 @@ module.exports = {
|
|
|
4
4
|
COMMAND_INIT: 'init',
|
|
5
5
|
COMMAND_ADD: 'add',
|
|
6
6
|
|
|
7
|
-
MAVEN_ARCHETYPE_VERSION: '2.4.
|
|
7
|
+
MAVEN_ARCHETYPE_VERSION: '2.4.1',
|
|
8
8
|
|
|
9
9
|
OPTIONS: Object.freeze({
|
|
10
10
|
JAVA: 'java',
|
|
@@ -15,6 +15,8 @@ module.exports = {
|
|
|
15
15
|
TINY_SAMPLE: 'tiny-sample',
|
|
16
16
|
SAMPLE: 'sample',
|
|
17
17
|
PIPELINE: 'pipeline',
|
|
18
|
+
HELM_UNIFIED_RUNTIME: 'helm-unified-runtime',
|
|
19
|
+
HELM: 'helm',
|
|
18
20
|
MTA: 'mta',
|
|
19
21
|
CONNECTIVITY: 'connectivity',
|
|
20
22
|
CF_MANIFEST: 'cf-manifest',
|
|
@@ -27,6 +29,7 @@ module.exports = {
|
|
|
27
29
|
POSTGRES: 'postgres',
|
|
28
30
|
SQLITE: 'sqlite',
|
|
29
31
|
H2: 'h2',
|
|
32
|
+
LIQUIBASE: 'liquibase',
|
|
30
33
|
LOCAL_MESSAGING: 'local-messaging',
|
|
31
34
|
FILE_BASED_MESSAGING: 'file-based-messaging',
|
|
32
35
|
ENTERPRISE_MESSAGING: 'enterprise-messaging',
|
|
@@ -35,11 +38,10 @@ module.exports = {
|
|
|
35
38
|
APPROUTER: 'approuter',
|
|
36
39
|
DESTINATION: 'destination',
|
|
37
40
|
DATA: 'data',
|
|
38
|
-
|
|
41
|
+
APPLICATION_LOGGING: 'application-logging',
|
|
39
42
|
LINT: 'lint',
|
|
40
43
|
LINT_GLOBAL: 'lint:global',
|
|
41
44
|
LINT_DEV: 'lint:dev',
|
|
42
|
-
HELM: 'helm',
|
|
43
45
|
TYPER: 'typer',
|
|
44
46
|
HTML5_REPO: 'html5-repo',
|
|
45
47
|
NOTIFICATIONS: 'notifications'
|
package/lib/init/index.js
CHANGED
|
@@ -5,17 +5,17 @@ const term = require('../util/term');
|
|
|
5
5
|
const { OPTIONS, COMMAND_INIT, PROJECT_FILES, REGEX_PROJECT_NAME } = require('./constants')
|
|
6
6
|
const {
|
|
7
7
|
NODEJS, JAVA,
|
|
8
|
-
HANA, APPROUTER, XSUAA,
|
|
8
|
+
HANA, APPROUTER, XSUAA, APPLICATION_LOGGING, ENTERPRISE_MESSAGING,
|
|
9
9
|
MTA, MULTITENANCY, PIPELINE,
|
|
10
10
|
TINY_SAMPLE, SAMPLE
|
|
11
11
|
} = OPTIONS
|
|
12
12
|
|
|
13
|
-
const cds = require('
|
|
13
|
+
const cds = require('..'), { exists, readdir } = cds.utils
|
|
14
14
|
const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) ? console.debug : undefined
|
|
15
15
|
|
|
16
16
|
module.exports = class CDSGenerator {
|
|
17
17
|
constructor() {
|
|
18
|
-
this.cwd = process.cwd()
|
|
18
|
+
this.cwd = process.cwd()
|
|
19
19
|
|
|
20
20
|
this.uiConfig = [{
|
|
21
21
|
title: 'Project Name',
|
|
@@ -60,7 +60,7 @@ module.exports = class CDSGenerator {
|
|
|
60
60
|
{ name: 'SAP HANA Cloud', value: HANA },
|
|
61
61
|
{ name: 'SAP Application Router', value: APPROUTER },
|
|
62
62
|
{ name: 'User Authentication via XSUAA', value: XSUAA },
|
|
63
|
-
{ name: '
|
|
63
|
+
{ name: 'Application Logging', value: APPLICATION_LOGGING },
|
|
64
64
|
{ name: 'SAP BTP Event Mesh', value: ENTERPRISE_MESSAGING }
|
|
65
65
|
],
|
|
66
66
|
multiple: true,
|
|
@@ -133,9 +133,12 @@ module.exports = class CDSGenerator {
|
|
|
133
133
|
// keep caller independent from internal names
|
|
134
134
|
options: {
|
|
135
135
|
cwd: options.cwd,
|
|
136
|
-
add: options.add
|
|
136
|
+
add: new Set(options.add)
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
// must be called after above code to ensure cds.cli.options.add is set
|
|
141
|
+
cds.add = require('./add')
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
this._initialize(projectName);
|
|
@@ -176,8 +179,8 @@ module.exports = class CDSGenerator {
|
|
|
176
179
|
for (const template of this.templateList) {
|
|
177
180
|
console.log(`Adding feature '${template.name}'...`);
|
|
178
181
|
await template.run();
|
|
179
|
-
await template.
|
|
180
|
-
await template.
|
|
182
|
+
await template.combine();
|
|
183
|
+
await template.combineSupported();
|
|
181
184
|
}
|
|
182
185
|
|
|
183
186
|
if (cds.cli.command === COMMAND_INIT) {
|
|
@@ -192,10 +195,10 @@ module.exports = class CDSGenerator {
|
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
|
|
195
|
-
async _createTemplate(
|
|
198
|
+
async _createTemplate(plugin) {
|
|
196
199
|
try {
|
|
197
|
-
const
|
|
198
|
-
return new
|
|
200
|
+
const Plugin = cds.add.registered.get(plugin) ?? require(`./template/${plugin}`)
|
|
201
|
+
return new Plugin(this)
|
|
199
202
|
} catch (err) {
|
|
200
203
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
201
204
|
const entries = (await readdir(path.join(__dirname, 'template')))
|
|
@@ -205,11 +208,11 @@ module.exports = class CDSGenerator {
|
|
|
205
208
|
entry !== 'nodejs' &&
|
|
206
209
|
entry !== 'java'
|
|
207
210
|
);
|
|
208
|
-
const fuzzySearch = require('../../bin/util/fuzzySearch')
|
|
209
|
-
const [bestMatch] = fuzzySearch(
|
|
210
|
-
throw `Unknown facet '${term.bold(
|
|
211
|
+
const fuzzySearch = require('../../bin/util/fuzzySearch')
|
|
212
|
+
const [bestMatch] = fuzzySearch(plugin, entries)
|
|
213
|
+
throw `Unknown facet '${term.bold(plugin)}'. Did you mean ${term.bold(`cds add ${bestMatch}`)}?\n\nHaven't found the proper facet yet? Here are all supported facets:\n\n ${term.bold(entries.join('\n '))}\n`
|
|
211
214
|
}
|
|
212
|
-
throw err
|
|
215
|
+
throw err
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
218
|
|
|
@@ -217,28 +220,39 @@ module.exports = class CDSGenerator {
|
|
|
217
220
|
const templates = new Map
|
|
218
221
|
const { command, options, argv } = cds.cli
|
|
219
222
|
|
|
220
|
-
const
|
|
223
|
+
const plugins = command === COMMAND_INIT ? options.add : new Set(argv[0].split(','))
|
|
221
224
|
|
|
222
|
-
for (let
|
|
225
|
+
for (let plugin of plugins) {
|
|
223
226
|
// Compat
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
if (plugin === 'helm' && cds.cli.options['internal-unified-runtime-charts']) {
|
|
228
|
+
plugin = 'helm-unified-runtime'
|
|
229
|
+
cds.cli.options.add.delete('helm')
|
|
230
|
+
cds.cli.options.add.add('helm-unified-runtime')
|
|
231
|
+
}
|
|
232
|
+
if (plugin === 'sample-tiny') plugin = 'tiny-sample'
|
|
233
|
+
if (plugin in { 'kibana-logging':1, 'kibana':1 }) plugin = 'application-logging'
|
|
234
|
+
if (plugin === 'postgresql') plugin = 'postgres'
|
|
227
235
|
|
|
228
|
-
if (!templates.has(
|
|
229
|
-
const template = await this._createTemplate(
|
|
236
|
+
if (!templates.has(plugin)) {
|
|
237
|
+
const template = await this._createTemplate(plugin)
|
|
230
238
|
if (await template.canRun()) {
|
|
231
239
|
DEBUG?.(`Adding feature '${template.name}'`)
|
|
232
|
-
templates.set(
|
|
233
|
-
const dependencies = await template.
|
|
234
|
-
dependencies?.forEach(d =>
|
|
240
|
+
templates.set(plugin, template)
|
|
241
|
+
const dependencies = await template.requires()
|
|
242
|
+
dependencies?.forEach(d => plugins.add(d))
|
|
235
243
|
}
|
|
236
244
|
}
|
|
237
245
|
}
|
|
238
246
|
|
|
239
247
|
const cmds = Object.values(OPTIONS)
|
|
240
248
|
this.templateList = Array.from(templates.entries())
|
|
241
|
-
.sort(([
|
|
249
|
+
.sort(([lhs], [rhs]) => {
|
|
250
|
+
const a = cmds.indexOf(lhs), b = cmds.indexOf(rhs)
|
|
251
|
+
if (a === -1 && b === -1) return 0
|
|
252
|
+
if (a === -1) return 1
|
|
253
|
+
if (b === -1) return -1
|
|
254
|
+
return a - b
|
|
255
|
+
})
|
|
242
256
|
.map((entry) => entry[1])
|
|
243
257
|
|
|
244
258
|
// check debug to avoid lengthy computation when not in debug mode
|