@sap/cds-compiler 4.3.2 → 4.4.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 +39 -0
- package/lib/api/main.js +14 -24
- package/lib/api/options.js +1 -0
- package/lib/api/trace.js +38 -0
- package/lib/base/location.js +46 -1
- package/lib/base/message-registry.js +68 -16
- package/lib/base/messages.js +8 -3
- package/lib/checks/.eslintrc.json +1 -0
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/selectItems.js +4 -1
- package/lib/compiler/assert-consistency.js +3 -2
- package/lib/compiler/base.js +1 -1
- package/lib/compiler/builtins.js +25 -1
- package/lib/compiler/checks.js +6 -5
- package/lib/compiler/define.js +12 -10
- package/lib/compiler/extend.js +44 -23
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +70 -53
- package/lib/compiler/kick-start.js +7 -5
- package/lib/compiler/populate.js +31 -22
- package/lib/compiler/propagator.js +6 -2
- package/lib/compiler/resolve.js +52 -17
- package/lib/compiler/shared.js +85 -39
- package/lib/compiler/tweak-assocs.js +64 -23
- package/lib/compiler/utils.js +40 -23
- package/lib/edm/.eslintrc.json +2 -0
- package/lib/edm/EdmPrimitiveTypeDefinitions.js +260 -0
- package/lib/edm/annotations/edmJson.js +994 -0
- package/lib/edm/annotations/genericTranslation.js +82 -423
- package/lib/edm/annotations/vocabularyDefinitions.js +160 -0
- package/lib/edm/csn2edm.js +12 -5
- package/lib/edm/edm.js +14 -73
- package/lib/edm/edmPreprocessor.js +6 -0
- package/lib/gen/Dictionary.json +187 -16
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageLexer.interp +1 -1
- package/lib/gen/languageLexer.js +1129 -671
- package/lib/gen/languageParser.js +4285 -4283
- package/lib/json/from-csn.js +13 -18
- package/lib/json/to-csn.js +11 -6
- package/lib/language/antlrParser.js +0 -1
- package/lib/language/docCommentParser.js +1 -1
- package/lib/language/errorStrategy.js +95 -30
- package/lib/language/genericAntlrParser.js +21 -1
- package/lib/main.js +13 -3
- package/lib/model/csnRefs.js +42 -8
- package/lib/model/csnUtils.js +14 -2
- package/lib/model/enrichCsn.js +33 -5
- package/lib/model/revealInternalProperties.js +5 -0
- package/lib/modelCompare/compare.js +76 -14
- package/lib/modelCompare/utils/filter.js +19 -12
- package/lib/optionProcessor.js +2 -0
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toHdbcds.js +3 -0
- package/lib/render/toRename.js +3 -1
- package/lib/render/toSql.js +46 -92
- package/lib/render/utils/common.js +76 -0
- package/lib/render/utils/delta.js +17 -3
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/db/.eslintrc.json +1 -0
- package/lib/transform/db/applyTransformations.js +30 -4
- package/lib/transform/db/associations.js +22 -10
- package/lib/transform/db/backlinks.js +6 -2
- package/lib/transform/db/expansion.js +2 -2
- package/lib/transform/db/transformExists.js +13 -39
- package/lib/transform/draft/db.js +14 -3
- package/lib/transform/draft/odata.js +5 -18
- package/lib/transform/effective/associations.js +46 -15
- package/lib/transform/effective/main.js +7 -2
- package/lib/transform/effective/misc.js +43 -24
- package/lib/transform/effective/queries.js +20 -22
- package/lib/transform/effective/types.js +6 -2
- package/lib/transform/forOdata.js +10 -3
- package/lib/transform/localized.js +1 -1
- package/lib/transform/parseExpr.js +73 -21
- package/lib/transform/translateAssocsToJoins.js +22 -15
- package/lib/utils/term.js +2 -2
- package/package.json +2 -1
|
@@ -5,166 +5,11 @@ const edmUtils = require('../edmUtils.js');
|
|
|
5
5
|
const oDataDictionary = require('../../gen/Dictionary.json');
|
|
6
6
|
const preprocessAnnotations = require('./preprocessAnnotations.js');
|
|
7
7
|
const { forEachDefinition } = require('../../model/csnUtils');
|
|
8
|
-
const { forEach } = require('../../utils/objectUtils');
|
|
9
8
|
const { isBetaEnabled, setProp } = require('../../base/model.js');
|
|
9
|
+
const { xpr2edmJson, getEdmJsonHandler } = require('./edmJson.js');
|
|
10
|
+
const { vocabularyDefinitions } = require('./vocabularyDefinitions.js');
|
|
11
|
+
const { EdmPathTypeMap } = require('../EdmPrimitiveTypeDefinitions.js');
|
|
10
12
|
|
|
11
|
-
/*
|
|
12
|
-
OASIS: https://github.com/oasis-tcs/odata-vocabularies/tree/master/vocabularies
|
|
13
|
-
Aggregation (published)
|
|
14
|
-
Authorization (published)
|
|
15
|
-
Capabilities (published)
|
|
16
|
-
Core (published)
|
|
17
|
-
JSON (published)
|
|
18
|
-
Measures (published)
|
|
19
|
-
Repeatability (published)
|
|
20
|
-
Temporal (published)
|
|
21
|
-
Validation (published)
|
|
22
|
-
|
|
23
|
-
SAP: https://github.com/SAP/odata-vocabularies/tree/master/vocabularies
|
|
24
|
-
Analytics (published)
|
|
25
|
-
CodeList (published)
|
|
26
|
-
Common (published)
|
|
27
|
-
Communication (published)
|
|
28
|
-
DataIntegration (published)
|
|
29
|
-
Graph (published, experimental)
|
|
30
|
-
Hierarchy (published, experimental)
|
|
31
|
-
HTML5 (published, experimental)
|
|
32
|
-
ODM (published, experimental)
|
|
33
|
-
Offline (experimental)
|
|
34
|
-
PDF (published)
|
|
35
|
-
PersonalData (published)
|
|
36
|
-
Session (published)
|
|
37
|
-
UI (published)
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
const vocabularyDefinitions = {
|
|
41
|
-
Aggregation: {
|
|
42
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Aggregation.V1.xml' },
|
|
43
|
-
inc: { Alias: 'Aggregation', Namespace: 'Org.OData.Aggregation.V1' },
|
|
44
|
-
int: { filename: 'Aggregation.xml' },
|
|
45
|
-
},
|
|
46
|
-
Analytics: {
|
|
47
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Analytics.xml' },
|
|
48
|
-
inc: { Alias: 'Analytics', Namespace: 'com.sap.vocabularies.Analytics.v1' },
|
|
49
|
-
int: { filename: 'Analytics.xml' },
|
|
50
|
-
},
|
|
51
|
-
Authorization: {
|
|
52
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Authorization.V1.xml' },
|
|
53
|
-
inc: { Alias: 'Authorization', Namespace: 'Org.OData.Authorization.V1' },
|
|
54
|
-
int: { filename: 'Authorization.xml' },
|
|
55
|
-
},
|
|
56
|
-
Capabilities: {
|
|
57
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Capabilities.V1.xml' },
|
|
58
|
-
inc: { Alias: 'Capabilities', Namespace: 'Org.OData.Capabilities.V1' },
|
|
59
|
-
int: { filename: 'Capabilities.xml' },
|
|
60
|
-
},
|
|
61
|
-
CodeList: {
|
|
62
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/CodeList.xml' },
|
|
63
|
-
inc: { Alias: 'CodeList', Namespace: 'com.sap.vocabularies.CodeList.v1' },
|
|
64
|
-
int: { filename: 'CodeList.xml' },
|
|
65
|
-
},
|
|
66
|
-
Common: {
|
|
67
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Common.xml' },
|
|
68
|
-
inc: { Alias: 'Common', Namespace: 'com.sap.vocabularies.Common.v1' },
|
|
69
|
-
int: { filename: 'Common.xml' },
|
|
70
|
-
},
|
|
71
|
-
Communication: {
|
|
72
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Communication.xml' },
|
|
73
|
-
inc: { Alias: 'Communication', Namespace: 'com.sap.vocabularies.Communication.v1' },
|
|
74
|
-
int: { filename: 'Communication.xml' },
|
|
75
|
-
},
|
|
76
|
-
Core: {
|
|
77
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml' },
|
|
78
|
-
inc: { Alias: 'Core', Namespace: 'Org.OData.Core.V1' },
|
|
79
|
-
int: { filename: 'Core.xml' },
|
|
80
|
-
},
|
|
81
|
-
DataIntegration: {
|
|
82
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/DataIntegration.xml' },
|
|
83
|
-
inc: { Alias: 'DataIntegration', Namespace: 'com.sap.vocabularies.DataIntegration.v1' },
|
|
84
|
-
int: { filename: 'DataIntegration.xml' },
|
|
85
|
-
},
|
|
86
|
-
Graph: {
|
|
87
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Graph.xml' },
|
|
88
|
-
inc: { Alias: 'Graph', Namespace: 'com.sap.vocabularies.Graph.v1' },
|
|
89
|
-
int: { filename: 'Graph.xml' },
|
|
90
|
-
},
|
|
91
|
-
Hierarchy: {
|
|
92
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Hierarchy.xml' },
|
|
93
|
-
inc: { Alias: 'Hierarchy', Namespace: 'com.sap.vocabularies.Hierarchy.v1' },
|
|
94
|
-
int: { filename: 'Hierarchy.xml' },
|
|
95
|
-
},
|
|
96
|
-
HTML5: {
|
|
97
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/HTML5.xml' },
|
|
98
|
-
inc: { Alias: 'HTML5', Namespace: 'com.sap.vocabularies.HTML5.v1' },
|
|
99
|
-
int: { filename: 'HTML5.xml' },
|
|
100
|
-
},
|
|
101
|
-
JSON: {
|
|
102
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.JSON.V1.xml' },
|
|
103
|
-
inc: { Alias: 'JSON', Namespace: 'Org.OData.JSON.V1' },
|
|
104
|
-
int: { filename: 'JSON.xml' },
|
|
105
|
-
},
|
|
106
|
-
Measures: {
|
|
107
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Measures.V1.xml' },
|
|
108
|
-
inc: { Alias: 'Measures', Namespace: 'Org.OData.Measures.V1' },
|
|
109
|
-
int: { filename: 'Measures.xml' },
|
|
110
|
-
},
|
|
111
|
-
ODM: {
|
|
112
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/ODM.xml' },
|
|
113
|
-
inc: { Alias: 'ODM', Namespace: 'com.sap.vocabularies.ODM.v1' },
|
|
114
|
-
int: { filename: 'ODM.xml' },
|
|
115
|
-
},
|
|
116
|
-
Offline: {
|
|
117
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Offline.xml' },
|
|
118
|
-
inc: { Alias: 'Offline', Namespace: 'com.sap.vocabularies.Offline.v1' },
|
|
119
|
-
int: { filename: 'Offline.xml' },
|
|
120
|
-
},
|
|
121
|
-
PDF: {
|
|
122
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/PDF.xml' },
|
|
123
|
-
inc: { Alias: 'PDF', Namespace: 'com.sap.vocabularies.PDF.v1' },
|
|
124
|
-
int: { filename: 'PDF.xml' },
|
|
125
|
-
},
|
|
126
|
-
PersonalData: {
|
|
127
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/PersonalData.xml' },
|
|
128
|
-
inc: { Alias: 'PersonalData', Namespace: 'com.sap.vocabularies.PersonalData.v1' },
|
|
129
|
-
int: { filename: 'PersonalData.xml' },
|
|
130
|
-
},
|
|
131
|
-
Repeatability: {
|
|
132
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Repeatability.V1.xml' },
|
|
133
|
-
inc: { Alias: 'Repeatability', Namespace: 'Org.OData.Repeatability.V1' },
|
|
134
|
-
int: { filename: 'Repeatability.xml' },
|
|
135
|
-
},
|
|
136
|
-
Session: {
|
|
137
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Session.xml' },
|
|
138
|
-
inc: { Alias: 'Session', Namespace: 'com.sap.vocabularies.Session.v1' },
|
|
139
|
-
int: { filename: 'Session.xml' },
|
|
140
|
-
},
|
|
141
|
-
UI: {
|
|
142
|
-
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/UI.xml' },
|
|
143
|
-
inc: { Alias: 'UI', Namespace: 'com.sap.vocabularies.UI.v1' },
|
|
144
|
-
int: { filename: 'UI.xml' },
|
|
145
|
-
},
|
|
146
|
-
Validation: {
|
|
147
|
-
ref: { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Validation.V1.xml' },
|
|
148
|
-
inc: { Alias: 'Validation', Namespace: 'Org.OData.Validation.V1' },
|
|
149
|
-
int: { filename: 'Validation.xml' },
|
|
150
|
-
},
|
|
151
|
-
/* unvalidated vocabularies below here:
|
|
152
|
-
A vocabulary is unvalidated if it doesn't have an int.filename property as this indicates that
|
|
153
|
-
the vocabulary is added to the validation dictionary
|
|
154
|
-
Example:
|
|
155
|
-
'Org.Snafu.V1': {
|
|
156
|
-
'ref': { Uri: 'https://snafu.org/snafu.xml' },
|
|
157
|
-
'inc': { Alias: 'Snafu', Namespace: 'Org.Snafu.V1' },
|
|
158
|
-
},
|
|
159
|
-
*/
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
/* create inverted voc definitions list to allow addressing full qualified vocabularies
|
|
163
|
-
Object.entries(vocabularyDefinitions).forEach(([n, v]) => {
|
|
164
|
-
if(!vocabularyDefinitions[v.inc.Namespace])
|
|
165
|
-
vocabularyDefinitions[v.inc.Namespace] = vocabularyDefinitions[n];
|
|
166
|
-
});
|
|
167
|
-
*/
|
|
168
13
|
/** ************************************************************************************************
|
|
169
14
|
* csn2annotationEdm
|
|
170
15
|
*
|
|
@@ -174,20 +19,20 @@ Object.entries(vocabularyDefinitions).forEach(([n, v]) => {
|
|
|
174
19
|
*/
|
|
175
20
|
function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
176
21
|
Edm = undefined, options = undefined, messageFunctions = undefined, mergedVocDefs = vocabularyDefinitions ) {
|
|
177
|
-
// global variable where we store all the generated annotations
|
|
178
|
-
const
|
|
22
|
+
const gAnnosArray = []; // global variable where we store all the generated annotations
|
|
23
|
+
const usedExperimentalTerms = {}; // take note of all experimental annos that have been used
|
|
24
|
+
const usedDeprecatedTerms = {}; // take note of all deprecated annos that have been used
|
|
179
25
|
|
|
26
|
+
const { v } = options;
|
|
180
27
|
const { message } = messageFunctions;
|
|
181
|
-
|
|
28
|
+
const { handleEdmJson } = getEdmJsonHandler(Edm, options, messageFunctions, handleTerm);
|
|
182
29
|
const [ userDefinedTermDict, allKnownVocabularies ] = createUserDefinedTermDictionary();
|
|
183
30
|
|
|
31
|
+
|
|
184
32
|
allKnownVocabularies.push(...Object.keys(mergedVocDefs));
|
|
185
33
|
allKnownVocabularies.sort((a, b) => b.length - a.length);
|
|
186
34
|
const whatsMyTermNamespace = anno => allKnownVocabularies.reduce((rc, ns) => (!rc && anno && anno.startsWith(`@${ns}.`) ? ns : rc), undefined);
|
|
187
35
|
|
|
188
|
-
// Static dynamic expression dictionary, loaded with Edm creators
|
|
189
|
-
const [ dynamicExpressions, dynamicExpressionNames ] = initEdmJson();
|
|
190
|
-
|
|
191
36
|
// annotation preprocessing
|
|
192
37
|
preprocessAnnotations.preprocessAnnotations(reqDefs, serviceName, options);
|
|
193
38
|
|
|
@@ -209,63 +54,6 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
209
54
|
{ name: serviceName, '#': 'service' } );
|
|
210
55
|
}
|
|
211
56
|
|
|
212
|
-
// provide functions for dictionary lookup
|
|
213
|
-
// use closure to avoid making "dict" and "experimental" global variables
|
|
214
|
-
const { getDictTerm, getDictType } = (function createDictGetters() {
|
|
215
|
-
const dict = options.dictReplacement || oDataDictionary; // tests can set different dictionary via options
|
|
216
|
-
const experimental = {}; // take note of all experimental annos that have been used
|
|
217
|
-
const deprecated = {}; // take note of all deprecated annos that have been used
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
// called to look-up a term in the dictionary
|
|
221
|
-
// in addition: - note usage of the respective vocabulary
|
|
222
|
-
// - issue a warning if the term is flagged as "experimental"
|
|
223
|
-
getDictTerm(termName, msg) {
|
|
224
|
-
const dictTerm = (dict.terms[termName] ||
|
|
225
|
-
userDefinedTermDict.terms[`${serviceName}.${termName}`] ||
|
|
226
|
-
userDefinedTermDict.terms[termName]);
|
|
227
|
-
// register vocabulary usage if possible
|
|
228
|
-
const vocName = termName.slice(0, termName.indexOf('.'));
|
|
229
|
-
const myVocDef = mergedVocDefs[vocName];
|
|
230
|
-
if (myVocDef && !myVocDef.$ignore)
|
|
231
|
-
myVocDef.used = true;
|
|
232
|
-
else if (dictTerm?.$myServiceRoot &&
|
|
233
|
-
userDefinedTermDict.xrefs[dictTerm?.$myServiceRoot])
|
|
234
|
-
userDefinedTermDict.xrefs[dictTerm.$myServiceRoot].used = true;
|
|
235
|
-
if (dictTerm) {
|
|
236
|
-
// issue message for usage of experimental Terms, but only once per Term
|
|
237
|
-
if (dictTerm.$experimental && !experimental[termName]) {
|
|
238
|
-
message('odata-anno-dict', msg.location, { anno: msg.anno(), '#': 'experimental' });
|
|
239
|
-
experimental[termName] = true;
|
|
240
|
-
}
|
|
241
|
-
if (dictTerm.$deprecated && !deprecated[termName]) {
|
|
242
|
-
message('odata-anno-def', msg.location,
|
|
243
|
-
{ anno: msg.anno(), depr: dictTerm.$deprecationText, '#': 'deprecated' });
|
|
244
|
-
deprecated[termName] = true;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return dictTerm;
|
|
248
|
-
},
|
|
249
|
-
// called to look-up a type in the dictionary
|
|
250
|
-
// in addition, note usage of the respective vocabulary
|
|
251
|
-
getDictType(typeName) {
|
|
252
|
-
const dictType = (dict.types[typeName] ||
|
|
253
|
-
userDefinedTermDict.types[`${serviceName}.${typeName}`] ||
|
|
254
|
-
userDefinedTermDict.types[typeName]);
|
|
255
|
-
if (dictType) {
|
|
256
|
-
// register usage of vocabulary
|
|
257
|
-
const vocName = typeName.slice(0, typeName.indexOf('.'));
|
|
258
|
-
const myVocDef = mergedVocDefs[vocName];
|
|
259
|
-
if (myVocDef && !myVocDef.$ignore)
|
|
260
|
-
myVocDef.used = true;
|
|
261
|
-
}
|
|
262
|
-
return dictType;
|
|
263
|
-
},
|
|
264
|
-
};
|
|
265
|
-
}());
|
|
266
|
-
|
|
267
|
-
const { v } = options;
|
|
268
|
-
|
|
269
57
|
// Copy annotations from origin to parameter entity if it's
|
|
270
58
|
// qualified with #$parameters or if its applicable to an EntitySet or Singleton
|
|
271
59
|
forEachDefinition(reqDefs, (object) => {
|
|
@@ -514,6 +302,12 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
514
302
|
if (knownAnnos.length === 0)
|
|
515
303
|
return;
|
|
516
304
|
}
|
|
305
|
+
if (isBetaEnabled(options, 'annotationExpressions')) {
|
|
306
|
+
knownAnnos.forEach((knownAnno) => {
|
|
307
|
+
if (knownAnno.search(/\.\$edmJson\./g) < 0)
|
|
308
|
+
carrier[knownAnno] = xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
517
311
|
|
|
518
312
|
const prefixTree = createPrefixTree();
|
|
519
313
|
|
|
@@ -803,13 +597,18 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
803
597
|
steps.splice(i, steps.length - i, steps.slice(i).join('.'));
|
|
804
598
|
}
|
|
805
599
|
if (innerAnnotation) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
600
|
+
// A voc annotation has two steps (Namespace+Name),
|
|
601
|
+
// any further steps need to be rendered separately
|
|
602
|
+
if (innerAnnotation.startsWith('sap.')) {
|
|
603
|
+
steps.push(`@${innerAnnotation}`);
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
const innerAnnoSteps = innerAnnotation.split('.');
|
|
607
|
+
const tailSteps = innerAnnoSteps.splice(2, innerAnnoSteps.length - 2);
|
|
608
|
+
// prepend annotation prefix (path) to tail steps
|
|
609
|
+
tailSteps.splice(0, 0, `@${innerAnnoSteps.join('.')}`);
|
|
610
|
+
steps.push(...tailSteps);
|
|
611
|
+
}
|
|
813
612
|
}
|
|
814
613
|
mergePathStepsIntoPrefixTree(prefixTreeP, steps, 0);
|
|
815
614
|
}
|
|
@@ -1142,8 +941,12 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
1142
941
|
// note: expr can also be provided if an enum/complex type/collection is expected
|
|
1143
942
|
function handleExpression( value, dTypeName ) {
|
|
1144
943
|
let typeName = 'Path';
|
|
1145
|
-
if ( [
|
|
1146
|
-
|
|
944
|
+
if ( EdmPathTypeMap[dTypeName] ) {
|
|
945
|
+
if (dTypeName === 'Edm.AnyPropertyPath')
|
|
946
|
+
typeName = 'PropertyPath';
|
|
947
|
+
else
|
|
948
|
+
typeName = dTypeName.split('.')[1];
|
|
949
|
+
}
|
|
1147
950
|
|
|
1148
951
|
if (value) {
|
|
1149
952
|
// replace all occurrences of '.' by '/' up to first '@'
|
|
@@ -1496,142 +1299,6 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
1496
1299
|
}
|
|
1497
1300
|
|
|
1498
1301
|
|
|
1499
|
-
// Not everything that can occur in OData annotations can be expressed with
|
|
1500
|
-
// corresponding constructs in cds annotations. For these special cases
|
|
1501
|
-
// we have a kind of "inline assembler" mode, i.e. you can in cds provide
|
|
1502
|
-
// as annotation value a json snippet that looks like the final edm-json.
|
|
1503
|
-
// See example in test/odataAnnotations/smallTests/edmJson_noReverse_ok
|
|
1504
|
-
// and test3/ODataBackends/DynExpr
|
|
1505
|
-
|
|
1506
|
-
function handleEdmJson( obj, msg, exprDef = undefined ) {
|
|
1507
|
-
let edmNode;
|
|
1508
|
-
if (obj == null)
|
|
1509
|
-
return edmNode;
|
|
1510
|
-
|
|
1511
|
-
const dynExprs = edmUtils.intersect(dynamicExpressionNames, Object.keys(obj));
|
|
1512
|
-
|
|
1513
|
-
if (dynExprs.length > 1) {
|
|
1514
|
-
message('odata-anno-value', msg.location,
|
|
1515
|
-
{ anno: msg.anno(), rawvalues: dynExprs, '#': 'multexpr' });
|
|
1516
|
-
return edmNode;
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
if (dynExprs.length === 0) {
|
|
1520
|
-
if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 1) {
|
|
1521
|
-
const k = Object.keys(obj)[0];
|
|
1522
|
-
const val = obj[k];
|
|
1523
|
-
edmNode = new Edm.ValueThing(v, k[0] === '$' ? k.slice(1) : k, val );
|
|
1524
|
-
edmNode.setJSON( { [edmNode.kind]: val } );
|
|
1525
|
-
}
|
|
1526
|
-
// This thing is either a record or a collection or a literal
|
|
1527
|
-
else if (Array.isArray(obj)) {
|
|
1528
|
-
// EDM JSON doesn't mention annotations on collections
|
|
1529
|
-
edmNode = new Edm.Collection(v);
|
|
1530
|
-
obj.forEach(o => edmNode.append(handleEdmJson(o, msg)));
|
|
1531
|
-
}
|
|
1532
|
-
else if (typeof obj === 'object') {
|
|
1533
|
-
edmNode = new Edm.Record(v);
|
|
1534
|
-
const annos = Object.create(null);
|
|
1535
|
-
const props = Object.create(null);
|
|
1536
|
-
Object.entries(obj).forEach(([ k, val ]) => {
|
|
1537
|
-
if (k === '@type') {
|
|
1538
|
-
edmNode.setJSON({ Type: val });
|
|
1539
|
-
// try to shorten full qualified type URI to short type name
|
|
1540
|
-
const parts = val.split('#');
|
|
1541
|
-
const shortTypeName = parts[parts.length - 1];
|
|
1542
|
-
edmNode.setXml({ Type: shortTypeName });
|
|
1543
|
-
}
|
|
1544
|
-
else {
|
|
1545
|
-
let child;
|
|
1546
|
-
const [ head, tail ] = k.split('@');
|
|
1547
|
-
if (tail) {
|
|
1548
|
-
child = handleTerm(tail, val, msg);
|
|
1549
|
-
}
|
|
1550
|
-
else {
|
|
1551
|
-
child = new Edm.PropertyValue(v, head);
|
|
1552
|
-
child.append(handleEdmJson(val, msg));
|
|
1553
|
-
}
|
|
1554
|
-
if (child) {
|
|
1555
|
-
if (tail && head.length) {
|
|
1556
|
-
if (!annos[head])
|
|
1557
|
-
annos[head] = [ child ];
|
|
1558
|
-
else
|
|
1559
|
-
annos[head].push(child);
|
|
1560
|
-
}
|
|
1561
|
-
else {
|
|
1562
|
-
if (head.length)
|
|
1563
|
-
props[head] = child;
|
|
1564
|
-
edmNode.append(child);
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
});
|
|
1569
|
-
// add collected annotations to record members
|
|
1570
|
-
Object.entries(annos).forEach(([ n, val ]) => {
|
|
1571
|
-
if (props[n])
|
|
1572
|
-
props[n].prepend(...val);
|
|
1573
|
-
});
|
|
1574
|
-
}
|
|
1575
|
-
else { // literal
|
|
1576
|
-
edmNode = new Edm.ValueThing(v,
|
|
1577
|
-
exprDef && exprDef.valueThingName || getXmlTypeName(obj), obj);
|
|
1578
|
-
// typename for static expression rendering
|
|
1579
|
-
edmNode.setJSON( { [getJsonTypeName(obj)]: obj } );
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
else {
|
|
1583
|
-
// name of special property determines element kind
|
|
1584
|
-
exprDef = dynamicExpressions[dynExprs[0]];
|
|
1585
|
-
edmNode = exprDef.create(obj);
|
|
1586
|
-
|
|
1587
|
-
// iterate over each obj.property and translate expression into EDM
|
|
1588
|
-
forEach(obj, (name, val) => {
|
|
1589
|
-
if (exprDef) {
|
|
1590
|
-
if (exprDef.anno && name[0] === '@') {
|
|
1591
|
-
edmNode.append(handleTerm(name.slice(1), val, msg));
|
|
1592
|
-
}
|
|
1593
|
-
else if (exprDef.attr && exprDef.attr.includes(name)) {
|
|
1594
|
-
if (name[0] === '$')
|
|
1595
|
-
edmNode.setEdmAttribute(name.slice(1), val);
|
|
1596
|
-
}
|
|
1597
|
-
else if (exprDef.jsonAttr && exprDef.jsonAttr.includes(name)) {
|
|
1598
|
-
if (name[0] === '$')
|
|
1599
|
-
edmNode.setJSON( { [name.slice(1)]: val });
|
|
1600
|
-
}
|
|
1601
|
-
else if (exprDef.children) {
|
|
1602
|
-
if (Array.isArray(val)) {
|
|
1603
|
-
val.forEach((a) => {
|
|
1604
|
-
edmNode.append(handleEdmJson(a, msg, exprDef));
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
else {
|
|
1608
|
-
edmNode.append(handleEdmJson(val, msg, exprDef));
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
});
|
|
1613
|
-
}
|
|
1614
|
-
return edmNode;
|
|
1615
|
-
|
|
1616
|
-
function getXmlTypeName( val ) {
|
|
1617
|
-
let typeName = 'String';
|
|
1618
|
-
if (typeof val === 'boolean')
|
|
1619
|
-
typeName = 'Bool';
|
|
1620
|
-
|
|
1621
|
-
else if (typeof val === 'number')
|
|
1622
|
-
typeName = Number.isInteger(val) ? 'Int' : 'Decimal';
|
|
1623
|
-
|
|
1624
|
-
return typeName;
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
function getJsonTypeName( val ) {
|
|
1628
|
-
const typeName = getXmlTypeName(val);
|
|
1629
|
-
if (typeName === 'Int')
|
|
1630
|
-
return 'Edm.Int32';
|
|
1631
|
-
return `Edm.${typeName}`;
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
1302
|
/**
|
|
1636
1303
|
* translate vocabulary definitions into a userDefinedTermDict
|
|
1637
1304
|
* with the same structure as the global jsonDictionary that
|
|
@@ -1763,65 +1430,57 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
1763
1430
|
}
|
|
1764
1431
|
}
|
|
1765
1432
|
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
$And: { create: () => new Edm.Expr(v, 'And'), anno: true },
|
|
1770
|
-
$Or: { create: () => new Edm.Expr(v, 'Or'), anno: true },
|
|
1771
|
-
$Not: { create: () => new Edm.Expr(v, 'Not'), anno: true },
|
|
1772
|
-
$Eq: { create: () => new Edm.Expr(v, 'Eq'), anno: true },
|
|
1773
|
-
$Ne: { create: () => new Edm.Expr(v, 'Ne'), anno: true },
|
|
1774
|
-
$Gt: { create: () => new Edm.Expr(v, 'Gt'), anno: true },
|
|
1775
|
-
$Ge: { create: () => new Edm.Expr(v, 'Ge'), anno: true },
|
|
1776
|
-
$Lt: { create: () => new Edm.Expr(v, 'Lt'), anno: true },
|
|
1777
|
-
$Le: { create: () => new Edm.Expr(v, 'Le'), anno: true },
|
|
1778
|
-
// valueThingName: 'EnumMember' Implicit Cast Rule String => Primitive Type is OK
|
|
1779
|
-
$Has: { create: () => new Edm.Expr(v, 'Has'), anno: true },
|
|
1780
|
-
$In: { create: () => new Edm.Expr(v, 'In'), anno: true },
|
|
1781
|
-
$Add: { create: () => new Edm.Expr(v, 'Add'), anno: true },
|
|
1782
|
-
$Sub: { create: () => new Edm.Expr(v, 'Sub'), anno: true },
|
|
1783
|
-
$Neg: { create: () => new Edm.Expr(v, 'Neg'), anno: true },
|
|
1784
|
-
$Mul: { create: () => new Edm.Expr(v, 'Mul'), anno: true },
|
|
1785
|
-
$Div: { create: () => new Edm.Expr(v, 'Div'), anno: true },
|
|
1786
|
-
$DivBy: { create: () => new Edm.Expr(v, 'DivBy'), anno: true },
|
|
1787
|
-
$Mod: { create: () => new Edm.Expr(v, 'Mod'), anno: true },
|
|
1788
|
-
$Apply: {
|
|
1789
|
-
create: () => new Edm.Apply(v),
|
|
1790
|
-
attr: [ '$Function' ],
|
|
1791
|
-
anno: true,
|
|
1792
|
-
},
|
|
1793
|
-
$Cast: {
|
|
1794
|
-
create: () => new Edm.Cast(v),
|
|
1795
|
-
attr: [ '$Type' ],
|
|
1796
|
-
jsonAttr: [ '$Collection' ],
|
|
1797
|
-
anno: true,
|
|
1798
|
-
},
|
|
1799
|
-
$IsOf: {
|
|
1800
|
-
create: () => new Edm.IsOf(v),
|
|
1801
|
-
attr: [ '$Type' ],
|
|
1802
|
-
anno: true,
|
|
1803
|
-
},
|
|
1804
|
-
$If: { create: () => new Edm.If(v), anno: true },
|
|
1805
|
-
$LabeledElement: {
|
|
1806
|
-
create: () => new Edm.LabeledElement(v),
|
|
1807
|
-
attr: [ '$Name' ],
|
|
1808
|
-
anno: true,
|
|
1809
|
-
},
|
|
1810
|
-
$LabeledElementReference: {
|
|
1811
|
-
create: obj => new Edm.LabeledElementReference(v, obj.$LabeledElementReference),
|
|
1812
|
-
},
|
|
1813
|
-
$UrlRef: { create: () => new Edm.UrlRef(v), anno: true },
|
|
1814
|
-
$Null: { create: () => new Edm.Null(v), anno: true, children: false },
|
|
1815
|
-
};
|
|
1433
|
+
//-------------------------------------------------------------------------------------------------
|
|
1434
|
+
// Dictionary access
|
|
1435
|
+
//-------------------------------------------------------------------------------------------------
|
|
1816
1436
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1437
|
+
// called to look-up a term in the dictionary
|
|
1438
|
+
// in addition: - note usage of the respective vocabulary
|
|
1439
|
+
// - issue a warning if the term is flagged as "experimental"
|
|
1440
|
+
function getDictTerm( termName, msg ) {
|
|
1441
|
+
const dict = options.dictReplacement || oDataDictionary; // tests can set different dictionary via options
|
|
1442
|
+
const dictTerm = (dict.terms[termName] ||
|
|
1443
|
+
userDefinedTermDict.terms[`${serviceName}.${termName}`] ||
|
|
1444
|
+
userDefinedTermDict.terms[termName]);
|
|
1445
|
+
// register vocabulary usage if possible
|
|
1446
|
+
const vocName = termName.slice(0, termName.indexOf('.'));
|
|
1447
|
+
const myVocDef = mergedVocDefs[vocName];
|
|
1448
|
+
if (myVocDef && !myVocDef.$ignore)
|
|
1449
|
+
myVocDef.used = true;
|
|
1450
|
+
else if (dictTerm?.$myServiceRoot &&
|
|
1451
|
+
userDefinedTermDict.xrefs[dictTerm?.$myServiceRoot])
|
|
1452
|
+
userDefinedTermDict.xrefs[dictTerm.$myServiceRoot].used = true;
|
|
1453
|
+
if (dictTerm) {
|
|
1454
|
+
// issue message for usage of experimental Terms, but only once per Term
|
|
1455
|
+
if (dictTerm.$experimental && !usedExperimentalTerms[termName]) {
|
|
1456
|
+
message('odata-anno-dict', msg.location, { anno: msg.anno(), '#': 'experimental' });
|
|
1457
|
+
usedExperimentalTerms[termName] = true;
|
|
1458
|
+
}
|
|
1459
|
+
if (dictTerm.$deprecated && !usedDeprecatedTerms[termName]) {
|
|
1460
|
+
message('odata-anno-def', msg.location,
|
|
1461
|
+
{ anno: msg.anno(), depr: dictTerm.$deprecationText, '#': 'deprecated' });
|
|
1462
|
+
usedDeprecatedTerms[termName] = true;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return dictTerm;
|
|
1824
1466
|
}
|
|
1467
|
+
// called to look-up a type in the dictionary
|
|
1468
|
+
// in addition, note usage of the respective vocabulary
|
|
1469
|
+
function getDictType( typeName ) {
|
|
1470
|
+
const dict = options.dictReplacement || oDataDictionary; // tests can set different dictionary via options
|
|
1471
|
+
const dictType = (dict.types[typeName] ||
|
|
1472
|
+
userDefinedTermDict.types[`${serviceName}.${typeName}`] ||
|
|
1473
|
+
userDefinedTermDict.types[typeName]);
|
|
1474
|
+
if (dictType) {
|
|
1475
|
+
// register usage of vocabulary
|
|
1476
|
+
const vocName = typeName.slice(0, typeName.indexOf('.'));
|
|
1477
|
+
const myVocDef = mergedVocDefs[vocName];
|
|
1478
|
+
if (myVocDef && !myVocDef.$ignore)
|
|
1479
|
+
myVocDef.used = true;
|
|
1480
|
+
}
|
|
1481
|
+
return dictType;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1825
1484
|
//-------------------------------------------------------------------------------------------------
|
|
1826
1485
|
//-------------------------------------------------------------------------------------------------
|
|
1827
1486
|
//-------------------------------------------------------------------------------------------------
|