@sap/cds-compiler 4.3.0 → 4.4.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 +36 -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 +22 -22
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +70 -53
- package/lib/compiler/kick-start.js +9 -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 +74 -38
- 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 +252 -0
- package/lib/edm/annotations/edmJson.js +994 -0
- package/lib/edm/annotations/genericTranslation.js +75 -421
- 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 +5 -2
- package/lib/transform/localized.js +1 -1
- package/lib/transform/parseExpr.js +73 -21
- package/lib/transform/translateAssocsToJoins.js +24 -16
- package/lib/utils/term.js +2 -2
- package/package.json +2 -1
|
@@ -5,166 +5,10 @@ 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');
|
|
10
11
|
|
|
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
12
|
/** ************************************************************************************************
|
|
169
13
|
* csn2annotationEdm
|
|
170
14
|
*
|
|
@@ -174,20 +18,20 @@ Object.entries(vocabularyDefinitions).forEach(([n, v]) => {
|
|
|
174
18
|
*/
|
|
175
19
|
function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
176
20
|
Edm = undefined, options = undefined, messageFunctions = undefined, mergedVocDefs = vocabularyDefinitions ) {
|
|
177
|
-
// global variable where we store all the generated annotations
|
|
178
|
-
const
|
|
21
|
+
const gAnnosArray = []; // global variable where we store all the generated annotations
|
|
22
|
+
const usedExperimentalTerms = {}; // take note of all experimental annos that have been used
|
|
23
|
+
const usedDeprecatedTerms = {}; // take note of all deprecated annos that have been used
|
|
179
24
|
|
|
25
|
+
const { v } = options;
|
|
180
26
|
const { message } = messageFunctions;
|
|
181
|
-
|
|
27
|
+
const { handleEdmJson } = getEdmJsonHandler(Edm, options, messageFunctions, handleTerm);
|
|
182
28
|
const [ userDefinedTermDict, allKnownVocabularies ] = createUserDefinedTermDictionary();
|
|
183
29
|
|
|
30
|
+
|
|
184
31
|
allKnownVocabularies.push(...Object.keys(mergedVocDefs));
|
|
185
32
|
allKnownVocabularies.sort((a, b) => b.length - a.length);
|
|
186
33
|
const whatsMyTermNamespace = anno => allKnownVocabularies.reduce((rc, ns) => (!rc && anno && anno.startsWith(`@${ns}.`) ? ns : rc), undefined);
|
|
187
34
|
|
|
188
|
-
// Static dynamic expression dictionary, loaded with Edm creators
|
|
189
|
-
const [ dynamicExpressions, dynamicExpressionNames ] = initEdmJson();
|
|
190
|
-
|
|
191
35
|
// annotation preprocessing
|
|
192
36
|
preprocessAnnotations.preprocessAnnotations(reqDefs, serviceName, options);
|
|
193
37
|
|
|
@@ -209,63 +53,6 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
209
53
|
{ name: serviceName, '#': 'service' } );
|
|
210
54
|
}
|
|
211
55
|
|
|
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
56
|
// Copy annotations from origin to parameter entity if it's
|
|
270
57
|
// qualified with #$parameters or if its applicable to an EntitySet or Singleton
|
|
271
58
|
forEachDefinition(reqDefs, (object) => {
|
|
@@ -514,6 +301,12 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
514
301
|
if (knownAnnos.length === 0)
|
|
515
302
|
return;
|
|
516
303
|
}
|
|
304
|
+
if (isBetaEnabled(options, 'annotationExpressions')) {
|
|
305
|
+
knownAnnos.forEach((knownAnno) => {
|
|
306
|
+
if (knownAnno.search(/\.\$edmJson\./g) < 0)
|
|
307
|
+
carrier[knownAnno] = xpr2edmJson(carrier, knownAnno, location, options, messageFunctions);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
517
310
|
|
|
518
311
|
const prefixTree = createPrefixTree();
|
|
519
312
|
|
|
@@ -803,13 +596,18 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
803
596
|
steps.splice(i, steps.length - i, steps.slice(i).join('.'));
|
|
804
597
|
}
|
|
805
598
|
if (innerAnnotation) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
599
|
+
// A voc annotation has two steps (Namespace+Name),
|
|
600
|
+
// any further steps need to be rendered separately
|
|
601
|
+
if (innerAnnotation.startsWith('sap.')) {
|
|
602
|
+
steps.push(`@${innerAnnotation}`);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
const innerAnnoSteps = innerAnnotation.split('.');
|
|
606
|
+
const tailSteps = innerAnnoSteps.splice(2, innerAnnoSteps.length - 2);
|
|
607
|
+
// prepend annotation prefix (path) to tail steps
|
|
608
|
+
tailSteps.splice(0, 0, `@${innerAnnoSteps.join('.')}`);
|
|
609
|
+
steps.push(...tailSteps);
|
|
610
|
+
}
|
|
813
611
|
}
|
|
814
612
|
mergePathStepsIntoPrefixTree(prefixTreeP, steps, 0);
|
|
815
613
|
}
|
|
@@ -1496,142 +1294,6 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
1496
1294
|
}
|
|
1497
1295
|
|
|
1498
1296
|
|
|
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
1297
|
/**
|
|
1636
1298
|
* translate vocabulary definitions into a userDefinedTermDict
|
|
1637
1299
|
* with the same structure as the global jsonDictionary that
|
|
@@ -1763,65 +1425,57 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
|
|
|
1763
1425
|
}
|
|
1764
1426
|
}
|
|
1765
1427
|
|
|
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
|
-
};
|
|
1428
|
+
//-------------------------------------------------------------------------------------------------
|
|
1429
|
+
// Dictionary access
|
|
1430
|
+
//-------------------------------------------------------------------------------------------------
|
|
1816
1431
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1432
|
+
// called to look-up a term in the dictionary
|
|
1433
|
+
// in addition: - note usage of the respective vocabulary
|
|
1434
|
+
// - issue a warning if the term is flagged as "experimental"
|
|
1435
|
+
function getDictTerm( termName, msg ) {
|
|
1436
|
+
const dict = options.dictReplacement || oDataDictionary; // tests can set different dictionary via options
|
|
1437
|
+
const dictTerm = (dict.terms[termName] ||
|
|
1438
|
+
userDefinedTermDict.terms[`${serviceName}.${termName}`] ||
|
|
1439
|
+
userDefinedTermDict.terms[termName]);
|
|
1440
|
+
// register vocabulary usage if possible
|
|
1441
|
+
const vocName = termName.slice(0, termName.indexOf('.'));
|
|
1442
|
+
const myVocDef = mergedVocDefs[vocName];
|
|
1443
|
+
if (myVocDef && !myVocDef.$ignore)
|
|
1444
|
+
myVocDef.used = true;
|
|
1445
|
+
else if (dictTerm?.$myServiceRoot &&
|
|
1446
|
+
userDefinedTermDict.xrefs[dictTerm?.$myServiceRoot])
|
|
1447
|
+
userDefinedTermDict.xrefs[dictTerm.$myServiceRoot].used = true;
|
|
1448
|
+
if (dictTerm) {
|
|
1449
|
+
// issue message for usage of experimental Terms, but only once per Term
|
|
1450
|
+
if (dictTerm.$experimental && !usedExperimentalTerms[termName]) {
|
|
1451
|
+
message('odata-anno-dict', msg.location, { anno: msg.anno(), '#': 'experimental' });
|
|
1452
|
+
usedExperimentalTerms[termName] = true;
|
|
1453
|
+
}
|
|
1454
|
+
if (dictTerm.$deprecated && !usedDeprecatedTerms[termName]) {
|
|
1455
|
+
message('odata-anno-def', msg.location,
|
|
1456
|
+
{ anno: msg.anno(), depr: dictTerm.$deprecationText, '#': 'deprecated' });
|
|
1457
|
+
usedDeprecatedTerms[termName] = true;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
return dictTerm;
|
|
1461
|
+
}
|
|
1462
|
+
// called to look-up a type in the dictionary
|
|
1463
|
+
// in addition, note usage of the respective vocabulary
|
|
1464
|
+
function getDictType( typeName ) {
|
|
1465
|
+
const dict = options.dictReplacement || oDataDictionary; // tests can set different dictionary via options
|
|
1466
|
+
const dictType = (dict.types[typeName] ||
|
|
1467
|
+
userDefinedTermDict.types[`${serviceName}.${typeName}`] ||
|
|
1468
|
+
userDefinedTermDict.types[typeName]);
|
|
1469
|
+
if (dictType) {
|
|
1470
|
+
// register usage of vocabulary
|
|
1471
|
+
const vocName = typeName.slice(0, typeName.indexOf('.'));
|
|
1472
|
+
const myVocDef = mergedVocDefs[vocName];
|
|
1473
|
+
if (myVocDef && !myVocDef.$ignore)
|
|
1474
|
+
myVocDef.used = true;
|
|
1475
|
+
}
|
|
1476
|
+
return dictType;
|
|
1824
1477
|
}
|
|
1478
|
+
|
|
1825
1479
|
//-------------------------------------------------------------------------------------------------
|
|
1826
1480
|
//-------------------------------------------------------------------------------------------------
|
|
1827
1481
|
//-------------------------------------------------------------------------------------------------
|