@sap/cds-dk 8.4.1 → 8.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -2
- package/bin/add.js +2 -12
- package/bin/cds.js +5 -0
- package/bin/debug.js +90 -0
- package/bin/watch.js +12 -2
- package/lib/bind/index.js +1 -1
- package/lib/bind/userCdsrcJsonStorageProvider.js +0 -19
- package/lib/build/buildTaskEngine.js +1 -1
- package/lib/build/provider/hana/2migration.js +34 -20
- package/lib/build/provider/hana/index.js +74 -41
- package/lib/build/provider/internalBuildTaskProvider.js +1 -1
- package/lib/build/provider/mtx-extension/index.js +4 -4
- package/lib/build/provider/mtx-sidecar/index.js +2 -2
- package/lib/build/provider/nodejs/index.js +3 -19
- package/lib/build/util.js +41 -17
- package/lib/deploy/to-hana/hdiDeployUtil.js +14 -10
- package/lib/import/message.js +2 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +5 -0
- package/lib/import/odata/v4parser.js +32 -43
- package/lib/index.js +14 -14
- package/lib/init/add.js +26 -0
- package/lib/init/constants.js +5 -6
- package/lib/init/index.js +17 -25
- package/lib/init/merge.js +1 -4
- package/lib/init/projectReader.js +75 -9
- package/lib/init/registries/mta.js +0 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/cloud-logging/files/package.json.hbs +1 -12
- package/lib/init/template/cloud-logging/files/values.yaml.hbs +16 -0
- package/lib/init/template/cloud-logging/index.js +14 -10
- package/lib/init/template/data/as-csv.js +1 -1
- package/lib/init/template/data/as-json.js +5 -5
- package/lib/init/template/data/index.js +1 -26
- package/lib/init/template/esm/files/package.json.hbs +3 -0
- package/lib/init/template/esm/index.js +16 -0
- package/lib/init/template/hana/files/package.json.hbs +18 -4
- package/lib/init/template/handler/files/handler.xs.hbs +56 -0
- package/lib/init/template/handler/index.js +84 -9
- package/lib/init/template/helm/index.js +4 -1
- package/lib/init/template/http/index.js +108 -39
- package/lib/init/template/sample/files/nodejs/{admin-service.js → admin-service.js.hbs} +8 -1
- package/lib/init/template/sample/files/nodejs/{cat-service.js → cat-service.js.hbs} +8 -3
- package/lib/init/template/sample/index.js +4 -2
- package/lib/init/template/side-by-side-extensibility/index.js +1 -0
- package/lib/init/template/telemetry/files/package.json.hbs +18 -0
- package/lib/init/template/telemetry/index.js +8 -2
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/workzone-standard/index.js +1 -1
- package/lib/init/types.d.ts +0 -6
- package/lib/watch/node-watch.js +25 -9
- package/npm-shrinkwrap.json +28 -33
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ const path = require('path')
|
|
|
3
3
|
const cds = require('../../../cds')
|
|
4
4
|
const cmd = require('../../../util/command');
|
|
5
5
|
const EdmxBuildPlugin = require('../edmxBuildPlugin')
|
|
6
|
-
const { BuildError, getWorkspaces } = require('../../util')
|
|
6
|
+
const { BuildError, getWorkspaces, findWorkspaceRoot } = 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,
|
|
9
9
|
OPTION_WS_PACK} = require('../../constants')
|
|
@@ -160,14 +160,14 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
async _packWorkspaceDependencies(dest) {
|
|
163
|
-
const wsRoot =
|
|
163
|
+
const wsRoot = findWorkspaceRoot(cds.root)
|
|
164
164
|
const appPkg = require(path.join(dest, 'package.json'))
|
|
165
165
|
let workspaces
|
|
166
166
|
if (this.task.options.workspaces) {
|
|
167
167
|
workspaces = Array.isArray(this.task.options.workspaces) ? this.task.options.workspaces : [this.task.options.workspaces]
|
|
168
168
|
} else {
|
|
169
169
|
// devDependencies are not considered
|
|
170
|
-
workspaces = await getWorkspaces(true, false
|
|
170
|
+
workspaces = await getWorkspaces(wsRoot, true, false);
|
|
171
171
|
}
|
|
172
172
|
if (workspaces.length) {
|
|
173
173
|
let pkgDescriptors
|
|
@@ -197,22 +197,6 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
static _findWorkspaceRoot(dir) {
|
|
201
|
-
try {
|
|
202
|
-
if (require(path.join(dir, 'package.json')).workspaces) {
|
|
203
|
-
return dir
|
|
204
|
-
}
|
|
205
|
-
} catch (err) {
|
|
206
|
-
// ignore
|
|
207
|
-
}
|
|
208
|
-
if (fs.existsSync(path.join(dir, '.gitmodules'))) {
|
|
209
|
-
return // project root reached
|
|
210
|
-
}
|
|
211
|
-
if (path.dirname(dir) !== dir) {
|
|
212
|
-
return this._findWorkspaceRoot(path.dirname(dir))
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
200
|
static async _execNpmPack(dest, wsRoot, workspaces) {
|
|
217
201
|
const args = ['pack', '-ws', '--json', `--pack-destination=${dest}`]
|
|
218
202
|
workspaces.forEach(w => args.push(`-w=${w}`))
|
package/lib/build/util.js
CHANGED
|
@@ -7,6 +7,7 @@ const IS_WIN = require('os').platform() === 'win32'
|
|
|
7
7
|
const { SEVERITY_ERROR, FILE_EXT_CDS } = require('./constants');
|
|
8
8
|
const DEBUG = cds.debug('cli|build')
|
|
9
9
|
const SECRETS = /(passw)|(cert)|(ca)|(secret)|(key)/i
|
|
10
|
+
const WS_MAX_DEPTH = 2
|
|
10
11
|
|
|
11
12
|
function getProperty(src, segments) {
|
|
12
13
|
segments = Array.isArray(segments) ? segments : segments.split('.')
|
|
@@ -98,13 +99,13 @@ function _redacted(cred) {
|
|
|
98
99
|
if (!cred) return cred
|
|
99
100
|
if (Array.isArray(cred)) return cred.map(c => typeof c === 'string' ? '...' : _redacted(c))
|
|
100
101
|
if (typeof cred === 'object') {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
const newCred = Object.assign({}, cred)
|
|
103
|
+
Object.keys(newCred).forEach(k => (typeof newCred[k] === 'string' && SECRETS.test(k)) ? (newCred[k] = '...') : (newCred[k] = _redacted(newCred[k])))
|
|
104
|
+
return newCred
|
|
104
105
|
}
|
|
105
106
|
return cred
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
+
|
|
108
109
|
/**
|
|
109
110
|
* Returns a list of fully qualified model names belonging to the '@sap' namespace that cannot be resolved.
|
|
110
111
|
* E.g. the module might NOT have been installed.
|
|
@@ -173,28 +174,30 @@ async function pathExists(path) {
|
|
|
173
174
|
return fs.promises.access(path).then(() => true).catch(() => false);
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
async function getWorkspacePaths() {
|
|
178
|
+
const wsRoot = findWorkspaceRoot(cds.root)
|
|
179
|
+
if (!wsRoot) {
|
|
180
|
+
return []
|
|
181
|
+
}
|
|
182
|
+
return (await getWorkspaces(wsRoot)).filter(ws => cds.root !== path.join(wsRoot, ws)).map(ws => path.join(wsRoot, ws))
|
|
183
|
+
}
|
|
184
|
+
|
|
176
185
|
/**
|
|
177
186
|
* Returns the list of workspaces defined for the current project. A workspace dependency
|
|
178
187
|
* needs to be defined resulting in a corresponding sym-link.
|
|
179
|
-
* @returns the paths are relative to '
|
|
188
|
+
* @returns the paths are relative to 'wsRoot'.
|
|
180
189
|
*/
|
|
181
|
-
async function getWorkspaces(resolve = false, devDependencies = true
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
} catch (e) {
|
|
186
|
-
if (e.code === 'MODULE_NOT_FOUND') {
|
|
187
|
-
DEBUG?.(`No package.json found in project '${wsRoot}', skipping workspace resolution.`)
|
|
188
|
-
return []
|
|
189
|
-
}
|
|
190
|
-
throw e
|
|
190
|
+
async function getWorkspaces(wsRoot, resolve = false, devDependencies = true) {
|
|
191
|
+
wsRoot ??= findWorkspaceRoot(cds.root)
|
|
192
|
+
if (!wsRoot) {
|
|
193
|
+
return []
|
|
191
194
|
}
|
|
192
|
-
|
|
193
|
-
const workspaces = []
|
|
195
|
+
const pgkJsonWsRoot = require(path.join(wsRoot, 'package.json'))
|
|
194
196
|
let pgkJson = pgkJsonWsRoot
|
|
195
197
|
if (wsRoot !== cds.root) {
|
|
196
198
|
pgkJson = require(path.join(cds.root, 'package.json'))
|
|
197
199
|
}
|
|
200
|
+
const workspaces = []
|
|
198
201
|
if (pgkJsonWsRoot.workspaces) {
|
|
199
202
|
if (resolve) {
|
|
200
203
|
_validateWsDependencies(wsRoot, pgkJson.dependencies, devDependencies ? pgkJson.devDependencies : {})
|
|
@@ -215,6 +218,25 @@ async function getWorkspaces(resolve = false, devDependencies = true, wsRoot = c
|
|
|
215
218
|
return workspaces
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
function findWorkspaceRoot(currentPath, depth = 0) {
|
|
222
|
+
if (depth > WS_MAX_DEPTH) {
|
|
223
|
+
DEBUG?.(`No workspaces exist, max depth of ${WS_MAX_DEPTH} reached`)
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
const packageJson = path.join(currentPath, 'package.json')
|
|
227
|
+
if (fs.existsSync(packageJson)) {
|
|
228
|
+
if (require(path.join(currentPath, 'package.json')).workspaces) {
|
|
229
|
+
return currentPath
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (fs.existsSync(path.join(currentPath, '.gitmodules'))) {
|
|
233
|
+
return // project root reached
|
|
234
|
+
}
|
|
235
|
+
if (path.dirname(currentPath) !== currentPath) {
|
|
236
|
+
return findWorkspaceRoot(path.dirname(currentPath), depth + 1)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
218
240
|
/**
|
|
219
241
|
* This JavaScript function filterFeaturePaths is used to filter and categorize file paths
|
|
220
242
|
* from a given model into two categories: base and features.
|
|
@@ -452,7 +474,9 @@ module.exports = {
|
|
|
452
474
|
getI18nDefaultFolder,
|
|
453
475
|
normalizePath,
|
|
454
476
|
pathExists,
|
|
477
|
+
getWorkspacePaths,
|
|
455
478
|
getWorkspaces,
|
|
479
|
+
findWorkspaceRoot,
|
|
456
480
|
filterFeaturePaths,
|
|
457
481
|
getFiles,
|
|
458
482
|
BuildMessage,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
-
const util = require('util');
|
|
3
2
|
const { bold } = require('../../util/term');
|
|
4
3
|
|
|
5
4
|
const HDI_DEPLOY_LIB = '@sap/hdi-deploy';
|
|
@@ -40,15 +39,20 @@ module.exports = new class HdiDeployUtil {
|
|
|
40
39
|
if (options.use_hdb === false) options.use_hdb = undefined
|
|
41
40
|
deployerEnv.HDI_DEPLOY_OPTIONS = JSON.stringify(options)
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
return await new Promise((resolve, reject) => {
|
|
43
|
+
deploy(dbDir, deployerEnv, (error, response) => {
|
|
44
|
+
if (error) return reject(error)
|
|
45
|
+
if (response?.exitCode) {
|
|
46
|
+
let message = `HDI deployment failed with exit code ${response.exitCode}.`
|
|
47
|
+
if (response.signal) message += `. ${response.signal}`
|
|
48
|
+
return reject(new Error(message))
|
|
49
|
+
}
|
|
50
|
+
return resolve()
|
|
51
|
+
}, {
|
|
52
|
+
stderrCB: buffer => console.error(buffer.toString()),
|
|
53
|
+
stdoutCB: buffer => console.log(buffer.toString())
|
|
54
|
+
})
|
|
55
|
+
})
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
_loadHdiDeployLib(cwd) {
|
package/lib/import/message.js
CHANGED
|
@@ -28,7 +28,7 @@ const messages = {
|
|
|
28
28
|
BOUND_ACTION_COLLISION: 'The combination of Action name and binding parameter type must be unique for Bound Action ',
|
|
29
29
|
STREAM_NO_COLLECTION: `'Edm.Stream' cannot be of Collection type.`,
|
|
30
30
|
UNSUPPORTED_PROPERTY_TYPE: 'Property cannot be of EntityType. Check the type: ',
|
|
31
|
-
|
|
31
|
+
UNRESOLVED_SCHEMA_NAMESPACE: `Could not resolve the schema `,
|
|
32
32
|
INVALID_DATATYPE: `Invalid Data Type `,
|
|
33
33
|
ELEMENT_NAME_COLLISION: 'Collision between EntityContainer Element Name and Schema Element Name is currently not supported. Please check the element name: ',
|
|
34
34
|
NO_DEFAULT_FOR_COLLECTIONS: 'WARNING: Collection type cannot have a Default value.',
|
|
@@ -38,6 +38,7 @@ const messages = {
|
|
|
38
38
|
NULLABLE_KEY: 'WARNING: Key element cannot be Nullable.',
|
|
39
39
|
COLLISION_DETECTED: `INFO: Element name collision detected. Adding suffix to affected type category.`,
|
|
40
40
|
SPECIFY_CONFIG: 'For --config option, please specify correct JSON Object.',
|
|
41
|
+
INVALID_ANNOTATION: 'Annotation element must have a Term attribute',
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
function getMessages() {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
3
|
+
const message = require("../../message").getMessages();
|
|
2
4
|
|
|
3
5
|
const vocabulariesMap = new Map([
|
|
4
6
|
['org.odata.core.v1', () => require('../vocabularies/Org.OData.Core.V1.json')],
|
|
@@ -1754,6 +1756,9 @@ class AnnotationExpression extends Expression {
|
|
|
1754
1756
|
annotate(result) { super.annotate(this.getTargetPropertyName(), this.getTarget(), result); }
|
|
1755
1757
|
interpret() {
|
|
1756
1758
|
const element = this.getElement();
|
|
1759
|
+
if(!Object.hasOwn(element, "attributes") || !Object.hasOwn(element.attributes, "Term")) {
|
|
1760
|
+
throw new Error(message.INVALID_ANNOTATION);
|
|
1761
|
+
}
|
|
1757
1762
|
let name = element.attributes.Term;
|
|
1758
1763
|
if (element.attributes.Qualifier) name += '#' + element.attributes.Qualifier;
|
|
1759
1764
|
name = '@' + name;
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
"use strict";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const messages = require("../message").getMessages();
|
|
8
|
+
const common = require("../common");
|
|
9
|
+
const versionInfo = require("../../../package.json").version;
|
|
10
|
+
const Multimap = require("./util/MultiMap");
|
|
11
11
|
const ignoreObjects = ["$Reference"]; // add all the objects that needs to be ignored for parsing.
|
|
12
12
|
const { warn, info } = require("../../util/term");
|
|
13
13
|
const MetadataConverterFactory = require("./metadataconverter/MetadataConverterFactory");
|
|
@@ -428,6 +428,11 @@ function _parseAnnotationTerms(annotationTerm, annotationTermObject, csnDefsTarg
|
|
|
428
428
|
function _validateAnnotationNamespace(annotationTerm, vocabNamespaceToAlias) {
|
|
429
429
|
let aliasOrNamespace = annotationTerm.substring(1, annotationTerm.lastIndexOf('.'));
|
|
430
430
|
|
|
431
|
+
// This check is for ignoring the @cds annotations given for special cases, e.g. @cds.validate = false for collided action/function
|
|
432
|
+
if (aliasOrNamespace === "cds") {
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
431
436
|
for (let alias of Object.values(known_vocabularies)) {
|
|
432
437
|
if (alias === aliasOrNamespace) {
|
|
433
438
|
return;
|
|
@@ -1358,29 +1363,6 @@ function _parseEntityContainer(csnDefs, entityContainerElements, parserContext)
|
|
|
1358
1363
|
return csnDefs;
|
|
1359
1364
|
}
|
|
1360
1365
|
|
|
1361
|
-
/**
|
|
1362
|
-
* @param {List<Object>} dataObjList, action/function object list
|
|
1363
|
-
* @returns unique parameter list
|
|
1364
|
-
*/
|
|
1365
|
-
function _collectAllParameters(dataObjList) {
|
|
1366
|
-
let uniqueParams = [], paramNames = [], params;
|
|
1367
|
-
|
|
1368
|
-
for (let dataObj of dataObjList) {
|
|
1369
|
-
params = dataObj.$Parameter;
|
|
1370
|
-
|
|
1371
|
-
if (params) {
|
|
1372
|
-
for (let i = 0; i < params.length; i++) {
|
|
1373
|
-
if (!paramNames.includes(params[i].$Name)) {
|
|
1374
|
-
paramNames.push(params[i].$Name);
|
|
1375
|
-
uniqueParams.push(params[i]);
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
return uniqueParams;
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
1366
|
/**
|
|
1385
1367
|
* @param {Boolean} isAction, to identify action/function
|
|
1386
1368
|
* @param {String} fqName, fully qualified name
|
|
@@ -1389,7 +1371,7 @@ function _collectAllParameters(dataObjList) {
|
|
|
1389
1371
|
*
|
|
1390
1372
|
* Scenarios:
|
|
1391
1373
|
* 1. Unbound Actions can't have collision. Action name must be unique.
|
|
1392
|
-
* 2. Unbound Functions can have collision;
|
|
1374
|
+
* 2. Unbound Functions can have collision; we will parse only one function with the same name having no paramter and a generic String return type.
|
|
1393
1375
|
*/
|
|
1394
1376
|
function _populateUnboundActionFunction(isAction, fqName, schemaDataList, parserContext) {
|
|
1395
1377
|
let [schemaName, actFunName] = _extractSchemaNameAndElementName(fqName);
|
|
@@ -1409,8 +1391,12 @@ function _populateUnboundActionFunction(isAction, fqName, schemaDataList, parser
|
|
|
1409
1391
|
}
|
|
1410
1392
|
else {
|
|
1411
1393
|
if (dataList.length > 1) {
|
|
1412
|
-
actionFunctionObject['$Parameter'] =
|
|
1394
|
+
actionFunctionObject['$Parameter'] = [];
|
|
1413
1395
|
parserContext.unboundFunctions[fqName] = actionFunctionObject;
|
|
1396
|
+
parserContext.unboundFunctions[fqName]["@cds.validate"] = false;
|
|
1397
|
+
if(parserContext.unboundFunctions[fqName].$ReturnType){
|
|
1398
|
+
parserContext.unboundFunctions[fqName].$ReturnType.$Type = "Edm.String";
|
|
1399
|
+
}
|
|
1414
1400
|
}
|
|
1415
1401
|
else {
|
|
1416
1402
|
parserContext.unboundFunctions[fqName] = actionFunctionObject;
|
|
@@ -1439,12 +1425,11 @@ function _collectUnboundActionFunction(schemaDataList, parserContext) {
|
|
|
1439
1425
|
* @param {Object} parserContext
|
|
1440
1426
|
*
|
|
1441
1427
|
* Scenarios for bound actions, functions:
|
|
1442
|
-
* 1. Actions with same name and binding parameter type can
|
|
1443
|
-
* 2. Functions can have collision and we will
|
|
1428
|
+
* 1. Actions with same name and binding parameter type can have collision and we will parse only one action with that name having no paramter and a genric String return type.
|
|
1429
|
+
* 2. Functions can have collision and we will parse only one function with that name having no paramter and a genric String return type.
|
|
1444
1430
|
* Special scenario is when same function name is bound to different entity as well.
|
|
1445
1431
|
*/
|
|
1446
1432
|
function _collectBoundActionFunction(isAction, currNamespace, elementName, elementDataList, parserContext) {
|
|
1447
|
-
let functionObjList; // list to collect all the collision obj for function
|
|
1448
1433
|
|
|
1449
1434
|
for (let i = 0; i < elementDataList.length; i++) {
|
|
1450
1435
|
let dataObj = elementDataList[i];
|
|
@@ -1480,7 +1465,12 @@ function _collectBoundActionFunction(isAction, currNamespace, elementName, eleme
|
|
|
1480
1465
|
parserContext.entityToBoundActions[boundEntityName][elementName] = dataObj;
|
|
1481
1466
|
}
|
|
1482
1467
|
else {
|
|
1483
|
-
|
|
1468
|
+
parserContext.entityToBoundActions[boundEntityName][elementName]["@cds.validate"] = false;
|
|
1469
|
+
parserContext.entityToBoundActions[boundEntityName][elementName]["$Parameter"] = [];
|
|
1470
|
+
if (!parserContext.entityToBoundActions[boundEntityName][elementName].$ReturnType) {
|
|
1471
|
+
parserContext.entityToBoundActions[boundEntityName][elementName].$ReturnType = {};
|
|
1472
|
+
}
|
|
1473
|
+
parserContext.entityToBoundActions[boundEntityName][elementName].$ReturnType.$Type = "Edm.String";
|
|
1484
1474
|
}
|
|
1485
1475
|
}
|
|
1486
1476
|
else {
|
|
@@ -1488,18 +1478,12 @@ function _collectBoundActionFunction(isAction, currNamespace, elementName, eleme
|
|
|
1488
1478
|
if (!parserContext.entityToBoundFunctions[boundEntityName]) {
|
|
1489
1479
|
parserContext.entityToBoundFunctions[boundEntityName] = {};
|
|
1490
1480
|
}
|
|
1491
|
-
if (!functionObjList || !parserContext.entityToBoundFunctions[boundEntityName][elementName]) {
|
|
1492
|
-
functionObjList = [];
|
|
1493
|
-
}
|
|
1494
1481
|
parserContext.entityToBoundFunctions[boundEntityName][elementName] = dataObj;
|
|
1495
|
-
functionObjList.push(dataObj);
|
|
1496
1482
|
}
|
|
1497
1483
|
else {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
functionObjList = [functionObject]; // reset the function object list with recently formed object
|
|
1502
|
-
parserContext.entityToBoundFunctions[boundEntityName][elementName] = functionObject;
|
|
1484
|
+
parserContext.entityToBoundFunctions[boundEntityName][elementName]["@cds.validate"] = false;
|
|
1485
|
+
parserContext.entityToBoundFunctions[boundEntityName][elementName]["$Parameter"] = [];
|
|
1486
|
+
parserContext.entityToBoundFunctions[boundEntityName][elementName].$ReturnType.$Type = "Edm.String";
|
|
1503
1487
|
}
|
|
1504
1488
|
// throw error if the return type is missing
|
|
1505
1489
|
if (!parserContext.entityToBoundFunctions[boundEntityName][elementName].$ReturnType) {
|
|
@@ -1688,7 +1672,12 @@ function _generateEDMX2JSON(edmx, name_space) {
|
|
|
1688
1672
|
if (missingReferencedDocuments?.length > 0) {
|
|
1689
1673
|
console.log(missingReferencedDocuments);
|
|
1690
1674
|
}
|
|
1691
|
-
|
|
1675
|
+
|
|
1676
|
+
if (error) {
|
|
1677
|
+
reject(error);
|
|
1678
|
+
} else {
|
|
1679
|
+
resolve(json);
|
|
1680
|
+
}
|
|
1692
1681
|
});
|
|
1693
1682
|
} catch (err) {
|
|
1694
1683
|
reject(err);
|
package/lib/index.js
CHANGED
|
@@ -35,6 +35,20 @@ class CdsDk {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const REQUIRED_CDS_MAJOR = 7, REQUIRED_CDS_MINOR = 2
|
|
39
|
+
const [major, minor] = cds.version.split('.').map(Number)
|
|
40
|
+
if (major < REQUIRED_CDS_MAJOR || major === REQUIRED_CDS_MAJOR && minor < REQUIRED_CDS_MINOR) {
|
|
41
|
+
const [dkVersion] = require('../package.json').version.split('.')
|
|
42
|
+
|
|
43
|
+
console.error(`
|
|
44
|
+
This application uses '@sap/cds' version ${major}.${minor}, which is not compatible with the installed '@sap/cds-dk' version ${dkVersion}.
|
|
45
|
+
You can either:
|
|
46
|
+
- update '@sap/cds' to the latest version (recommended)
|
|
47
|
+
- downgrade '@sap/cds-dk' to version ${REQUIRED_CDS_MAJOR}
|
|
48
|
+
`)
|
|
49
|
+
process.exit(1)
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
cds.extend (cds.constructor) .with (CdsDk)
|
|
39
53
|
|
|
40
54
|
class CdsDkAdd {
|
|
@@ -49,20 +63,6 @@ if (process.argv[2] in { add:1, init:1, help:1 }) {
|
|
|
49
63
|
cds.extend (cds.constructor) .with (CdsDkBuild)
|
|
50
64
|
}
|
|
51
65
|
|
|
52
|
-
const REQUIRED_CDS_MAJOR = 7, REQUIRED_CDS_MINOR = 2
|
|
53
|
-
const [major, minor] = cds.version.split('.').map(Number)
|
|
54
|
-
if (major < REQUIRED_CDS_MAJOR || major === REQUIRED_CDS_MAJOR && minor < REQUIRED_CDS_MINOR) {
|
|
55
|
-
const [dkVersion] = require('../package.json').version.split('.')
|
|
56
|
-
|
|
57
|
-
console.error(`
|
|
58
|
-
This application uses '@sap/cds' version ${major}.${minor}, which is not compatible with the installed '@sap/cds-dk' version ${dkVersion}.
|
|
59
|
-
You can either:
|
|
60
|
-
- update '@sap/cds' to the latest version (recommended)
|
|
61
|
-
- downgrade '@sap/cds-dk' to version ${REQUIRED_CDS_MAJOR}
|
|
62
|
-
`)
|
|
63
|
-
process.exit(1)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
66
|
function _local (id) {
|
|
67
67
|
return require.resolve (id, {paths:[
|
|
68
68
|
process.cwd(), // project-local module is preferred
|
package/lib/init/add.js
CHANGED
|
@@ -15,5 +15,31 @@ module.exports = {
|
|
|
15
15
|
register: (name, plugin) => {
|
|
16
16
|
registered.set(name, plugin)
|
|
17
17
|
},
|
|
18
|
+
filterStringAsRegex,
|
|
18
19
|
registered
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Turns a filter string with optional meta characters into a regular expression.
|
|
24
|
+
* If no meta characters are found, the string is treated as an include pattern.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} spec the filter string
|
|
27
|
+
* @returns {RegExp} the regular expression
|
|
28
|
+
*/
|
|
29
|
+
function filterStringAsRegex(spec) {
|
|
30
|
+
if (typeof spec === 'string') {
|
|
31
|
+
try {
|
|
32
|
+
if (spec.match(/[\^$|*]/)) {
|
|
33
|
+
spec = spec.replace(/^\*/, '.*') // * at start would be invalid, so make it a .*
|
|
34
|
+
return new RegExp(spec, 'i')
|
|
35
|
+
}
|
|
36
|
+
else { // no meta chars -> include semantics
|
|
37
|
+
spec = spec.replace(/\./g, '\\.') // escape literal dot
|
|
38
|
+
return new RegExp(spec, 'i')
|
|
39
|
+
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
throw err.message // user error, so cut off stack trace
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return /.*/
|
|
45
|
+
}
|
package/lib/init/constants.js
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
COMMAND_ADD: 'add',
|
|
6
6
|
|
|
7
7
|
JAVA_LTS_VERSIONS: [17, 21],
|
|
8
|
-
MAVEN_ARCHETYPE_VERSION: '3.4.
|
|
8
|
+
MAVEN_ARCHETYPE_VERSION: '3.4.1',
|
|
9
9
|
|
|
10
10
|
OPTIONS: Object.freeze({
|
|
11
11
|
COMPLETION: 'completion',
|
|
@@ -13,9 +13,13 @@ module.exports = {
|
|
|
13
13
|
JAVA_MVN: 'java:mvn',
|
|
14
14
|
JAVA_PACKAGE: 'java:package',
|
|
15
15
|
NODEJS: 'nodejs',
|
|
16
|
+
ESM: 'esm',
|
|
16
17
|
SAMPLES: 'samples', // deprecated
|
|
17
18
|
TINY_SAMPLE: 'tiny-sample',
|
|
18
19
|
SAMPLE: 'sample',
|
|
20
|
+
TYPER: 'typer',
|
|
21
|
+
TYPESCRIPT: 'typescript',
|
|
22
|
+
HANDLER: 'handler', // influenced by esm, typer and typescript
|
|
19
23
|
MTA: 'mta',
|
|
20
24
|
CF_MANIFEST: 'cf-manifest',
|
|
21
25
|
HELM: 'helm',
|
|
@@ -57,8 +61,6 @@ module.exports = {
|
|
|
57
61
|
LINT_GLOBAL: 'lint:global',
|
|
58
62
|
LINT_DEV: 'lint:dev',
|
|
59
63
|
PIPELINE: 'pipeline',
|
|
60
|
-
TYPER: 'typer',
|
|
61
|
-
TYPESCRIPT: 'typescript'
|
|
62
64
|
}),
|
|
63
65
|
|
|
64
66
|
REGEX_JAVA_PACKAGE: /^[a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*$/g,
|
|
@@ -71,9 +73,6 @@ module.exports = {
|
|
|
71
73
|
CAPIRE: 'https://cap.cloud.sap',
|
|
72
74
|
MAVEN_ARCHETYPE_HELP: `https://cap.cloud.sap/docs/java/developing-applications/building#the-maven-archetype`,
|
|
73
75
|
MAVEN_INSTALL_HELP: `https://maven.apache.org/install.html`,
|
|
74
|
-
CAP_JS_COMMUNITY_ODATA_V2: 'https://github.com/cap-js-community/odata-v2-adapter',
|
|
75
|
-
CAP_JS_COMMUNITY_EVENT_QUEUE: 'https://github.com/cap-js-community/event-queue',
|
|
76
|
-
CAP_JS_COMMUNITY_WEBSOCKET: 'https://github.com/cap-js-community/websocket',
|
|
77
76
|
CF_CLI: 'https://github.com/cloudfoundry/cli'
|
|
78
77
|
}),
|
|
79
78
|
|
package/lib/init/index.js
CHANGED
|
@@ -12,17 +12,13 @@ const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) ? console.debug : undefi
|
|
|
12
12
|
|
|
13
13
|
module.exports = class CDSGenerator {
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const fromDk = readdirSync(join(__dirname, 'template'))
|
|
19
|
-
const fromPlugins = Object.keys(Object.fromEntries(require('./add').registered))
|
|
20
|
-
return [...fromDk, ...fromPlugins]
|
|
21
|
-
.filter(plugin => !excluded?.includes(plugin))
|
|
15
|
+
constructor() {
|
|
16
|
+
this.cwd = process.cwd()
|
|
17
|
+
this.uiConfig = require('./bas') // Used by CAP Generator
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
static help({ exclude = [] } = {}) {
|
|
25
|
-
if (!cds.add) return //
|
|
21
|
+
if (!cds.add) return // shell completion: cds.add is undefined and not needed
|
|
26
22
|
|
|
27
23
|
const plugins = this.readPlugins(exclude)
|
|
28
24
|
const nameFixedLength = Math.max(...plugins.map(plugin => plugin.name.length))
|
|
@@ -35,10 +31,14 @@ module.exports = class CDSGenerator {
|
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
/**
|
|
34
|
+
* @param excluded {string[]}
|
|
38
35
|
* @returns {{name: string, module: import('module')}[]}
|
|
39
36
|
*/
|
|
40
37
|
static readPlugins(excluded = []) {
|
|
41
|
-
const
|
|
38
|
+
const fromDk = readdirSync(join(__dirname, 'template'))
|
|
39
|
+
const fromPlugins = Object.keys(Object.fromEntries(require('./add').registered))
|
|
40
|
+
const all = [...fromDk, ...fromPlugins]
|
|
41
|
+
.filter(plugin => !excluded?.includes(plugin))
|
|
42
42
|
.map(plugin => ({
|
|
43
43
|
name: plugin,
|
|
44
44
|
module: cds.add.registered.get(plugin) ?? require('./template/' + plugin)
|
|
@@ -51,12 +51,7 @@ module.exports = class CDSGenerator {
|
|
|
51
51
|
if (b === -1) return -1
|
|
52
52
|
return a - b
|
|
53
53
|
}
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
constructor() {
|
|
58
|
-
this.cwd = process.cwd()
|
|
59
|
-
this.uiConfig = require('./bas') // Used by CAP Generator
|
|
54
|
+
return all.sort(byPriority)
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
/**
|
|
@@ -216,15 +211,14 @@ module.exports = class CDSGenerator {
|
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
const cmds = Object.values(OPTIONS)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (b === -1) return -1
|
|
214
|
+
const priorities = new Map(cmds.map((cmd, i) => [cmd, i]))
|
|
215
|
+
this.templateList = Array.from(templates.keys())
|
|
216
|
+
.sort((lhs, rhs) => {
|
|
217
|
+
const a = priorities.get(lhs) ?? Infinity
|
|
218
|
+
const b = priorities.get(rhs) ?? Infinity
|
|
225
219
|
return a - b
|
|
226
220
|
})
|
|
227
|
-
.map(
|
|
221
|
+
.map(key => templates.get(key))
|
|
228
222
|
|
|
229
223
|
DEBUG?.(`Features: ${this.templateList.map(({ name }) => name).join(', ')}`);
|
|
230
224
|
}
|
|
@@ -240,11 +234,9 @@ module.exports = class CDSGenerator {
|
|
|
240
234
|
|
|
241
235
|
const { options } = cds.cli
|
|
242
236
|
if (typeof options.add === 'string') {
|
|
243
|
-
tokens = options.add.split(/[,\s+]/g)
|
|
244
|
-
|
|
237
|
+
tokens = options.add.split(/[,\s+]/g)
|
|
245
238
|
} else if (Array.isArray(options.add)) {
|
|
246
239
|
tokens = options.add
|
|
247
|
-
|
|
248
240
|
} else if (options.add instanceof Set) {
|
|
249
241
|
tokens = [...options.add];
|
|
250
242
|
}
|
package/lib/init/merge.js
CHANGED
|
@@ -6,11 +6,8 @@ const { readYAML, writeYAML, readJSON } = require('../util/fs')
|
|
|
6
6
|
const { detectIndent } = require('./indent')
|
|
7
7
|
const { colors } = require('../util/term')
|
|
8
8
|
|
|
9
|
-
function _isObject(item) {
|
|
10
|
-
return item && typeof item === 'object' && !Array.isArray(item)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
function _mergeObject(target, source) {
|
|
10
|
+
const _isObject = item => item && typeof item === 'object' && !Array.isArray(item)
|
|
14
11
|
const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse)
|
|
15
12
|
if (_isObject(target) && _isObject(source)) {
|
|
16
13
|
for (const key in source) {
|