@sap/cds-compiler 2.13.8 → 2.15.6
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 +128 -4
- package/bin/cdsc.js +112 -37
- package/lib/api/main.js +63 -22
- package/lib/api/options.js +2 -3
- package/lib/api/validate.js +6 -6
- package/lib/base/message-registry.js +100 -17
- package/lib/base/messages.js +85 -64
- package/lib/base/optionProcessorHelper.js +19 -0
- package/lib/checks/annotationsOData.js +11 -32
- package/lib/checks/arrayOfs.js +1 -34
- package/lib/checks/validator.js +2 -4
- package/lib/compiler/assert-consistency.js +1 -0
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +11 -0
- package/lib/compiler/checks.js +22 -70
- package/lib/compiler/define.js +59 -11
- package/lib/compiler/extend.js +20 -3
- package/lib/compiler/finalize-parse-cdl.js +26 -20
- package/lib/compiler/index.js +75 -26
- package/lib/compiler/populate.js +36 -17
- package/lib/compiler/propagator.js +4 -1
- package/lib/compiler/resolve.js +104 -16
- package/lib/compiler/shared.js +61 -27
- package/lib/compiler/tweak-assocs.js +7 -1
- package/lib/edm/annotations/genericTranslation.js +93 -21
- package/lib/edm/csn2edm.js +216 -98
- package/lib/edm/edm.js +305 -226
- package/lib/edm/edmPreprocessor.js +499 -423
- package/lib/edm/edmUtils.js +22 -22
- package/lib/gen/Dictionary.json +98 -22
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageParser.js +4636 -4368
- package/lib/json/csnVersion.js +10 -11
- package/lib/json/from-csn.js +3 -2
- package/lib/json/to-csn.js +0 -2
- package/lib/language/docCommentParser.js +2 -2
- package/lib/language/genericAntlrParser.js +47 -2
- package/lib/language/language.g4 +59 -27
- package/lib/main.d.ts +19 -1
- package/lib/main.js +6 -0
- package/lib/model/csnRefs.js +33 -6
- package/lib/model/csnUtils.js +193 -75
- package/lib/model/enrichCsn.js +1 -0
- package/lib/model/revealInternalProperties.js +2 -2
- package/lib/modelCompare/compare.js +6 -6
- package/lib/optionProcessor.js +62 -26
- package/lib/render/toCdl.js +844 -679
- package/lib/render/toHdbcds.js +189 -243
- package/lib/render/toSql.js +180 -198
- package/lib/render/utils/common.js +131 -15
- package/lib/transform/db/.eslintrc.json +1 -1
- package/lib/transform/db/associations.js +2 -2
- package/lib/transform/db/constraints.js +3 -1
- package/lib/transform/db/expansion.js +15 -10
- package/lib/transform/db/flattening.js +94 -64
- package/lib/transform/db/transformExists.js +7 -7
- package/lib/transform/db/views.js +6 -3
- package/lib/transform/forHanaNew.js +43 -26
- package/lib/transform/forOdataNew.js +43 -42
- package/lib/transform/localized.js +12 -7
- package/lib/transform/odata/toFinalBaseType.js +8 -6
- package/lib/transform/odata/typesExposure.js +145 -197
- package/lib/transform/transformUtilsNew.js +9 -12
- package/lib/transform/translateAssocsToJoins.js +5 -1
- package/lib/transform/universalCsn/coreComputed.js +5 -3
- package/lib/transform/universalCsn/universalCsnEnricher.js +27 -5
- package/lib/utils/moduleResolve.js +13 -6
- package/package.json +1 -1
- package/share/messages/message-explanations.json +2 -1
- package/share/messages/syntax-expected-integer.md +37 -0
- package/lib/transform/odata/attachPath.js +0 -96
- package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
- package/lib/transform/odata/generateForeignKeyElements.js +0 -261
- package/lib/transform/odata/referenceFlattener.js +0 -296
- package/lib/transform/odata/sortByAssociationDependency.js +0 -105
- package/lib/transform/odata/structuralPath.js +0 -72
- package/lib/transform/odata/structureFlattener.js +0 -171
package/lib/edm/edm.js
CHANGED
|
@@ -1,23 +1,91 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
1
|
'use strict'
|
|
4
2
|
|
|
5
3
|
const edmUtils = require('./edmUtils.js');
|
|
6
4
|
const { isBuiltinType } = require('../model/csnUtils.js');
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const { forEach } = require("../utils/objectUtils");
|
|
6
|
+
|
|
7
|
+
// facet definitions, optional could either be true or array of edm types
|
|
8
|
+
// remove indicates wether or not the canonic facet shall be removed when applying @odata.Type
|
|
9
|
+
const EdmTypeFacetMap = {
|
|
10
|
+
'MaxLength': { v2: true, v4: true, remove: true, optional: true },
|
|
11
|
+
'Precision': { v2: true, v4: true, remove: true, optional: true },
|
|
12
|
+
'Scale': { v2: true, v4: true, remove: true, optional: true },
|
|
13
|
+
'SRID': { v4: true, remove: true, optional: true },
|
|
14
|
+
//'FixedLength': { v2: true },
|
|
15
|
+
//'Collation': { v2: true },
|
|
16
|
+
//'Unicode': { v2: true, v4: true },
|
|
17
|
+
};
|
|
18
|
+
const EdmTypeFacetNames = Object.keys(EdmTypeFacetMap);
|
|
19
|
+
|
|
20
|
+
// Merged primitive type map with descriptions taken from V4 spec and filled up with V2 spec
|
|
21
|
+
const EdmPrimitiveTypeMap = {
|
|
22
|
+
'Edm.Binary': { v2: true, v4: true, MaxLength: true, FixedLength: true, desc: 'Binary data' },
|
|
23
|
+
'Edm.Boolean': { v2: true, v4: true, desc: 'Binary-valued logic' },
|
|
24
|
+
'Edm.Byte': { v2: true, v4: true, desc: 'Unsigned 8-bit integer' },
|
|
25
|
+
'Edm.Date': { v4: true, desc: 'Date without a time-zone offset' },
|
|
26
|
+
'Edm.DateTime': { v2: true, Precision: true, desc: 'Date and time with values ranging from 12:00:00 midnight, January 1, 1753 A.D. through 11:59:59 P.M, December 31, 9999 A.D.' },
|
|
27
|
+
'Edm.DateTimeOffset': { v2: true, v4: true, Precision: true, desc: 'Date and time with a time-zone offset, no leap seconds' },
|
|
28
|
+
'Edm.Decimal': { v2: true, v4: true, Precision: true, Scale: true, desc: 'Numeric values with decimal representation' },
|
|
29
|
+
'Edm.Double': { v2: true, v4: true, desc: 'IEEE 754 binary64 floating-point number (15-17 decimal digits)' },
|
|
30
|
+
'Edm.Duration': { v4: true, Precision: true, desc: 'Signed duration in days, hours, minutes, and (sub)seconds' },
|
|
31
|
+
'Edm.Guid': { v2: true, v4: true, desc: '16-byte (128-bit) unique identifier' },
|
|
32
|
+
'Edm.Int16': { v2: true, v4: true, desc: 'Signed 16-bit integer' },
|
|
33
|
+
'Edm.Int32': { v2: true, v4: true, desc: 'Signed 32-bit integer' },
|
|
34
|
+
'Edm.Int64': { v2: true, v4: true, desc: 'Signed 64-bit integer' },
|
|
35
|
+
'Edm.SByte': { v2: true, v4: true, desc: 'Signed 8-bit integer' },
|
|
36
|
+
'Edm.Single': { v2: true, v4: true, desc: 'IEEE 754 binary32 floating-point number (6-9 decimal digits)' },
|
|
37
|
+
'Edm.Stream': { v4: true, MaxLength: true, desc: 'Binary data stream' },
|
|
38
|
+
'Edm.String': { v2: true, v4: true, MaxLength: true, FixedLength: true, Collation: true, Unicode: true, desc: 'Sequence of characters' },
|
|
39
|
+
'Edm.Time': { v2: true, Precision: true, desc: 'time of day with values ranging from 0:00:00.x to 23:59:59.y, where x and y depend upon the precision' },
|
|
40
|
+
'Edm.TimeOfDay': { v4: true, Precision: true, desc: 'Clock time 00:00-23:59:59.999999999999' },
|
|
41
|
+
'Edm.Geography': { v4: true, SRID: true, desc: 'Abstract base type for all Geography types' },
|
|
42
|
+
'Edm.GeographyPoint': { v4: true, SRID: true, desc: 'A point in a round-earth coordinate system' },
|
|
43
|
+
'Edm.GeographyLineString': { v4: true, SRID: true, desc: 'Line string in a round-earth coordinate system' },
|
|
44
|
+
'Edm.GeographyPolygon': { v4: true, SRID: true, desc: 'Polygon in a round-earth coordinate system' },
|
|
45
|
+
'Edm.GeographyMultiPoint': { v4: true, SRID: true, desc: 'Collection of points in a round-earth coordinate system' },
|
|
46
|
+
'Edm.GeographyMultiLineString': { v4: true, SRID: true, desc: 'Collection of line strings in a round-earth coordinate system' },
|
|
47
|
+
'Edm.GeographyMultiPolygon': { v4: true, SRID: true, desc: 'Collection of polygons in a round-earth coordinate system' },
|
|
48
|
+
'Edm.GeographyCollection': { v4: true, SRID: true, desc: 'Collection of arbitrary Geography values' },
|
|
49
|
+
'Edm.Geometry': { v4: true, SRID: true, desc: 'Abstract base type for all Geometry types' },
|
|
50
|
+
'Edm.GeometryPoint': { v4: true, SRID: true, desc: 'Point in a flat-earth coordinate system' },
|
|
51
|
+
'Edm.GeometryLineString': { v4: true, SRID: true, desc: 'Line string in a flat-earth coordinate system' },
|
|
52
|
+
'Edm.GeometryPolygon': { v4: true, SRID: true, descr: 'Polygon in a flat-earth coordinate system' },
|
|
53
|
+
'Edm.GeometryMultiPoint': { v4: true, SRID: true, desc: 'Collection of points in a flat-earth coordinate system' },
|
|
54
|
+
'Edm.GeometryMultiLineString': { v4: true, SRID: true, desc: 'Collection of line strings in a flat-earth coordinate system' },
|
|
55
|
+
'Edm.GeometryMultiPolygon': { v4: true, SRID: true, desc: 'Collection of polygons in a flat-earth coordinate system' },
|
|
56
|
+
'Edm.GeometryCollection': { v4: true, SRID: true, desc: 'Collection of arbitrary Geometry values' },
|
|
57
|
+
'Edm.PrimitiveType': { v4: true, desc: 'Abstract meta type' },
|
|
58
|
+
//'Edm.Untyped': { v4: true, desc: 'Abstract void type' },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function getEdm(options, messageFunctions) {
|
|
62
|
+
const { error } = messageFunctions || { error: ()=>true, warning: ()=>true };
|
|
9
63
|
class Node
|
|
10
64
|
{
|
|
11
|
-
|
|
65
|
+
/**
|
|
66
|
+
* @param {boolean[]} v Versions in the form of [<v2>, <v4>].
|
|
67
|
+
* @param {object} attributes
|
|
68
|
+
* @param {CSN.Model} csn
|
|
69
|
+
*/
|
|
70
|
+
constructor(v, attributes = Object.create(null), csn=undefined)
|
|
12
71
|
{
|
|
13
72
|
if(!attributes || typeof attributes !== 'object')
|
|
14
73
|
error(null, 'Please debug me: attributes must be a dictionary');
|
|
15
74
|
if(!Array.isArray(v))
|
|
16
75
|
error(null, 'Please debug me: v is either undefined or not an array: ' + v);
|
|
17
|
-
if(v.filter(v=>v).length
|
|
76
|
+
if(v.filter(v => v).length !== 1)
|
|
18
77
|
error(null, 'Please debug me: exactly one version must be set');
|
|
19
|
-
|
|
20
|
-
|
|
78
|
+
|
|
79
|
+
// Common attributes of JSON and XML.
|
|
80
|
+
// Note: Can't assign attributes directly, due to the input object being modified.
|
|
81
|
+
// The caller re-uses the object for other nodes.
|
|
82
|
+
this._edmAttributes = Object.assign(Object.create(null), attributes);
|
|
83
|
+
this._xmlOnlyAttributes = Object.create(null);
|
|
84
|
+
this._jsonOnlyAttributes = Object.create(null);
|
|
85
|
+
|
|
86
|
+
this._children = [];
|
|
87
|
+
this._ignoreChildren = false;
|
|
88
|
+
this._v = v;
|
|
21
89
|
|
|
22
90
|
if(this.v2)
|
|
23
91
|
this.setSapVocabularyAsAttributes(csn);
|
|
@@ -30,44 +98,53 @@ module.exports = function (options, error) {
|
|
|
30
98
|
return this.constructor.name
|
|
31
99
|
}
|
|
32
100
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Set the EDM(X) attribute on the Node.
|
|
103
|
+
* @param {string} key
|
|
104
|
+
* @param {any} value
|
|
105
|
+
*/
|
|
106
|
+
setEdmAttribute(key, value) {
|
|
107
|
+
if(key !== undefined && key !== null && value !== undefined && value !== null)
|
|
108
|
+
this._edmAttributes[key] = value;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove the EDM(X) attribute on the Node.
|
|
113
|
+
* @param {string} name
|
|
114
|
+
*/
|
|
115
|
+
removeEdmAttribute(name) {
|
|
116
|
+
if (name in this._edmAttributes)
|
|
117
|
+
delete this._edmAttributes[name];
|
|
48
118
|
}
|
|
49
119
|
|
|
50
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Set properties that should only appear in the XML representation
|
|
122
|
+
* @param {object} attributes
|
|
123
|
+
* @return {any}
|
|
124
|
+
*/
|
|
51
125
|
setXml(attributes)
|
|
52
126
|
{
|
|
53
|
-
if(!attributes || typeof attributes !== 'object')
|
|
54
|
-
error(null, 'Please debug me: attributes must be a dictionary');
|
|
55
127
|
return Object.assign(this._xmlOnlyAttributes, attributes);
|
|
56
128
|
}
|
|
57
129
|
|
|
58
|
-
|
|
59
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Set properties that should only appear in the JSON representation.
|
|
132
|
+
* Today JSON attributes are not rendered in toJSONattributes()
|
|
133
|
+
*
|
|
134
|
+
* @param {object} attributes
|
|
135
|
+
* @return {any}
|
|
136
|
+
*/
|
|
60
137
|
setJSON(attributes)
|
|
61
138
|
{
|
|
62
|
-
if(!attributes || typeof attributes !== 'object')
|
|
63
|
-
error(null, 'Please debug me: attributes must be a dictionary');
|
|
64
139
|
return Object.assign(this._jsonOnlyAttributes, attributes);
|
|
65
140
|
}
|
|
66
141
|
|
|
67
142
|
prepend(...children)
|
|
68
143
|
{
|
|
69
144
|
this._children.splice(0, 0, ...children.filter(c => c));
|
|
145
|
+
return this;
|
|
70
146
|
}
|
|
147
|
+
|
|
71
148
|
append(...children)
|
|
72
149
|
{
|
|
73
150
|
// remove undefined entries
|
|
@@ -78,9 +155,9 @@ module.exports = function (options, error) {
|
|
|
78
155
|
// virtual
|
|
79
156
|
toJSON()
|
|
80
157
|
{
|
|
81
|
-
|
|
158
|
+
const json = Object.create(null);
|
|
82
159
|
// $kind Property MAY be omitted in JSON for performance reasons
|
|
83
|
-
if(!
|
|
160
|
+
if(!(this.kind in Node.noJsonKinds))
|
|
84
161
|
json['$Kind'] = this.kind;
|
|
85
162
|
|
|
86
163
|
this.toJSONattributes(json);
|
|
@@ -91,7 +168,7 @@ module.exports = function (options, error) {
|
|
|
91
168
|
// virtual
|
|
92
169
|
toJSONattributes(json)
|
|
93
170
|
{
|
|
94
|
-
|
|
171
|
+
forEach(this._edmAttributes, (p, v) => {
|
|
95
172
|
if (p !== 'Name')
|
|
96
173
|
json[p[0] === '@' ? p : '$' + p] = v;
|
|
97
174
|
});
|
|
@@ -101,9 +178,9 @@ module.exports = function (options, error) {
|
|
|
101
178
|
// virtual
|
|
102
179
|
toJSONchildren(json)
|
|
103
180
|
{
|
|
104
|
-
// any child with a Name should be added by
|
|
181
|
+
// any child with a Name should be added by its name into the JSON object
|
|
105
182
|
// all others must overload toJSONchildren()
|
|
106
|
-
this._children.filter(c => c.Name).forEach(c => json[c.Name] = c.toJSON());
|
|
183
|
+
this._children.filter(c => c._edmAttributes.Name).forEach(c => json[c._edmAttributes.Name] = c.toJSON());
|
|
107
184
|
}
|
|
108
185
|
|
|
109
186
|
// virtual
|
|
@@ -112,9 +189,9 @@ module.exports = function (options, error) {
|
|
|
112
189
|
let kind = this.kind;
|
|
113
190
|
let head = indent + '<' + kind;
|
|
114
191
|
|
|
115
|
-
if(kind
|
|
116
|
-
delete this.Collection;
|
|
117
|
-
this.Type=`Collection(${this.Type})`;
|
|
192
|
+
if(kind==='Parameter' && this._edmAttributes.Collection) {
|
|
193
|
+
delete this._edmAttributes.Collection;
|
|
194
|
+
this._edmAttributes.Type=`Collection(${this._edmAttributes.Type})`;
|
|
118
195
|
}
|
|
119
196
|
|
|
120
197
|
head += this.toXMLattributes();
|
|
@@ -135,12 +212,12 @@ module.exports = function (options, error) {
|
|
|
135
212
|
toXMLattributes()
|
|
136
213
|
{
|
|
137
214
|
let tmpStr = '';
|
|
138
|
-
|
|
139
|
-
if (typeof
|
|
215
|
+
forEach(this._edmAttributes, (p, v) => {
|
|
216
|
+
if (v !== undefined && typeof v !== 'object')
|
|
140
217
|
tmpStr += ' ' + p + '="' + edmUtils.escapeStringForAttributeValue(v) + '"'
|
|
141
218
|
});
|
|
142
|
-
|
|
143
|
-
if (typeof v !== 'object')
|
|
219
|
+
forEach(this._xmlOnlyAttributes, (p, v) => {
|
|
220
|
+
if (v !== undefined && typeof v !== 'object')
|
|
144
221
|
tmpStr += ' ' + p + '="' + edmUtils.escapeStringForAttributeValue(v) + '"'
|
|
145
222
|
});
|
|
146
223
|
return tmpStr;
|
|
@@ -170,13 +247,16 @@ module.exports = function (options, error) {
|
|
|
170
247
|
}
|
|
171
248
|
}
|
|
172
249
|
|
|
250
|
+
// $kind Property MAY be omitted in JSON for performance reasons
|
|
251
|
+
Node.noJsonKinds = {'Property':1, 'EntitySet':1, 'ActionImport':1, 'FunctionImport':1, 'Singleton':1, 'Schema':1};
|
|
252
|
+
|
|
173
253
|
class Reference extends Node
|
|
174
254
|
{
|
|
175
255
|
constructor(v, details)
|
|
176
256
|
{
|
|
177
257
|
super(v, details);
|
|
178
258
|
if(this.v2)
|
|
179
|
-
this['xmlns:edmx'] = 'http://docs.oasis-open.org/odata/ns/edmx';
|
|
259
|
+
this._edmAttributes['xmlns:edmx'] = 'http://docs.oasis-open.org/odata/ns/edmx';
|
|
180
260
|
}
|
|
181
261
|
|
|
182
262
|
get kind() { return 'edmx:Reference' }
|
|
@@ -207,12 +287,12 @@ module.exports = function (options, error) {
|
|
|
207
287
|
{
|
|
208
288
|
constructor(v, ns, alias=undefined, serviceCsn=null, annotations=[], withEntityContainer=true)
|
|
209
289
|
{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if(alias != undefined)
|
|
290
|
+
const props = { Namespace: ns };
|
|
291
|
+
if(alias !== undefined)
|
|
213
292
|
props.Alias = alias;
|
|
214
293
|
super(v, props);
|
|
215
|
-
this.
|
|
294
|
+
this._annotations = annotations;
|
|
295
|
+
this._actions = Object.create(null);
|
|
216
296
|
this.setXml( { xmlns: (this.v2) ? 'http://schemas.microsoft.com/ado/2008/09/edm' : 'http://docs.oasis-open.org/odata/ns/edm' } );
|
|
217
297
|
|
|
218
298
|
if(this.v2 && serviceCsn)
|
|
@@ -227,17 +307,17 @@ module.exports = function (options, error) {
|
|
|
227
307
|
// append for rendering, ok ec has Name
|
|
228
308
|
this.append(ec);
|
|
229
309
|
// set as attribute for later access...
|
|
230
|
-
this.
|
|
310
|
+
this._ec = ec;
|
|
231
311
|
}
|
|
232
312
|
}
|
|
233
313
|
|
|
234
314
|
// hold actions and functions in V4
|
|
235
315
|
addAction(action)
|
|
236
316
|
{
|
|
237
|
-
if(this._actions[action.Name])
|
|
238
|
-
this._actions[action.Name].push(action);
|
|
317
|
+
if(this._actions[action._edmAttributes.Name])
|
|
318
|
+
this._actions[action._edmAttributes.Name].push(action);
|
|
239
319
|
else
|
|
240
|
-
this._actions[action.Name] = [action];
|
|
320
|
+
this._actions[action._edmAttributes.Name] = [action];
|
|
241
321
|
}
|
|
242
322
|
|
|
243
323
|
setAnnotations(annotations)
|
|
@@ -249,7 +329,7 @@ module.exports = function (options, error) {
|
|
|
249
329
|
innerXML(indent, what)
|
|
250
330
|
{
|
|
251
331
|
let xml = '';
|
|
252
|
-
if(what
|
|
332
|
+
if(what==='metadata' || what==='all')
|
|
253
333
|
{
|
|
254
334
|
xml += super.innerXML(indent);
|
|
255
335
|
edmUtils.forAll(this._actions, actionArray => {
|
|
@@ -257,11 +337,11 @@ module.exports = function (options, error) {
|
|
|
257
337
|
xml += action.toXML(indent, what) + '\n'; });
|
|
258
338
|
});
|
|
259
339
|
}
|
|
260
|
-
if(what
|
|
340
|
+
if(what==='annotations' || what==='all')
|
|
261
341
|
{
|
|
262
342
|
if(this._annotations.length > 0) {
|
|
263
|
-
this._annotations.filter(a => a.Term).forEach(a => xml += a.toXML(indent) + '\n');
|
|
264
|
-
this._annotations.filter(a => a.Target).forEach(a => xml += a.toXML(indent) + '\n');
|
|
343
|
+
this._annotations.filter(a => a._edmAttributes.Term).forEach(a => xml += a.toXML(indent) + '\n');
|
|
344
|
+
this._annotations.filter(a => a._edmAttributes.Target).forEach(a => xml += a.toXML(indent) + '\n');
|
|
265
345
|
}
|
|
266
346
|
}
|
|
267
347
|
return xml;
|
|
@@ -270,7 +350,7 @@ module.exports = function (options, error) {
|
|
|
270
350
|
// no $Namespace
|
|
271
351
|
toJSONattributes(json)
|
|
272
352
|
{
|
|
273
|
-
edmUtils.forAll(this, (v,p) => {
|
|
353
|
+
edmUtils.forAll(this._edmAttributes, (v,p) => {
|
|
274
354
|
if (p !== 'Name' && p !== 'Namespace')
|
|
275
355
|
json[p[0] === '@' ? p : '$' + p] = v;
|
|
276
356
|
});
|
|
@@ -281,13 +361,13 @@ module.exports = function (options, error) {
|
|
|
281
361
|
// 'edmx:DataServices' should not appear in JSON
|
|
282
362
|
super.toJSONchildren(json);
|
|
283
363
|
if(this._annotations.length > 0) {
|
|
284
|
-
this._annotations.filter(a => a.Term).forEach(a => {
|
|
364
|
+
this._annotations.filter(a => a._edmAttributes.Term).forEach(a => {
|
|
285
365
|
Object.entries(a.toJSON()).forEach(([n, v]) => {
|
|
286
366
|
json[n] = v;
|
|
287
367
|
});
|
|
288
368
|
});
|
|
289
369
|
let json_Annotations = Object.create(null);
|
|
290
|
-
this._annotations.filter(a => a.Target).forEach(a => json_Annotations[a.Target] = a.toJSON());
|
|
370
|
+
this._annotations.filter(a => a._edmAttributes.Target).forEach(a => json_Annotations[a._edmAttributes.Target] = a.toJSON());
|
|
291
371
|
if(Object.keys(json_Annotations).length)
|
|
292
372
|
json['$Annotations'] = json_Annotations;
|
|
293
373
|
}
|
|
@@ -308,7 +388,7 @@ module.exports = function (options, error) {
|
|
|
308
388
|
constructor(v)
|
|
309
389
|
{
|
|
310
390
|
super(v);
|
|
311
|
-
this.
|
|
391
|
+
this._schemas = Object.create(null);
|
|
312
392
|
|
|
313
393
|
if(this.v2)
|
|
314
394
|
this.setXml( { 'm:DataServiceVersion': '2.0' } )
|
|
@@ -327,7 +407,7 @@ module.exports = function (options, error) {
|
|
|
327
407
|
toJSONchildren(json)
|
|
328
408
|
{
|
|
329
409
|
// 'edmx:DataServices' should not appear in JSON
|
|
330
|
-
this._children.forEach(s => json[s.Namespace] = s.toJSON());
|
|
410
|
+
this._children.forEach(s => json[s._edmAttributes.Namespace] = s.toJSON());
|
|
331
411
|
return json;
|
|
332
412
|
}
|
|
333
413
|
}
|
|
@@ -347,12 +427,15 @@ module.exports = function (options, error) {
|
|
|
347
427
|
constructor(v, service)
|
|
348
428
|
{
|
|
349
429
|
super(v, { Version : (v[1]) ? '4.0' : '1.0' });
|
|
350
|
-
this.
|
|
430
|
+
this._service = service;
|
|
431
|
+
this._defaultRefs = [];
|
|
351
432
|
|
|
352
|
-
|
|
433
|
+
const xmlProps = Object.create(null);
|
|
353
434
|
if(this.v4)
|
|
354
435
|
{
|
|
355
|
-
xmlProps['xmlns:edmx']
|
|
436
|
+
xmlProps['xmlns:edmx'] = 'http://docs.oasis-open.org/odata/ns/edmx';
|
|
437
|
+
xmlProps['xmlns:m'] = undefined;
|
|
438
|
+
xmlProps['xmlns:sap'] = undefined;
|
|
356
439
|
}
|
|
357
440
|
else
|
|
358
441
|
{
|
|
@@ -365,19 +448,6 @@ module.exports = function (options, error) {
|
|
|
365
448
|
|
|
366
449
|
get kind() { return 'edmx:Edmx' }
|
|
367
450
|
|
|
368
|
-
hasAnnotations()
|
|
369
|
-
{
|
|
370
|
-
let rc = false;
|
|
371
|
-
this._service._children.forEach(c =>
|
|
372
|
-
{ if(c._annotations.length > 0) rc = true; } )
|
|
373
|
-
return rc;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
getSchemaCount()
|
|
377
|
-
{
|
|
378
|
-
return this._service._children.length;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
451
|
getAnnotations(schemaIndex=0)
|
|
382
452
|
{
|
|
383
453
|
if(this._service && this._service._children[schemaIndex])
|
|
@@ -397,12 +467,12 @@ module.exports = function (options, error) {
|
|
|
397
467
|
let schema = this._service._children[0];
|
|
398
468
|
|
|
399
469
|
let json = Object.create(null);
|
|
400
|
-
json['$Version'] = this.Version;
|
|
401
|
-
json['$EntityContainer'] = schema.Namespace + '.' + schema._ec.Name;
|
|
470
|
+
json['$Version'] = this._edmAttributes.Version;
|
|
471
|
+
json['$EntityContainer'] = schema._edmAttributes.Namespace + '.' + schema._ec._edmAttributes.Name;
|
|
402
472
|
|
|
403
473
|
let reference_json = Object.create(null);
|
|
404
|
-
this._defaultRefs.forEach(r => reference_json[r.Uri] = r.toJSON());
|
|
405
|
-
this._children.forEach(r => reference_json[r.Uri] = r.toJSON());
|
|
474
|
+
this._defaultRefs.forEach(r => reference_json[r._edmAttributes.Uri] = r.toJSON());
|
|
475
|
+
this._children.forEach(r => reference_json[r._edmAttributes.Uri] = r.toJSON());
|
|
406
476
|
|
|
407
477
|
if(Object.keys(reference_json).length)
|
|
408
478
|
json['$Reference'] = reference_json;
|
|
@@ -415,9 +485,7 @@ module.exports = function (options, error) {
|
|
|
415
485
|
// all(default), metadata, annotations
|
|
416
486
|
toXML(what='all')
|
|
417
487
|
{
|
|
418
|
-
|
|
419
|
-
rc += `${super.toXML('', what)}`;
|
|
420
|
-
return rc;
|
|
488
|
+
return '<?xml version="1.0" encoding="utf-8"?>\n' + super.toXML('', what);
|
|
421
489
|
}
|
|
422
490
|
|
|
423
491
|
innerXML(indent, what)
|
|
@@ -434,33 +502,32 @@ module.exports = function (options, error) {
|
|
|
434
502
|
|
|
435
503
|
class EntityContainer extends Node
|
|
436
504
|
{
|
|
437
|
-
constructor() {
|
|
438
|
-
super(
|
|
439
|
-
this.
|
|
505
|
+
constructor(v, attributes, csn) {
|
|
506
|
+
super(v, attributes, csn);
|
|
507
|
+
this._registry = Object.create(null);
|
|
440
508
|
}
|
|
441
509
|
// use the _SetAttributes
|
|
442
510
|
setSapVocabularyAsAttributes(csn)
|
|
443
511
|
{
|
|
444
512
|
super.setSapVocabularyAsAttributes(csn, true);
|
|
445
513
|
}
|
|
514
|
+
|
|
446
515
|
register(entry) {
|
|
447
|
-
if(!this._registry[entry.Name])
|
|
448
|
-
this._registry[entry.Name] = [entry];
|
|
516
|
+
if(!this._registry[entry._edmAttributes.Name])
|
|
517
|
+
this._registry[entry._edmAttributes.Name] = [entry];
|
|
449
518
|
else
|
|
450
|
-
this._registry[entry.Name].push(entry);
|
|
451
|
-
|
|
519
|
+
this._registry[entry._edmAttributes.Name].push(entry);
|
|
520
|
+
this.append(entry);
|
|
452
521
|
}
|
|
453
522
|
}
|
|
454
523
|
|
|
455
524
|
|
|
456
|
-
|
|
457
525
|
class Singleton extends Node
|
|
458
526
|
{
|
|
459
527
|
toJSONattributes(json)
|
|
460
528
|
{
|
|
461
|
-
|
|
462
|
-
if (p !== 'Name')
|
|
463
|
-
{
|
|
529
|
+
forEach(this._edmAttributes, (p, v) => {
|
|
530
|
+
if (p !== 'Name') {
|
|
464
531
|
if(p === 'EntityType') // it's $Type in json
|
|
465
532
|
json['$Type'] = v;
|
|
466
533
|
else
|
|
@@ -473,7 +540,7 @@ module.exports = function (options, error) {
|
|
|
473
540
|
toJSONchildren(json)
|
|
474
541
|
{
|
|
475
542
|
let json_navPropBinding = Object.create(null);
|
|
476
|
-
this._children.forEach(npb => json_navPropBinding[npb.Path] = npb.Target);
|
|
543
|
+
this._children.forEach(npb => json_navPropBinding[npb._edmAttributes.Path] = npb._edmAttributes.Target);
|
|
477
544
|
if(Object.keys(json_navPropBinding).length > 0)
|
|
478
545
|
json['$NavigationPropertyBinding'] = json_navPropBinding;
|
|
479
546
|
|
|
@@ -481,7 +548,7 @@ module.exports = function (options, error) {
|
|
|
481
548
|
}
|
|
482
549
|
|
|
483
550
|
getDuplicateMessage() {
|
|
484
|
-
return `EntityType "${this.EntityType}"`
|
|
551
|
+
return `EntityType "${this._edmAttributes.EntityType}"`
|
|
485
552
|
}
|
|
486
553
|
}
|
|
487
554
|
|
|
@@ -534,13 +601,13 @@ module.exports = function (options, error) {
|
|
|
534
601
|
constructor(v, details)
|
|
535
602
|
{
|
|
536
603
|
super(v, details);
|
|
537
|
-
this.
|
|
604
|
+
this._returnType = undefined;
|
|
538
605
|
}
|
|
539
606
|
|
|
540
607
|
innerXML(indent)
|
|
541
608
|
{
|
|
542
609
|
let xml = super.innerXML(indent);
|
|
543
|
-
if(this._returnType
|
|
610
|
+
if(this._returnType !== undefined)
|
|
544
611
|
xml += this._returnType.toXML(indent) + '\n';
|
|
545
612
|
return xml
|
|
546
613
|
}
|
|
@@ -573,12 +640,12 @@ module.exports = function (options, error) {
|
|
|
573
640
|
*/
|
|
574
641
|
class FunctionImport extends Node {
|
|
575
642
|
getDuplicateMessage() {
|
|
576
|
-
return `Function "${this.Name}"`
|
|
643
|
+
return `Function "${this._edmAttributes.Name}"`
|
|
577
644
|
}
|
|
578
645
|
} //ActionFunctionBase {}
|
|
579
646
|
class ActionImport extends Node {
|
|
580
647
|
getDuplicateMessage() {
|
|
581
|
-
return `Action "${this.Name}"`
|
|
648
|
+
return `Action "${this._edmAttributes.Name}"`
|
|
582
649
|
}
|
|
583
650
|
}
|
|
584
651
|
|
|
@@ -586,75 +653,81 @@ module.exports = function (options, error) {
|
|
|
586
653
|
{
|
|
587
654
|
constructor(v, attributes, csn, typeName='Type')
|
|
588
655
|
{
|
|
589
|
-
if(!(csn instanceof Object || (typeof csn === 'object' && csn !== null)))
|
|
590
|
-
error(null, 'Please debug me: csn must be an object');
|
|
591
|
-
|
|
592
656
|
// ??? Is CSN still required? NavProp?
|
|
593
657
|
super(v, attributes, csn);
|
|
594
|
-
this.
|
|
595
|
-
|
|
596
|
-
if(this[typeName]
|
|
658
|
+
this._typeName = typeName;
|
|
659
|
+
this._scalarType = undefined;
|
|
660
|
+
if(this._edmAttributes[typeName] === undefined)
|
|
597
661
|
{
|
|
598
662
|
let typecsn = csn.type ? csn : (csn.items && csn.items.type ? csn.items : csn);
|
|
599
663
|
// Complex/EntityType are derived from TypeBase
|
|
600
664
|
// but have no type attribute in their CSN
|
|
601
665
|
if(typecsn.type) { // this thing has a type
|
|
602
666
|
// check whether this is a scalar type (or array of scalar type) or a named type
|
|
603
|
-
let scalarType = undefined;
|
|
604
667
|
if(typecsn.items && typecsn.items.type &&
|
|
605
668
|
isBuiltinType(typecsn.items.type)) {
|
|
606
|
-
|
|
669
|
+
this._scalarType = typecsn.items;
|
|
607
670
|
}
|
|
608
671
|
else if(isBuiltinType(typecsn.type)) {
|
|
609
|
-
|
|
672
|
+
this._scalarType = typecsn;
|
|
610
673
|
}
|
|
611
|
-
if(
|
|
612
|
-
this[typeName] = csn._edmType;
|
|
674
|
+
if(this._scalarType) {
|
|
675
|
+
this._edmAttributes[typeName] = csn._edmType;
|
|
613
676
|
// CDXCORE-CDXCORE-173 ignore type facets for Edm.Stream
|
|
614
677
|
// cds-compiler/issues/7835: Only set length for Binary as long as it is
|
|
615
678
|
// unclear how many bytes a string character represents.
|
|
616
679
|
// We can't calculate an unambiguous byte stream length for DB dependent
|
|
617
680
|
// multi-byte characters.
|
|
618
|
-
if(!(this[typeName] === 'Edm.Stream' &&
|
|
619
|
-
!
|
|
620
|
-
edmUtils.addTypeFacets(this,
|
|
681
|
+
if(!(this._edmAttributes[typeName] === 'Edm.Stream' &&
|
|
682
|
+
!( /*scalarType.type === 'cds.String' ||*/ this._scalarType.type === 'cds.Binary')))
|
|
683
|
+
edmUtils.addTypeFacets(this, this._scalarType);
|
|
684
|
+
// CDXCORE-245:
|
|
685
|
+
// map type to @odata.Type
|
|
686
|
+
// optionally add @odata { MaxLength, Precision, Scale, SRID } but only in combination with @odata.Type
|
|
687
|
+
const odataType = csn['@odata.Type'];
|
|
688
|
+
if(odataType)
|
|
689
|
+
{
|
|
690
|
+
const td = EdmPrimitiveTypeMap[odataType];
|
|
691
|
+
// If type is known, it must be available in the current version
|
|
692
|
+
// Reason: EDMX Importer may set `@odata.Type: 'Edm.DateTime'` on imported V2 services
|
|
693
|
+
// Not filtering out this incompatible type here in case of a V4 rendering would
|
|
694
|
+
// produce an unrecoverable error.
|
|
695
|
+
if(td && (td.v2 === this.v2 || td.v4 === this.v4)) {
|
|
696
|
+
this.setEdmAttribute(typeName, odataType);
|
|
697
|
+
EdmTypeFacetNames.forEach(facet => {
|
|
698
|
+
if(EdmTypeFacetMap[facet].remove)
|
|
699
|
+
this.removeEdmAttribute(facet);
|
|
700
|
+
if(td[facet] !== undefined &&
|
|
701
|
+
(EdmTypeFacetMap[facet].v2 === this.v2 ||
|
|
702
|
+
EdmTypeFacetMap[facet].v4 === this.v4)
|
|
703
|
+
) {
|
|
704
|
+
this.setEdmAttribute(facet, csn['@odata.'+facet]);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
}
|
|
621
709
|
}
|
|
622
710
|
else {
|
|
623
|
-
this[typeName] = typecsn.type;
|
|
624
|
-
}
|
|
625
|
-
// CDXCORE-245:
|
|
626
|
-
// map type to @odata.Type
|
|
627
|
-
// optionally add @odata.MaxLength but only in combination with @odata.Type
|
|
628
|
-
// In absence of checks restrict @odata.Type to 'Edm.String' and 'Edm.Int[16,32,64]'
|
|
629
|
-
let odataType = csn['@odata.Type'];
|
|
630
|
-
if(odataType === 'Edm.String')
|
|
631
|
-
{
|
|
632
|
-
this[typeName] = odataType;
|
|
633
|
-
if(csn['@odata.MaxLength']) {
|
|
634
|
-
this['MaxLength'] = csn['@odata.MaxLength'];
|
|
635
|
-
}
|
|
636
|
-
} else if(['Edm.Int16', 'Edm.Int32', 'Edm.Int64'].includes(odataType)) {
|
|
637
|
-
this[typeName] = odataType;
|
|
711
|
+
this._edmAttributes[typeName] = typecsn.type;
|
|
638
712
|
}
|
|
639
713
|
}
|
|
640
714
|
}
|
|
715
|
+
|
|
641
716
|
// Set the collection property if this is either an element or a parameter
|
|
642
|
-
|
|
643
|
-
this.set({ _isCollection: csn._isCollection });
|
|
644
|
-
}
|
|
717
|
+
this._isCollection = (csn.kind === undefined) ? csn._isCollection : false;
|
|
645
718
|
|
|
646
|
-
if(options.whatsMySchemaName && this[typeName]) {
|
|
647
|
-
let schemaName = options.whatsMySchemaName(this[typeName]);
|
|
719
|
+
if(options.whatsMySchemaName && this._edmAttributes[typeName]) {
|
|
720
|
+
let schemaName = options.whatsMySchemaName(this._edmAttributes[typeName]);
|
|
648
721
|
if(schemaName && schemaName !== options.serviceName) {
|
|
649
|
-
this[typeName] = this[typeName].replace(options.serviceName + '.', '');
|
|
722
|
+
this._edmAttributes[typeName] = this._edmAttributes[typeName].replace(options.serviceName + '.', '');
|
|
650
723
|
}
|
|
651
724
|
}
|
|
652
725
|
|
|
653
726
|
// store undecorated type for JSON
|
|
654
|
-
this.
|
|
727
|
+
this._type = this._edmAttributes[typeName];
|
|
655
728
|
// decorate for XML (not for Complex/EntityType)
|
|
656
729
|
if(this._isCollection)
|
|
657
|
-
this[typeName] = `Collection(${this[typeName]})`
|
|
730
|
+
this._edmAttributes[typeName] = `Collection(${this._edmAttributes[typeName]})`
|
|
658
731
|
}
|
|
659
732
|
|
|
660
733
|
toJSONattributes(json)
|
|
@@ -664,7 +737,7 @@ module.exports = function (options, error) {
|
|
|
664
737
|
if(this._type !== 'Edm.String' && this._type) // Edm.String is default)
|
|
665
738
|
json['$'+this._typeName] = this._type;
|
|
666
739
|
|
|
667
|
-
edmUtils.forAll(this, (v,p) => {
|
|
740
|
+
edmUtils.forAll(this._edmAttributes, (v,p) => {
|
|
668
741
|
if (p !== 'Name' && p !== this._typeName
|
|
669
742
|
// remove this line if Nullable=true becomes default
|
|
670
743
|
&& !(p === 'Nullable' && v == false))
|
|
@@ -721,7 +794,9 @@ module.exports = function (options, error) {
|
|
|
721
794
|
});
|
|
722
795
|
|
|
723
796
|
if(csn.$edmKeyPaths && csn.$edmKeyPaths.length)
|
|
724
|
-
this.
|
|
797
|
+
this._keys = new Key(v, csn.$edmKeyPaths);
|
|
798
|
+
else
|
|
799
|
+
this._keys = undefined;
|
|
725
800
|
}
|
|
726
801
|
|
|
727
802
|
innerXML(indent)
|
|
@@ -788,7 +863,7 @@ module.exports = function (options, error) {
|
|
|
788
863
|
{
|
|
789
864
|
toJSONattributes(json)
|
|
790
865
|
{
|
|
791
|
-
json[this.Name] = this.Value;
|
|
866
|
+
json[this._edmAttributes.Name] = this._edmAttributes.Value;
|
|
792
867
|
return json;
|
|
793
868
|
}
|
|
794
869
|
}
|
|
@@ -798,7 +873,7 @@ module.exports = function (options, error) {
|
|
|
798
873
|
constructor(v, attributes, csn)
|
|
799
874
|
{
|
|
800
875
|
super(v, attributes, csn);
|
|
801
|
-
this.
|
|
876
|
+
this._csn = csn;
|
|
802
877
|
if(this.v2)
|
|
803
878
|
{
|
|
804
879
|
let typecsn = csn.items || csn;
|
|
@@ -806,7 +881,7 @@ module.exports = function (options, error) {
|
|
|
806
881
|
// see edmUtils.mapsCdsToEdmType => add sap:display-format annotation
|
|
807
882
|
// only if Edm.DateTime is the result of a cast from Edm.Date
|
|
808
883
|
// but not if Edm.DateTime is the result of a regular cds type mapping
|
|
809
|
-
if(this.Type === 'Edm.DateTime'
|
|
884
|
+
if(this._edmAttributes.Type === 'Edm.DateTime'
|
|
810
885
|
&& (typecsn.type !== 'cds.DateTime' && typecsn.type !== 'cds.Timestamp'))
|
|
811
886
|
this.setXml( { 'sap:display-format' : 'Date' } );
|
|
812
887
|
|
|
@@ -818,14 +893,14 @@ module.exports = function (options, error) {
|
|
|
818
893
|
{
|
|
819
894
|
// From the Spec: In OData 4.01 responses a collection-valued property MUST specify a value for the Nullable attribute.
|
|
820
895
|
if(this._isCollection) {
|
|
821
|
-
this.Nullable = !this.isNotNullable();
|
|
896
|
+
this._edmAttributes.Nullable = !this.isNotNullable();
|
|
822
897
|
}
|
|
823
898
|
// Nullable=true is default, mention Nullable=false only in XML
|
|
824
899
|
// Nullable=false is default for EDM JSON representation 4.01
|
|
825
900
|
// When a key explicitly (!) has 'notNull = false', it stays nullable
|
|
826
901
|
else if(this.isNotNullable())
|
|
827
902
|
{
|
|
828
|
-
this.Nullable = false;
|
|
903
|
+
this._edmAttributes.Nullable = false;
|
|
829
904
|
}
|
|
830
905
|
}
|
|
831
906
|
|
|
@@ -842,7 +917,7 @@ module.exports = function (options, error) {
|
|
|
842
917
|
{
|
|
843
918
|
super.toJSONattributes(json);
|
|
844
919
|
// mention all nullable elements explicitly, remove if Nullable=true becomes default
|
|
845
|
-
if(this.Nullable === undefined || this.Nullable === true)
|
|
920
|
+
if(this._edmAttributes.Nullable === undefined || this._edmAttributes.Nullable === true)
|
|
846
921
|
{
|
|
847
922
|
json['$Nullable'] = true;
|
|
848
923
|
}
|
|
@@ -864,9 +939,6 @@ module.exports = function (options, error) {
|
|
|
864
939
|
{
|
|
865
940
|
let json = Object.create(null);
|
|
866
941
|
this.toJSONattributes(json);
|
|
867
|
-
// !this._nullable if Nullable=true become default
|
|
868
|
-
if(this._nullable)
|
|
869
|
-
json['$Nullable'] = this._nullable;
|
|
870
942
|
return json;
|
|
871
943
|
}
|
|
872
944
|
}
|
|
@@ -875,29 +947,16 @@ module.exports = function (options, error) {
|
|
|
875
947
|
{
|
|
876
948
|
constructor(v, attributes, csn)
|
|
877
949
|
{
|
|
878
|
-
// the annotations in this array shall become exposed as Property attributes in
|
|
879
|
-
// the V2 metadata.xml
|
|
880
|
-
// @ts-ignore
|
|
881
|
-
Property.SAP_Annotation_Attribute_WhiteList = [
|
|
882
|
-
'@sap.hierarchy.node.for', // -> sap:hierarchy-node-for
|
|
883
|
-
'@sap.hierarchy.parent.node.for', // -> sap:hierarchy-parent-node-for
|
|
884
|
-
'@sap.hierarchy.level.for', // -> sap:hierarchy-level-for
|
|
885
|
-
'@sap.hierarchy.drill.state.for', // -> sap:hierarchy-drill-state-for
|
|
886
|
-
'@sap.hierarchy.node.descendant.count.for', // -> sap:hierarchy-node-descendant-count-for
|
|
887
|
-
'@sap.parameter'
|
|
888
|
-
];
|
|
889
|
-
|
|
890
950
|
super(v, attributes, csn);
|
|
891
951
|
// TIPHANACDS-4180
|
|
892
952
|
if(this.v2)
|
|
893
953
|
{
|
|
894
954
|
if(csn['@odata.etag'] == true || csn['@cds.etag'] == true)
|
|
895
|
-
this.ConcurrencyMode='Fixed'
|
|
955
|
+
this._edmAttributes.ConcurrencyMode='Fixed'
|
|
896
956
|
|
|
897
957
|
// translate the following @sap annos as xml attributes to the Property
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
if (Property.SAP_Annotation_Attribute_WhiteList.includes(p))
|
|
958
|
+
forEach(csn, (p, v) => {
|
|
959
|
+
if (p in Property.SAP_Annotation_Attributes)
|
|
901
960
|
this.setXml( { ['sap:' + p.slice(5).replace(/\./g, '-')] : v });
|
|
902
961
|
});
|
|
903
962
|
}
|
|
@@ -907,7 +966,7 @@ module.exports = function (options, error) {
|
|
|
907
966
|
// added a @Core.ComputedDefaultValue for complex defaults
|
|
908
967
|
if (csn.default && !csn['@Core.ComputedDefaultValue']) {
|
|
909
968
|
|
|
910
|
-
|
|
969
|
+
const def = csn.default;
|
|
911
970
|
// if def has a value, it's a simple value
|
|
912
971
|
let defVal = def.val;
|
|
913
972
|
// if it's a simple value with signs, produce a string representation
|
|
@@ -928,7 +987,7 @@ module.exports = function (options, error) {
|
|
|
928
987
|
Additionally: The attribute is named 'Default' in V2 and 'DefaultValue' in V4
|
|
929
988
|
*/
|
|
930
989
|
if(this.v4)
|
|
931
|
-
this[`Default${this.v4 ? 'Value' : ''}`] = defVal;
|
|
990
|
+
this._edmAttributes[`Default${this.v4 ? 'Value' : ''}`] = defVal;
|
|
932
991
|
}
|
|
933
992
|
}
|
|
934
993
|
}
|
|
@@ -937,6 +996,17 @@ module.exports = function (options, error) {
|
|
|
937
996
|
// static get isProperty() { return true }
|
|
938
997
|
}
|
|
939
998
|
|
|
999
|
+
// the annotations in this array shall become exposed as Property attributes in
|
|
1000
|
+
// the V2 metadata.xml
|
|
1001
|
+
Property.SAP_Annotation_Attributes = {
|
|
1002
|
+
'@sap.hierarchy.node.for':1, // -> sap:hierarchy-node-for
|
|
1003
|
+
'@sap.hierarchy.parent.node.for':1, // -> sap:hierarchy-parent-node-for
|
|
1004
|
+
'@sap.hierarchy.level.for':1, // -> sap:hierarchy-level-for
|
|
1005
|
+
'@sap.hierarchy.drill.state.for':1, // -> sap:hierarchy-drill-state-for
|
|
1006
|
+
'@sap.hierarchy.node.descendant.count.for':1, // -> sap:hierarchy-node-descendant-count-for
|
|
1007
|
+
'@sap.parameter':1
|
|
1008
|
+
};
|
|
1009
|
+
|
|
940
1010
|
class PropertyRef extends Node
|
|
941
1011
|
{
|
|
942
1012
|
constructor(v, Name, Alias) {
|
|
@@ -944,7 +1014,7 @@ module.exports = function (options, error) {
|
|
|
944
1014
|
}
|
|
945
1015
|
|
|
946
1016
|
toJSON() {
|
|
947
|
-
return this.Alias ? { [this.Alias]:this.Name } : this.Name;
|
|
1017
|
+
return this._edmAttributes.Alias ? { [this._edmAttributes.Alias]:this._edmAttributes.Name } : this._edmAttributes.Name;
|
|
948
1018
|
}
|
|
949
1019
|
}
|
|
950
1020
|
|
|
@@ -955,12 +1025,12 @@ module.exports = function (options, error) {
|
|
|
955
1025
|
super(v, attributes, csn);
|
|
956
1026
|
|
|
957
1027
|
if(mode != null)
|
|
958
|
-
this.Mode = mode;
|
|
1028
|
+
this._edmAttributes.Mode = mode;
|
|
959
1029
|
|
|
960
1030
|
// V2 XML: Parameters that are not explicitly marked as Nullable or NotNullable in the CSN must become Nullable=true
|
|
961
1031
|
// V2 XML Spec does only mention default Nullable=true for Properties not for Parameters so omitting Nullable=true let
|
|
962
1032
|
// the client assume that Nullable is false.... Correct Nullable Handling is done inside Parameter constructor
|
|
963
|
-
if(this.v2 && this.Nullable === undefined)
|
|
1033
|
+
if(this.v2 && this._edmAttributes.Nullable === undefined)
|
|
964
1034
|
this.setXml({Nullable: true});
|
|
965
1035
|
}
|
|
966
1036
|
|
|
@@ -968,7 +1038,7 @@ module.exports = function (options, error) {
|
|
|
968
1038
|
{
|
|
969
1039
|
// we need Name but NO $kind, can't use standard to JSON()
|
|
970
1040
|
let json = Object.create(null);
|
|
971
|
-
json['$Name'] = this.Name;
|
|
1041
|
+
json['$Name'] = this._edmAttributes.Name;
|
|
972
1042
|
return this.toJSONattributes(json);
|
|
973
1043
|
}
|
|
974
1044
|
}
|
|
@@ -984,28 +1054,34 @@ module.exports = function (options, error) {
|
|
|
984
1054
|
let [src, tgt] = edmUtils.determineMultiplicity(csn._constraints._partnerCsn || csn);
|
|
985
1055
|
csn._constraints._multiplicity = csn._constraints._partnerCsn ? [tgt, src] : [src, tgt];
|
|
986
1056
|
|
|
987
|
-
this.
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
_targetCsn: csn._target
|
|
991
|
-
} );
|
|
1057
|
+
this._type = attributes.Type;
|
|
1058
|
+
this._isCollection = this.isToMany();
|
|
1059
|
+
this._targetCsn = csn._target;
|
|
992
1060
|
|
|
993
1061
|
if (this.v4)
|
|
994
1062
|
{
|
|
1063
|
+
if(options.isStructFormat && this._csn.key)
|
|
1064
|
+
this._edmAttributes.Nullable = false;
|
|
1065
|
+
|
|
995
1066
|
// either csn has multiplicity or we have to use the multiplicity of the backlink
|
|
996
1067
|
if(this._isCollection) {
|
|
997
|
-
this.Type = `Collection(${attributes.Type})`
|
|
1068
|
+
this._edmAttributes.Type = `Collection(${attributes.Type})`
|
|
998
1069
|
// attribute Nullable is not allowed in combination with Collection (see Spec)
|
|
999
1070
|
// Even if min cardinality is > 0, remove Nullable, because the implicit OData contract
|
|
1000
1071
|
// is that a navigation property must either return an empty collection or all collection
|
|
1001
1072
|
// values are !null (with other words: a collection must never return [1,2,null,3])
|
|
1002
|
-
delete this.Nullable;
|
|
1073
|
+
delete this._edmAttributes.Nullable;
|
|
1003
1074
|
}
|
|
1004
1075
|
// we have exactly one selfReference or the default partner
|
|
1005
|
-
let partner =
|
|
1076
|
+
let partner =
|
|
1077
|
+
!csn.$noPartner ?
|
|
1078
|
+
csn._selfReferences.length === 1
|
|
1079
|
+
? csn._selfReferences[0]
|
|
1080
|
+
: csn._constraints._partnerCsn
|
|
1081
|
+
: undefined;
|
|
1006
1082
|
if(partner && partner['@odata.navigable'] !== false) {
|
|
1007
1083
|
// $abspath[0] is main entity
|
|
1008
|
-
this.Partner = partner.$abspath.slice(1).join(options.pathDelimiter);
|
|
1084
|
+
this._edmAttributes.Partner = partner.$abspath.slice(1).join(options.pathDelimiter);
|
|
1009
1085
|
}
|
|
1010
1086
|
|
|
1011
1087
|
/*
|
|
@@ -1018,9 +1094,9 @@ module.exports = function (options, error) {
|
|
|
1018
1094
|
2) ContainsTarget stems from the @odata.contained annotation
|
|
1019
1095
|
*/
|
|
1020
1096
|
if(csn['@odata.contained'] == true || csn.containsTarget) {
|
|
1021
|
-
this.ContainsTarget = true;
|
|
1097
|
+
this._edmAttributes.ContainsTarget = true;
|
|
1022
1098
|
}
|
|
1023
|
-
if(this.ContainsTarget === undefined && csn.type === 'cds.Composition') {
|
|
1099
|
+
if(this._edmAttributes.ContainsTarget === undefined && csn.type === 'cds.Composition') {
|
|
1024
1100
|
// Delete is redundant in containment
|
|
1025
1101
|
// TODO: to be specified via @sap.on.delete
|
|
1026
1102
|
this.append(new OnDelete(v, { Action: 'Cascade' } ) );
|
|
@@ -1031,7 +1107,7 @@ module.exports = function (options, error) {
|
|
|
1031
1107
|
if (this.v2 && this.isNotNullable()) {
|
|
1032
1108
|
// in V2 not null must be expressed with target cardinality of 1 or more,
|
|
1033
1109
|
// store Nullable=false and evaluate in determineMultiplicity()
|
|
1034
|
-
delete this.Nullable;
|
|
1110
|
+
delete this._edmAttributes.Nullable;
|
|
1035
1111
|
}
|
|
1036
1112
|
|
|
1037
1113
|
// store NavProp reference in the model for bidirectional $Partner tagging (done in getReferentialConstraints())
|
|
@@ -1075,10 +1151,10 @@ module.exports = function (options, error) {
|
|
|
1075
1151
|
switch(c.kind) {
|
|
1076
1152
|
case 'ReferentialConstraint':
|
|
1077
1153
|
// collect ref constraints in dictionary
|
|
1078
|
-
json_constraints[c.Property] = c.ReferencedProperty;
|
|
1154
|
+
json_constraints[c._edmAttributes.Property] = c._edmAttributes.ReferencedProperty;
|
|
1079
1155
|
break;
|
|
1080
1156
|
case 'OnDelete':
|
|
1081
|
-
json['$OnDelete'] = c.Action;
|
|
1157
|
+
json['$OnDelete'] = c._edmAttributes.Action;
|
|
1082
1158
|
break;
|
|
1083
1159
|
default:
|
|
1084
1160
|
error(null, 'Please debug me: Unhandled NavProp child: ' + c.kind);
|
|
@@ -1109,6 +1185,12 @@ module.exports = function (options, error) {
|
|
|
1109
1185
|
|
|
1110
1186
|
class ReferentialConstraint extends Node
|
|
1111
1187
|
{
|
|
1188
|
+
constructor(v, attributes, csn) {
|
|
1189
|
+
super(v, attributes, csn);
|
|
1190
|
+
this._d = null;
|
|
1191
|
+
this._p = null;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1112
1194
|
innerXML(indent)
|
|
1113
1195
|
{
|
|
1114
1196
|
if(this._d && this._p)
|
|
@@ -1140,12 +1222,18 @@ module.exports = function (options, error) {
|
|
|
1140
1222
|
{
|
|
1141
1223
|
// short form: key: value
|
|
1142
1224
|
const inlineConstExpr =
|
|
1143
|
-
[ 'Edm.Binary', 'Edm.Boolean', 'Edm.Byte', 'Edm.Date', 'Edm.DateTimeOffset',
|
|
1144
|
-
'Edm.Int16', 'Edm.Int32', 'Edm.Int64', 'Edm.SByte','Edm.Single',
|
|
1225
|
+
[ 'Edm.Binary', 'Edm.Boolean', 'Edm.Byte', 'Edm.Date', 'Edm.DateTimeOffset', 'Edm.Decimal', 'Edm.Double', 'Edm.Duration', 'Edm.Guid',
|
|
1226
|
+
'Edm.Int16', 'Edm.Int32', 'Edm.Int64', 'Edm.SByte','Edm.Single', 'Edm.Stream', 'Edm.String', 'Edm.TimeOfDay',
|
|
1227
|
+
// Edm.Geo* according to https://issues.oasis-open.org/browse/ODATA-1323
|
|
1228
|
+
/* 'Edm.Geography', 'Edm.GeographyPoint', 'Edm.GeographyLineString', 'Edm.GeographyPolygon', 'Edm.GeographyMultiPoint',
|
|
1229
|
+
'Edm.GeographyMultiLineString', 'Edm.GeographyMultiPolygon', 'Edm.GeographyCollection', 'Edm.Geometry', 'Edm.GeometryPoint',
|
|
1230
|
+
'Edm.GeometryLineString', 'Edm.GeometryPolygon', 'Edm.GeometryMultiPoint', 'Edm.GeometryMultiLineString', 'Edm.GeometryMultiPolygon',
|
|
1231
|
+
'Edm.GeometryCollection',
|
|
1232
|
+
*/
|
|
1145
1233
|
/* UI.xml: defines Annotations with generic type 'Edm.PrimitiveType' */
|
|
1146
|
-
'Edm.PrimitiveType', 'Bool'
|
|
1147
|
-
// Official JSON V4.01 Spec defines these paths as constant inline expression
|
|
1148
|
-
|
|
1234
|
+
'Edm.PrimitiveType', 'Edm.Untyped', 'Bool',
|
|
1235
|
+
// Official JSON V4.01 Spec defines these paths as constant inline expression:
|
|
1236
|
+
'AnnotationPath', 'ModelElementPath', 'NavigationPropertyPath', 'PropertyPath',
|
|
1149
1237
|
];
|
|
1150
1238
|
|
|
1151
1239
|
const dict = this._jsonOnlyAttributes;
|
|
@@ -1156,20 +1244,13 @@ module.exports = function (options, error) {
|
|
|
1156
1244
|
switch(inline[0])
|
|
1157
1245
|
{
|
|
1158
1246
|
/* short notation for Edm.Boolean, Edm.String and Edm.Float, see internal project:
|
|
1159
|
-
|
|
1160
|
-
|
|
1247
|
+
edmx2csn-npm/edm-converters/blob/835d92a1aa6b0be25c56cef85e260c9188187429/lib/edmxV40ToJsonV40/README.md
|
|
1248
|
+
*/
|
|
1161
1249
|
case 'Edm.Boolean':
|
|
1162
1250
|
v = (v=='true'?true:(v=='false'?false:v));
|
|
1163
1251
|
// eslint-no-fallthrough
|
|
1164
|
-
case 'Edm.String':
|
|
1165
|
-
// eslint-no-fallthrough
|
|
1166
|
-
case 'Edm.Float':
|
|
1167
|
-
// eslint-no-fallthrough
|
|
1168
|
-
return v;
|
|
1169
1252
|
default:
|
|
1170
|
-
|
|
1171
|
-
// because they didn't want to lookup the type in the vocabulary
|
|
1172
|
-
return { '$Cast': v, '$Type': inline[0] };
|
|
1253
|
+
return v;
|
|
1173
1254
|
}
|
|
1174
1255
|
}
|
|
1175
1256
|
else
|
|
@@ -1199,13 +1280,12 @@ module.exports = function (options, error) {
|
|
|
1199
1280
|
constructor(v, target)
|
|
1200
1281
|
{
|
|
1201
1282
|
super(v, { Target: target });
|
|
1202
|
-
|
|
1203
|
-
this.setXml( { xmlns : 'http://docs.oasis-open.org/odata/ns/edm' } );
|
|
1283
|
+
this.setXml( { xmlns : this.v2 ? 'http://docs.oasis-open.org/odata/ns/edm' : undefined } );
|
|
1204
1284
|
}
|
|
1205
1285
|
|
|
1206
1286
|
toJSONattributes(json)
|
|
1207
1287
|
{
|
|
1208
|
-
|
|
1288
|
+
forEach(this._edmAttributes, (p, v) => {
|
|
1209
1289
|
if (p !== 'Target')
|
|
1210
1290
|
json[p[0] === '@' ? p : '$' + p] = v;
|
|
1211
1291
|
});
|
|
@@ -1254,7 +1334,7 @@ module.exports = function (options, error) {
|
|
|
1254
1334
|
}
|
|
1255
1335
|
|
|
1256
1336
|
getJsonFQTermName() {
|
|
1257
|
-
return '@' + this.Term + (this.Qualifier ? '#' + this.Qualifier : '');
|
|
1337
|
+
return '@' + this._edmAttributes.Term + (this._edmAttributes.Qualifier ? '#' + this._edmAttributes.Qualifier : '');
|
|
1258
1338
|
}
|
|
1259
1339
|
}
|
|
1260
1340
|
|
|
@@ -1271,11 +1351,11 @@ module.exports = function (options, error) {
|
|
|
1271
1351
|
{
|
|
1272
1352
|
toJSONattributes(json)
|
|
1273
1353
|
{
|
|
1274
|
-
if(this.Type)
|
|
1275
|
-
json['@type'] = this.Type;
|
|
1276
|
-
let keys = Object.keys(this).filter(k => k !== 'Type');
|
|
1354
|
+
if(this._edmAttributes.Type)
|
|
1355
|
+
json['@type'] = this._edmAttributes.Type;
|
|
1356
|
+
let keys = Object.keys(this._edmAttributes).filter(k => k !== 'Type');
|
|
1277
1357
|
for(const key of keys)
|
|
1278
|
-
json['$'+key] = this[key];
|
|
1358
|
+
json['$'+key] = this._edmAttributes[key];
|
|
1279
1359
|
}
|
|
1280
1360
|
|
|
1281
1361
|
toJSONchildren(json)
|
|
@@ -1295,7 +1375,7 @@ module.exports = function (options, error) {
|
|
|
1295
1375
|
json[n] = a;
|
|
1296
1376
|
});
|
|
1297
1377
|
// render property as const expr (or subnode)
|
|
1298
|
-
json[c.Property] = c.toJSON();
|
|
1378
|
+
json[c._edmAttributes.Property] = c.toJSON();
|
|
1299
1379
|
break;
|
|
1300
1380
|
}
|
|
1301
1381
|
default:
|
|
@@ -1310,7 +1390,7 @@ module.exports = function (options, error) {
|
|
|
1310
1390
|
constructor(v, property)
|
|
1311
1391
|
{
|
|
1312
1392
|
super(v);
|
|
1313
|
-
this.Property = property;
|
|
1393
|
+
this._edmAttributes.Property = property;
|
|
1314
1394
|
}
|
|
1315
1395
|
|
|
1316
1396
|
toJSON()
|
|
@@ -1324,7 +1404,7 @@ module.exports = function (options, error) {
|
|
|
1324
1404
|
}
|
|
1325
1405
|
}
|
|
1326
1406
|
mergeJSONannotations() {
|
|
1327
|
-
return super.mergeJSONAnnotations(this.Property);
|
|
1407
|
+
return super.mergeJSONAnnotations(this._edmAttributes.Property);
|
|
1328
1408
|
}
|
|
1329
1409
|
}
|
|
1330
1410
|
|
|
@@ -1333,14 +1413,10 @@ module.exports = function (options, error) {
|
|
|
1333
1413
|
constructor(v, kind, details)
|
|
1334
1414
|
{
|
|
1335
1415
|
super(v, details);
|
|
1336
|
-
this.
|
|
1416
|
+
this._kind = kind;
|
|
1337
1417
|
}
|
|
1338
1418
|
|
|
1339
|
-
|
|
1340
|
-
{
|
|
1341
|
-
Object.defineProperty(this, 'kind',
|
|
1342
|
-
{ get: function() { return kind; }});
|
|
1343
|
-
}
|
|
1419
|
+
get kind() { return this._kind; }
|
|
1344
1420
|
}
|
|
1345
1421
|
|
|
1346
1422
|
class ValueThing extends Thing
|
|
@@ -1348,7 +1424,7 @@ module.exports = function (options, error) {
|
|
|
1348
1424
|
constructor(v, kind, value)
|
|
1349
1425
|
{
|
|
1350
1426
|
super(v, kind, undefined);
|
|
1351
|
-
this.
|
|
1427
|
+
this._value = value;
|
|
1352
1428
|
}
|
|
1353
1429
|
|
|
1354
1430
|
toXML(indent='')
|
|
@@ -1410,10 +1486,11 @@ module.exports = function (options, error) {
|
|
|
1410
1486
|
}
|
|
1411
1487
|
class Cast extends AnnotationBase {
|
|
1412
1488
|
toXMLattributes() {
|
|
1489
|
+
// TODO: Why json?
|
|
1413
1490
|
if(this._jsonOnlyAttributes['Collection'])
|
|
1414
|
-
return ` Type="Collection(${this.Type})"`
|
|
1491
|
+
return ` Type="Collection(${this._edmAttributes.Type})"`
|
|
1415
1492
|
else
|
|
1416
|
-
return ` Type="${this.Type}"`
|
|
1493
|
+
return ` Type="${this._edmAttributes.Type}"`
|
|
1417
1494
|
}
|
|
1418
1495
|
toJSON() {
|
|
1419
1496
|
const json = this.mergeJSONAnnotations();
|
|
@@ -1452,7 +1529,7 @@ module.exports = function (options, error) {
|
|
|
1452
1529
|
|
|
1453
1530
|
toJSONattributes(json) // including Name
|
|
1454
1531
|
{
|
|
1455
|
-
|
|
1532
|
+
forEach(this._edmAttributes, (p, v) => {
|
|
1456
1533
|
json[p[0] === '@' ? p : '$' + p] = v;
|
|
1457
1534
|
});
|
|
1458
1535
|
return json;
|
|
@@ -1481,10 +1558,10 @@ module.exports = function (options, error) {
|
|
|
1481
1558
|
constructor(v, details, navProp, fromRole, toRole, multiplicity)
|
|
1482
1559
|
{
|
|
1483
1560
|
super(v, details);
|
|
1484
|
-
this.
|
|
1485
|
-
this._end.push(
|
|
1561
|
+
this._end = [
|
|
1486
1562
|
new End(v, { Role: fromRole[0], Type: fromRole[1], Multiplicity: multiplicity[0] } ),
|
|
1487
|
-
new End(v, { Role: toRole[0], Type: toRole[1], Multiplicity: multiplicity[1] } )
|
|
1563
|
+
new End(v, { Role: toRole[0], Type: toRole[1], Multiplicity: multiplicity[1] } )
|
|
1564
|
+
];
|
|
1488
1565
|
|
|
1489
1566
|
// set Delete:Cascade on composition end
|
|
1490
1567
|
if(navProp._csn.type === 'cds.Composition')
|
|
@@ -1515,7 +1592,7 @@ module.exports = function (options, error) {
|
|
|
1515
1592
|
);
|
|
1516
1593
|
}
|
|
1517
1594
|
getDuplicateMessage() {
|
|
1518
|
-
return `Association "${this.Association}"`
|
|
1595
|
+
return `Association "${this._edmAttributes.Association}"`
|
|
1519
1596
|
}
|
|
1520
1597
|
}
|
|
1521
1598
|
|
|
@@ -1526,8 +1603,8 @@ module.exports = function (options, error) {
|
|
|
1526
1603
|
function(v, from, to, c)
|
|
1527
1604
|
{
|
|
1528
1605
|
let node = new ReferentialConstraint(v, {});
|
|
1529
|
-
node.
|
|
1530
|
-
node.
|
|
1606
|
+
node._d = new Dependent(v, { Role: from } );
|
|
1607
|
+
node._p = new Principal(v, { Role: to } );
|
|
1531
1608
|
|
|
1532
1609
|
edmUtils.forAll(c, cv => {
|
|
1533
1610
|
node._d.append(new PropertyRef(v, cv[0].join(options.pathDelimiter)));
|
|
@@ -1591,3 +1668,5 @@ module.exports = function (options, error) {
|
|
|
1591
1668
|
}
|
|
1592
1669
|
|
|
1593
1670
|
} // instance function
|
|
1671
|
+
|
|
1672
|
+
module.exports = { EdmTypeFacetMap, EdmTypeFacetNames, EdmPrimitiveTypeMap, getEdm };
|