@sap/cds-compiler 3.4.4 → 3.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 +72 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +12 -12
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +58 -59
- package/lib/api/options.js +4 -2
- package/lib/api/validate.js +2 -2
- package/lib/base/cleanSymbols.js +2 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +6 -6
- package/lib/base/location.js +11 -12
- package/lib/base/message-registry.js +124 -28
- package/lib/base/messages.js +247 -179
- package/lib/base/model.js +14 -11
- package/lib/base/node-helpers.js +9 -10
- package/lib/base/optionProcessorHelper.js +138 -129
- package/lib/checks/actionsFunctions.js +5 -5
- package/lib/checks/annotationsOData.js +4 -4
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +3 -3
- package/lib/checks/defaultValues.js +3 -3
- package/lib/checks/elements.js +7 -7
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +4 -4
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/managedWithoutKeys.js +1 -1
- package/lib/checks/nonexpandableStructured.js +5 -3
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +5 -6
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -2
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +4 -4
- package/lib/checks/types.js +7 -7
- package/lib/checks/utils.js +4 -4
- package/lib/checks/validator.js +16 -13
- package/lib/compiler/.eslintrc.json +1 -1
- package/lib/compiler/assert-consistency.js +0 -1
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +73 -15
- package/lib/compiler/define.js +3 -7
- package/lib/compiler/extend.js +212 -32
- package/lib/compiler/finalize-parse-cdl.js +7 -2
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +2 -5
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/shared.js +23 -12
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +6 -0
- package/lib/edm/annotations/genericTranslation.js +553 -319
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +88 -75
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +5 -5
- package/lib/edm/edmPreprocessor.js +106 -76
- package/lib/edm/edmUtils.js +41 -2
- package/lib/gen/Dictionary.json +34 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +66 -63
- package/lib/gen/language.tokens +81 -81
- package/lib/gen/languageLexer.interp +4 -10
- package/lib/gen/languageLexer.js +854 -869
- package/lib/gen/languageLexer.tokens +79 -81
- package/lib/gen/languageParser.js +14360 -14146
- package/lib/inspect/inspectModelStatistics.js +2 -2
- package/lib/inspect/inspectPropagation.js +6 -6
- package/lib/inspect/inspectUtils.js +2 -2
- package/lib/json/from-csn.js +82 -40
- package/lib/json/to-csn.js +82 -157
- package/lib/language/.eslintrc.json +1 -4
- package/lib/language/genericAntlrParser.js +59 -38
- package/lib/language/language.g4 +1508 -1490
- package/lib/language/multiLineStringParser.js +1 -1
- package/lib/main.js +3 -3
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/utils/filter.js +4 -3
- package/lib/optionProcessor.js +5 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +225 -159
- package/lib/render/toHdbcds.js +63 -63
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +55 -65
- package/lib/render/utils/common.js +20 -37
- package/lib/render/utils/delta.js +3 -3
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/assertUnique.js +13 -12
- package/lib/transform/db/associations.js +5 -5
- package/lib/transform/db/cdsPersistence.js +10 -8
- package/lib/transform/db/constraints.js +14 -14
- package/lib/transform/db/expansion.js +20 -22
- package/lib/transform/db/flattening.js +24 -42
- package/lib/transform/db/groupByOrderBy.js +3 -3
- package/lib/transform/db/temporal.js +6 -6
- package/lib/transform/db/transformExists.js +23 -23
- package/lib/transform/db/views.js +16 -16
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +12 -40
- package/lib/transform/forRelationalDB.js +16 -6
- package/lib/transform/localized.js +2 -2
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +106 -62
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +2 -2
- package/lib/transform/translateAssocsToJoins.js +24 -19
- package/lib/transform/universalCsn/coreComputed.js +10 -10
- package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
- package/lib/transform/universalCsn/utils.js +3 -3
- package/lib/utils/file.js +5 -5
- package/lib/utils/moduleResolve.js +13 -13
- package/lib/utils/objectUtils.js +6 -6
- package/lib/utils/term.js +5 -2
- package/lib/utils/timetrace.js +51 -24
- package/package.json +5 -7
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/redirected-to-complex.md +4 -4
- package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
|
@@ -206,7 +206,7 @@ module.exports = (csn, options) => {
|
|
|
206
206
|
* @param {object} root
|
|
207
207
|
* @returns {object|string|null}
|
|
208
208
|
*/
|
|
209
|
-
function getTargetAspectBase(root) {
|
|
209
|
+
function getTargetAspectBase( root ) {
|
|
210
210
|
if (root.target && root.target.elements) {
|
|
211
211
|
return root.target;
|
|
212
212
|
}
|
|
@@ -229,7 +229,7 @@ module.exports = (csn, options) => {
|
|
|
229
229
|
* @see getTargetAspectBase for details on how we find our "start"
|
|
230
230
|
* @param {object} root
|
|
231
231
|
*/
|
|
232
|
-
function setTargetAspectIfRequired(root) {
|
|
232
|
+
function setTargetAspectIfRequired( root ) {
|
|
233
233
|
if (root.$origin || root.target && root.target.elements) {
|
|
234
234
|
const base = getTargetAspectBase(root);
|
|
235
235
|
if (base && (base.elements || typeof base === 'string' && csn.definitions[base].kind === 'aspect')) {
|
|
@@ -324,7 +324,7 @@ module.exports = (csn, options) => {
|
|
|
324
324
|
* of the `member`
|
|
325
325
|
* @param {object} [force=null] Overwrite any member propagation rules or any except and always propagate the corresponding keys
|
|
326
326
|
*/
|
|
327
|
-
function propagateMemberPropsFromOrigin(member, except = null, force = null) {
|
|
327
|
+
function propagateMemberPropsFromOrigin( member, except = null, force = null ) {
|
|
328
328
|
const memberChain = getOriginChain(member);
|
|
329
329
|
const virtualOrigin = Object.create(null); // To collect stuff across the origin chain - currently only for .items via type-of
|
|
330
330
|
|
|
@@ -359,7 +359,7 @@ module.exports = (csn, options) => {
|
|
|
359
359
|
* @returns {boolean} whether props from the members origin should be propagated
|
|
360
360
|
* @todo check if still necessary
|
|
361
361
|
*/
|
|
362
|
-
function skipMemberPropagation(origin) {
|
|
362
|
+
function skipMemberPropagation( origin ) {
|
|
363
363
|
// For empty members (`{}`), the origin was set in a previous call to `getOrigin(definition)`.
|
|
364
364
|
return !origin;
|
|
365
365
|
}
|
|
@@ -374,7 +374,7 @@ module.exports = (csn, options) => {
|
|
|
374
374
|
* @param {CSN.Element} target
|
|
375
375
|
* @param {CSN.Element} source
|
|
376
376
|
*/
|
|
377
|
-
function onlyWithTypeRef(prop, target, source) {
|
|
377
|
+
function onlyWithTypeRef( prop, target, source ) {
|
|
378
378
|
const typeIsTypeRef = Boolean(typeof target.type === 'object' && target.type.ref);
|
|
379
379
|
if (typeIsTypeRef) {
|
|
380
380
|
const referencedArtifact = csn.definitions[target.type.ref[0]];
|
|
@@ -390,7 +390,7 @@ module.exports = (csn, options) => {
|
|
|
390
390
|
*
|
|
391
391
|
* @param {object} art Target object for propagation
|
|
392
392
|
*/
|
|
393
|
-
function propagateOnArtifactLevel(art) {
|
|
393
|
+
function propagateOnArtifactLevel( art ) {
|
|
394
394
|
// check if art was already processed by the status flag
|
|
395
395
|
// TODO: clean up later on, together with validator clean up probably or
|
|
396
396
|
// when this module is meant to be used standalone -> use internal cache to store already processed definitions?
|
|
@@ -407,7 +407,7 @@ module.exports = (csn, options) => {
|
|
|
407
407
|
* @param {CSN.Element} targetsOrigin
|
|
408
408
|
* @param {CSN.Element} rootOrigin
|
|
409
409
|
*/
|
|
410
|
-
function definitionPropagation(targetDefinition, targetsOrigin, rootOrigin) {
|
|
410
|
+
function definitionPropagation( targetDefinition, targetsOrigin, rootOrigin ) {
|
|
411
411
|
// if target was already processed -> continue
|
|
412
412
|
if (targetDefinition._status === 'propagated')
|
|
413
413
|
return;
|
|
@@ -430,7 +430,7 @@ module.exports = (csn, options) => {
|
|
|
430
430
|
* @param {CSN.Definition|CSN.Element} source
|
|
431
431
|
* @param {CSN.Definition|CSN.Element} root
|
|
432
432
|
*/
|
|
433
|
-
function propagateDefProps(definition, source, root) {
|
|
433
|
+
function propagateDefProps( definition, source, root ) {
|
|
434
434
|
copyProperties(source, definition, getDefinitionPropagationRuleFor);
|
|
435
435
|
// If $origin is an object, it is the anonymous prototype of `definition`
|
|
436
436
|
// e.g. for structure includes annotations are part of the $origin object and must be copied over to the `definition`
|
|
@@ -454,7 +454,7 @@ module.exports = (csn, options) => {
|
|
|
454
454
|
* @param {CSN.Artifact|CSN.Element} start
|
|
455
455
|
* @returns {CSN.Artifact|CSN.Element|null} Null if no origin with .elements was found
|
|
456
456
|
*/
|
|
457
|
-
function getFirstOriginWithElements(start) {
|
|
457
|
+
function getFirstOriginWithElements( start ) {
|
|
458
458
|
let target = start;
|
|
459
459
|
let firstOriginWithElements;
|
|
460
460
|
do {
|
|
@@ -479,7 +479,7 @@ module.exports = (csn, options) => {
|
|
|
479
479
|
* @returns {object[]} chain of origin - target
|
|
480
480
|
* @todo Optimize: Only return the chain until the first propagated thing?
|
|
481
481
|
*/
|
|
482
|
-
function getOriginChain(start) {
|
|
482
|
+
function getOriginChain( start ) {
|
|
483
483
|
const chain = [];
|
|
484
484
|
let target = start;
|
|
485
485
|
let origin;
|
|
@@ -504,7 +504,7 @@ module.exports = (csn, options) => {
|
|
|
504
504
|
* @param {CSN.Query} query
|
|
505
505
|
* @param {CSN.Artifact} artifact
|
|
506
506
|
*/
|
|
507
|
-
function propagateToPublishedMixin(query, artifact) {
|
|
507
|
+
function propagateToPublishedMixin( query, artifact ) {
|
|
508
508
|
const elements = query.SELECT.elements || artifact.elements;
|
|
509
509
|
forEachValue(elements, (element) => {
|
|
510
510
|
if (element.target) {
|
|
@@ -520,7 +520,7 @@ module.exports = (csn, options) => {
|
|
|
520
520
|
/**
|
|
521
521
|
* @param {CSN.Element} member
|
|
522
522
|
*/
|
|
523
|
-
function calculateForeignKeys(member) {
|
|
523
|
+
function calculateForeignKeys( member ) {
|
|
524
524
|
// managed assocs in universal CSN have no longer keys
|
|
525
525
|
// if they are not explicitly defined - PR#8064
|
|
526
526
|
const target = artifactRef(member.target);
|
|
@@ -538,7 +538,7 @@ module.exports = (csn, options) => {
|
|
|
538
538
|
* @param {CSN.Definition} target
|
|
539
539
|
* @param {CSN.Definition} source
|
|
540
540
|
*/
|
|
541
|
-
function onlyViaArtifact(prop, target, source) {
|
|
541
|
+
function onlyViaArtifact( prop, target, source ) {
|
|
542
542
|
if (!target.kind)
|
|
543
543
|
return;
|
|
544
544
|
const primarySourceRef = getQueryPrimarySource(target.query || target.projection);
|
|
@@ -553,7 +553,7 @@ module.exports = (csn, options) => {
|
|
|
553
553
|
* @param {string} key identifier of the csn prop we are looking for
|
|
554
554
|
* @returns {Function} which can be used to apply custom propagation rules for certain props
|
|
555
555
|
*/
|
|
556
|
-
function getMemberPropagationRuleFor(key) {
|
|
556
|
+
function getMemberPropagationRuleFor( key ) {
|
|
557
557
|
return memberPropagationRules[key] || memberPropagationRules[key.charAt(0)] || getDefinitionPropagationRuleFor(key);
|
|
558
558
|
}
|
|
559
559
|
|
|
@@ -563,7 +563,7 @@ module.exports = (csn, options) => {
|
|
|
563
563
|
* @param {string} key identifier of the csn prop we are looking for
|
|
564
564
|
* @returns {Function} which can be used to apply custom propagation rules for certain props
|
|
565
565
|
*/
|
|
566
|
-
function getDefinitionPropagationRuleFor(key) {
|
|
566
|
+
function getDefinitionPropagationRuleFor( key ) {
|
|
567
567
|
return definitionPropagationRules[key] || definitionPropagationRules[key.charAt(0)];
|
|
568
568
|
}
|
|
569
569
|
|
|
@@ -573,7 +573,7 @@ module.exports = (csn, options) => {
|
|
|
573
573
|
* @param {CSN.Artifact} parent
|
|
574
574
|
* @param {CSN.Artifact} rootArtifact The artifact that had the localized
|
|
575
575
|
*/
|
|
576
|
-
function attachAnnosForTextsTable(parent, rootArtifact) {
|
|
576
|
+
function attachAnnosForTextsTable( parent, rootArtifact ) {
|
|
577
577
|
const isFioriDraftEnabled = rootArtifact && (rootArtifact['@fiori.draft.enabled'] === true || getOriginChain(rootArtifact).some(({ origin }) => origin['@fiori.draft.enabled'] === true));
|
|
578
578
|
if (isFioriDraftEnabled) {
|
|
579
579
|
setAnnotationIfNotDefined(parent, '@assert.unique.locale', [ { '=': 'locale' } ]);
|
|
@@ -606,7 +606,7 @@ module.exports = (csn, options) => {
|
|
|
606
606
|
* @param {object} [except=null] array of properties which should not be propagated
|
|
607
607
|
* @param {object} [force=null] Force propagation of the contained keys via a custom rule.
|
|
608
608
|
*/
|
|
609
|
-
function copyProperties(from, to, getCustomRule, except = null, force = null) {
|
|
609
|
+
function copyProperties( from, to, getCustomRule, except = null, force = null ) {
|
|
610
610
|
const keys = Object.keys(from);
|
|
611
611
|
// Copy over properties from the origin element to the target.
|
|
612
612
|
for (const key of keys) {
|
|
@@ -626,7 +626,7 @@ function copyProperties(from, to, getCustomRule, except = null, force = null) {
|
|
|
626
626
|
* @param {object} elements
|
|
627
627
|
* @returns {boolean} whether some element in the elements has an annotation
|
|
628
628
|
*/
|
|
629
|
-
function hasAnnotationOnSubelement(elements) {
|
|
629
|
+
function hasAnnotationOnSubelement( elements ) {
|
|
630
630
|
for (const element of Object.values(elements)) {
|
|
631
631
|
if (Object.keys(element).some(key => key.startsWith('@')))
|
|
632
632
|
return true;
|
|
@@ -654,7 +654,7 @@ function skip() {
|
|
|
654
654
|
* @param {object} target
|
|
655
655
|
* @param {object} source
|
|
656
656
|
*/
|
|
657
|
-
function always(prop, target, source) {
|
|
657
|
+
function always( prop, target, source ) {
|
|
658
658
|
const val = source[prop];
|
|
659
659
|
if (Array.isArray(val))
|
|
660
660
|
target[prop] = [ ...val ];
|
|
@@ -669,7 +669,7 @@ function always(prop, target, source) {
|
|
|
669
669
|
* @param {CSN.Definition} target
|
|
670
670
|
* @param {CSN.Definition} source
|
|
671
671
|
*/
|
|
672
|
-
function onlyTypeDef(prop, target, source) {
|
|
672
|
+
function onlyTypeDef( prop, target, source ) {
|
|
673
673
|
if (target.kind !== 'type')
|
|
674
674
|
return;
|
|
675
675
|
target[prop] = source[prop];
|
|
@@ -684,7 +684,7 @@ function onlyTypeDef(prop, target, source) {
|
|
|
684
684
|
* @param {object} target
|
|
685
685
|
* @param {object} source
|
|
686
686
|
*/
|
|
687
|
-
function notWithPersistenceTable(prop, target, source) {
|
|
687
|
+
function notWithPersistenceTable( prop, target, source ) {
|
|
688
688
|
const tableAnno = target['@cds.persistence.table'];
|
|
689
689
|
if (tableAnno === undefined || tableAnno === null)
|
|
690
690
|
target[prop] = source[prop];
|
|
@@ -699,7 +699,7 @@ function notWithPersistenceTable(prop, target, source) {
|
|
|
699
699
|
* @param {CSN.Element} target
|
|
700
700
|
* @param {CSN.Element} source
|
|
701
701
|
*/
|
|
702
|
-
function notWithTypeOrigin(prop, target, source) {
|
|
702
|
+
function notWithTypeOrigin( prop, target, source ) {
|
|
703
703
|
if (source.kind !== 'type')
|
|
704
704
|
target[prop] = source[prop];
|
|
705
705
|
}
|
|
@@ -712,7 +712,7 @@ function notWithTypeOrigin(prop, target, source) {
|
|
|
712
712
|
* @param {CSN.Element} target
|
|
713
713
|
* @param {CSN.Element} source
|
|
714
714
|
*/
|
|
715
|
-
function nullStopsPropagation(prop, target, source) {
|
|
715
|
+
function nullStopsPropagation( prop, target, source ) {
|
|
716
716
|
if (source[prop] !== null)
|
|
717
717
|
target[prop] = source[prop];
|
|
718
718
|
}
|
|
@@ -732,7 +732,7 @@ function nullStopsPropagation(prop, target, source) {
|
|
|
732
732
|
* @param {CSN.Element} target
|
|
733
733
|
* @param {CSN.Element} source
|
|
734
734
|
*/
|
|
735
|
-
function specialItemsRules(prop, target, source) {
|
|
735
|
+
function specialItemsRules( prop, target, source ) {
|
|
736
736
|
if (source.kind !== 'type' && ((!source.type && !target.type) || !(source[prop].type && source[prop].type.ref || !isBuiltinType(source[prop].type))))
|
|
737
737
|
target[prop] = source[prop];
|
|
738
738
|
}
|
|
@@ -746,7 +746,7 @@ function specialItemsRules(prop, target, source) {
|
|
|
746
746
|
* @param {CSN.Element} target
|
|
747
747
|
* @param {CSN.Element} source
|
|
748
748
|
*/
|
|
749
|
-
function notWithItemsOrElements(prop, target, source) {
|
|
749
|
+
function notWithItemsOrElements( prop, target, source ) {
|
|
750
750
|
if (!target.items && !target.elements || !source.target)
|
|
751
751
|
target[prop] = source[prop];
|
|
752
752
|
}
|
|
@@ -759,7 +759,7 @@ function notWithItemsOrElements(prop, target, source) {
|
|
|
759
759
|
* @param {CSN.Element} target
|
|
760
760
|
* @param {CSN.Element} source
|
|
761
761
|
*/
|
|
762
|
-
function notWithTypeRef(prop, target, source) {
|
|
762
|
+
function notWithTypeRef( prop, target, source ) {
|
|
763
763
|
const typeIsTypeRef = Boolean(typeof target.type === 'object' && target.type.ref);
|
|
764
764
|
if (!typeIsTypeRef)
|
|
765
765
|
target[prop] = source[prop];
|
|
@@ -12,7 +12,7 @@ const { setProp } = require('../../base/model');
|
|
|
12
12
|
* @param {string} name Name of the annotations
|
|
13
13
|
* @param {any} value Value of the annotation
|
|
14
14
|
*/
|
|
15
|
-
function setAnnotationIfNotDefined(carrier, name, value) {
|
|
15
|
+
function setAnnotationIfNotDefined( carrier, name, value ) {
|
|
16
16
|
if (carrier[name] === undefined)
|
|
17
17
|
carrier[name] = value;
|
|
18
18
|
}
|
|
@@ -26,7 +26,7 @@ function setAnnotationIfNotDefined(carrier, name, value) {
|
|
|
26
26
|
*
|
|
27
27
|
* @param {CSN.Model} csn
|
|
28
28
|
*/
|
|
29
|
-
function makeClientCompatible(csn) {
|
|
29
|
+
function makeClientCompatible( csn ) {
|
|
30
30
|
applyTransformations(csn, {
|
|
31
31
|
actions: removeNullProperty,
|
|
32
32
|
notNull: removeNullProperty,
|
|
@@ -52,7 +52,7 @@ function makeClientCompatible(csn) {
|
|
|
52
52
|
* @param {object} node
|
|
53
53
|
* @param {string} prop
|
|
54
54
|
*/
|
|
55
|
-
function removeNullProperty(node, prop) {
|
|
55
|
+
function removeNullProperty( node, prop ) {
|
|
56
56
|
if (node[prop] === null)
|
|
57
57
|
delete node[prop];
|
|
58
58
|
}
|
package/lib/utils/file.js
CHANGED
|
@@ -12,7 +12,7 @@ const util = require('util');
|
|
|
12
12
|
* @param {string} src
|
|
13
13
|
* @returns {string[]}
|
|
14
14
|
*/
|
|
15
|
-
function splitLines(src) {
|
|
15
|
+
function splitLines( src ) {
|
|
16
16
|
return src.split(/\r\n?|\n/);
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -27,7 +27,7 @@ function splitLines(src) {
|
|
|
27
27
|
* @param {object} fileCache
|
|
28
28
|
* @param {boolean} enableTrace
|
|
29
29
|
*/
|
|
30
|
-
function cdsFs(fileCache, enableTrace) {
|
|
30
|
+
function cdsFs( fileCache, enableTrace ) {
|
|
31
31
|
const readFile = _wrapReadFileCached(fs.readFile);
|
|
32
32
|
const readFileSync = _wrapReadFileCached((filename, enc, cb) => {
|
|
33
33
|
try {
|
|
@@ -60,11 +60,11 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
60
60
|
realpathSync,
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
function realpath(path, cb) {
|
|
63
|
+
function realpath( path, cb ) {
|
|
64
64
|
return fs.realpath.native(path, cb);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
function realpathSync(path, cb) {
|
|
67
|
+
function realpathSync( path, cb ) {
|
|
68
68
|
try {
|
|
69
69
|
cb(null, fs.realpathSync.native(path));
|
|
70
70
|
}
|
|
@@ -133,7 +133,7 @@ function cdsFs(fileCache, enableTrace) {
|
|
|
133
133
|
*
|
|
134
134
|
* @param {(filename: string, cb: (err, data) => void) => void} fsStat
|
|
135
135
|
*/
|
|
136
|
-
function _wrapIsFileCached(fsStat) {
|
|
136
|
+
function _wrapIsFileCached( fsStat ) {
|
|
137
137
|
return ( filename, cb ) => {
|
|
138
138
|
let body = fileCache[filename];
|
|
139
139
|
if (body !== undefined) {
|
|
@@ -30,7 +30,7 @@ const extensions = [ '.cds', '.csn', '.json' ];
|
|
|
30
30
|
* @param {CSN.Options} options
|
|
31
31
|
* @returns {string}
|
|
32
32
|
*/
|
|
33
|
-
function adaptCdsModule(modulePath, options = {}) {
|
|
33
|
+
function adaptCdsModule( modulePath, options = {} ) {
|
|
34
34
|
if (modulePath.startsWith( '@sap/cds/' )) {
|
|
35
35
|
if (options.cdsHome)
|
|
36
36
|
return options.cdsHome + modulePath.slice(8);
|
|
@@ -166,7 +166,7 @@ function resolveModuleSync( dep, fileCache, options, messageFunctions ) {
|
|
|
166
166
|
return result;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
function _errorFileNotFound(dep, options, { error }) {
|
|
169
|
+
function _errorFileNotFound( dep, options, { error } ) {
|
|
170
170
|
if (dep.resolved) {
|
|
171
171
|
let resolved = path.relative( dep.basedir, dep.resolved );
|
|
172
172
|
if (options.testMode)
|
|
@@ -204,7 +204,7 @@ function _errorFileNotFound(dep, options, { error }) {
|
|
|
204
204
|
* @param {ResolveOptions} options
|
|
205
205
|
* @param {(err, result) => void} callback
|
|
206
206
|
*/
|
|
207
|
-
function resolveCDS(moduleName, options, callback) {
|
|
207
|
+
function resolveCDS( moduleName, options, callback ) {
|
|
208
208
|
const isWindows = (process.platform === 'win32');
|
|
209
209
|
let resolvedBaseDir = path.resolve(options.basedir);
|
|
210
210
|
|
|
@@ -252,7 +252,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
252
252
|
* @param {string} absoluteModulePath
|
|
253
253
|
* @param {(err, filepath: string|null) => void} cb
|
|
254
254
|
*/
|
|
255
|
-
function loadAsLocalFileOrDirectory(absoluteModulePath, cb) {
|
|
255
|
+
function loadAsLocalFileOrDirectory( absoluteModulePath, cb ) {
|
|
256
256
|
loadAsFile(absoluteModulePath, (err, filepath) => {
|
|
257
257
|
if (!err && filepath)
|
|
258
258
|
cb(null, filepath);
|
|
@@ -268,7 +268,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
268
268
|
* @param {string} absoluteModulePath
|
|
269
269
|
* @param {(err, filepath: string|null) => void} cb
|
|
270
270
|
*/
|
|
271
|
-
function loadAsFile(absoluteModulePath, cb) {
|
|
271
|
+
function loadAsFile( absoluteModulePath, cb ) {
|
|
272
272
|
const extensionsToTry = [ '' ].concat(options.extensions);
|
|
273
273
|
loadFileWithExtensions(extensionsToTry);
|
|
274
274
|
|
|
@@ -277,7 +277,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
277
277
|
*
|
|
278
278
|
* @param {string[]} exts The extensions to try. Loaded in the order of the array.
|
|
279
279
|
*/
|
|
280
|
-
function loadFileWithExtensions(exts) {
|
|
280
|
+
function loadFileWithExtensions( exts ) {
|
|
281
281
|
if (exts.length === 0) {
|
|
282
282
|
// If we reach this point then no file with the given extensions could be found.
|
|
283
283
|
cb(makeNotFoundError(), null);
|
|
@@ -300,7 +300,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
300
300
|
* @param {string} absoluteModulePath
|
|
301
301
|
* @param {(err, filepath: string|null) => void} cb
|
|
302
302
|
*/
|
|
303
|
-
function loadAsDirectory(absoluteModulePath, cb) {
|
|
303
|
+
function loadAsDirectory( absoluteModulePath, cb ) {
|
|
304
304
|
loadAndParsePackageJsonInDirectory(absoluteModulePath, (packageErr, packageJson) => {
|
|
305
305
|
const main = packageCdsMain(packageJson);
|
|
306
306
|
if (!packageErr && main)
|
|
@@ -309,7 +309,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
309
309
|
loadIndex();
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
-
function loadMain(main) {
|
|
312
|
+
function loadMain( main ) {
|
|
313
313
|
const file = path.join(absoluteModulePath, main);
|
|
314
314
|
loadAsFile(file, (fileErr, filePath) => {
|
|
315
315
|
if (!fileErr && filePath)
|
|
@@ -337,11 +337,11 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
337
337
|
*
|
|
338
338
|
* @param {string} absoluteDir
|
|
339
339
|
*/
|
|
340
|
-
function loadNodeModules(absoluteDir) {
|
|
340
|
+
function loadNodeModules( absoluteDir ) {
|
|
341
341
|
const dirs = nodeModulesPaths(absoluteDir);
|
|
342
342
|
loadFromNodeDirs(dirs);
|
|
343
343
|
|
|
344
|
-
function loadFromNodeDirs(nodeDirs) {
|
|
344
|
+
function loadFromNodeDirs( nodeDirs ) {
|
|
345
345
|
const dir = nodeDirs.shift();
|
|
346
346
|
if (!dir) {
|
|
347
347
|
// We're at root
|
|
@@ -365,7 +365,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
365
365
|
* @param {string} packageDir
|
|
366
366
|
* @param {(err, json) => void} cb
|
|
367
367
|
*/
|
|
368
|
-
function loadAndParsePackageJsonInDirectory(packageDir, cb) {
|
|
368
|
+
function loadAndParsePackageJsonInDirectory( packageDir, cb ) {
|
|
369
369
|
const file = path.join(packageDir, 'package.json');
|
|
370
370
|
|
|
371
371
|
options.readFile(file, DEFAULT_ENCODING, (err, content) => {
|
|
@@ -390,7 +390,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
390
390
|
* @param {string} absoluteStart
|
|
391
391
|
* @returns {string[]} Array of possible "node_modules" folders for the given path.
|
|
392
392
|
*/
|
|
393
|
-
function nodeModulesPaths(absoluteStart) {
|
|
393
|
+
function nodeModulesPaths( absoluteStart ) {
|
|
394
394
|
// Use platform-dependent separator. All NodeJS `path` methods use the system's path separator.
|
|
395
395
|
const parts = absoluteStart.split(path.sep);
|
|
396
396
|
// Do NOT use global node_modules directories.
|
|
@@ -429,7 +429,7 @@ function resolveCDS(moduleName, options, callback) {
|
|
|
429
429
|
*
|
|
430
430
|
* @param {string} moduleName
|
|
431
431
|
*/
|
|
432
|
-
function isLocalFile(moduleName) {
|
|
432
|
+
function isLocalFile( moduleName ) {
|
|
433
433
|
// Starts with or is equal to '..'
|
|
434
434
|
// Starts with '/'
|
|
435
435
|
// Starts with 'C:/' or 'C:\'
|
package/lib/utils/objectUtils.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @param {string} property
|
|
9
9
|
* @param {object} targetObj
|
|
10
10
|
*/
|
|
11
|
-
function copyPropIfExist(sourceObj, property, targetObj) {
|
|
11
|
+
function copyPropIfExist( sourceObj, property, targetObj ) {
|
|
12
12
|
if (sourceObj && property in sourceObj)
|
|
13
13
|
targetObj[property] = sourceObj[property];
|
|
14
14
|
}
|
|
@@ -21,7 +21,7 @@ function copyPropIfExist(sourceObj, property, targetObj) {
|
|
|
21
21
|
* @param {object} obj Object with prototype.
|
|
22
22
|
* @return {object} Object without prototype, i.e. a dict.
|
|
23
23
|
*/
|
|
24
|
-
function createDict(obj) {
|
|
24
|
+
function createDict( obj ) {
|
|
25
25
|
const dict = Object.create(null);
|
|
26
26
|
const keys = Object.keys(obj);
|
|
27
27
|
for (const key of keys)
|
|
@@ -33,9 +33,9 @@ function createDict(obj) {
|
|
|
33
33
|
* Loops over all elements in an object and calls the specified callback(key,obj)
|
|
34
34
|
*
|
|
35
35
|
* @param {object} obj
|
|
36
|
-
* @param {(string, object) => void} callback
|
|
36
|
+
* @param {(key: string, value: object) => void} callback
|
|
37
37
|
*/
|
|
38
|
-
function forEach(obj, callback) {
|
|
38
|
+
function forEach( obj, callback ) {
|
|
39
39
|
for (const key in obj) {
|
|
40
40
|
if (Object.prototype.hasOwnProperty.call(obj, key))
|
|
41
41
|
callback(key, obj[key]);
|
|
@@ -49,7 +49,7 @@ function forEach(obj, callback) {
|
|
|
49
49
|
* @param {object} o the object which values should be iterated
|
|
50
50
|
* @param {Function} callback
|
|
51
51
|
*/
|
|
52
|
-
function forEachValue(o, callback) {
|
|
52
|
+
function forEachValue( o, callback ) {
|
|
53
53
|
for (const key in o) {
|
|
54
54
|
if (Object.prototype.hasOwnProperty.call(o, key))
|
|
55
55
|
callback(o[key]);
|
|
@@ -63,7 +63,7 @@ function forEachValue(o, callback) {
|
|
|
63
63
|
* @param {object} o the object which keys should be iterated
|
|
64
64
|
* @param {Function} callback
|
|
65
65
|
*/
|
|
66
|
-
function forEachKey(o, callback) {
|
|
66
|
+
function forEachKey( o, callback ) {
|
|
67
67
|
for (const key in o) {
|
|
68
68
|
if (Object.prototype.hasOwnProperty.call(o, key))
|
|
69
69
|
callback(key);
|
package/lib/utils/term.js
CHANGED
|
@@ -33,11 +33,14 @@ const t = {
|
|
|
33
33
|
cyan: '\x1b[36m', // Foreground Cyan
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @param {string|boolean} [useColor]
|
|
38
|
+
*/
|
|
39
|
+
function term( useColor = 'auto' ) {
|
|
37
40
|
let hasColor = hasColorShell;
|
|
38
41
|
changeColorMode(useColor);
|
|
39
42
|
|
|
40
|
-
function changeColorMode(mode) {
|
|
43
|
+
function changeColorMode( mode ) {
|
|
41
44
|
switch (mode) {
|
|
42
45
|
case false:
|
|
43
46
|
case 'never':
|
package/lib/utils/timetrace.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { CompilerAssertion } = require('../base/error');
|
|
4
|
+
|
|
5
|
+
function hrtimeToSec( dt ) {
|
|
6
|
+
const sec = (dt / BigInt('1000000000')).toString().padStart(2, ' ');
|
|
7
|
+
// first, get remaining ns, then convert to ms.
|
|
8
|
+
const msec = ((dt % BigInt('1000000000')) / BigInt('1000000')).toString().padStart(3, '0');
|
|
9
|
+
return [ sec, msec ];
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
/**
|
|
4
13
|
* A single StopWatch encapsulates the runtime of a selected code frame.
|
|
5
14
|
*
|
|
@@ -71,6 +80,20 @@ class TimeTracer {
|
|
|
71
80
|
*/
|
|
72
81
|
constructor() {
|
|
73
82
|
this.traceStack = [];
|
|
83
|
+
this.lastStop = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reset the time tracer. Use this if an exception is thrown, because then
|
|
88
|
+
* start/end won't correctly match.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} reason
|
|
91
|
+
*/
|
|
92
|
+
reset(reason) {
|
|
93
|
+
// eslint-disable-next-line no-console
|
|
94
|
+
console.error(`Reset TimeTrace: Stopping all timers because: ${ reason }`);
|
|
95
|
+
while (this.traceStack.length)
|
|
96
|
+
this.stop(this.traceStack[this.traceStack.length - 1].id);
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
/**
|
|
@@ -81,46 +104,50 @@ class TimeTracer {
|
|
|
81
104
|
* @memberOf TimeTracer
|
|
82
105
|
*/
|
|
83
106
|
start(id) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
107
|
+
// Get time between last stop and new start: Those sections were not tracked.
|
|
108
|
+
const [ sec, msec ] = this.lastStop ? hrtimeToSec(this.lastStop.stop()) : [ ' 0', '000' ];
|
|
109
|
+
this.lastStop = null;
|
|
110
|
+
let base = `${ ' '.repeat(this.traceStack.length * 2) }${ id } started:`;
|
|
111
|
+
base += ' '.repeat(60 - base.length);
|
|
112
|
+
if (sec !== ' 0' || msec !== '000')
|
|
88
113
|
// eslint-disable-next-line no-console
|
|
89
|
-
console.error(`${
|
|
90
|
-
|
|
91
|
-
catch (e) {
|
|
114
|
+
console.error( `${ base } ${ sec }s ${ msec }ms (since last stop)` );
|
|
115
|
+
else
|
|
92
116
|
// eslint-disable-next-line no-console
|
|
93
|
-
console.error(
|
|
94
|
-
|
|
117
|
+
console.error( `${ base }` );
|
|
118
|
+
this.traceStack.push(new StopWatch(id));
|
|
95
119
|
}
|
|
96
120
|
|
|
97
121
|
/**
|
|
98
122
|
* Stop the current TimeTrace and log the execution time.
|
|
99
123
|
*
|
|
100
|
-
*
|
|
124
|
+
* @param {string} id
|
|
101
125
|
* @memberOf TimeTracer
|
|
102
126
|
*/
|
|
103
|
-
stop() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
// eslint-disable-next-line no-console
|
|
116
|
-
console.error(`Stopping time trace failed: ${ e }`);
|
|
127
|
+
stop(id) {
|
|
128
|
+
if (this.traceStack.length === 0)
|
|
129
|
+
throw new CompilerAssertion('TimeTracer mismatch: called stop() too many times');
|
|
130
|
+
const current = this.traceStack.pop();
|
|
131
|
+
if (current.id !== id)
|
|
132
|
+
throw new CompilerAssertion(`TimeTracer mismatch; expected id: “${ id }”, was “${ current.id }”`);
|
|
133
|
+
let diff = '';
|
|
134
|
+
if (this.lastStop !== null) {
|
|
135
|
+
const [ sec, msec ] = hrtimeToSec(this.lastStop.stop());
|
|
136
|
+
if ( sec !== ' 0' || msec !== '000')
|
|
137
|
+
diff = ` (diff to last stop: ${ sec }s ${ msec }ms)`;
|
|
117
138
|
}
|
|
139
|
+
const [ sec, msec ] = hrtimeToSec(current.stop());
|
|
140
|
+
const base = `${ ' '.repeat(this.traceStack.length * 2) }${ current.id } took:`;
|
|
141
|
+
// eslint-disable-next-line no-console
|
|
142
|
+
console.error( `${ base }${ ' '.repeat(60 - base.length) } ${ sec }s ${ msec }ms${ diff }` );
|
|
143
|
+
this.lastStop = new StopWatch(id);
|
|
118
144
|
}
|
|
119
145
|
}
|
|
120
146
|
|
|
121
147
|
const ignoreTimeTrace = {
|
|
122
148
|
start: () => { /* ignore */ },
|
|
123
149
|
stop: () => { /* ignore */ },
|
|
150
|
+
reset: () => { /* ignore */ },
|
|
124
151
|
};
|
|
125
152
|
|
|
126
153
|
const doTimeTrace = process && process.env && process.env.CDSC_TIMETRACING !== undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.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)",
|
|
@@ -21,16 +21,14 @@
|
|
|
21
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
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
23
|
"testverbose": "node scripts/verifyGrammarChecksum.js && mocha --parallel test/ test3/",
|
|
24
|
-
"test3": "node scripts/verifyGrammarChecksum.js &&
|
|
25
|
-
"deployTest3SQL": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/
|
|
24
|
+
"test3": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 test3/",
|
|
25
|
+
"deployTest3SQL": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/test.deploy.hana-sql.js",
|
|
26
26
|
"deployTest3": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/testDeployment.js",
|
|
27
|
+
"deployHanaDeltaSQL": "CDS_COMPILER_DEPLOY_HANA=1 mocha test3/test.deploy.hana-sql.delta.js",
|
|
27
28
|
"deployDiffs": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/deployDiffs.js",
|
|
28
29
|
"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
30
|
"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/ && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint .",
|
|
31
|
+
"lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ types/ && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint .",
|
|
34
32
|
"tslint": "tsc --pretty -p .",
|
|
35
33
|
"updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
|
|
36
34
|
"generateCompilerRefs": "cross-env MAKEREFS='true' mocha test/testCompiler.js",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The redirected target is a complex view, for example, contains a JOIN or UNION.
|
|
4
4
|
|
|
5
5
|
The message's severity is `Info` and is raised by the compiler.
|
|
6
|
-
It is emitted to help developers identify possible
|
|
6
|
+
It is emitted to help developers identify possible modeling issues.
|
|
7
7
|
|
|
8
8
|
## Example
|
|
9
9
|
|
|
@@ -33,7 +33,7 @@ The cross join in the view `CrossJoin` results in multiple rows with the same
|
|
|
33
33
|
`id`. Following the redirected view now returns multiple results, effectively
|
|
34
34
|
making the to-one association a to-many association.
|
|
35
35
|
|
|
36
|
-
Visualizing the tables with a bit of data, this
|
|
36
|
+
Visualizing the tables with a bit of data, this issue becomes obvious:
|
|
37
37
|
|
|
38
38
|
```markdown
|
|
39
39
|
Main Secondary
|
|
@@ -54,8 +54,8 @@ CrossJoin
|
|
|
54
54
|
## How to Fix
|
|
55
55
|
|
|
56
56
|
Ensure that the redirected association points to an entity that is a reasonable
|
|
57
|
-
redirection target.
|
|
58
|
-
|
|
57
|
+
redirection target. That means, the redirection target shouldn't accidentally
|
|
58
|
+
make it a to-many association.
|
|
59
59
|
|
|
60
60
|
## Related Messages
|
|
61
61
|
|