@sap/cds-compiler 4.0.0 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -5
- package/bin/cdsc.js +12 -12
- package/doc/CHANGELOG_BETA.md +11 -0
- package/lib/api/main.js +60 -12
- package/lib/api/validate.js +1 -1
- package/lib/base/location.js +6 -7
- package/lib/base/message-registry.js +84 -38
- package/lib/base/messages.js +11 -10
- package/lib/base/model.js +6 -2
- package/lib/checks/defaultValues.js +6 -6
- package/lib/checks/foreignKeys.js +0 -5
- package/lib/checks/onConditions.js +17 -12
- package/lib/checks/queryNoDbArtifacts.js +132 -72
- package/lib/checks/sql-snippets.js +15 -4
- package/lib/checks/types.js +3 -3
- package/lib/checks/utils.js +1 -1
- package/lib/compiler/assert-consistency.js +44 -16
- package/lib/compiler/base.js +1 -0
- package/lib/compiler/builtins.js +7 -8
- package/lib/compiler/checks.js +274 -197
- package/lib/compiler/classes.js +62 -0
- package/lib/compiler/cycle-detector.js +3 -3
- package/lib/compiler/define.js +63 -50
- package/lib/compiler/extend.js +38 -20
- package/lib/compiler/finalize-parse-cdl.js +2 -1
- package/lib/compiler/generate.js +0 -8
- package/lib/compiler/index.js +9 -7
- package/lib/compiler/kick-start.js +2 -0
- package/lib/compiler/populate.js +139 -110
- package/lib/compiler/propagator.js +4 -3
- package/lib/compiler/resolve.js +157 -126
- package/lib/compiler/shared.js +706 -404
- package/lib/compiler/tweak-assocs.js +21 -10
- package/lib/compiler/utils.js +228 -36
- package/lib/edm/annotations/genericTranslation.js +30 -2
- package/lib/edm/edm.js +4 -1
- package/lib/edm/edmPreprocessor.js +12 -5
- package/lib/edm/edmUtils.js +2 -4
- package/lib/gen/Dictionary.json +34 -10
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3987 -3963
- package/lib/json/from-csn.js +43 -47
- package/lib/json/to-csn.js +11 -11
- package/lib/language/antlrParser.js +2 -1
- package/lib/language/genericAntlrParser.js +52 -43
- package/lib/language/language.g4 +59 -59
- package/lib/language/multiLineStringParser.js +2 -0
- package/lib/main.d.ts +5 -0
- package/lib/model/csnRefs.js +37 -19
- package/lib/model/csnUtils.js +20 -16
- package/lib/model/revealInternalProperties.js +29 -21
- package/lib/model/sortViews.js +4 -2
- package/lib/modelCompare/compare.js +112 -39
- package/lib/modelCompare/utils/filter.js +54 -24
- package/lib/optionProcessor.js +6 -6
- package/lib/render/manageConstraints.js +20 -17
- package/lib/render/toCdl.js +34 -20
- package/lib/render/toHdbcds.js +2 -2
- package/lib/render/toRename.js +4 -9
- package/lib/render/toSql.js +77 -26
- package/lib/render/utils/common.js +3 -3
- package/lib/render/utils/unique.js +52 -0
- package/lib/transform/db/applyTransformations.js +61 -20
- package/lib/transform/db/assertUnique.js +7 -8
- package/lib/transform/db/associations.js +2 -2
- package/lib/transform/db/cdsPersistence.js +8 -8
- package/lib/transform/db/expansion.js +17 -21
- package/lib/transform/db/flattening.js +23 -23
- package/lib/transform/db/rewriteCalculatedElements.js +20 -14
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/db/transformExists.js +8 -7
- package/lib/transform/db/views.js +73 -33
- package/lib/transform/draft/db.js +11 -9
- package/lib/transform/draft/odata.js +1 -1
- package/lib/transform/{forOdataNew.js → forOdata.js} +56 -42
- package/lib/transform/forRelationalDB.js +69 -75
- package/lib/transform/localized.js +6 -5
- package/lib/transform/odata/toFinalBaseType.js +3 -3
- package/lib/transform/{transformUtilsNew.js → transformUtils.js} +4 -101
- package/lib/transform/translateAssocsToJoins.js +14 -28
- package/package.json +1 -1
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
- package/share/messages/message-explanations.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
|
-
getUtils, cloneCsnNonDict, applyTransformationsOnNonDictionary,
|
|
4
|
+
getUtils, cloneCsnNonDict, applyTransformationsOnNonDictionary, forEachDefinition,
|
|
5
5
|
} = require('../../model/csnUtils');
|
|
6
|
-
const { implicitAs } = require('../../model/csnRefs');
|
|
6
|
+
const { implicitAs, columnAlias } = require('../../model/csnRefs');
|
|
7
7
|
const { ModelError } = require('../../base/error');
|
|
8
|
+
const { setProp } = require('../../base/model');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* If a mixin association is published, return the mixin association.
|
|
@@ -66,10 +67,11 @@ function usesMixinAssociation( query, association, associationName ) {
|
|
|
66
67
|
* @returns {(query: CSN.Query, artifact: CSN.Artifact, artName: string, path: CSN.Path) => void} Transformer function for views
|
|
67
68
|
*/
|
|
68
69
|
function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
70
|
+
const csnUtils = getUtils(csn);
|
|
69
71
|
const {
|
|
70
72
|
get$combined, isAssocOrComposition,
|
|
71
73
|
inspectRef, queryOrMain, // csnRefs
|
|
72
|
-
} =
|
|
74
|
+
} = csnUtils;
|
|
73
75
|
const pathDelimiter = options.forHana && (options.sqlMapping === 'hdbcds') ? '.' : '_';
|
|
74
76
|
const { error, info } = messageFunctions;
|
|
75
77
|
const doA2J = !(options.transformation === 'hdbcds' && options.sqlMapping === 'hdbcds');
|
|
@@ -213,7 +215,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
213
215
|
else
|
|
214
216
|
info('query-ignoring-assoc-in-union', queryPath, { name: elemName, '#': 'std' });
|
|
215
217
|
|
|
216
|
-
elem
|
|
218
|
+
elem.$ignore = true;
|
|
217
219
|
}
|
|
218
220
|
else {
|
|
219
221
|
error(null, queryPath, { name: elemName }, 'Association $(NAME) can\'t be published in a SAP HANA CDS UNION');
|
|
@@ -270,7 +272,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
270
272
|
}, {}, elementsPath.concat(elemName));
|
|
271
273
|
}
|
|
272
274
|
|
|
273
|
-
if (!mixinElem
|
|
275
|
+
if (!mixinElem.$ignore)
|
|
274
276
|
columnMap[elemName] = { ref: [ mixinElemName ], as: elemName };
|
|
275
277
|
|
|
276
278
|
if (query.SELECT) {
|
|
@@ -311,7 +313,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
311
313
|
|
|
312
314
|
|
|
313
315
|
/**
|
|
314
|
-
* Loop over the columns and call all
|
|
316
|
+
* Loop over the columns and call all the given functions with the column and the path
|
|
315
317
|
*
|
|
316
318
|
* @param {Function[]} functions
|
|
317
319
|
* @param {CSN.Column[]} columns
|
|
@@ -332,6 +334,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
332
334
|
*/
|
|
333
335
|
// eslint-disable-next-line complexity
|
|
334
336
|
function transformViewOrEntity( query, artifact, artName, path ) {
|
|
337
|
+
csnUtils.initDefinition(artifact);
|
|
335
338
|
const { elements } = queryOrMain(query, artifact);
|
|
336
339
|
// We use the elements from the leading query/main artifact - adapt the path
|
|
337
340
|
const elementsPath = elements === artifact.elements ? path.slice(0, 2).concat('elements') : path.concat('elements');
|
|
@@ -340,7 +343,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
340
343
|
let hasNonAssocElements = false;
|
|
341
344
|
const isSelect = query && query.SELECT;
|
|
342
345
|
const isProjection = !!artifact.projection || query && query.SELECT && !query.SELECT.columns;
|
|
343
|
-
const columnMap = getColumnMap(query);
|
|
346
|
+
const columnMap = getColumnMap(query, csnUtils);
|
|
344
347
|
const isSelectStar = query && query.SELECT && query.SELECT.columns && query.SELECT.columns.indexOf('*') !== -1;
|
|
345
348
|
|
|
346
349
|
// check all queries/subqueries for mixin publishing inside of unions -> forbidden in hdbcds
|
|
@@ -365,7 +368,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
365
368
|
addForeignKeysToColumns(columnMap, elem, elemName);
|
|
366
369
|
}
|
|
367
370
|
// Views must have at least one element that is not an unmanaged assoc
|
|
368
|
-
if (!elem.on && !elem
|
|
371
|
+
if (!elem.on && !elem.$ignore)
|
|
369
372
|
hasNonAssocElements = true;
|
|
370
373
|
|
|
371
374
|
// (180 b) Create MIXINs for association elements in projections or views (those that are not mixins by themselves)
|
|
@@ -383,7 +386,7 @@ function getViewTransformer( csn, options, messageFunctions, transformCommon ) {
|
|
|
383
386
|
|
|
384
387
|
if (isSelect) {
|
|
385
388
|
// Build new columns from the column map - bring elements and columns back in sync basically
|
|
386
|
-
query.SELECT.columns = Object.keys(elements).filter(elem => !elements[elem]
|
|
389
|
+
query.SELECT.columns = Object.keys(elements).filter(elem => !elements[elem].$ignore).map(key => stripLeadingSelf(columnMap[key]));
|
|
387
390
|
// If following an association, explicitly set the implicit alias
|
|
388
391
|
// due to an issue with HANA - this seems to only have an effect on ref files with hdbcds-hdbcds, so only run then
|
|
389
392
|
const columnProcessors = [];
|
|
@@ -476,45 +479,82 @@ function getLastRefStepString( ref ) {
|
|
|
476
479
|
}
|
|
477
480
|
|
|
478
481
|
/**
|
|
479
|
-
*
|
|
482
|
+
* This function is similar to csnRefs()' `columnName()`, but does not split the
|
|
483
|
+
* last `col.ref` segment on `.`.
|
|
480
484
|
*
|
|
485
|
+
* TODO: The HDBCDS backend relies on this. Also the HDI backend relies
|
|
486
|
+
* on this for virtual elements somehow. That can probably be fixed
|
|
487
|
+
* by using csnRefs()'s `getElement()`.
|
|
488
|
+
* TODO: Remove this function; update HDBCDS/HDI
|
|
489
|
+
*
|
|
490
|
+
* @param {CSN.Column} col
|
|
491
|
+
* @returns {string}
|
|
492
|
+
*/
|
|
493
|
+
function columnNameForMap( col ) {
|
|
494
|
+
return col.as || (!col.args && col.func) || (col.ref && getLastRefStepString( col.ref ));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Build a map of the resulting names (i.e. the element name of the column) and references
|
|
499
|
+
* to the respective columns.
|
|
481
500
|
* This can later be used to match from elements to columns.
|
|
482
501
|
*
|
|
483
502
|
* @param {CSN.Query} query
|
|
503
|
+
* @param {object} csnUtils
|
|
484
504
|
* @returns {object}
|
|
485
505
|
*/
|
|
486
|
-
function getColumnMap( query ) {
|
|
506
|
+
function getColumnMap( query, csnUtils ) {
|
|
487
507
|
const map = Object.create(null);
|
|
488
|
-
if (query
|
|
508
|
+
if (query?.SELECT?.columns) {
|
|
489
509
|
query.SELECT.columns.forEach((col) => {
|
|
490
|
-
if (col
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
map[col.as] = col;
|
|
496
|
-
}
|
|
497
|
-
else if (col.ref) {
|
|
498
|
-
// .id on last path step can happen with hdbcds.hdbcds and malicious CSN input - maybe also with params?
|
|
499
|
-
// We made things right in the end with the second add of missing stuff, but why not do it
|
|
500
|
-
// right from the getgo
|
|
501
|
-
const last = getLastRefStepString(col.ref);
|
|
502
|
-
if (!map[last])
|
|
503
|
-
map[last] = col;
|
|
504
|
-
}
|
|
505
|
-
else if (col.func) {
|
|
506
|
-
map[col.func] = col;
|
|
507
|
-
}
|
|
508
|
-
else if (!map[col]) {
|
|
509
|
-
map[col] = col;
|
|
510
|
+
if (col !== '*') {
|
|
511
|
+
// Fallback to csnUtils for columns without any alias (internal one is created)
|
|
512
|
+
const as = columnNameForMap(col) || csnUtils.getColumnName( col );
|
|
513
|
+
if (as && !map[as])
|
|
514
|
+
map[as] = col;
|
|
510
515
|
}
|
|
511
516
|
});
|
|
512
517
|
}
|
|
513
|
-
|
|
514
518
|
return map;
|
|
515
519
|
}
|
|
516
520
|
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Ensure that each column in the CSN has a name. A column does not have
|
|
524
|
+
* a name if the column is an expression and there is no explicit alias.
|
|
525
|
+
* In that case an internal alias (from csnRefs()) is used and made explicit
|
|
526
|
+
* via non-enumerable `as`.
|
|
527
|
+
*
|
|
528
|
+
* For HDBCDS, the alias is made explicit as an enumerable property, because
|
|
529
|
+
* HDBCDS does not support expressions as columns without aliases.
|
|
530
|
+
*
|
|
531
|
+
* Notes:
|
|
532
|
+
* - The alias is removed after A2J: we rely on the compiler ignoring non-enumerable CSN properties.
|
|
533
|
+
* - We can't use e.g. `$as`, as csnRefs() does not use that property, and it must not
|
|
534
|
+
* invent another name for the column (could happen after flattening).
|
|
535
|
+
*
|
|
536
|
+
* @param {CSN.Model} csn
|
|
537
|
+
* @param {CSN.Options} options
|
|
538
|
+
* @param {object} csnUtils
|
|
539
|
+
*/
|
|
540
|
+
function ensureColumnNames( csn, options, csnUtils ) {
|
|
541
|
+
forEachDefinition(csn, (def) => {
|
|
542
|
+
csnUtils.initDefinition(def);
|
|
543
|
+
for (const query of csnUtils.$getQueries(def) || []) {
|
|
544
|
+
for (const col of query._select.columns || []) {
|
|
545
|
+
if (col !== '*' && !columnAlias(col)) {
|
|
546
|
+
if (options.transformation === 'hdbcds')
|
|
547
|
+
col.as = csnUtils.getColumnName(col);
|
|
548
|
+
else
|
|
549
|
+
setProp(col, 'as', csnUtils.getColumnName(col));
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
517
556
|
module.exports = {
|
|
518
557
|
getViewTransformer,
|
|
519
558
|
getColumnMap,
|
|
559
|
+
ensureColumnNames,
|
|
520
560
|
};
|
|
@@ -5,7 +5,7 @@ const {
|
|
|
5
5
|
getResultingName, forEachMemberRecursively,
|
|
6
6
|
} = require('../../model/csnUtils');
|
|
7
7
|
const { setProp, isDeprecatedEnabled } = require('../../base/model');
|
|
8
|
-
const { getTransformers } = require('../
|
|
8
|
+
const { getTransformers } = require('../transformUtils');
|
|
9
9
|
const { ModelError } = require('../../base/error');
|
|
10
10
|
const draftAnnotation = '@odata.draft.enabled';
|
|
11
11
|
const booleanBuiltin = 'cds.Boolean';
|
|
@@ -124,16 +124,18 @@ function generateDrafts( csn, options, pathDelimiter, messageFunctions ) {
|
|
|
124
124
|
error(null, path, 'Expecting element to have a type when used in a draft-enabled artifact');
|
|
125
125
|
if (elt.key && elt.key === true && !elt.virtual)
|
|
126
126
|
keys.push(elt);
|
|
127
|
-
}, [ 'definitions', artifactName ],
|
|
127
|
+
}, [ 'definitions', artifactName ], false, { elementsOnly: true });
|
|
128
128
|
|
|
129
129
|
// In contrast to EDM, the DB entity may have more than one technical keys but should have ideally exactly one key of type cds.UUID
|
|
130
|
-
if (keys.length !== 1)
|
|
131
|
-
warning(null, [ 'definitions', artifactName ],
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
if (keys.length !== 1) {
|
|
131
|
+
warning(null, [ 'definitions', artifactName ], { count: keys.length },
|
|
132
|
+
'Entity annotated with “@odata.draft.enabled” should have exactly one key element, but found $(COUNT)');
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const uuidCount = keys.reduce((acc, k) => ((k.type === 'cds.String' && k.$renamed === 'cds.UUID' && k.length === 36) ? acc + 1 : acc), 0);
|
|
136
|
+
if (uuidCount === 0)
|
|
137
|
+
warning(null, [ 'definitions', artifactName ], 'Entity annotated with “@odata.draft.enabled” should have one key element of type “cds.UUID”');
|
|
138
|
+
}
|
|
137
139
|
|
|
138
140
|
// Ignore boolean return value. We know that we're inside a service or else we wouldn't have reached this code.
|
|
139
141
|
const matchingService = getMatchingService(artifactName) || '';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const { forEachDefinition, getServiceNames } = require('../../model/csnUtils');
|
|
4
4
|
const { forEach } = require('../../utils/objectUtils');
|
|
5
5
|
const { isArtifactInSomeService, getServiceOfArtifact } = require('../odata/utils');
|
|
6
|
-
const { getTransformers } = require('../
|
|
6
|
+
const { getTransformers } = require('../transformUtils');
|
|
7
7
|
const { ModelError } = require('../../base/error');
|
|
8
8
|
const { makeMessageFunction } = require('../../base/messages');
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { makeMessageFunction } = require('../base/messages');
|
|
4
4
|
const { isDeprecatedEnabled, isBetaEnabled } = require('../base/model');
|
|
5
|
-
const transformUtils = require('./
|
|
5
|
+
const transformUtils = require('./transformUtils');
|
|
6
6
|
const { cloneCsnNonDict,
|
|
7
7
|
forEachDefinition,
|
|
8
8
|
forEachMemberRecursively,
|
|
@@ -312,79 +312,93 @@ function transform4odataWithCsn(inputModel, options) {
|
|
|
312
312
|
node['@Core.Computed'] = true;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
// Rename shorthand annotations within artifact or element 'node' according to a builtin
|
|
316
|
-
// list.
|
|
315
|
+
// Rename shorthand annotations within artifact or element 'node' according to a builtin list
|
|
317
316
|
function renameShorthandAnnotations(node) {
|
|
318
|
-
// FIXME: Verify this list - are they all still required? Do we need any more?
|
|
319
317
|
const setMappings = {
|
|
320
318
|
'@label': '@Common.Label',
|
|
321
319
|
'@title': '@Common.Label',
|
|
322
320
|
'@description': '@Core.Description',
|
|
323
321
|
};
|
|
324
322
|
const renameMappings = {
|
|
325
|
-
'@ValueList.entity': '@Common.ValueList
|
|
326
|
-
'@ValueList.type': '@Common.ValueList
|
|
327
|
-
'@Capabilities.Deletable': '@Capabilities.DeleteRestrictions
|
|
328
|
-
'@Capabilities.Insertable': '@Capabilities.InsertRestrictions
|
|
329
|
-
'@Capabilities.Updatable': '@Capabilities.UpdateRestrictions
|
|
330
|
-
'@Capabilities.Readable': '@Capabilities.ReadRestrictions
|
|
323
|
+
'@ValueList.entity': { val: '@Common.ValueList', op: 'entity' },
|
|
324
|
+
'@ValueList.type': { val: '@Common.ValueList', op: 'type' },
|
|
325
|
+
'@Capabilities.Deletable': { val: '@Capabilities.DeleteRestrictions', op: 'Deletable' },
|
|
326
|
+
'@Capabilities.Insertable': { val: '@Capabilities.InsertRestrictions', op: 'Insertable' },
|
|
327
|
+
'@Capabilities.Updatable': { val: '@Capabilities.UpdateRestrictions', op: 'Updatable' },
|
|
328
|
+
'@Capabilities.Readable': { val: '@Capabilities.ReadRestrictions', op: 'Readable' }
|
|
331
329
|
};
|
|
332
330
|
|
|
333
331
|
const setShortCuts = Object.keys(setMappings);
|
|
334
332
|
const renameShortCuts = Object.keys(renameMappings);
|
|
333
|
+
|
|
334
|
+
// Capabilities shortcuts have precedence over @readonly/@insertonly
|
|
335
335
|
Object.keys(node).forEach( name => {
|
|
336
336
|
if (!name.startsWith('@'))
|
|
337
337
|
return;
|
|
338
338
|
// Rename according to map above
|
|
339
|
-
const renamePrefix = (name in renameMappings)
|
|
339
|
+
const renamePrefix = (name in renameMappings)
|
|
340
|
+
? name
|
|
341
|
+
: renameShortCuts.find(p => name.startsWith(p + '.'));
|
|
340
342
|
if(renamePrefix) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
const mapping = renameMappings[renamePrefix];
|
|
344
|
+
renameAnnotation(node, name, name.replace(renamePrefix, `${mapping.val}.${mapping.op}`));
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
343
347
|
// The two mappings have no overlap, so no need to check for second map if first matched.
|
|
344
348
|
// Rename according to map above
|
|
345
|
-
const setPrefix = (name in setMappings)
|
|
349
|
+
const setPrefix = (name in setMappings)
|
|
350
|
+
? name
|
|
351
|
+
: setShortCuts.find(p => name.startsWith(p + '.') || name.startsWith(p + '#'));
|
|
346
352
|
if(setPrefix) {
|
|
347
353
|
setAnnotation(node, name.replace(setPrefix, setMappings[setPrefix]), node[name]);
|
|
348
354
|
}
|
|
349
355
|
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Special case: '@readonly' becomes a triplet of capability restrictions for entities,
|
|
359
|
+
// but '@Core.Computed' for everything else.
|
|
350
360
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if
|
|
354
|
-
|
|
361
|
+
// only if not both readonly/insertonly are true do the mapping
|
|
362
|
+
if(!(node['@readonly'] && node['@insertonly'])) {
|
|
363
|
+
if(node['@readonly']) {
|
|
364
|
+
const setRO = (qualifier) => {
|
|
355
365
|
if (node.kind === 'entity' || node.kind === 'aspect') {
|
|
356
|
-
setAnnotation(node,
|
|
357
|
-
setAnnotation(node,
|
|
358
|
-
setAnnotation(node,
|
|
366
|
+
setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
|
|
367
|
+
setAnnotation(node, `@Capabilities.InsertRestrictions${ qualifier ? '#' + qualifier : ''}.Insertable`, false);
|
|
368
|
+
setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
|
|
359
369
|
} else {
|
|
360
370
|
setAnnotation(node, '@Core.Computed', true);
|
|
361
371
|
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
else if (name === '@insertonly' && node[name]) {
|
|
365
|
-
if (node.kind === 'entity' || node.kind === 'aspect') {
|
|
366
|
-
setAnnotation(node, '@Capabilities.DeleteRestrictions.Deletable', false);
|
|
367
|
-
setAnnotation(node, '@Capabilities.ReadRestrictions.Readable', false);
|
|
368
|
-
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
372
|
+
};
|
|
373
|
+
setRO(undefined);
|
|
371
374
|
}
|
|
372
|
-
//
|
|
373
|
-
if (
|
|
374
|
-
|
|
375
|
-
|
|
375
|
+
// @insertonly is effective on entities/queries only
|
|
376
|
+
if (node['@insertonly'] && (node.kind === 'entity' || node.kind === 'aspect')) {
|
|
377
|
+
const setIO = (qualifier) => {
|
|
378
|
+
setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
|
|
379
|
+
setAnnotation(node, `@Capabilities.ReadRestrictions${ qualifier ? '#' + qualifier : ''}.Readable`, false);
|
|
380
|
+
setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
|
|
381
|
+
}
|
|
382
|
+
setIO(undefined);
|
|
376
383
|
}
|
|
384
|
+
}
|
|
377
385
|
|
|
378
|
-
|
|
379
|
-
|
|
386
|
+
// @Validation.Pattern is applicable to "Term" => node.kind === annotation
|
|
387
|
+
if (node['@assert.format'] != null)
|
|
388
|
+
setAnnotation(node, '@Validation.Pattern', node['@assert.format']);
|
|
380
389
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
390
|
+
// Only on element level
|
|
391
|
+
if(node.kind == null) {
|
|
392
|
+
if (node['@mandatory']&& node['@Common.FieldControl'] === undefined) {
|
|
393
|
+
setAnnotation(node, '@Common.FieldControl', { '#': 'Mandatory' });
|
|
386
394
|
}
|
|
387
|
-
|
|
395
|
+
if (node['@assert.range'] != null &&
|
|
396
|
+
(Array.isArray(node['@assert.range']) &&
|
|
397
|
+
node['@assert.range'].length === 2)) {
|
|
398
|
+
setAnnotation(node, '@Validation.Minimum', node['@assert.range'][0]);
|
|
399
|
+
setAnnotation(node, '@Validation.Maximum', node['@assert.range'][1]);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
388
402
|
}
|
|
389
403
|
|
|
390
404
|
// Apply default type facets to each type definition and every member
|