@sap/cds-compiler 3.4.2 → 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 +80 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +15 -16
- package/bin/cdshi.js +19 -6
- package/doc/CHANGELOG_ARCHIVE.md +2 -2
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +61 -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 +177 -58
- package/lib/base/messages.js +252 -180
- 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/.eslintrc.json +2 -0
- 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 +4 -1
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/builtins.js +14 -14
- package/lib/compiler/checks.js +123 -48
- package/lib/compiler/define.js +12 -13
- package/lib/compiler/extend.js +266 -60
- package/lib/compiler/finalize-parse-cdl.js +10 -5
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +14 -6
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +27 -16
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +20 -0
- package/lib/edm/annotations/genericTranslation.js +604 -358
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +275 -222
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +6 -6
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +107 -77
- package/lib/edm/edmUtils.js +44 -5
- package/lib/gen/Dictionary.json +210 -8
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +67 -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 +14309 -13832
- 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 +102 -55
- package/lib/json/to-csn.js +119 -198
- package/lib/language/antlrParser.js +5 -2
- package/lib/language/docCommentParser.js +6 -6
- package/lib/language/errorStrategy.js +43 -23
- package/lib/language/genericAntlrParser.js +113 -133
- package/lib/language/language.g4 +1550 -1506
- package/lib/language/multiLineStringParser.js +3 -3
- package/lib/language/textUtils.js +2 -2
- package/lib/main.js +3 -3
- package/lib/model/csnRefs.js +5 -0
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/compare.js +2 -2
- package/lib/modelCompare/utils/.eslintrc.json +22 -0
- package/lib/modelCompare/utils/filter.js +100 -0
- package/lib/optionProcessor.js +5 -0
- package/lib/render/.eslintrc.json +1 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +311 -276
- package/lib/render/toHdbcds.js +97 -94
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +127 -223
- package/lib/render/utils/common.js +141 -108
- package/lib/render/utils/delta.js +227 -0
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/.eslintrc.json +2 -0
- 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/.eslintrc.json +1 -35
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +8 -29
- package/lib/transform/forRelationalDB.js +16 -6
- package/lib/transform/localized.js +11 -10
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +113 -47
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +17 -10
- 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 -8
- 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
- package/lib/modelCompare/filter.js +0 -83
|
@@ -10,12 +10,12 @@ const { forEachDefinition } = require('../../model/csnUtils.js');
|
|
|
10
10
|
* options:
|
|
11
11
|
* v
|
|
12
12
|
*
|
|
13
|
-
* This module never produces errors. In case of "unexpected" situations we issue a
|
|
13
|
+
* This module never produces errors. In case of "unexpected" situations we issue a message and
|
|
14
14
|
* try to proceed with the processing as good as possible.
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
17
|
function preprocessAnnotations(csn, serviceName, options) {
|
|
18
|
-
const {
|
|
18
|
+
const { message } = makeMessageFunction(csn, options);
|
|
19
19
|
let fkSeparator = '_';
|
|
20
20
|
|
|
21
21
|
resolveShortcuts();
|
|
@@ -32,7 +32,7 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// return value can be null is target has no key
|
|
35
|
-
function getKeyOfTargetOfManagedAssoc(assoc) {
|
|
35
|
+
function getKeyOfTargetOfManagedAssoc(anno, assoc) {
|
|
36
36
|
// assoc.target can be the name of the target or the object itself
|
|
37
37
|
let targetName = (typeof assoc.target === 'object') ? assoc.target.name : assoc.target;
|
|
38
38
|
let target = (typeof assoc.target === 'object') ? assoc.target : csn.definitions[assoc.target];
|
|
@@ -40,10 +40,11 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
40
40
|
let keyNames = Object.keys(target.elements).filter(x => target.elements[x].key && !target.elements[x].target);
|
|
41
41
|
if (keyNames.length === 0) {
|
|
42
42
|
keyNames.push('MISSING');
|
|
43
|
-
|
|
43
|
+
message('odata-anno-preproc', null, { anno, name: targetName, '#': 'nokey' },
|
|
44
|
+
'target $(NAME) has no key');
|
|
44
45
|
}
|
|
45
46
|
else if (keyNames.length > 1)
|
|
46
|
-
|
|
47
|
+
message('odata-anno-preproc', null, { anno, name: targetName, '#': 'multkeys' });
|
|
47
48
|
|
|
48
49
|
return keyNames[0];
|
|
49
50
|
}
|
|
@@ -58,32 +59,29 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
58
59
|
let art = null;
|
|
59
60
|
|
|
60
61
|
forEachDefinition(csn, (artifact, artifactName) => {
|
|
62
|
+
const location = [ 'definitions', artifactName ];
|
|
61
63
|
if(artifactName === serviceName || artifactName.startsWith(serviceName + '.')) {
|
|
62
64
|
art = artifactName;
|
|
63
|
-
handleAnnotations(artifactName, artifact);
|
|
65
|
+
handleAnnotations(artifactName, artifact, location);
|
|
64
66
|
artifact.elements && Object.entries(artifact.elements).forEach(([elementName, element]) => {
|
|
65
|
-
handleAnnotations(elementName, element);
|
|
67
|
+
handleAnnotations(elementName, element, [ ...location, 'elements', elementName ]);
|
|
66
68
|
});
|
|
67
69
|
artifact.actions && Object.values(artifact.actions).forEach(action => {
|
|
68
70
|
action.params && Object.entries(action.params).forEach(([paramName, param]) => {
|
|
69
|
-
handleAnnotations(paramName, param);
|
|
71
|
+
handleAnnotations(paramName, param, [ ...location, 'actions', action, 'params', paramName ]);
|
|
70
72
|
});
|
|
71
73
|
});
|
|
72
74
|
}
|
|
73
75
|
});
|
|
74
76
|
|
|
75
|
-
function handleAnnotations(carrierName, carrier) {
|
|
77
|
+
function handleAnnotations(carrierName, carrier, location) {
|
|
76
78
|
|
|
77
79
|
// collect the names of the carrier's annotation properties
|
|
78
|
-
let annoNames = Object.keys(carrier).filter( x => x
|
|
80
|
+
let annoNames = Object.keys(carrier).filter( x => x[0] === '@')
|
|
79
81
|
|
|
80
82
|
for (let aName of annoNames) {
|
|
81
83
|
let aNameWithoutQualifier = aName.split('#')[0];
|
|
82
84
|
|
|
83
|
-
//for warning messages
|
|
84
|
-
let ctx = 'target: ' + art + '/' + carrierName;
|
|
85
|
-
|
|
86
|
-
|
|
87
85
|
// Always - draft annotations, value is action name
|
|
88
86
|
// - v2: prefix with entity name
|
|
89
87
|
// - prefix with service name
|
|
@@ -91,11 +89,11 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
91
89
|
|
|
92
90
|
// Always - FixedValueListShortcut
|
|
93
91
|
// expand shortcut form of ValueList annotation
|
|
94
|
-
fixedValueListShortCut(carrier, aNameWithoutQualifier
|
|
92
|
+
fixedValueListShortCut(carrier, aNameWithoutQualifier);
|
|
95
93
|
|
|
96
94
|
// Always - TextArrangementReordering
|
|
97
95
|
// convert @Common.TextArrangement annotation that is on same level as Text annotation into a nested annotation
|
|
98
|
-
textArrangementReordering(carrier, aName, aNameWithoutQualifier
|
|
96
|
+
textArrangementReordering(carrier, aName, aNameWithoutQualifier);
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
// inner functions
|
|
@@ -121,9 +119,9 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
121
119
|
}
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
function fixedValueListShortCut(carrier,
|
|
125
|
-
if (
|
|
126
|
-
|
|
122
|
+
function fixedValueListShortCut(carrier, anno) {
|
|
123
|
+
if (anno === '@Common.ValueList.entity' ||
|
|
124
|
+
anno === '@Common.ValueList.viaAssociation') {
|
|
127
125
|
|
|
128
126
|
const _fixedValueListShortCut = () => {
|
|
129
127
|
// note: we loop over all annotations that were originally present, even if they are
|
|
@@ -136,7 +134,7 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
if (carrier.kind === 'entity') {
|
|
139
|
-
|
|
137
|
+
message('odata-anno-preproc', [...location, anno], { anno, '#': 'notforentity' });
|
|
140
138
|
return false;
|
|
141
139
|
}
|
|
142
140
|
|
|
@@ -146,32 +144,37 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
146
144
|
let enameShort = null; // (string) name of value list entity, short (i.e. name within service)
|
|
147
145
|
let enameFull = null; // (string) name of value list entity, fully qualified name
|
|
148
146
|
|
|
149
|
-
if (
|
|
147
|
+
if (anno === '@Common.ValueList.viaAssociation') {
|
|
150
148
|
// value is expected to be an expression, namely the path to an association of the carrier entity
|
|
151
149
|
let assocName = carrier['@Common.ValueList.viaAssociation']['='];
|
|
152
150
|
if (!assocName) {
|
|
153
|
-
|
|
151
|
+
message('odata-anno-preproc', [...location, anno], { anno, '#': 'viaassoc' });
|
|
154
152
|
return false;
|
|
155
153
|
}
|
|
156
154
|
let assoc = csn.definitions[art].elements[assocName];
|
|
157
155
|
if (!assoc || !assoc.target) {
|
|
158
|
-
|
|
156
|
+
message('odata-anno-preproc', [...location, anno], { anno, id: assocName, '#': 'noassoc' });
|
|
159
157
|
return false;
|
|
160
158
|
}
|
|
161
159
|
|
|
162
160
|
enameFull = assoc.target.name || assoc.target; // full name
|
|
163
161
|
enameShort = enameFull.split('.').pop();
|
|
164
162
|
}
|
|
165
|
-
else if (
|
|
163
|
+
else if (anno === '@Common.ValueList.entity') {
|
|
166
164
|
// if both annotations are present, ignore 'entity' and raise a message
|
|
167
165
|
if (annoNames.map(x=>x.split('#')[0]).find(x=>(x==='@Common.ValueList.viaAssociation'))) {
|
|
168
|
-
|
|
166
|
+
message('odata-anno-preproc', [...location, anno],
|
|
167
|
+
{
|
|
168
|
+
name: '@Common.ValueList.entity', anno: '@Common.ValueList',
|
|
169
|
+
value: 'entity', code: 'viaAssociation', '#': 'vallistignored'
|
|
170
|
+
});
|
|
169
171
|
return false;
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
let annoVal = carrier['@Common.ValueList.entity']; // name of value list entity
|
|
173
175
|
if (annoVal['=']) {
|
|
174
|
-
|
|
176
|
+
message('odata-anno-preproc', [...location, anno], { anno, '#': 'notastring' },
|
|
177
|
+
);
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
let nameprefix = art.replace(/.[^.]+$/, ''); // better way of getting the service name?
|
|
@@ -182,7 +185,7 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
182
185
|
|
|
183
186
|
let vlEntity = csn.definitions[enameFull]; // (object) value list entity
|
|
184
187
|
if (!vlEntity) {
|
|
185
|
-
|
|
188
|
+
message('odata-anno-preproc', [...location, anno ], { anno, id: enameFull, '#': 'notexist' });
|
|
186
189
|
return false;
|
|
187
190
|
}
|
|
188
191
|
|
|
@@ -196,7 +199,8 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
196
199
|
// if this is a managed assoc, use fk field instead (if there is a single one)
|
|
197
200
|
let localDataProp = carrierName.split('/').pop();
|
|
198
201
|
if (carrier.target && carrier.on === undefined) {
|
|
199
|
-
localDataProp = localDataProp + fkSeparator +
|
|
202
|
+
localDataProp = localDataProp + fkSeparator +
|
|
203
|
+
getKeyOfTargetOfManagedAssoc(anno, carrier);
|
|
200
204
|
}
|
|
201
205
|
|
|
202
206
|
// if this carrier is a generated foreign key field and the association is marked @cds.api.ignore
|
|
@@ -209,15 +213,15 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
// valueListProp: the (single) key field of the value list entity
|
|
212
|
-
// if no key or multiple keys ->
|
|
216
|
+
// if no key or multiple keys -> message
|
|
213
217
|
let valueListProp = null;
|
|
214
218
|
let keys = Object.keys(vlEntity.elements).filter( x => vlEntity.elements[x].key && !vlEntity.elements[x].target );
|
|
215
219
|
if (keys.length === 0) {
|
|
216
|
-
|
|
220
|
+
message('odata-anno-preproc', [...location, anno], { anno, name: enameFull, '#': 'vhlnokey' });
|
|
217
221
|
return false;
|
|
218
222
|
}
|
|
219
223
|
else if (keys.length > 1)
|
|
220
|
-
|
|
224
|
+
message('odata-anno-preproc', [...location, anno], { anno, name: enameFull, '#': 'vhlmultkeys' });
|
|
221
225
|
valueListProp = keys[0];
|
|
222
226
|
|
|
223
227
|
// textField:
|
|
@@ -278,20 +282,20 @@ function preprocessAnnotations(csn, serviceName, options) {
|
|
|
278
282
|
|
|
279
283
|
const success = _fixedValueListShortCut();
|
|
280
284
|
if (!success) {
|
|
281
|
-
// In case of failure, avoid subsequent
|
|
282
|
-
delete carrier[
|
|
285
|
+
// In case of failure, avoid subsequent messages
|
|
286
|
+
delete carrier[anno];
|
|
283
287
|
delete carrier['@Common.ValueList.type'];
|
|
284
288
|
}
|
|
285
289
|
}
|
|
286
290
|
}
|
|
287
291
|
|
|
288
|
-
function textArrangementReordering(carrier, aName, aNameWithoutQualifier
|
|
292
|
+
function textArrangementReordering(carrier, aName, aNameWithoutQualifier) {
|
|
289
293
|
if (aNameWithoutQualifier === '@Common.TextArrangement') {
|
|
290
294
|
let value = carrier[aName];
|
|
291
295
|
let textAnno = carrier['@Common.Text'];
|
|
292
296
|
// can only occur if there is a @Common.Text annotation at the same target
|
|
293
297
|
if (!textAnno) {
|
|
294
|
-
|
|
298
|
+
message('odata-anno-preproc', [...location, '@Common.TextArrangement'], { anno: '@Common.TextArrangement', name: '@Common.Text', '#': 'txtarr' });
|
|
295
299
|
}
|
|
296
300
|
|
|
297
301
|
//change the scalar anno into a "pseudo-structured" one
|