@sap/cds-compiler 3.4.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +15 -16
- package/bin/cdshi.js +19 -6
- package/doc/CHANGELOG_ARCHIVE.md +2 -2
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +61 -59
- package/lib/api/options.js +4 -2
- package/lib/api/validate.js +2 -2
- package/lib/base/cleanSymbols.js +2 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +6 -6
- package/lib/base/location.js +11 -12
- package/lib/base/message-registry.js +177 -58
- package/lib/base/messages.js +252 -180
- package/lib/base/model.js +14 -11
- package/lib/base/node-helpers.js +9 -10
- package/lib/base/optionProcessorHelper.js +138 -129
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +5 -5
- package/lib/checks/annotationsOData.js +4 -4
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +3 -3
- package/lib/checks/defaultValues.js +3 -3
- package/lib/checks/elements.js +7 -7
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +4 -4
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/managedWithoutKeys.js +1 -1
- package/lib/checks/nonexpandableStructured.js +5 -3
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +5 -6
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -2
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +4 -4
- package/lib/checks/types.js +7 -7
- package/lib/checks/utils.js +4 -4
- package/lib/checks/validator.js +16 -13
- package/lib/compiler/.eslintrc.json +4 -1
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/builtins.js +14 -14
- package/lib/compiler/checks.js +123 -48
- package/lib/compiler/define.js +12 -13
- package/lib/compiler/extend.js +266 -60
- package/lib/compiler/finalize-parse-cdl.js +10 -5
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +14 -6
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +27 -16
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +20 -0
- package/lib/edm/annotations/genericTranslation.js +604 -358
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +275 -222
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +6 -6
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +107 -77
- package/lib/edm/edmUtils.js +44 -5
- package/lib/gen/Dictionary.json +210 -8
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +67 -63
- package/lib/gen/language.tokens +81 -81
- package/lib/gen/languageLexer.interp +4 -10
- package/lib/gen/languageLexer.js +854 -869
- package/lib/gen/languageLexer.tokens +79 -81
- package/lib/gen/languageParser.js +14309 -13832
- package/lib/inspect/inspectModelStatistics.js +2 -2
- package/lib/inspect/inspectPropagation.js +6 -6
- package/lib/inspect/inspectUtils.js +2 -2
- package/lib/json/from-csn.js +102 -55
- package/lib/json/to-csn.js +119 -198
- package/lib/language/antlrParser.js +5 -2
- package/lib/language/docCommentParser.js +6 -6
- package/lib/language/errorStrategy.js +43 -23
- package/lib/language/genericAntlrParser.js +113 -133
- package/lib/language/language.g4 +1550 -1506
- package/lib/language/multiLineStringParser.js +3 -3
- package/lib/language/textUtils.js +2 -2
- package/lib/main.js +3 -3
- package/lib/model/csnRefs.js +5 -0
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/compare.js +2 -2
- package/lib/modelCompare/utils/.eslintrc.json +22 -0
- package/lib/modelCompare/utils/filter.js +100 -0
- package/lib/optionProcessor.js +5 -0
- package/lib/render/.eslintrc.json +1 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +311 -276
- package/lib/render/toHdbcds.js +97 -94
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +127 -223
- package/lib/render/utils/common.js +141 -108
- package/lib/render/utils/delta.js +227 -0
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/assertUnique.js +13 -12
- package/lib/transform/db/associations.js +5 -5
- package/lib/transform/db/cdsPersistence.js +10 -8
- package/lib/transform/db/constraints.js +14 -14
- package/lib/transform/db/expansion.js +20 -22
- package/lib/transform/db/flattening.js +24 -42
- package/lib/transform/db/groupByOrderBy.js +3 -3
- package/lib/transform/db/temporal.js +6 -6
- package/lib/transform/db/transformExists.js +23 -23
- package/lib/transform/db/views.js +16 -16
- package/lib/transform/draft/.eslintrc.json +1 -35
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +8 -29
- package/lib/transform/forRelationalDB.js +16 -6
- package/lib/transform/localized.js +11 -10
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +113 -47
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +17 -10
- package/lib/transform/translateAssocsToJoins.js +24 -19
- package/lib/transform/universalCsn/coreComputed.js +10 -10
- package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
- package/lib/transform/universalCsn/utils.js +3 -3
- package/lib/utils/file.js +5 -5
- package/lib/utils/moduleResolve.js +13 -13
- package/lib/utils/objectUtils.js +6 -6
- package/lib/utils/term.js +5 -2
- package/lib/utils/timetrace.js +51 -24
- package/package.json +5 -8
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/redirected-to-complex.md +4 -4
- package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
- package/lib/modelCompare/filter.js +0 -83
package/lib/edm/csn2edm.js
CHANGED
|
@@ -9,7 +9,7 @@ const VALUELIST_NAVPROP_PREFIX = '';
|
|
|
9
9
|
const edmUtils = require('./edmUtils.js')
|
|
10
10
|
const { initializeModel } = require('./edmPreprocessor.js');
|
|
11
11
|
const translate = require('./annotations/genericTranslation.js');
|
|
12
|
-
const { setProp } = require('../base/model');
|
|
12
|
+
const { setProp, isBetaEnabled } = require('../base/model');
|
|
13
13
|
const { cloneCsnNonDict, isEdmPropertyRendered, isBuiltinType } = require('../model/csnUtils');
|
|
14
14
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
15
15
|
const { makeMessageFunction } = require('../base/messages');
|
|
@@ -30,7 +30,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
30
30
|
|
|
31
31
|
// use original options for messages; cloned CSN for semantic location
|
|
32
32
|
const messageFunctions = makeMessageFunction(csn, _options, 'to.edmx');
|
|
33
|
-
const { info, warning, error, message,
|
|
33
|
+
const { info, warning, error, message, throwWithError } = messageFunctions;
|
|
34
34
|
checkCSNVersion(csn, _options);
|
|
35
35
|
|
|
36
36
|
let rc = Object.create(null);
|
|
@@ -43,7 +43,8 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
43
43
|
setProp(csn.meta, 'options', _csn.meta.options);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const [
|
|
46
|
+
const [
|
|
47
|
+
allServices,
|
|
47
48
|
allSchemas,
|
|
48
49
|
reqDefs,
|
|
49
50
|
whatsMyServiceRootName,
|
|
@@ -54,7 +55,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
54
55
|
|
|
55
56
|
const v = options.v;
|
|
56
57
|
if(Object.keys(allServices).length === 0) {
|
|
57
|
-
info(null, null,
|
|
58
|
+
info(null, null, 'No Services in model');
|
|
58
59
|
return rc;
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -76,7 +77,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
76
77
|
services[serviceCsn.name] = createEdm(serviceCsn);
|
|
77
78
|
return services; }, rc);
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
throwWithError();
|
|
80
81
|
return rc;
|
|
81
82
|
|
|
82
83
|
//--------------------------------------------------------------------------------
|
|
@@ -91,6 +92,8 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
91
92
|
// let alias = serviceCsn.alias || baseName(baseName(serviceCsn.name, '::'), '.');
|
|
92
93
|
// FIXME: UI5 cannot deal with spec conforming simpleid alias names
|
|
93
94
|
|
|
95
|
+
function markRendered(def) { setProp(def, '$isRendered', true); }
|
|
96
|
+
|
|
94
97
|
const service = new Edm.DataServices(v);
|
|
95
98
|
/** @type {object} */
|
|
96
99
|
const edm = new Edm.Edm(v, service);
|
|
@@ -135,6 +138,24 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
135
138
|
return fqSchemaXRef.reduce((rc, sn) => !rc && n && n.startsWith(sn + '.') ? sn : rc, undefined);
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
// tunnel schema xref and servicename in options to edm.Typebase to rectify
|
|
142
|
+
// type references that are eventually also prefixed with the service schema name.
|
|
143
|
+
options.serviceName = serviceCsn.name;
|
|
144
|
+
// List of all schema names in this service, including the service itself
|
|
145
|
+
options.whatsMySchemaName = whatsMySchemaName;
|
|
146
|
+
options.whatsMyServiceRootName = whatsMyServiceRootName;
|
|
147
|
+
|
|
148
|
+
let xServiceRefs = {};
|
|
149
|
+
const UsedTypes = {};
|
|
150
|
+
function collectUsedType(csn, typeName = (csn.items?.type || csn.type)) {
|
|
151
|
+
if(typeName) {
|
|
152
|
+
if(UsedTypes[typeName])
|
|
153
|
+
UsedTypes[typeName].push(csn)
|
|
154
|
+
else
|
|
155
|
+
UsedTypes[typeName] = [ csn ];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
138
159
|
// create schema containers
|
|
139
160
|
const subSchemaDictionary = {
|
|
140
161
|
[serviceCsn.name]: {
|
|
@@ -147,26 +168,24 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
147
168
|
};
|
|
148
169
|
|
|
149
170
|
if(options.isV4()) {
|
|
150
|
-
// tunnel schema xref and servicename in options to edm.Typebase to rectify
|
|
151
|
-
// type references that are eventually also prefixed with the service schema name.
|
|
152
|
-
options.serviceName = serviceCsn.name;
|
|
153
|
-
// List of all schema names in this service, including the service itself
|
|
154
|
-
options.whatsMySchemaName = whatsMySchemaName;
|
|
155
|
-
|
|
156
171
|
// Add additional schema containers as sub contexts to the service
|
|
157
172
|
Object.entries(allSchemas).forEach(([fqName, art]) => {
|
|
158
173
|
if(serviceCsn.name === whatsMyServiceRootName(fqName) &&
|
|
159
|
-
fqName.startsWith(serviceCsn.name + '.')
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
name
|
|
165
|
-
fqName,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
fqName.startsWith(serviceCsn.name + '.')) {
|
|
175
|
+
if(art.kind === 'reference')
|
|
176
|
+
fqSchemaXRef.push(fqName);
|
|
177
|
+
if(art.kind === 'schema') {
|
|
178
|
+
fqSchemaXRef.push(fqName);
|
|
179
|
+
// Strip the toplevel service schema name (see comment above)
|
|
180
|
+
const name = fqName.replace(serviceCsn.name + '.', '');
|
|
181
|
+
subSchemaDictionary[name] = {
|
|
182
|
+
name,
|
|
183
|
+
fqName,
|
|
184
|
+
_csn: art,
|
|
185
|
+
container: false,
|
|
186
|
+
definitions: Object.create(null)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
170
189
|
}
|
|
171
190
|
}, subSchemaDictionary);
|
|
172
191
|
|
|
@@ -175,20 +194,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
175
194
|
|
|
176
195
|
// Fill the schemas and references, fqSchemaXRef must be complete
|
|
177
196
|
populateSchemas(subSchemaDictionary);
|
|
178
|
-
|
|
179
|
-
/* TODO:
|
|
180
|
-
const references = Object.entries(allSchemas).reduce((references, [fqName, art]) => {
|
|
181
|
-
// add references
|
|
182
|
-
if(fqName.startsWith(serviceCsn.name + '.') && art.kind === 'reference') {
|
|
183
|
-
fqSchemaXRef.push(fqName);
|
|
184
|
-
references.push(art);
|
|
185
|
-
}
|
|
186
|
-
return references;
|
|
187
|
-
}, []);
|
|
188
|
-
*/
|
|
189
|
-
// Add xrefs to full schema cross ref list for further usage
|
|
190
|
-
fqSchemaXRef.push(...xServiceRefs);
|
|
191
|
-
fqSchemaXRef.sort((a,b) => b.length-a.length);
|
|
197
|
+
xServiceRefs = populateXserviceRefs();
|
|
192
198
|
|
|
193
199
|
// Bring the schemas in alphabetical order, service first, root last
|
|
194
200
|
const sortedSchemaNames = Object.keys(subSchemaDictionary).filter(n => n !== fallBackSchemaName && n !== serviceCsn.name).sort();
|
|
@@ -203,13 +209,6 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
203
209
|
const schema = subSchemaDictionary[name];
|
|
204
210
|
service.registerSchema(schema.fqName, createSchema(schema));
|
|
205
211
|
});
|
|
206
|
-
|
|
207
|
-
// Add cross service references to the EDM
|
|
208
|
-
xServiceRefs.forEach(ref => {
|
|
209
|
-
let r = new Edm.Reference(v, ref.ref);
|
|
210
|
-
r.append(new Edm.Include(v, ref.inc))
|
|
211
|
-
edm._defaultRefs.push(r);
|
|
212
|
-
});
|
|
213
212
|
}
|
|
214
213
|
else {
|
|
215
214
|
populateSchemas(subSchemaDictionary);
|
|
@@ -223,13 +222,55 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
223
222
|
service._children.forEach(c => {
|
|
224
223
|
c._ec && Object.entries(c._ec._registry).forEach((([setName, arr]) => {
|
|
225
224
|
if(arr.length > 1) {
|
|
226
|
-
error(null, null, {
|
|
227
|
-
|
|
225
|
+
error(null, null, {
|
|
226
|
+
name: c._edmAttributes.Namespace,
|
|
227
|
+
id: setName,
|
|
228
|
+
names: arr.map(a => a.getDuplicateMessage())
|
|
229
|
+
}, 'Namespace $(NAME): Duplicate entries in EntityContainer with Name=$(ID) for $(NAMES)');
|
|
228
230
|
}
|
|
229
231
|
}));
|
|
230
232
|
});
|
|
231
|
-
// Create annotations and distribute into Schemas
|
|
232
|
-
addAnnotations();
|
|
233
|
+
// Create annotations and distribute into Schemas, merge vocabulary cross refs into xServiceRefs
|
|
234
|
+
addAnnotations(xServiceRefs);
|
|
235
|
+
|
|
236
|
+
// Finally add cross service references into the EDM and extract the targetSchemaNames
|
|
237
|
+
// for the type cross check
|
|
238
|
+
Object.values(xServiceRefs).forEach(ref => {
|
|
239
|
+
let r = new Edm.Reference(v, ref.ref);
|
|
240
|
+
r.append(new Edm.Include(v, ref.inc))
|
|
241
|
+
edm._defaultRefs.push(r);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
for(let typeName in UsedTypes) {
|
|
245
|
+
if(!isBuiltinType(typeName)) {
|
|
246
|
+
let iTypeName = typeName;
|
|
247
|
+
/*
|
|
248
|
+
Report type ref, if the type is
|
|
249
|
+
- not a builtin,
|
|
250
|
+
- not included in required definitions
|
|
251
|
+
- not a type clash (reported in type exposure),
|
|
252
|
+
- a @cds.external service member but can't be rendered
|
|
253
|
+
*/
|
|
254
|
+
if(!typeName.startsWith(serviceCsn.name + '.'))
|
|
255
|
+
iTypeName = serviceCsn.name + '.' + typeName;
|
|
256
|
+
const def = reqDefs.definitions[iTypeName];
|
|
257
|
+
|
|
258
|
+
const usages = UsedTypes[typeName].filter(u => !u.$NameClashReported);
|
|
259
|
+
if(usages.length > 0 && def && !def.$isRendered && def['@cds.external']) {
|
|
260
|
+
message('odata-spec-violation-type', usages[0].$location,
|
|
261
|
+
{
|
|
262
|
+
type: typeName,
|
|
263
|
+
anno: '@cds.external',
|
|
264
|
+
name: serviceCsn.name,
|
|
265
|
+
code: def.elements ? 'Edm.ComplexType' : 'Edm.TypeDefinition',
|
|
266
|
+
version: options.isV4() ? '4.0' : '2.0',
|
|
267
|
+
'#': 'external'
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
233
274
|
return edm
|
|
234
275
|
|
|
235
276
|
// Sort definitions into their schema container
|
|
@@ -289,12 +330,13 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
289
330
|
|
|
290
331
|
return Object.entries(allSchemas).reduce((references, [fqName, art]) => {
|
|
291
332
|
// add references
|
|
292
|
-
if(art.kind === 'reference' &&
|
|
293
|
-
|
|
294
|
-
|
|
333
|
+
if(art.kind === 'reference' &&
|
|
334
|
+
whatsMySchemaName(fqName) &&
|
|
335
|
+
serviceCsn.name === whatsMyServiceRootName(fqName, false)) {
|
|
336
|
+
references[art.inc.Namespace] = art;
|
|
295
337
|
}
|
|
296
338
|
return references;
|
|
297
|
-
},
|
|
339
|
+
}, {});
|
|
298
340
|
}
|
|
299
341
|
|
|
300
342
|
// Main schema creator function
|
|
@@ -331,25 +373,31 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
331
373
|
*/
|
|
332
374
|
edmUtils.foreach(schemaCsn.definitions,
|
|
333
375
|
a => a.kind === 'entity' && !a.abstract && a.name.startsWith(schemaNamePrefix),
|
|
334
|
-
createEntityTypeAndSet
|
|
376
|
+
[createEntityTypeAndSet, markRendered]
|
|
335
377
|
);
|
|
336
378
|
// create unbound actions/functions
|
|
337
|
-
edmUtils.foreach(schemaCsn.definitions,
|
|
379
|
+
edmUtils.foreach(schemaCsn.definitions,
|
|
338
380
|
a => (a.kind === 'action' || a.kind === 'function') && a.name.startsWith(schemaNamePrefix),
|
|
339
|
-
(options.isV4()) ? createActionV4 : createActionV2);
|
|
381
|
+
[(options.isV4()) ? createActionV4 : createActionV2, markRendered]);
|
|
340
382
|
|
|
341
383
|
// create the complex types
|
|
342
384
|
edmUtils.foreach(schemaCsn.definitions,
|
|
343
385
|
a => edmUtils.isStructuredType(a) && a.name.startsWith(schemaNamePrefix),
|
|
344
|
-
createComplexType);
|
|
386
|
+
[createComplexType, markRendered]);
|
|
345
387
|
|
|
346
388
|
if(options.isV4())
|
|
347
389
|
{
|
|
348
390
|
edmUtils.foreach(schemaCsn.definitions,
|
|
349
391
|
artifact => edmUtils.isDerivedType(artifact) &&
|
|
350
|
-
!artifact.target
|
|
392
|
+
!artifact.target&&
|
|
351
393
|
artifact.name.startsWith(schemaNamePrefix),
|
|
352
|
-
|
|
394
|
+
[createTypeDefinitionV4, markRendered]);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if(isBetaEnabled(options, 'odataTerms')) {
|
|
398
|
+
edmUtils.foreach(schemaCsn.definitions,
|
|
399
|
+
a => a.kind === 'annotation' && a.name.startsWith(schemaNamePrefix),
|
|
400
|
+
createTerm);
|
|
353
401
|
}
|
|
354
402
|
|
|
355
403
|
// fetch all exising children names in a map
|
|
@@ -370,19 +418,10 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
370
418
|
np.addReferentialConstraintNodes();
|
|
371
419
|
}
|
|
372
420
|
else {
|
|
373
|
-
|
|
421
|
+
addAssociationV2(np);
|
|
374
422
|
}
|
|
375
423
|
});
|
|
376
424
|
|
|
377
|
-
// remove EntityContainer if empty
|
|
378
|
-
if(Schema._ec && Schema._ec._children.length === 0) {
|
|
379
|
-
Schema._children.splice(Schema._children.indexOf(Schema._ec), 1);
|
|
380
|
-
}
|
|
381
|
-
if(Schema._children.length === 0) {
|
|
382
|
-
// FIXME: Location for sub schemas?
|
|
383
|
-
warning(null, ['definitions', Schema._edmAttributes.Namespace], { name: Schema._edmAttributes.Namespace }, 'Schema $(NAME) is empty');
|
|
384
|
-
}
|
|
385
|
-
|
|
386
425
|
Object.entries(NamesInSchemaXRef).forEach(([name, refs]) => {
|
|
387
426
|
if(refs.length > 1) {
|
|
388
427
|
error(null, ['definitions', `${Schema._edmAttributes.Namespace}.${name}`], { name: Schema._edmAttributes.Namespace },
|
|
@@ -413,7 +452,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
413
452
|
const pLoc = [...loc, 'elements', p._edmAttributes.Name];
|
|
414
453
|
edmTypeCompatibilityCheck(p, pLoc);
|
|
415
454
|
if(p._edmAttributes.Name === EntityTypeName)
|
|
416
|
-
message('odata-spec-violation-property-name', pLoc, {
|
|
455
|
+
message('odata-spec-violation-property-name', pLoc, { meta: entityCsn.kind });
|
|
417
456
|
|
|
418
457
|
if(options.isV2() && p._isCollection && !p._csn.target)
|
|
419
458
|
message('odata-spec-violation-array', pLoc, { version: '2.0' });
|
|
@@ -468,6 +507,140 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
468
507
|
});
|
|
469
508
|
}
|
|
470
509
|
|
|
510
|
+
function createComplexType(structuredTypeCsn)
|
|
511
|
+
{
|
|
512
|
+
// V4 attributes: Name, BaseType, Abstract, OpenType
|
|
513
|
+
const attributes = { Name: structuredTypeCsn.name.replace(schemaNamePrefix, '') };
|
|
514
|
+
|
|
515
|
+
const complexType = new Edm.ComplexType(v, attributes, structuredTypeCsn);
|
|
516
|
+
const elementsCsn = structuredTypeCsn.items || structuredTypeCsn;
|
|
517
|
+
const properties = createProperties(elementsCsn, structuredTypeCsn)[0];
|
|
518
|
+
const loc = ['definitions', structuredTypeCsn.name];
|
|
519
|
+
|
|
520
|
+
if(properties.length === 0) {
|
|
521
|
+
warning(null, loc, { name: structuredTypeCsn.name },
|
|
522
|
+
'EDM ComplexType $(NAME) has no properties');
|
|
523
|
+
}
|
|
524
|
+
if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
|
|
525
|
+
message('odata-spec-violation-id', loc, { id: attributes.Name });
|
|
526
|
+
|
|
527
|
+
properties.forEach(p => {
|
|
528
|
+
const pLoc = [ ...loc, ...(structuredTypeCsn.items ? ['items', 'elements'] : [ 'elements' ]), p._edmAttributes.Name ];
|
|
529
|
+
edmTypeCompatibilityCheck(p, pLoc);
|
|
530
|
+
if(p._edmAttributes.Name === complexType._edmAttributes.Name)
|
|
531
|
+
message('odata-spec-violation-property-name', pLoc, { meta: structuredTypeCsn.kind });
|
|
532
|
+
|
|
533
|
+
if(!edmUtils.isODataSimpleIdentifier(p._edmAttributes.Name))
|
|
534
|
+
message('odata-spec-violation-id', pLoc, { id: p._edmAttributes.Name });
|
|
535
|
+
|
|
536
|
+
if(options.isV2()) {
|
|
537
|
+
if(p._isCollection && !p._csn.target)
|
|
538
|
+
message('odata-spec-violation-array', pLoc, { version: '2.0' });
|
|
539
|
+
|
|
540
|
+
if(p._csn.target)
|
|
541
|
+
message('odata-spec-violation-assoc', pLoc, { version: '2.0' });
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
complexType.append(...(properties));
|
|
547
|
+
|
|
548
|
+
Schema.append(complexType);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* @param {object} elementsCsn
|
|
553
|
+
* @param {object} edmParentCsn
|
|
554
|
+
* @returns {[object[], any]} Returns a [ [ Edm Properties ], boolean hasStream ]:
|
|
555
|
+
* array of Edm Properties
|
|
556
|
+
* hasStream : value of @Core.MediaType assignment
|
|
557
|
+
*/
|
|
558
|
+
function createProperties(elementsCsn, edmParentCsn=elementsCsn)
|
|
559
|
+
{
|
|
560
|
+
const props = [];
|
|
561
|
+
let hasStream = false;
|
|
562
|
+
const streamProps = [];
|
|
563
|
+
|
|
564
|
+
elementsCsn.elements && Object.entries(elementsCsn.elements).forEach(([elementName, elementCsn]) =>
|
|
565
|
+
{
|
|
566
|
+
if(elementCsn._edmParentCsn == undefined)
|
|
567
|
+
setProp(elementCsn, '_edmParentCsn', edmParentCsn);
|
|
568
|
+
|
|
569
|
+
if(elementCsn.target) {
|
|
570
|
+
// Foreign keys are part of the generic elementCsn.elements property creation
|
|
571
|
+
|
|
572
|
+
// This is the V4 edmx:NavigationProperty
|
|
573
|
+
// gets rewritten for V2 in addAssociations()
|
|
574
|
+
|
|
575
|
+
// suppress navprop creation only if @odata.navigable:false is not annotated.
|
|
576
|
+
// (undefined !== false) still evaluates to true
|
|
577
|
+
if (!elementCsn._target.abstract && elementCsn['@odata.navigable'] !== false)
|
|
578
|
+
{
|
|
579
|
+
const navProp = new Edm.NavigationProperty(v, {
|
|
580
|
+
Name: elementName,
|
|
581
|
+
Type: elementCsn._target.name
|
|
582
|
+
}, elementCsn);
|
|
583
|
+
collectUsedType(elementCsn, elementCsn._target.name);
|
|
584
|
+
props.push(navProp);
|
|
585
|
+
// save the navProp in the global array for late constraint building
|
|
586
|
+
navigationProperties.push(navProp);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// render ordinary property if element is NOT ...
|
|
590
|
+
// 1) ... annotated @cds.api.ignore
|
|
591
|
+
// 2) ... annotated @odata.foreignKey4 and odataFormat: structured
|
|
592
|
+
|
|
593
|
+
else if(isEdmPropertyRendered(elementCsn, options))
|
|
594
|
+
{
|
|
595
|
+
// CDXCORE-CDXCORE-173
|
|
596
|
+
// V2: filter @Core.MediaType
|
|
597
|
+
if ( options.isV2() && elementCsn['@Core.MediaType']) {
|
|
598
|
+
hasStream = elementCsn['@Core.MediaType'];
|
|
599
|
+
delete elementCsn['@Core.MediaType'];
|
|
600
|
+
// CDXCORE-CDXCORE-177:
|
|
601
|
+
// V2: don't render element but add attribute 'm:HasStream="true' to EntityType
|
|
602
|
+
// V4: render property type 'Edm.Stream'
|
|
603
|
+
streamProps.push(elementName);
|
|
604
|
+
|
|
605
|
+
} else {
|
|
606
|
+
collectUsedType(elementCsn);
|
|
607
|
+
props.push(new Edm.Property(v, { Name: elementName }, elementCsn));
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
});
|
|
612
|
+
if(options.isV2()) {
|
|
613
|
+
if(streamProps.length > 1) { // TODO: why not mention 2.0 in text?
|
|
614
|
+
error(null, ['definitions', elementsCsn.name], { names: streamProps, version: '2.0', anno: '@Core.MediaType' },
|
|
615
|
+
'Expected only one element to be annotated with $(ANNO) for OData $(VERSION) but found $(NAMES)');
|
|
616
|
+
}
|
|
617
|
+
else if(streamProps.length === 1) {
|
|
618
|
+
info(null, ['definitions', elementsCsn.name], { id: streamProps[0], version: '2.0', anno: '@Core.MediaType' },
|
|
619
|
+
'Property $(ID) annotated with $(ANNO) is removed from EDM for OData $(VERSION)');
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return [ props, hasStream ];
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function createTerm(termCsn) {
|
|
626
|
+
const attributes = { Name: termCsn.name.replace(schemaNamePrefix, '') };
|
|
627
|
+
const term = new Edm.Term(v, attributes, termCsn);
|
|
628
|
+
Schema.append(term);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// V4 <TypeDefintion>
|
|
632
|
+
function createTypeDefinitionV4(typeCsn)
|
|
633
|
+
{
|
|
634
|
+
// derived types are already resolved to base types
|
|
635
|
+
const attributes = { Name: typeCsn.name.replace(schemaNamePrefix, '') };
|
|
636
|
+
if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
|
|
637
|
+
message('odata-spec-violation-id', ['definitions', typeCsn.name], { id: attributes.Name });
|
|
638
|
+
|
|
639
|
+
const typeDef = new Edm.TypeDefinition(v, attributes, typeCsn );
|
|
640
|
+
edmTypeCompatibilityCheck(typeDef, [ 'definitions', typeCsn.name ]);
|
|
641
|
+
Schema.append(typeDef);
|
|
642
|
+
}
|
|
643
|
+
|
|
471
644
|
// add bound/unbound actions/functions for V4
|
|
472
645
|
function createActionV4(actionCsn, _name, entityCsn=undefined)
|
|
473
646
|
{
|
|
@@ -528,7 +701,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
528
701
|
const pLoc = [ ...loc, 'params', p._edmAttributes.Name ];
|
|
529
702
|
if(!edmUtils.isODataSimpleIdentifier(parameterName))
|
|
530
703
|
message('odata-spec-violation-id', pLoc, { id: parameterName });
|
|
531
|
-
|
|
704
|
+
collectUsedType(parameterCsn);
|
|
532
705
|
edmTypeCompatibilityCheck(p, pLoc);
|
|
533
706
|
actionNode.append(p);
|
|
534
707
|
});
|
|
@@ -536,6 +709,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
536
709
|
// return type if any
|
|
537
710
|
if(actionCsn.returns) {
|
|
538
711
|
actionNode._returnType = new Edm.ReturnType(v, actionCsn.returns);
|
|
712
|
+
collectUsedType(actionCsn.returns);
|
|
539
713
|
edmTypeCompatibilityCheck(actionNode._returnType, [ ...loc, 'returns' ]);
|
|
540
714
|
// if binding type matches return type add attribute EntitySetPath
|
|
541
715
|
if(entityCsn != undefined && fullQualified(entityCsn.name) === actionNode._returnType._type) {
|
|
@@ -617,6 +791,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
617
791
|
actionCsn.params && Object.entries(actionCsn.params).forEach(([parameterName, parameterCsn]) => {
|
|
618
792
|
const pLoc = [...loc, 'params', parameterName];
|
|
619
793
|
const param = new Edm.Parameter(v, { Name: parameterName }, parameterCsn, 'In' );
|
|
794
|
+
collectUsedType(parameterCsn);
|
|
620
795
|
edmTypeCompatibilityCheck(param, pLoc);
|
|
621
796
|
if(!edmUtils.isODataSimpleIdentifier(parameterName))
|
|
622
797
|
message('odata-spec-violation-id', pLoc, { id: parameterName });
|
|
@@ -644,6 +819,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
644
819
|
const returns = action.returns.items || action.returns;
|
|
645
820
|
let type = returns.type;
|
|
646
821
|
if (type) {
|
|
822
|
+
collectUsedType(action.returns);
|
|
647
823
|
if (!isBuiltinType(type) && csn.definitions[type].kind !== 'entity' && csn.definitions[type].kind !== 'type') {
|
|
648
824
|
message('odata-spec-violation-returns', returnsLoc, { kind: action.kind, version: '2.0' });
|
|
649
825
|
}
|
|
@@ -671,147 +847,21 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
671
847
|
}
|
|
672
848
|
}
|
|
673
849
|
|
|
674
|
-
/**
|
|
675
|
-
* @param {object} elementsCsn
|
|
676
|
-
* @param {object} edmParentCsn
|
|
677
|
-
* @returns {[object[], any]} Returns a [ [ Edm Properties ], boolean hasStream ]:
|
|
678
|
-
* array of Edm Properties
|
|
679
|
-
* hasStream : value of @Core.MediaType assignment
|
|
680
|
-
*/
|
|
681
|
-
function createProperties(elementsCsn, edmParentCsn=elementsCsn)
|
|
682
|
-
{
|
|
683
|
-
const props = [];
|
|
684
|
-
let hasStream = false;
|
|
685
|
-
const streamProps = [];
|
|
686
|
-
|
|
687
|
-
elementsCsn.elements && Object.entries(elementsCsn.elements).forEach(([elementName, elementCsn]) =>
|
|
688
|
-
{
|
|
689
|
-
if(elementCsn._edmParentCsn == undefined)
|
|
690
|
-
setProp(elementCsn, '_edmParentCsn', edmParentCsn);
|
|
691
|
-
|
|
692
|
-
if(elementCsn.target) {
|
|
693
|
-
// Foreign keys are part of the generic elementCsn.elements property creation
|
|
694
|
-
|
|
695
|
-
// This is the V4 edmx:NavigationProperty
|
|
696
|
-
// gets rewritten for V2 in addAssociations()
|
|
697
|
-
|
|
698
|
-
// suppress navprop creation only if @odata.navigable:false is not annotated.
|
|
699
|
-
// (undefined !== false) still evaluates to true
|
|
700
|
-
if (!elementCsn._target.abstract && elementCsn['@odata.navigable'] !== false)
|
|
701
|
-
{
|
|
702
|
-
const navProp = new Edm.NavigationProperty(v, {
|
|
703
|
-
Name: elementName,
|
|
704
|
-
Type: elementCsn._target.name
|
|
705
|
-
}, elementCsn);
|
|
706
|
-
props.push(navProp);
|
|
707
|
-
// save the navProp in the global array for late constraint building
|
|
708
|
-
navigationProperties.push(navProp);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
// render ordinary property if element is NOT ...
|
|
712
|
-
// 1) ... annotated @cds.api.ignore
|
|
713
|
-
// 2) ... annotated @odata.foreignKey4 and odataFormat: structured
|
|
714
|
-
|
|
715
|
-
else if(isEdmPropertyRendered(elementCsn, options))
|
|
716
|
-
{
|
|
717
|
-
// CDXCORE-CDXCORE-173
|
|
718
|
-
// V2: filter @Core.MediaType
|
|
719
|
-
if ( options.isV2() && elementCsn['@Core.MediaType']) {
|
|
720
|
-
hasStream = elementCsn['@Core.MediaType'];
|
|
721
|
-
delete elementCsn['@Core.MediaType'];
|
|
722
|
-
// CDXCORE-CDXCORE-177:
|
|
723
|
-
// V2: don't render element but add attribute 'm:HasStream="true' to EntityType
|
|
724
|
-
// V4: render property type 'Edm.Stream'
|
|
725
|
-
streamProps.push(elementName);
|
|
726
|
-
|
|
727
|
-
} else {
|
|
728
|
-
props.push(new Edm.Property(v, { Name: elementName }, elementCsn));
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
});
|
|
733
|
-
if(options.isV2()) {
|
|
734
|
-
if(streamProps.length > 1) { // TODO: why not mention 2.0 in text?
|
|
735
|
-
error(null, ['definitions', elementsCsn.name], { names: streamProps, version: '2.0', anno: '@Core.MediaType' },
|
|
736
|
-
`Expected only one element to be annotated with $(ANNO) for OData $(VERSION) but found $(NAMES)`);
|
|
737
|
-
}
|
|
738
|
-
else if(streamProps.length === 1) {
|
|
739
|
-
info(null, ['definitions', elementsCsn.name], { id: streamProps[0], version: '2.0', anno: '@Core.MediaType' },
|
|
740
|
-
'Property $(ID) annotated with $(ANNO) is removed from EDM for OData $(VERSION)');
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return [ props, hasStream ];
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
function createComplexType(structuredTypeCsn)
|
|
747
|
-
{
|
|
748
|
-
// V4 attributes: Name, BaseType, Abstract, OpenType
|
|
749
|
-
const attributes = { Name: structuredTypeCsn.name.replace(schemaNamePrefix, '') };
|
|
750
|
-
|
|
751
|
-
const complexType = new Edm.ComplexType(v, attributes, structuredTypeCsn);
|
|
752
|
-
const elementsCsn = structuredTypeCsn.items || structuredTypeCsn;
|
|
753
|
-
const properties = createProperties(elementsCsn, structuredTypeCsn)[0];
|
|
754
|
-
const loc = ['definitions', structuredTypeCsn.name];
|
|
755
|
-
|
|
756
|
-
if(properties.length === 0) {
|
|
757
|
-
warning(null, loc, { name: structuredTypeCsn.name },
|
|
758
|
-
'EDM ComplexType $(NAME) has no properties');
|
|
759
|
-
}
|
|
760
|
-
if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
|
|
761
|
-
message('odata-spec-violation-id', loc, { id: attributes.Name });
|
|
762
|
-
|
|
763
|
-
properties.forEach(p => {
|
|
764
|
-
const pLoc = [ ...loc, ...(structuredTypeCsn.items ? ['items', 'elements'] : [ 'elements' ]), p._edmAttributes.Name ];
|
|
765
|
-
edmTypeCompatibilityCheck(p, pLoc);
|
|
766
|
-
if(p._edmAttributes.Name === complexType._edmAttributes.Name)
|
|
767
|
-
message('odata-spec-violation-property-name', pLoc, { kind: structuredTypeCsn.kind });
|
|
768
|
-
|
|
769
|
-
if(!edmUtils.isODataSimpleIdentifier(p._edmAttributes.Name))
|
|
770
|
-
message('odata-spec-violation-id', pLoc, { id: p._edmAttributes.Name });
|
|
771
|
-
|
|
772
|
-
if(options.isV2()) {
|
|
773
|
-
if(p._isCollection && !p._csn.target)
|
|
774
|
-
message('odata-spec-violation-array', pLoc, { version: '2.0' });
|
|
775
|
-
|
|
776
|
-
if(p._csn.target)
|
|
777
|
-
message('odata-spec-violation-assoc', pLoc, { version: '2.0' });
|
|
778
|
-
}
|
|
779
|
-
});
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
complexType.append(...(properties));
|
|
783
|
-
|
|
784
|
-
Schema.append(complexType);
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// V4 <TypeDefintion>
|
|
788
|
-
function createTypeDefinition(typeCsn)
|
|
789
|
-
{
|
|
790
|
-
// derived types are already resolved to base types
|
|
791
|
-
const attributes = { Name: typeCsn.name.replace(schemaNamePrefix, '') };
|
|
792
|
-
if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
|
|
793
|
-
message('odata-spec-violation-id', ['definitions', typeCsn.name], { id: attributes.Name });
|
|
794
|
-
|
|
795
|
-
const typeDef = new Edm.TypeDefinition(v, attributes, typeCsn );
|
|
796
|
-
edmTypeCompatibilityCheck(typeDef, [ 'definitions', typeCsn.name ]);
|
|
797
|
-
Schema.append(typeDef);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
850
|
/*
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
851
|
+
addAssociation() constructs a V2 association.
|
|
852
|
+
In V4 all this has been simplified very much, the only thing actually left over is
|
|
853
|
+
<ReferentialConstriant> that is then a sub element to <NavigationProperty>.
|
|
854
|
+
However, referential constraints are substantially different to its V2 counterpart,
|
|
855
|
+
so it is better to reimplement proper V4 construction of<NavigationProperty> in a separate
|
|
856
|
+
function.
|
|
857
|
+
|
|
858
|
+
This method does:
|
|
859
|
+
rewrite <NavigationProperty> attributes to be V2 compliant
|
|
860
|
+
add <Association> elements to the schema
|
|
861
|
+
add <End>, <ReferentialConstraint>, <Dependent> and <Principal> sub elements to <Association>
|
|
862
|
+
add <AssociationSet> to the EntityContainer for each <Association>
|
|
813
863
|
*/
|
|
814
|
-
function
|
|
864
|
+
function addAssociationV2(navigationProperty)
|
|
815
865
|
{
|
|
816
866
|
let constraints = navigationProperty._csn._constraints;
|
|
817
867
|
let parentName = navigationProperty._csn._edmParentCsn.name.replace(schemaNamePrefix, '');
|
|
@@ -930,8 +980,8 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
930
980
|
}
|
|
931
981
|
|
|
932
982
|
// generate the Edm.Annotations tree and append it to the corresponding schema
|
|
933
|
-
function addAnnotations() {
|
|
934
|
-
let { annos, usedVocabularies } = translate.csn2annotationEdm(reqDefs, serviceCsn.name, Edm, options, messageFunctions);
|
|
983
|
+
function addAnnotations(xServiceRefs) {
|
|
984
|
+
let { annos, usedVocabularies, xrefs } = translate.csn2annotationEdm(reqDefs, csn.vocabularies, serviceCsn.name, Edm, options, messageFunctions);
|
|
935
985
|
// distribute edm:Annotations into the schemas
|
|
936
986
|
// Distribute each anno into Schema
|
|
937
987
|
annos.forEach(anno => {
|
|
@@ -939,21 +989,24 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
|
|
|
939
989
|
// if no target schema has been found, it's a service annotation that applies to the service schema
|
|
940
990
|
if(targetSchema === undefined)
|
|
941
991
|
targetSchema = serviceCsn.name;
|
|
942
|
-
if(targetSchema) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
anno.setEdmAttribute('Target', newTarget);
|
|
946
|
-
}
|
|
947
|
-
edm._service._schemas[targetSchema]._annotations.push(anno);
|
|
992
|
+
if(targetSchema !== serviceCsn.name) {
|
|
993
|
+
const newTarget = anno._edmAttributes.Target.replace(serviceCsn.name + '.', '');
|
|
994
|
+
anno.setEdmAttribute('Target', newTarget);
|
|
948
995
|
}
|
|
996
|
+
edm._service._schemas[targetSchema]._annotations.push(anno);
|
|
949
997
|
});
|
|
950
998
|
annos = [];
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
999
|
+
|
|
1000
|
+
// create service cross reference and merge it into xServiceRefs
|
|
1001
|
+
xrefs.forEach(xr => {
|
|
1002
|
+
if(xr !== serviceCsn.name) {
|
|
1003
|
+
const art = edmUtils.createSchemaRef(allServices, xr);
|
|
1004
|
+
if(xServiceRefs[art.inc.Namespace] === undefined)
|
|
1005
|
+
xServiceRefs[art.inc.Namespace] = art;
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
// merge vocabulary cross references into xServiceRefs
|
|
1009
|
+
usedVocabularies.forEach(art => xServiceRefs[art.inc.Namespace] = art);
|
|
957
1010
|
}
|
|
958
1011
|
|
|
959
1012
|
function edmTypeCompatibilityCheck(p, pLoc) {
|