@sap/cds-compiler 3.4.4 → 3.5.2
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 +58 -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 +17 -7
- 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
|
@@ -10,9 +10,9 @@ const { setProp } = require('../base/model');
|
|
|
10
10
|
const { copyAnnotations, applyTransformations } = require('../model/csnUtils');
|
|
11
11
|
const { cloneCsnNonDict, cloneCsnDictionary, getUtils } = require('../model/csnUtils');
|
|
12
12
|
const { typeParameters, isBuiltinType } = require('../compiler/builtins');
|
|
13
|
-
const { ModelError } = require(
|
|
13
|
+
const { ModelError } = require('../base/error');
|
|
14
14
|
const { forEach } = require('../utils/objectUtils');
|
|
15
|
-
const { pathName } = require(
|
|
15
|
+
const { pathName } = require('../compiler/utils');
|
|
16
16
|
|
|
17
17
|
const RestrictedOperators = ['<', '>', '>=', '<='];
|
|
18
18
|
const RelationalOperators = ['=', '!=', '<>', 'is' /*, 'like'*/,...RestrictedOperators];
|
|
@@ -12,16 +12,16 @@ const { timetrace } = require('../utils/timetrace');
|
|
|
12
12
|
const internalArtifactKinds = ['builtin', '$parameters', 'param'];
|
|
13
13
|
|
|
14
14
|
function translateAssocsToJoinsCSN(csn, options){
|
|
15
|
-
timetrace.start('Recompiling model');
|
|
15
|
+
timetrace.start('A2J: Recompiling model');
|
|
16
16
|
// Do not re-complain about localized
|
|
17
17
|
const compileOptions = { ...options, $skipNameCheck: true };
|
|
18
18
|
delete compileOptions.csnFlavor;
|
|
19
19
|
const model = recompileX(csn, compileOptions);
|
|
20
|
-
timetrace.stop();
|
|
21
|
-
timetrace.start('Translating associations to joins');
|
|
20
|
+
timetrace.stop('A2J: Recompiling model');
|
|
21
|
+
timetrace.start('A2J: Translating associations to joins');
|
|
22
22
|
translateAssocsToJoins(model, options);
|
|
23
|
-
timetrace.stop();
|
|
24
|
-
timetrace.start('Post-processing columns');
|
|
23
|
+
timetrace.stop('A2J: Translating associations to joins');
|
|
24
|
+
timetrace.start('A2J: Post-processing columns');
|
|
25
25
|
// Use the effective elements list as columns
|
|
26
26
|
forEachDefinition(model, art => {
|
|
27
27
|
if (art.$queries) {
|
|
@@ -36,7 +36,7 @@ function translateAssocsToJoinsCSN(csn, options){
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
|
-
timetrace.stop();
|
|
39
|
+
timetrace.stop('A2J: Post-processing columns');
|
|
40
40
|
|
|
41
41
|
if (options.messages) {
|
|
42
42
|
// Make sure that we don't complain twice about the same things
|
|
@@ -46,8 +46,7 @@ function translateAssocsToJoinsCSN(csn, options){
|
|
|
46
46
|
// If A2J reports error - end! Continuing with a broken CSN makes no sense
|
|
47
47
|
makeMessageFunction(model, options).throwWithAnyError();
|
|
48
48
|
// FIXME: Move this somewhere more appropriate
|
|
49
|
-
|
|
50
|
-
return compact;
|
|
49
|
+
return compactModel(model, compileOptions);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
function translateAssocsToJoins(model, inputOptions = {})
|
|
@@ -329,9 +328,10 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
329
328
|
|
|
330
329
|
for(let i = 0; i < tail.length-1; i++) {
|
|
331
330
|
if(tail[i]._navigation && tail[i]._navigation.$njr) {
|
|
332
|
-
// the correct flattened foreign key must match the leaf artifact of this path
|
|
331
|
+
// the correct flattened foreign key must match the leaf artifact and access path prefix of this path
|
|
333
332
|
const leafArt = tail[tail.length-1]._artifact;
|
|
334
|
-
const
|
|
333
|
+
const tailPath = tail.map(p=>p.id).join(pathDelimiter);
|
|
334
|
+
const fk = tail[i]._artifact.$flatSrcFKs.find(f => f._artifact === leafArt && f.acc.startsWith(tailPath));
|
|
335
335
|
if(!fk) {
|
|
336
336
|
// const revealInternalProperties = require('../model/revealInternalProperties.js');
|
|
337
337
|
// console.log('++++++++ Path tail: ', revealInternalProperties(tail[tail.length-1]._artifact));
|
|
@@ -565,7 +565,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
565
565
|
QATs until a QA has been found).
|
|
566
566
|
*/
|
|
567
567
|
if(!assoc.$flatSrcFKs)
|
|
568
|
-
setProp(assoc, '$flatSrcFKs', flattenElement(assoc, true, assoc.name.id));
|
|
568
|
+
setProp(assoc, '$flatSrcFKs', flattenElement(assoc, true, assoc.name.id, assoc.name.id));
|
|
569
569
|
if(!assoc.$flatTgtFKs)
|
|
570
570
|
setProp(assoc, '$flatTgtFKs', flattenElement(assoc, false));
|
|
571
571
|
|
|
@@ -664,7 +664,8 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
664
664
|
}
|
|
665
665
|
// If this is a backlink condition, produce the
|
|
666
666
|
// ON cond of the forward assoc with swapped src/tgt aliases
|
|
667
|
-
else if(i < args.length-2 && args[i].path &&
|
|
667
|
+
else if(i < args.length-2 && args[i].path &&
|
|
668
|
+
args[i+1]?.literal === 'token' && args[i+1]?.val === '=' && args[i+2].path)
|
|
668
669
|
{
|
|
669
670
|
let fwdAssoc = getForwardAssociation(args[i].path, args[i+2].path);
|
|
670
671
|
if(fwdAssoc)
|
|
@@ -1088,11 +1089,11 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1088
1089
|
respecting the src or the target side of the ON condition.
|
|
1089
1090
|
Return an array of column names and it's leaf element.
|
|
1090
1091
|
*/
|
|
1091
|
-
function flattenElement(element, srcSide, prefix)
|
|
1092
|
+
function flattenElement(element, srcSide, prefix, acc)
|
|
1092
1093
|
{
|
|
1093
1094
|
// terminate if element is unstructured
|
|
1094
1095
|
if(!element.foreignKeys && !element.elements)
|
|
1095
|
-
return [ { id: prefix, _artifact: element } ];
|
|
1096
|
+
return [ { id: prefix, _artifact: element, acc } ];
|
|
1096
1097
|
|
|
1097
1098
|
let paths = [];
|
|
1098
1099
|
// get paths of managed assocs (unmanaged assocs are not allowed in FK paths)
|
|
@@ -1103,7 +1104,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1103
1104
|
let fk = element.foreignKeys[fkn];
|
|
1104
1105
|
// once a fk is to be followed, treat all sub patsh as srcSide, this will add fk.name.id only
|
|
1105
1106
|
if(srcSide)
|
|
1106
|
-
paths = paths.concat(flattenElement(fk.targetElement._artifact, true, fk.name.id));
|
|
1107
|
+
paths = paths.concat(flattenElement(fk.targetElement._artifact, true, fk.name.id, fk.targetElement.path.map(ps => ps.id).join(pathDelimiter)));
|
|
1107
1108
|
else
|
|
1108
1109
|
{
|
|
1109
1110
|
// consume path segments until the next assoc and substitute against fk alias until path is eaten up
|
|
@@ -1113,7 +1114,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1113
1114
|
[tail, fkPrefix] = substituteFKAliasForPath(assocStep, tail, fkPrefix);
|
|
1114
1115
|
[assocStep, tail, fkPrefix] = pathAsStringUpToAssoc(tail, fkPrefix);
|
|
1115
1116
|
}
|
|
1116
|
-
paths = paths.concat(flattenElement(fk.targetElement._artifact, true, fkPrefix));
|
|
1117
|
+
paths = paths.concat(flattenElement(fk.targetElement._artifact, true, fkPrefix, fk.targetElement.path.map(ps => ps.id).join(pathDelimiter)));
|
|
1117
1118
|
}
|
|
1118
1119
|
}
|
|
1119
1120
|
}
|
|
@@ -1123,11 +1124,15 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1123
1124
|
for(let n in element.elements)
|
|
1124
1125
|
{
|
|
1125
1126
|
let elt = element.elements[n];
|
|
1126
|
-
paths = paths.concat(flattenElement(elt, true, elt.name.id));
|
|
1127
|
+
paths = paths.concat(flattenElement(elt, true, elt.name.id, elt.name.id));
|
|
1127
1128
|
}
|
|
1128
1129
|
}
|
|
1129
1130
|
return paths.map(p => {
|
|
1130
|
-
return {
|
|
1131
|
+
return {
|
|
1132
|
+
id: (prefix ? prefix + pathDelimiter : '' ) + p.id,
|
|
1133
|
+
acc: (acc ? acc + pathDelimiter : '') + p.acc,
|
|
1134
|
+
_artifact: p._artifact
|
|
1135
|
+
}
|
|
1131
1136
|
} );
|
|
1132
1137
|
}
|
|
1133
1138
|
|
|
@@ -1556,7 +1561,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1556
1561
|
if(!qat[qatChildrenName]) {
|
|
1557
1562
|
setProp(qat, '$njr', true);
|
|
1558
1563
|
// flatten left hand side ON condition paths ( => foreign keys to the source side)
|
|
1559
|
-
setProp(art, '$flatSrcFKs', flattenElement(art, true, art.name.id));
|
|
1564
|
+
setProp(art, '$flatSrcFKs', flattenElement(art, true, art.name.id, art.name.id));
|
|
1560
1565
|
}
|
|
1561
1566
|
}
|
|
1562
1567
|
else {
|
|
@@ -10,17 +10,17 @@ const { setAnnotationIfNotDefined } = require('./utils');
|
|
|
10
10
|
*
|
|
11
11
|
* @param {CSN.Model} csn
|
|
12
12
|
*/
|
|
13
|
-
function setCoreComputedOnViews(csn) {
|
|
13
|
+
function setCoreComputedOnViews( csn ) {
|
|
14
14
|
const {
|
|
15
15
|
artifactRef, getColumn, getElement, getOrigin,
|
|
16
16
|
} = getUtils(csn, 'init-all');
|
|
17
17
|
|
|
18
|
-
forEachDefinition(csn, (artifact) => {
|
|
18
|
+
forEachDefinition(csn, (artifact, name, prop, path) => {
|
|
19
19
|
if (artifact.query || artifact.projection) {
|
|
20
20
|
forAllQueries(getNormalizedQuery(artifact).query, (query) => {
|
|
21
21
|
if (query.SELECT)
|
|
22
22
|
traverseQueryAndAttachCoreComputed(query, query.SELECT.elements || artifact.elements);
|
|
23
|
-
});
|
|
23
|
+
}, path);
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
/**
|
|
@@ -33,7 +33,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
33
33
|
* @param {CSN.Query} query
|
|
34
34
|
* @param {CSN.Elements} elements
|
|
35
35
|
*/
|
|
36
|
-
function traverseQueryAndAttachCoreComputed(query, elements) {
|
|
36
|
+
function traverseQueryAndAttachCoreComputed( query, elements ) {
|
|
37
37
|
for (const [ name, element ] of Object.entries(elements)) {
|
|
38
38
|
const ancestor = getAncestor(element, name, query.SELECT);
|
|
39
39
|
|
|
@@ -53,7 +53,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
53
53
|
* @param {CSN.QuerySelect} base
|
|
54
54
|
* @returns {CSN.Column|CSN.Element}
|
|
55
55
|
*/
|
|
56
|
-
function getAncestor(element, name, base) {
|
|
56
|
+
function getAncestor( element, name, base ) {
|
|
57
57
|
const column = getColumn(element);
|
|
58
58
|
if (column)
|
|
59
59
|
return column;
|
|
@@ -81,7 +81,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
81
81
|
* @returns {CSN.Element}
|
|
82
82
|
* @todo cleanup throw(s) - but leave in during dev
|
|
83
83
|
*/
|
|
84
|
-
function getElementFromFrom(name, base) {
|
|
84
|
+
function getElementFromFrom( name, base ) {
|
|
85
85
|
if (base.SELECT && base.SELECT.elements) {
|
|
86
86
|
return getAncestor(base.SELECT.elements[name], name, base.SELECT);
|
|
87
87
|
}
|
|
@@ -108,7 +108,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
108
108
|
* @param {string} name
|
|
109
109
|
* @returns {CSN.Element|null} Null if no element was found
|
|
110
110
|
*/
|
|
111
|
-
function checkJoinSources(args, name) {
|
|
111
|
+
function checkJoinSources( args, name ) {
|
|
112
112
|
for (const arg of args) {
|
|
113
113
|
if (arg.args) { // Join after join - A join B on <..> join C on <..>
|
|
114
114
|
const result = checkJoinSources(arg.args, name);
|
|
@@ -130,7 +130,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
130
130
|
*
|
|
131
131
|
* @param {CSN.Column} column
|
|
132
132
|
*/
|
|
133
|
-
function attachCoreComputed(column) {
|
|
133
|
+
function attachCoreComputed( column ) {
|
|
134
134
|
if (needsCoreComputed(column))
|
|
135
135
|
setAnnotationIfNotDefined(getElement(column), '@Core.Computed', true);
|
|
136
136
|
}
|
|
@@ -141,7 +141,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
141
141
|
* @param {CSN.Column} column
|
|
142
142
|
* @returns {boolean}
|
|
143
143
|
*/
|
|
144
|
-
function needsCoreComputed(column) {
|
|
144
|
+
function needsCoreComputed( column ) {
|
|
145
145
|
return column &&
|
|
146
146
|
(
|
|
147
147
|
column.xpr || column.func || column.val !== undefined || column.param || column.SELECT || column.SET ||
|
|
@@ -155,7 +155,7 @@ function setCoreComputedOnViews(csn) {
|
|
|
155
155
|
* @param {CSN.Column} column
|
|
156
156
|
* @param {Function} callback
|
|
157
157
|
*/
|
|
158
|
-
function traverseExpandInline(column, callback) {
|
|
158
|
+
function traverseExpandInline( column, callback ) {
|
|
159
159
|
if (column.expand) {
|
|
160
160
|
column.expand.forEach((col) => {
|
|
161
161
|
callback(col);
|
|
@@ -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:\'
|