@sap/cds-compiler 2.15.8 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -1590
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +61 -46
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1592 -0
- package/doc/CHANGELOG_BETA.md +26 -5
- package/doc/CHANGELOG_DEPRECATED.md +55 -1
- package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
- package/doc/Versioning.md +20 -1
- package/lib/api/.eslintrc.json +2 -2
- package/lib/api/main.js +282 -156
- package/lib/api/options.js +17 -88
- package/lib/api/validate.js +6 -10
- package/lib/base/keywords.js +280 -110
- package/lib/base/message-registry.js +85 -25
- package/lib/base/messages.js +119 -89
- package/lib/base/model.js +46 -2
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +15 -12
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -0
- package/lib/checks/elements.js +6 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -1
- package/lib/checks/selectItems.js +101 -15
- package/lib/checks/types.js +7 -8
- package/lib/checks/utils.js +2 -2
- package/lib/checks/validator.js +3 -3
- package/lib/compiler/assert-consistency.js +78 -21
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +177 -10
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +75 -18
- package/lib/compiler/finalize-parse-cdl.js +25 -18
- package/lib/compiler/index.js +27 -11
- package/lib/compiler/moduleLayers.js +7 -0
- package/lib/compiler/populate.js +26 -39
- package/lib/compiler/propagator.js +12 -7
- package/lib/compiler/resolve.js +207 -236
- package/lib/compiler/shared.js +100 -93
- package/lib/compiler/tweak-assocs.js +13 -20
- package/lib/compiler/utils.js +20 -6
- package/lib/edm/annotations/preprocessAnnotations.js +12 -13
- package/lib/edm/csn2edm.js +35 -37
- package/lib/edm/edm.js +22 -13
- package/lib/edm/edmAnnoPreprocessor.js +349 -0
- package/lib/edm/edmInboundChecks.js +85 -0
- package/lib/edm/edmPreprocessor.js +338 -689
- package/lib/edm/edmUtils.js +97 -67
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +8 -31
- package/lib/gen/language.tokens +105 -114
- package/lib/gen/languageLexer.interp +1 -34
- package/lib/gen/languageLexer.js +892 -1007
- package/lib/gen/languageLexer.tokens +95 -106
- package/lib/gen/languageParser.js +20629 -22474
- package/lib/inspect/.eslintrc.json +4 -0
- package/lib/inspect/index.js +14 -0
- package/lib/inspect/inspectModelStatistics.js +81 -0
- package/lib/inspect/inspectPropagation.js +189 -0
- package/lib/inspect/inspectUtils.js +44 -0
- package/lib/json/from-csn.js +74 -69
- package/lib/json/to-csn.js +17 -14
- package/lib/language/antlrParser.js +2 -2
- package/lib/language/docCommentParser.js +61 -38
- package/lib/language/errorStrategy.js +52 -40
- package/lib/language/genericAntlrParser.js +424 -292
- package/lib/language/language.g4 +604 -687
- package/lib/language/multiLineStringParser.js +14 -42
- package/lib/language/textUtils.js +44 -0
- package/lib/main.d.ts +28 -42
- package/lib/main.js +104 -81
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +57 -30
- package/lib/model/csnUtils.js +189 -287
- package/lib/model/revealInternalProperties.js +32 -10
- package/lib/model/sortViews.js +32 -31
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +91 -57
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/DuplicateChecker.js +4 -7
- package/lib/render/manageConstraints.js +70 -2
- package/lib/render/toCdl.js +387 -367
- package/lib/render/toHdbcds.js +20 -16
- package/lib/render/toRename.js +44 -22
- package/lib/render/toSql.js +81 -59
- package/lib/render/utils/common.js +16 -3
- package/lib/render/utils/sql.js +20 -19
- package/lib/sql-identifier.js +6 -0
- package/lib/transform/db/.eslintrc.json +3 -2
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +5 -16
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +7 -6
- package/lib/transform/db/flattening.js +16 -18
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/db/views.js +3 -3
- package/lib/transform/draft/.eslintrc.json +2 -2
- package/lib/transform/draft/db.js +6 -6
- package/lib/transform/draft/odata.js +6 -7
- package/lib/transform/forHanaNew.js +30 -24
- package/lib/transform/forOdataNew.js +14 -16
- package/lib/transform/localized.js +35 -25
- package/lib/transform/odata/toFinalBaseType.js +10 -10
- package/lib/transform/odata/typesExposure.js +17 -8
- package/lib/transform/odata/utils.js +1 -38
- package/lib/transform/transformUtilsNew.js +63 -77
- package/lib/transform/translateAssocsToJoins.js +2 -2
- package/lib/transform/universalCsn/.eslintrc.json +2 -2
- package/lib/transform/universalCsn/coreComputed.js +11 -6
- package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
- package/lib/utils/file.js +31 -21
- package/lib/utils/moduleResolve.js +0 -1
- package/lib/utils/timetrace.js +20 -21
- package/package.json +34 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/doc/ApiMigration.md +0 -237
- package/doc/CommandLineMigration.md +0 -58
- package/doc/ErrorMessages.md +0 -175
- package/doc/FioriAnnotations.md +0 -94
- package/doc/ODataTransformation.md +0 -273
- package/lib/backends.js +0 -529
- package/lib/checks/unknownMagic.js +0 -41
- package/lib/fix_antlr4-8_warning.js +0 -56
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
const { hasErrors, makeMessageFunction } = require('../base/messages');
|
|
8
8
|
const { setProp } = require('../base/model');
|
|
9
|
-
const { csnRefs } = require('../model/csnRefs');
|
|
10
9
|
|
|
11
10
|
const { copyAnnotations, applyTransformations } = require('../model/csnUtils');
|
|
12
|
-
const { cloneCsnNonDict, cloneCsnDictionary, getUtils
|
|
11
|
+
const { cloneCsnNonDict, cloneCsnDictionary, getUtils } = require('../model/csnUtils');
|
|
12
|
+
const { typeParameters, isBuiltinType } = require('../compiler/builtins');
|
|
13
13
|
const { ModelError } = require("../base/error");
|
|
14
14
|
const { forEach } = require('../utils/objectUtils');
|
|
15
15
|
|
|
@@ -20,20 +20,18 @@ const { forEach } = require('../utils/objectUtils');
|
|
|
20
20
|
// TODO: check the situation with assocs with values. In compacted CSN such elements have only "@Core.Computed": true
|
|
21
21
|
function getTransformers(model, options, pathDelimiter = '_') {
|
|
22
22
|
const { error, warning, info } = makeMessageFunction(model, options);
|
|
23
|
+
const csnUtils = getUtils(model);
|
|
23
24
|
const {
|
|
24
25
|
getCsnDef,
|
|
25
|
-
|
|
26
|
+
getFinalBaseTypeWithProps,
|
|
26
27
|
hasAnnotationValue,
|
|
27
28
|
inspectRef,
|
|
28
29
|
isStructured,
|
|
29
|
-
} = getUtils(model);
|
|
30
|
-
|
|
31
|
-
const {
|
|
32
30
|
effectiveType,
|
|
33
|
-
} =
|
|
34
|
-
|
|
31
|
+
} = csnUtils;
|
|
35
32
|
|
|
36
33
|
return {
|
|
34
|
+
csnUtils,
|
|
37
35
|
resolvePath,
|
|
38
36
|
flattenPath,
|
|
39
37
|
addDefaultTypeFacets,
|
|
@@ -45,7 +43,6 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
45
43
|
copyTypeProperties,
|
|
46
44
|
isAssociationOperand,
|
|
47
45
|
isDollarSelfOrProjectionOperand,
|
|
48
|
-
getFinalBaseType,
|
|
49
46
|
createExposingProjection,
|
|
50
47
|
createAndAddDraftAdminDataProjection,
|
|
51
48
|
createScalarElement,
|
|
@@ -243,21 +240,19 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
243
240
|
// for type of 'x' -> elem.type is an object, not a string -> use directly
|
|
244
241
|
let elemType;
|
|
245
242
|
if (!elem.elements) // structures do not have final base type
|
|
246
|
-
elemType =
|
|
243
|
+
elemType = getFinalBaseTypeWithProps(elem.type);
|
|
247
244
|
|
|
248
245
|
const struct = elemType ? elemType.elements : elem.elements;
|
|
249
246
|
|
|
250
247
|
// Collect all child elements (recursively) into 'result'
|
|
251
248
|
// TODO: Do not report collisions in the generated elements here, but instead
|
|
252
|
-
//
|
|
249
|
+
// leave that work to the receiver of this result
|
|
253
250
|
let result = Object.create(null);
|
|
254
251
|
const addGeneratedFlattenedElement = (e, eName) => {
|
|
255
|
-
if(result[eName])
|
|
256
|
-
error(
|
|
257
|
-
|
|
258
|
-
} else {
|
|
252
|
+
if (result[eName])
|
|
253
|
+
error('name-duplicate-element', pathInCsn, { '#': 'flatten-element-gen', name: eName })
|
|
254
|
+
else
|
|
259
255
|
result[eName] = e;
|
|
260
|
-
}
|
|
261
256
|
}
|
|
262
257
|
forEach(struct, (childName, childElem) => {
|
|
263
258
|
if (isStructured(childElem)) {
|
|
@@ -287,7 +282,11 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
287
282
|
|
|
288
283
|
// Fix all collected flat elements (names, annotations, properties, origin ..)
|
|
289
284
|
forEach(result, (name, flatElem) => {
|
|
290
|
-
// Copy annotations from struct (not overwriting, because deep annotations should have precedence)
|
|
285
|
+
// Copy annotations from struct (not overwriting, because deep annotations should have precedence).
|
|
286
|
+
// Attention:
|
|
287
|
+
// This has historic reasons. We don't copy doc-comments because copying annotations
|
|
288
|
+
// is questionable to begin with. Only selected annotations should have been copied,
|
|
289
|
+
// if at all.
|
|
291
290
|
copyAnnotations(elem, flatElem, false);
|
|
292
291
|
// Copy selected type properties
|
|
293
292
|
const props = ['key', 'virtual', 'masked', 'viaAll'];
|
|
@@ -395,78 +394,65 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
395
394
|
}
|
|
396
395
|
|
|
397
396
|
/**
|
|
398
|
-
* Replace the type of '
|
|
399
|
-
*
|
|
400
|
-
* Similar with associations and compositions (we probably need a _baseType link)
|
|
397
|
+
* Replace the type of 'nodeWithType' with its final base type, i.e. copy relevant type properties and
|
|
398
|
+
* set the `type` property to the builtin if scalar or delete it if structured/arrayed.
|
|
401
399
|
*
|
|
402
|
-
* @param {
|
|
400
|
+
* @param {object} nodeWithType
|
|
403
401
|
* @param {WeakMap} [resolved] WeakMap containing already resolved refs
|
|
404
402
|
* @param {boolean} [keepLocalized=false] Whether to clone .localized from a type def
|
|
405
|
-
* @returns {void}
|
|
406
403
|
*/
|
|
407
|
-
function toFinalBaseType(
|
|
408
|
-
|
|
409
|
-
if (!
|
|
410
|
-
// In case of a ref -> Follow the ref
|
|
411
|
-
if (node.type && node.type.ref) {
|
|
412
|
-
const finalBaseType = getFinalBaseType(node.type, undefined, resolved);
|
|
413
|
-
if(finalBaseType === null)
|
|
414
|
-
throw Error('Failed to obtain final base type for reference : ' + node.type.ref.join('/'));
|
|
415
|
-
if(finalBaseType.elements) {
|
|
416
|
-
// This changes the order - to be discussed!
|
|
417
|
-
node.elements = cloneCsnNonDict(finalBaseType, options).elements; // copy elements
|
|
418
|
-
delete node.type; // delete the type reference as edm processing does not expect it
|
|
419
|
-
} else if(finalBaseType.items) {
|
|
420
|
-
// This changes the order - to be discussed!
|
|
421
|
-
node.items = cloneCsnNonDict(finalBaseType.items, options); // copy items
|
|
422
|
-
delete node.type;
|
|
423
|
-
} else {
|
|
424
|
-
node.type=finalBaseType;
|
|
425
|
-
}
|
|
404
|
+
function toFinalBaseType(nodeWithType, resolved = new WeakMap(), keepLocalized = false) {
|
|
405
|
+
const type = nodeWithType?.type;
|
|
406
|
+
if (!type || nodeWithType.elements || nodeWithType.items || resolved.has(nodeWithType)) {
|
|
426
407
|
return;
|
|
427
408
|
}
|
|
428
|
-
//
|
|
429
|
-
|
|
409
|
+
// The caller may use `{ art }` syntax for `{ ref }` objects, but we only use
|
|
410
|
+
// it to indicate that an artifact has been processed.
|
|
411
|
+
resolved.set(nodeWithType, nodeWithType);
|
|
430
412
|
|
|
431
|
-
//
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (typeDef.items || typeDef.elements) {
|
|
435
|
-
// cloneCsn only works correctly if we start "from the top"
|
|
436
|
-
const cloneTypeDef = cloneCsnNonDict(typeDef, options);
|
|
437
|
-
// With hdbcds-hdbcds, don't resolve structured types - but propagate ".items", to turn into LargeString later on.
|
|
438
|
-
if(typeDef.items) {
|
|
439
|
-
delete node.type;
|
|
440
|
-
if(!node.items)
|
|
441
|
-
Object.assign(node, {items: cloneTypeDef.items});
|
|
442
|
-
}
|
|
443
|
-
if(typeDef.elements && !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds')) {
|
|
444
|
-
if(!typeDef.items)
|
|
445
|
-
delete node.type;
|
|
446
|
-
if(!node.elements)
|
|
447
|
-
Object.assign(node, {elements: cloneTypeDef.elements});
|
|
448
|
-
}
|
|
413
|
+
// Nothing to copy from builtin.
|
|
414
|
+
if (typeof type === 'string' && isBuiltinType(type))
|
|
415
|
+
return;
|
|
449
416
|
|
|
417
|
+
let typeRef = null;
|
|
418
|
+
if (resolved.has(type)) {
|
|
419
|
+
typeRef = resolved.get(type)?.art
|
|
420
|
+
// The cached entry may not be resolved, yet.
|
|
421
|
+
if (typeRef.type && !isBuiltinType(typeRef.type))
|
|
422
|
+
typeRef = getFinalBaseTypeWithProps(typeRef.type);
|
|
423
|
+
} else {
|
|
424
|
+
typeRef = getFinalBaseTypeWithProps(type);
|
|
425
|
+
}
|
|
450
426
|
|
|
427
|
+
if (typeRef.elements || typeRef.items) {
|
|
428
|
+
// Copy elements/items and we're finished. No need to look up actual base type,
|
|
429
|
+
// since it must also be structured and must contain at least as many elements,
|
|
430
|
+
// if not more (in client style CSN).
|
|
431
|
+
if (typeRef.elements && !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds')) {
|
|
432
|
+
nodeWithType.elements = cloneCsnDictionary(typeRef.elements, options);
|
|
433
|
+
delete nodeWithType.type;
|
|
434
|
+
}
|
|
435
|
+
if (typeRef.items) {
|
|
436
|
+
nodeWithType.items = cloneCsnNonDict(typeRef.items, options);
|
|
437
|
+
delete nodeWithType.type;
|
|
438
|
+
}
|
|
451
439
|
return;
|
|
452
440
|
}
|
|
453
|
-
|
|
454
|
-
if (
|
|
455
|
-
|
|
456
|
-
|
|
441
|
+
|
|
442
|
+
if (typeRef.enum && nodeWithType.enum === undefined)
|
|
443
|
+
nodeWithType.enum = cloneCsnDictionary(typeRef.enum, options);
|
|
444
|
+
|
|
445
|
+
// Copy type and type arguments (+ localized)
|
|
446
|
+
|
|
447
|
+
for (const param of typeParameters.list) {
|
|
448
|
+
if (nodeWithType[param] === undefined && typeRef[param] !== undefined &&!typeRef.$default) {
|
|
449
|
+
nodeWithType[param] = typeRef[param];
|
|
450
|
+
}
|
|
457
451
|
}
|
|
458
|
-
if (
|
|
459
|
-
|
|
460
|
-
if (
|
|
461
|
-
|
|
462
|
-
if (node.scale === undefined && typeDef.scale !== undefined)
|
|
463
|
-
Object.assign(node, { scale: typeDef.scale });
|
|
464
|
-
if (node.srid === undefined && typeDef.srid !== undefined)
|
|
465
|
-
Object.assign(node, { srid: typeDef.srid });
|
|
466
|
-
if (keepLocalized && node.localized === undefined && typeDef.localized !== undefined)
|
|
467
|
-
Object.assign(node, { localized: typeDef.localized });
|
|
468
|
-
node.type = typeDef.type;
|
|
469
|
-
toFinalBaseType(node);
|
|
452
|
+
if (keepLocalized && nodeWithType.localized === undefined && typeRef.localized !== undefined)
|
|
453
|
+
nodeWithType.localized = typeRef.localized;
|
|
454
|
+
if (typeRef.type)
|
|
455
|
+
nodeWithType.type = typeRef.type;
|
|
470
456
|
}
|
|
471
457
|
|
|
472
458
|
// Return a full projection 'projectionId' of artifact 'art' for exposure in 'service'.
|
|
@@ -57,10 +57,10 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
57
57
|
const options = model.options || inputOptions;
|
|
58
58
|
|
|
59
59
|
// create JOINs for foreign key paths
|
|
60
|
-
const noJoinForFK = options.forHana ? !options.
|
|
60
|
+
const noJoinForFK = options.forHana ? !options.joinfk : true;
|
|
61
61
|
|
|
62
62
|
// Note: This is called from the 'forHana' transformations, so it is controlled by its options)
|
|
63
|
-
const pathDelimiter = (options.forHana && options.
|
|
63
|
+
const pathDelimiter = (options.forHana && options.sqlMapping === 'hdbcds') ? '.' : '_';
|
|
64
64
|
|
|
65
65
|
forEachDefinition(model, prepareAssociations);
|
|
66
66
|
forEachDefinition(model, transformQueries);
|
|
@@ -12,7 +12,7 @@ const { setAnnotationIfNotDefined } = require('./utils');
|
|
|
12
12
|
*/
|
|
13
13
|
function setCoreComputedOnViews(csn) {
|
|
14
14
|
const {
|
|
15
|
-
artifactRef, getColumn, getElement,
|
|
15
|
+
artifactRef, getColumn, getElement, getOrigin,
|
|
16
16
|
} = getUtils(csn, 'init-all');
|
|
17
17
|
|
|
18
18
|
forEachDefinition(csn, (artifact) => {
|
|
@@ -57,7 +57,15 @@ function setCoreComputedOnViews(csn) {
|
|
|
57
57
|
const column = getColumn(element);
|
|
58
58
|
if (column)
|
|
59
59
|
return column;
|
|
60
|
-
|
|
60
|
+
const from = getElementFromFrom(name, base.from);
|
|
61
|
+
if (from)
|
|
62
|
+
return from;
|
|
63
|
+
// For .expand/.inline, we can find it via origin
|
|
64
|
+
// Although I would have expected to find it via getColumn...
|
|
65
|
+
const origin = getOrigin(element);
|
|
66
|
+
if (origin)
|
|
67
|
+
return origin;
|
|
68
|
+
throw new Error(`Could not find ancestor for ${JSON.stringify(element)} named ${name}`);
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
/**
|
|
@@ -87,10 +95,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
87
95
|
return getElementFromFrom(name, base.SET.args[0]);
|
|
88
96
|
}
|
|
89
97
|
else if (base.args && base.join) {
|
|
90
|
-
|
|
91
|
-
if (!result)
|
|
92
|
-
throw new Error(`Could not find ${name} in ${JSON.stringify(base.args)}`);
|
|
93
|
-
return result;
|
|
98
|
+
return checkJoinSources(base.args, name);
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
throw new Error(JSON.stringify(base));
|
|
@@ -29,10 +29,7 @@ module.exports = (csn, options) => {
|
|
|
29
29
|
const definitionPropagationRules = {
|
|
30
30
|
'@cds.autoexpose': onlyViaArtifact,
|
|
31
31
|
'@fiori.draft.enabled': onlyViaArtifact,
|
|
32
|
-
'@':
|
|
33
|
-
if (source[prop] !== null)
|
|
34
|
-
target[prop] = source[prop];
|
|
35
|
-
},
|
|
32
|
+
'@': nullStopsPropagation,
|
|
36
33
|
// Example: `type E : F;` does not have `elements`, but they are required for e.g. OData.
|
|
37
34
|
elements: onlyTypeDef,
|
|
38
35
|
'@cds.persistence.exists': skip,
|
|
@@ -48,7 +45,7 @@ module.exports = (csn, options) => {
|
|
|
48
45
|
'@cds.autoexposed': skip,
|
|
49
46
|
'@cds.redirection.target': skip,
|
|
50
47
|
type: always,
|
|
51
|
-
doc:
|
|
48
|
+
doc: nullStopsPropagation,
|
|
52
49
|
length: always,
|
|
53
50
|
precision: always,
|
|
54
51
|
scale: always,
|
|
@@ -94,6 +91,10 @@ module.exports = (csn, options) => {
|
|
|
94
91
|
}, // overwrite from defProps
|
|
95
92
|
kind: skip,
|
|
96
93
|
val: always,
|
|
94
|
+
type: notWithItemsOrElements,
|
|
95
|
+
target: notWithItemsOrElements,
|
|
96
|
+
keys: notWithItemsOrElements,
|
|
97
|
+
cardinality: notWithItemsOrElements,
|
|
97
98
|
};
|
|
98
99
|
|
|
99
100
|
generate();
|
|
@@ -702,6 +703,19 @@ function notWithTypeOrigin(prop, target, source) {
|
|
|
702
703
|
target[prop] = source[prop];
|
|
703
704
|
}
|
|
704
705
|
|
|
706
|
+
/**
|
|
707
|
+
* The value `null` tells us to skip the propagation of the property.
|
|
708
|
+
* This is the case e.g. for `doc` or for annotations.
|
|
709
|
+
*
|
|
710
|
+
* @param {string} prop
|
|
711
|
+
* @param {CSN.Element} target
|
|
712
|
+
* @param {CSN.Element} source
|
|
713
|
+
*/
|
|
714
|
+
function nullStopsPropagation(prop, target, source) {
|
|
715
|
+
if (source[prop] !== null)
|
|
716
|
+
target[prop] = source[prop];
|
|
717
|
+
}
|
|
718
|
+
|
|
705
719
|
/**
|
|
706
720
|
* Special propagation rules for .items - depending on the exact type of .items and the
|
|
707
721
|
* way it was referenced (type of, direct type, direct many), we need to propagate (or not).
|
|
@@ -722,6 +736,20 @@ function specialItemsRules(prop, target, source) {
|
|
|
722
736
|
target[prop] = source[prop];
|
|
723
737
|
}
|
|
724
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Don't propagate certain properties if the target already has a .items or .elements
|
|
741
|
+
*
|
|
742
|
+
* This happens with .expand/.inline
|
|
743
|
+
*
|
|
744
|
+
* @param {string} prop
|
|
745
|
+
* @param {CSN.Element} target
|
|
746
|
+
* @param {CSN.Element} source
|
|
747
|
+
*/
|
|
748
|
+
function notWithItemsOrElements(prop, target, source) {
|
|
749
|
+
if (!target.items && !target.elements || !source.target)
|
|
750
|
+
target[prop] = source[prop];
|
|
751
|
+
}
|
|
752
|
+
|
|
725
753
|
/**
|
|
726
754
|
* Some properties must not be copied over if the type of this member
|
|
727
755
|
* is a reference to another element.
|
package/lib/utils/file.js
CHANGED
|
@@ -61,12 +61,12 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
function realpath(path, cb) {
|
|
64
|
-
return fs.realpath(path, cb);
|
|
64
|
+
return fs.realpath.native(path, cb);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function realpathSync(path, cb) {
|
|
68
68
|
try {
|
|
69
|
-
cb(null, fs.realpathSync(path));
|
|
69
|
+
cb(null, fs.realpathSync.native(path));
|
|
70
70
|
}
|
|
71
71
|
catch (err) {
|
|
72
72
|
cb(err, null);
|
|
@@ -87,7 +87,7 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
87
87
|
}
|
|
88
88
|
let body = fileCache[filename];
|
|
89
89
|
if (body && typeof body === 'object' && body.realname) {
|
|
90
|
-
filename = body.realname; // use fs.realpath name
|
|
90
|
+
filename = body.realname; // use fs.realpath.native name
|
|
91
91
|
body = fileCache[filename];
|
|
92
92
|
}
|
|
93
93
|
if (body !== undefined && body !== true) { // true: we just know it is there
|
|
@@ -113,11 +113,16 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
113
113
|
traceFS( 'READFILE:start:', filename );
|
|
114
114
|
// TODO: set cache directly to some "delay" - store error differently?
|
|
115
115
|
// e.g. an error of callback functions!
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
try {
|
|
117
|
+
reader(filename, enc, (err, data) => {
|
|
118
|
+
fileCache[filename] = err || data;
|
|
119
|
+
traceFS('READFILE:data:', filename, err || data);
|
|
120
|
+
cb(err, data);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
cb(err); // if filename is not a valid (e.g. contains NUL byte), readFile() may throw
|
|
125
|
+
}
|
|
121
126
|
}
|
|
122
127
|
};
|
|
123
128
|
}
|
|
@@ -143,19 +148,24 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
143
148
|
// in the future (if we do module resolve ourself with just readFile),
|
|
144
149
|
// we avoid parallel readFile by storing having an array of `cb`s in
|
|
145
150
|
// fileCache[ filename ] before starting fs.readFile().
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
fileCache[filename]
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
try {
|
|
152
|
+
fsStat(filename, (err, stat) => {
|
|
153
|
+
if (err)
|
|
154
|
+
body = (err.code === 'ENOENT' || err.code === 'ENOTDIR') ? false : err;
|
|
155
|
+
else
|
|
156
|
+
body = !!(stat.isFile() || stat.isFIFO());
|
|
157
|
+
if (fileCache[filename] === undefined) // parallel readFile() has been processed
|
|
158
|
+
fileCache[filename] = body;
|
|
159
|
+
traceFS('ISFILE:data:', filename, body);
|
|
160
|
+
if (body instanceof Error)
|
|
161
|
+
cb(err);
|
|
162
|
+
else
|
|
163
|
+
cb(null, body);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
cb(err); // if filename is not a valid (e.g. contains NUL byte), fsStat() may throw
|
|
168
|
+
}
|
|
159
169
|
}
|
|
160
170
|
};
|
|
161
171
|
}
|
|
@@ -25,7 +25,6 @@ const extensions = [ '.cds', '.csn', '.json' ];
|
|
|
25
25
|
* @todo Re-think:
|
|
26
26
|
* - Why can't a JAVA installation set a (symbolic) link?
|
|
27
27
|
* - Preferred to a local installation? Not the node-way!
|
|
28
|
-
* - Why a global? The Umbrella could pass it as an option.
|
|
29
28
|
*
|
|
30
29
|
* @param {string} modulePath
|
|
31
30
|
* @param {CSN.Options} options
|
package/lib/utils/timetrace.js
CHANGED
|
@@ -14,47 +14,43 @@ class StopWatch {
|
|
|
14
14
|
*/
|
|
15
15
|
constructor(id) {
|
|
16
16
|
this.id = id;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// eslint-disable-next-line no-multi-assign
|
|
20
|
-
this.startTime = this.lapTime = process.hrtime();
|
|
17
|
+
this.startTime = process.hrtime.bigint();
|
|
18
|
+
this.lapTime = this.startTime;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
* Start watch.
|
|
23
|
+
*/
|
|
26
24
|
start() {
|
|
27
|
-
|
|
28
|
-
this.
|
|
25
|
+
this.startTime = process.hrtime.bigint();
|
|
26
|
+
this.lapTime = this.startTime;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
|
-
* Stop and return delta T
|
|
30
|
+
* Stop and return delta T in nanoseconds,
|
|
33
31
|
* but do not set start time
|
|
34
32
|
*/
|
|
35
33
|
stop() {
|
|
36
|
-
|
|
34
|
+
const endTime = process.hrtime.bigint();
|
|
35
|
+
return endTime - this.startTime;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
/**
|
|
40
|
-
* return lap time
|
|
41
|
-
*/
|
|
42
38
|
lap() {
|
|
43
|
-
const
|
|
44
|
-
|
|
39
|
+
const endTime = process.hrtime.bigint();
|
|
40
|
+
const dt = endTime - this.startTime;
|
|
41
|
+
this.lapTime = process.hrtime.bigint();
|
|
45
42
|
return dt;
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
// stop as sec.ns float
|
|
49
45
|
stopInFloatSecs() {
|
|
50
46
|
const dt = this.stop();
|
|
51
|
-
return dt
|
|
47
|
+
return dt / BigInt(1000000000);
|
|
52
48
|
}
|
|
53
49
|
|
|
54
50
|
// lap as sec.ns float
|
|
55
51
|
lapInFloatSecs() {
|
|
56
52
|
const dt = this.lap();
|
|
57
|
-
return dt
|
|
53
|
+
return dt / BigInt(1000000000);
|
|
58
54
|
}
|
|
59
55
|
}
|
|
60
56
|
|
|
@@ -63,7 +59,7 @@ class StopWatch {
|
|
|
63
59
|
*
|
|
64
60
|
* Results are logged to stderr
|
|
65
61
|
*
|
|
66
|
-
* To enable time tracing, set
|
|
62
|
+
* To enable time tracing, set CDSC_TIMETRACING to true in the environment
|
|
67
63
|
*
|
|
68
64
|
* @class TimeTracer
|
|
69
65
|
*/
|
|
@@ -107,10 +103,13 @@ class TimeTracer {
|
|
|
107
103
|
stop() {
|
|
108
104
|
try {
|
|
109
105
|
const current = this.traceStack.pop();
|
|
110
|
-
const
|
|
106
|
+
const dt = current.stop();
|
|
111
107
|
const base = `${ ' '.repeat(this.traceStack.length * 2) }${ current.id } took:`;
|
|
108
|
+
const sec = (dt / BigInt(1000000000)).toString();
|
|
109
|
+
// first, get remaining ns, then convert to ms.
|
|
110
|
+
const msec = ((dt % BigInt(1000000000)) / BigInt(1000000)).toString();
|
|
112
111
|
// eslint-disable-next-line no-console
|
|
113
|
-
console.error( `${ base }${ ' '.repeat(60 - base.length) } %ds %dms`,
|
|
112
|
+
console.error( `${ base }${ ' '.repeat(60 - base.length) } %ds %dms`, sec, msec );
|
|
114
113
|
}
|
|
115
114
|
catch (e) {
|
|
116
115
|
// eslint-disable-next-line no-console
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "CDS (Core Data Services) compiler and backends",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"author": "SAP SE (https://www.sap.com)",
|
|
7
7
|
"license": "SEE LICENSE IN LICENSE",
|
|
8
|
+
"type": "commonjs",
|
|
8
9
|
"bin": {
|
|
9
10
|
"cdsc": "bin/cdsc.js",
|
|
10
11
|
"cdshi": "bin/cdshi.js",
|
|
@@ -13,13 +14,42 @@
|
|
|
13
14
|
"main": "lib/main.js",
|
|
14
15
|
"types": "lib/main.d.ts",
|
|
15
16
|
"scripts": {
|
|
16
|
-
"
|
|
17
|
+
"download": "node scripts/downloadANTLR.js",
|
|
18
|
+
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js",
|
|
19
|
+
"xmakeBeforeInstall": "echo \"Due to binary mirror, use sqlite 5.0.11 explicitly\" && npm install --save --save-exact --no-package-lock sqlite3@5.0.11",
|
|
20
|
+
"xmakeAfterInstall": "npm run gen",
|
|
21
|
+
"xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
|
|
22
|
+
"test": "node scripts/verifyGrammarChecksum.js && mocha --reporter min --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter min --reporter-option maxDiffSize=0 test/ test3/",
|
|
23
|
+
"testverbose": "node scripts/verifyGrammarChecksum.js && mocha --parallel test/ test3/",
|
|
24
|
+
"test3": "node scripts/verifyGrammarChecksum.js && node scripts/linter/lintTests.js test3/ && mocha --reporter-option maxDiffSize=0 scripts/linter/lintMessages.js test3/",
|
|
25
|
+
"deployTest3SQL": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/testHANASQLDeployment.js",
|
|
26
|
+
"deployTest3": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/testDeployment.js",
|
|
27
|
+
"deployDiffs": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/deployDiffs.js",
|
|
28
|
+
"gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
|
|
29
|
+
"testdb": "node scripts/verifyGrammarChecksum.js && cross-env TESTDB='TRUE' mocha",
|
|
30
|
+
"testmigration": "npm install --no-save @sap/hana-client@2.3.123 @sap/hdi-deploy@3.10.0 && node scripts/verifyGrammarChecksum.js && cross-env TESTMIGRATION='TRUE' mocha",
|
|
31
|
+
"testall": "npm install --no-save @sap/hana-client@2.3.123 @sap/hdi-deploy@3.10.0 && node scripts/verifyGrammarChecksum.js && cross-env TESTDB='TRUE' TESTMIGRATION='TRUE' mocha",
|
|
32
|
+
"coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/ && nyc report --reporter=lcov",
|
|
33
|
+
"lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ types/ && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint .",
|
|
34
|
+
"tslint": "tsc --pretty -p .",
|
|
35
|
+
"updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
|
|
36
|
+
"generateCompilerRefs": "cross-env MAKEREFS='true' mocha test/testCompiler.js",
|
|
37
|
+
"generateEdmRefs": "cross-env MAKEREFS='true' mocha test/testEdmPositive.js",
|
|
38
|
+
"generateForHanaRefs": "cross-env MAKEREFS='true' mocha test/testHanaTransformation.js",
|
|
39
|
+
"generateOdataRefs": "cross-env MAKEREFS='true' mocha test/testODataTransformation.js",
|
|
40
|
+
"generateOdataAnnoRefs": "cross-env MAKEREFS='true' mocha test/testODataAnnotations.js",
|
|
41
|
+
"generateToSqlRefs": "cross-env MAKEREFS='true' mocha test/testToSql.js",
|
|
42
|
+
"generateToRenameRefs": "cross-env MAKEREFS='true' mocha test/testToRename.js",
|
|
43
|
+
"generateChecksRefs": "cross-env MAKEREFS='true' mocha test/testChecks.js",
|
|
44
|
+
"generateScenarioRefs": "cross-env MAKEREFS='true' mocha test/testScenarios.js",
|
|
45
|
+
"generateDraftRefs": "cross-env MAKEREFS='true' mocha test/testDraft.js",
|
|
46
|
+
"generateAllRefs": "node scripts/verifyGrammarChecksum.js && cross-env MAKEREFS='true' mocha --reporter-option maxDiffSize=0 test/ test3/"
|
|
17
47
|
},
|
|
18
48
|
"keywords": [
|
|
19
49
|
"CDS"
|
|
20
50
|
],
|
|
21
51
|
"dependencies": {
|
|
22
|
-
"antlr4": "4.
|
|
52
|
+
"antlr4": "4.9.3"
|
|
23
53
|
},
|
|
24
54
|
"files": [
|
|
25
55
|
"bin",
|
|
@@ -32,6 +62,6 @@
|
|
|
32
62
|
"LICENSE"
|
|
33
63
|
],
|
|
34
64
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
65
|
+
"node": ">=14"
|
|
36
66
|
}
|
|
37
67
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# syntax-expected-integer
|
|
2
2
|
|
|
3
3
|
The compiler expects a safe integer here.
|
|
4
|
-
The last safe
|
|
4
|
+
The last safe integer is `2^53 - 1` or `9007199254740991`.
|
|
5
5
|
|
|
6
|
-
A safe integer is an integer that
|
|
6
|
+
A safe integer is an integer that fulfills all of the following:
|
|
7
7
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
8
|
+
- Can be exactly represented as an IEEE-754 double precision number.
|
|
9
|
+
- The IEEE-754 representation cannot be the result of rounding any
|
|
10
10
|
other integer to fit the IEEE-754 representation.
|
|
11
11
|
|
|
12
12
|
The message's severity is `Error`.
|
|
@@ -15,13 +15,14 @@ The message's severity is `Error`.
|
|
|
15
15
|
|
|
16
16
|
Erroneous code example:
|
|
17
17
|
|
|
18
|
+
<!-- cds-mode: ignore -->
|
|
18
19
|
```cdl
|
|
19
20
|
type LengthIsUnsafe : String(9007199254740992);
|
|
20
21
|
type NotAnInteger : String(42.1);
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
In the
|
|
24
|
-
safe
|
|
24
|
+
In the erroneous example, the string length for the type `LengthIsUnsafe` is
|
|
25
|
+
not a safe integer. It is too large.
|
|
25
26
|
Likewise, the string length for the type `NotAnInteger` is a decimal.
|
|
26
27
|
|
|
27
28
|
## How to Fix
|
|
@@ -33,5 +34,5 @@ type LengthIsSafe : String(9007199254740991);
|
|
|
33
34
|
type AnInteger : String(42);
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
If not feasible, a string representation of the
|
|
37
|
-
|
|
37
|
+
If it's not feasible to use a safe integer, a string representation of the
|
|
38
|
+
number needs to be used, for example, in annotation values.
|