@sap/cds-compiler 4.1.2 → 4.2.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 +101 -1
- package/bin/cdsc.js +6 -3
- package/doc/CHANGELOG_BETA.md +5 -0
- package/doc/CHANGELOG_DEPRECATED.md +15 -0
- package/lib/api/main.js +2 -2
- package/lib/api/options.js +2 -2
- package/lib/api/validate.js +24 -24
- package/lib/base/message-registry.js +41 -6
- package/lib/base/messages.js +7 -0
- package/lib/base/model.js +37 -8
- package/lib/checks/elements.js +11 -10
- package/lib/checks/manyNavigations.js +33 -0
- package/lib/checks/onConditions.js +5 -2
- package/lib/checks/queryNoDbArtifacts.js +2 -3
- package/lib/checks/selectItems.js +4 -55
- package/lib/checks/utils.js +3 -2
- package/lib/checks/validator.js +3 -1
- package/lib/compiler/.eslintrc.json +2 -1
- package/lib/compiler/assert-consistency.js +27 -24
- package/lib/compiler/base.js +6 -2
- package/lib/compiler/builtins.js +34 -34
- package/lib/compiler/checks.js +179 -208
- package/lib/compiler/classes.js +2 -2
- package/lib/compiler/cycle-detector.js +6 -6
- package/lib/compiler/define.js +66 -45
- package/lib/compiler/extend.js +81 -72
- package/lib/compiler/finalize-parse-cdl.js +26 -26
- package/lib/compiler/generate.js +61 -45
- package/lib/compiler/index.js +47 -49
- package/lib/compiler/kick-start.js +8 -7
- package/lib/compiler/moduleLayers.js +1 -1
- package/lib/compiler/populate.js +42 -35
- package/lib/compiler/propagator.js +6 -6
- package/lib/compiler/resolve.js +170 -126
- package/lib/compiler/shared.js +122 -45
- package/lib/compiler/tweak-assocs.js +93 -40
- package/lib/compiler/utils.js +15 -12
- package/lib/edm/.eslintrc.json +40 -1
- package/lib/edm/annotations/genericTranslation.js +721 -707
- package/lib/edm/annotations/preprocessAnnotations.js +88 -77
- package/lib/edm/csn2edm.js +389 -378
- package/lib/edm/edm.js +678 -772
- package/lib/edm/edmAnnoPreprocessor.js +132 -146
- package/lib/edm/edmInboundChecks.js +29 -27
- package/lib/edm/edmPreprocessor.js +686 -646
- package/lib/edm/edmUtils.js +277 -296
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1253 -1276
- package/lib/json/from-csn.js +34 -4
- package/lib/json/to-csn.js +4 -4
- package/lib/language/language.g4 +2 -5
- package/lib/main.d.ts +61 -1
- package/lib/model/csnUtils.js +31 -2
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/modelCompare/compare.js +37 -2
- package/lib/modelCompare/utils/filter.js +1 -1
- package/lib/optionProcessor.js +15 -3
- package/lib/render/toCdl.js +30 -4
- package/lib/render/toSql.js +5 -9
- package/lib/render/utils/common.js +8 -6
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/constraints.js +47 -17
- package/lib/transform/db/expansion.js +121 -47
- package/lib/transform/db/flattening.js +75 -7
- package/lib/transform/forOdata.js +4 -1
- package/lib/transform/forRelationalDB.js +80 -62
- package/lib/transform/localized.js +91 -54
- package/lib/transform/transformUtils.js +9 -10
- package/lib/utils/file.js +7 -7
- package/lib/utils/moduleResolve.js +210 -121
- package/lib/utils/objectUtils.js +1 -1
- package/package.json +5 -5
|
@@ -5,10 +5,12 @@ const { forEachGeneric, applyTransformationsOnNonDictionary } = require('../mode
|
|
|
5
5
|
// Only to be used with validator.js - a correct this value needs to be provided!
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Validate select items of a query. If a column reference starts with $self or
|
|
8
|
+
* Validate select items of a query. If a column reference starts with $self or
|
|
9
|
+
* $projection, it must not contain association steps.
|
|
9
10
|
* Furthermore, for to.hdbcds, window functions are not allowed.
|
|
10
11
|
*
|
|
11
|
-
* For to.hdbcds-hdbcds, structures and managed associations are not allowed
|
|
12
|
+
* For to.hdbcds-hdbcds, structures and managed associations are not allowed
|
|
13
|
+
* as they are not flattened - @see rejectManagedAssociationsAndStructuresForHdbcdsNames
|
|
12
14
|
*
|
|
13
15
|
* @param {CSN.Query} query query object
|
|
14
16
|
* @todo Why do we care about this with $self?
|
|
@@ -17,58 +19,6 @@ function validateSelectItems( query ) {
|
|
|
17
19
|
const { SELECT } = query;
|
|
18
20
|
if (!SELECT)
|
|
19
21
|
return;
|
|
20
|
-
/**
|
|
21
|
-
* Check for a $self.<assoc> in columns etc. - since the $self.<assoc> references the "outside" view
|
|
22
|
-
* of the association, this is not allowed.
|
|
23
|
-
*
|
|
24
|
-
* @param {string} queryPart Part of the query that is being checked
|
|
25
|
-
* @returns {Function} Function as callback for applyTransformations
|
|
26
|
-
*/
|
|
27
|
-
function checkRefForInvalid$Self( queryPart ) {
|
|
28
|
-
const signalError = (error, parent, type) => {
|
|
29
|
-
if (queryPart === 'columns') {
|
|
30
|
-
error(null, parent.$path,
|
|
31
|
-
{ name: parent.ref[0], type },
|
|
32
|
-
'Select items starting with $(NAME) must not contain path steps of type $(TYPE)');
|
|
33
|
-
}
|
|
34
|
-
else if (queryPart === 'orderBy') {
|
|
35
|
-
error(null, parent.$path,
|
|
36
|
-
{ id: queryPart, type },
|
|
37
|
-
'Items of the $(ID)-clause must not contain path steps of type $(TYPE)');
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
error(null, parent.$path,
|
|
41
|
-
{ id: queryPart, name: parent.ref[0], type },
|
|
42
|
-
'Items of the $(ID)-clause starting with $(NAME) must not contain path steps of type $(TYPE)');
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
return function checkForInvalid$SelfInRef(parent) {
|
|
46
|
-
if (parent.ref && (parent.$scope === '$self' || parent.$scope === '$query')) {
|
|
47
|
-
const { _links } = parent;
|
|
48
|
-
for (let j = parent.$scope === '$self' ? 1 : 0; j < _links.length - 1; j++) {
|
|
49
|
-
if (_links[j].art.target) {
|
|
50
|
-
if (_links[j].art.on) {
|
|
51
|
-
// It's an unmanaged association - traversal is always forbidden
|
|
52
|
-
signalError(this.error, parent, _links[j].art.type);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
// It's a managed association - access of the foreign keys is allowed
|
|
56
|
-
const nextRef = parent.ref[j + 1].id || parent.ref[j + 1];
|
|
57
|
-
if (!_links[j].art.keys.some(r => r.ref[0] === nextRef))
|
|
58
|
-
signalError(this.error, parent, _links[j].art.type);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const last = _links[_links.length - 1];
|
|
64
|
-
|
|
65
|
-
if (last.art.target && last.art.on) {
|
|
66
|
-
// It's an unmanaged association - traversal is always forbidden
|
|
67
|
-
signalError(this.error, parent, last.art.type);
|
|
68
|
-
} // managed is okay, can be handled via tuple expansion
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
22
|
|
|
73
23
|
/**
|
|
74
24
|
* Check the given assoc filter for usage of $self - in an assoc-filter, you must only
|
|
@@ -90,7 +40,6 @@ function validateSelectItems( query ) {
|
|
|
90
40
|
|
|
91
41
|
const aTCB = (parent, prop) => {
|
|
92
42
|
applyTransformationsOnNonDictionary(parent, prop, {
|
|
93
|
-
ref: checkRefForInvalid$Self(prop).bind(this),
|
|
94
43
|
where: checkFilterForInvalid$Self.bind(this),
|
|
95
44
|
}, { skipStandard: { on: true }, drillRef: true });
|
|
96
45
|
};
|
package/lib/checks/utils.js
CHANGED
|
@@ -58,8 +58,9 @@ function otherSideIsExpandableStructure( on, startIndex ) {
|
|
|
58
58
|
* @returns {object} final artifact type
|
|
59
59
|
*/
|
|
60
60
|
function resolveArtifactType( art ) {
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
const type = art?._type?.type || art?.type;
|
|
62
|
+
if (type && !isBuiltinType(type))
|
|
63
|
+
return this.csnUtils.getFinalTypeInfo(type);
|
|
63
64
|
|
|
64
65
|
return art;
|
|
65
66
|
}
|
package/lib/checks/validator.js
CHANGED
|
@@ -11,6 +11,7 @@ const enrich = require('./enricher');
|
|
|
11
11
|
const { validateSelectItems } = require('./selectItems');
|
|
12
12
|
const { rejectParamDefaultsInHanaCds, warnAboutDefaultOnAssociationForHanaCds } = require('./defaultValues');
|
|
13
13
|
const validateCdsPersistenceAnnotation = require('./cdsPersistence');
|
|
14
|
+
const navigationIntoMany = require('./manyNavigations');
|
|
14
15
|
const checkUsedTypesForAnonymousAspectComposition = require('./managedInType');
|
|
15
16
|
const validateHasPersistedElements = require('./hasPersistedElements');
|
|
16
17
|
const checkForHanaTypes = require('./checkForTypes');
|
|
@@ -71,7 +72,7 @@ const forRelationalDBArtifactValidators
|
|
|
71
72
|
checkSqlAnnotationOnArtifact,
|
|
72
73
|
];
|
|
73
74
|
|
|
74
|
-
const forRelationalDBCsnValidators = [ nonexpandableStructuredInExpression ];
|
|
75
|
+
const forRelationalDBCsnValidators = [ nonexpandableStructuredInExpression, navigationIntoMany ];
|
|
75
76
|
/**
|
|
76
77
|
* @type {Array<(query: CSN.Query, path: CSN.Path) => void>}
|
|
77
78
|
*/
|
|
@@ -233,6 +234,7 @@ function forRelationalDB( csn, that ) {
|
|
|
233
234
|
{
|
|
234
235
|
skipArtifact: artifact => artifact.abstract ||
|
|
235
236
|
hasAnnotationValue(artifact, '@cds.persistence.skip') ||
|
|
237
|
+
hasAnnotationValue(artifact, '@cds.persistence.exists') ||
|
|
236
238
|
[ 'action', 'function', 'event' ].includes(artifact.kind),
|
|
237
239
|
});
|
|
238
240
|
}
|
|
@@ -80,7 +80,7 @@ const typeProperties = [
|
|
|
80
80
|
|
|
81
81
|
class InternalConsistencyError extends Error {
|
|
82
82
|
constructor(msg) {
|
|
83
|
-
super(`cds-compiler XSN consistency: ${ msg }`);
|
|
83
|
+
super( `cds-compiler XSN consistency: ${ msg }` );
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -270,7 +270,8 @@ function assertConsistency( model, stage ) {
|
|
|
270
270
|
requires: [ 'op', 'location', 'from' ],
|
|
271
271
|
optional: [
|
|
272
272
|
'name', '$parens', 'quantifier', 'mixin', 'excludingDict', 'columns', 'elements', '_deps',
|
|
273
|
-
'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit', '
|
|
273
|
+
'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit', '$limit',
|
|
274
|
+
'_origin', '_block',
|
|
274
275
|
'_projections', '_parent', '_main', '_effectiveType', '$effectiveSeqNo', '$expand',
|
|
275
276
|
'$tableAliases', 'kind', '_$next', '_combined', '$inlines', '_status',
|
|
276
277
|
],
|
|
@@ -284,7 +285,7 @@ function assertConsistency( model, stage ) {
|
|
|
284
285
|
requires: [ 'op', 'location', 'args', 'join' ],
|
|
285
286
|
optional: [
|
|
286
287
|
'on', '$parens', 'cardinality',
|
|
287
|
-
'kind', 'name', '_block', '_parent', '_main',
|
|
288
|
+
'kind', 'name', '_block', '_parent', '_main', '_user',
|
|
288
289
|
'$tableAliases', '_combined', '_joinParent', '$joinArgsIndex',
|
|
289
290
|
'_leadingQuery', '_$next', '_deps',
|
|
290
291
|
],
|
|
@@ -335,6 +336,7 @@ function assertConsistency( model, stage ) {
|
|
|
335
336
|
nulls: { test: locationVal( isString ), enum: [ 'first', 'last' ] },
|
|
336
337
|
$orderBy: { inherits: 'orderBy' },
|
|
337
338
|
groupBy: { inherits: 'value', test: isArray( expression ) },
|
|
339
|
+
$limit: { test: TODO },
|
|
338
340
|
limit: { requires: [ 'rows' ], optional: [ 'offset', 'location' ] },
|
|
339
341
|
rows: { inherits: 'value' },
|
|
340
342
|
offset: { inherits: 'value' },
|
|
@@ -507,7 +509,7 @@ function assertConsistency( model, stage ) {
|
|
|
507
509
|
],
|
|
508
510
|
// TODO: name requires if not in parser?
|
|
509
511
|
},
|
|
510
|
-
$priority: { test: isOneOf([ undefined, false, 'extend', 'annotate' ]) },
|
|
512
|
+
$priority: { test: isOneOf( [ undefined, false, 'extend', 'annotate' ] ) },
|
|
511
513
|
$annotations: { parser: true, kind: true, test: TODO }, // deprecated, still there for cds-lsp
|
|
512
514
|
name: {
|
|
513
515
|
isRequired: stageParser && (() => false), // not required in parser
|
|
@@ -605,7 +607,8 @@ function assertConsistency( model, stage ) {
|
|
|
605
607
|
// query specific
|
|
606
608
|
'where', 'columns', 'mixin', 'quantifier', 'offset',
|
|
607
609
|
'orderBy', '$orderBy', 'groupBy', 'excludingDict', 'having',
|
|
608
|
-
'limit', '
|
|
610
|
+
'$limit', 'limit', '_status', '_origin',
|
|
611
|
+
'_effectiveType', '$effectiveSeqNo',
|
|
609
612
|
],
|
|
610
613
|
},
|
|
611
614
|
_leadingQuery: { kind: true, test: TODO },
|
|
@@ -647,7 +650,7 @@ function assertConsistency( model, stage ) {
|
|
|
647
650
|
$inferred: {
|
|
648
651
|
parser: true,
|
|
649
652
|
kind: true,
|
|
650
|
-
test: isOneOf([
|
|
653
|
+
test: isOneOf( [
|
|
651
654
|
'', // constructed “super annotate” statement, redirected user-provided target
|
|
652
655
|
// Uppercase values are used in logic, lowercase value are "just for us", i.e.
|
|
653
656
|
// debugging or to add properties such as $generated in Universal CSN.
|
|
@@ -679,7 +682,7 @@ function assertConsistency( model, stage ) {
|
|
|
679
682
|
'rewrite', // on-conditions or FKeys are rewritten
|
|
680
683
|
'parent-origin', // annotation/property copied from parent that does not come through
|
|
681
684
|
// $origin and is not a direct annotation
|
|
682
|
-
]),
|
|
685
|
+
] ),
|
|
683
686
|
},
|
|
684
687
|
|
|
685
688
|
// Helper property for the XSN-to-CSN transformation, see function setExpandStatus():
|
|
@@ -688,7 +691,7 @@ function assertConsistency( model, stage ) {
|
|
|
688
691
|
$expand: {
|
|
689
692
|
kind: true,
|
|
690
693
|
// See description of `setExpandStatus()` of in `lib/compiler/utils.js`.
|
|
691
|
-
test: isOneOf([ 'origin', 'annotate', 'target' ]),
|
|
694
|
+
test: isOneOf( [ 'origin', 'annotate', 'target' ] ),
|
|
692
695
|
},
|
|
693
696
|
$inCycle: { kind: true, test: isBoolean },
|
|
694
697
|
|
|
@@ -696,7 +699,7 @@ function assertConsistency( model, stage ) {
|
|
|
696
699
|
$extra: { parser: true, test: TODO }, // for unexpected properties in CSN
|
|
697
700
|
$withLocalized: { test: isBoolean },
|
|
698
701
|
$sources: { parser: true, test: isArray( isString ) },
|
|
699
|
-
$expected: { parser: true, test: isOneOf([ 'approved-exists', 'exists' ]) },
|
|
702
|
+
$expected: { parser: true, test: isOneOf( [ 'approved-exists', 'exists' ] ) },
|
|
700
703
|
$messageFunctions: { test: TODO },
|
|
701
704
|
$functions: { test: TODO },
|
|
702
705
|
$assert: { test: TODO }, // currently just for missing Error[ref-cycle]
|
|
@@ -784,7 +787,7 @@ function assertConsistency( model, stage ) {
|
|
|
784
787
|
const requires = spec.requires || [];
|
|
785
788
|
// Do not test 'requires' with parse errors:
|
|
786
789
|
for (const p of requires) {
|
|
787
|
-
if (!names.includes(p)) {
|
|
790
|
+
if (!names.includes( p )) {
|
|
788
791
|
const req = spec.schema && spec.schema[p] && spec.schema[p].isRequired;
|
|
789
792
|
if ((req || schema[p] && schema[p].isRequired || noSyntaxErrors)( node ))
|
|
790
793
|
throw new InternalConsistencyError( `Required property '${ p }' missing in object${ at( [ node, parent ], prop, name ) }` );
|
|
@@ -792,7 +795,7 @@ function assertConsistency( model, stage ) {
|
|
|
792
795
|
}
|
|
793
796
|
const optional = spec.optional || [];
|
|
794
797
|
for (const n of names) {
|
|
795
|
-
const opt = Array.isArray(optional)
|
|
798
|
+
const opt = Array.isArray( optional )
|
|
796
799
|
? optional.includes( n ) || optional.includes( n.charAt(0) )
|
|
797
800
|
: optional( n, spec );
|
|
798
801
|
if (node[n] !== undefined) {
|
|
@@ -855,7 +858,7 @@ function assertConsistency( model, stage ) {
|
|
|
855
858
|
// TODO CSN parser?: { val: <token>, literal: 'token' } for keywords
|
|
856
859
|
if (typeof node === 'string')
|
|
857
860
|
return;
|
|
858
|
-
while (Array.isArray(node)) {
|
|
861
|
+
while (Array.isArray( node )) {
|
|
859
862
|
// TODO: also check getOwnPropertyNames(node)
|
|
860
863
|
if (node.length !== 1) {
|
|
861
864
|
node.forEach( n => expression( n, parent, prop, spec ) );
|
|
@@ -867,7 +870,7 @@ function assertConsistency( model, stage ) {
|
|
|
867
870
|
return;
|
|
868
871
|
isObject( node, parent, prop, spec, idx );
|
|
869
872
|
|
|
870
|
-
const s = spec[expressionSpec(node)] || {};
|
|
873
|
+
const s = spec[expressionSpec( node )] || {};
|
|
871
874
|
const sub = Object.assign( {}, s.inherits && schema[s.inherits], s );
|
|
872
875
|
if (spec.requires && sub.requires)
|
|
873
876
|
sub.requires = [ ...sub.requires, ...spec.requires ];
|
|
@@ -890,9 +893,9 @@ function assertConsistency( model, stage ) {
|
|
|
890
893
|
}
|
|
891
894
|
|
|
892
895
|
function args( node, parent, prop, spec ) {
|
|
893
|
-
if (Array.isArray(node)) {
|
|
896
|
+
if (Array.isArray( node )) {
|
|
894
897
|
if (parent.op && parent.op.val === 'xpr') // remove keywords for `xpr` expressions
|
|
895
|
-
node = node.filter( a => typeof a !== 'string');
|
|
898
|
+
node = node.filter( a => typeof a !== 'string' );
|
|
896
899
|
node.forEach( (item, idx) => expression( item, parent, prop, spec, idx ) );
|
|
897
900
|
}
|
|
898
901
|
else if (node && typeof node === 'object' && !Object.getPrototypeOf( node )) {
|
|
@@ -927,7 +930,7 @@ function assertConsistency( model, stage ) {
|
|
|
927
930
|
|
|
928
931
|
function isArray( func = standard ) {
|
|
929
932
|
return function vector( node, parent, prop, spec ) {
|
|
930
|
-
if (!Array.isArray(node))
|
|
933
|
+
if (!Array.isArray( node ))
|
|
931
934
|
throw new InternalConsistencyError( `Expected array${ at( [ null, parent ], prop ) }` );
|
|
932
935
|
node.forEach( (item, n) => func( item, parent, prop, spec, n ) );
|
|
933
936
|
};
|
|
@@ -960,8 +963,8 @@ function assertConsistency( model, stage ) {
|
|
|
960
963
|
|
|
961
964
|
function isOneOf( values ) {
|
|
962
965
|
return function isOneOfInner( node, parent, prop ) {
|
|
963
|
-
if (!values.includes(node))
|
|
964
|
-
throw new InternalConsistencyError( `Unexpected value '${ node }', expected ${ JSON.stringify(values) }${ at( [ node, parent ], prop ) }` );
|
|
966
|
+
if (!values.includes( node ))
|
|
967
|
+
throw new InternalConsistencyError( `Unexpected value '${ node }', expected ${ JSON.stringify( values ) }${ at( [ node, parent ], prop ) }` );
|
|
965
968
|
};
|
|
966
969
|
}
|
|
967
970
|
|
|
@@ -974,7 +977,7 @@ function assertConsistency( model, stage ) {
|
|
|
974
977
|
}
|
|
975
978
|
|
|
976
979
|
function isVal( node, parent, prop, spec ) {
|
|
977
|
-
if (Array.isArray(node))
|
|
980
|
+
if (Array.isArray( node ))
|
|
978
981
|
node.forEach( (item, n) => standard( item, parent, prop, spec, n ) );
|
|
979
982
|
else if (node !== null && ![ 'string', 'number', 'boolean' ].includes( typeof node ))
|
|
980
983
|
throw new InternalConsistencyError( `Expected array or simple value${ at( [ null, parent ], prop ) }` );
|
|
@@ -995,7 +998,7 @@ function assertConsistency( model, stage ) {
|
|
|
995
998
|
|
|
996
999
|
|
|
997
1000
|
function inDefinitions( art, parent, prop, spec, name ) {
|
|
998
|
-
if (Array.isArray(art)) // do not check with redefinitions
|
|
1001
|
+
if (Array.isArray( art )) // do not check with redefinitions
|
|
999
1002
|
return;
|
|
1000
1003
|
isObject( art, parent, prop, spec, name );
|
|
1001
1004
|
if (stageParser) {
|
|
@@ -1007,7 +1010,7 @@ function assertConsistency( model, stage ) {
|
|
|
1007
1010
|
!(model.vocabularies && model.vocabularies[art.name.absolute])) {
|
|
1008
1011
|
// TODO: sign ignored artifacts with $inferred = 'IGNORED'
|
|
1009
1012
|
if (parent.kind === 'source' ||
|
|
1010
|
-
art.name.absolute && art.name.absolute.startsWith('localized.'))
|
|
1013
|
+
art.name.absolute && art.name.absolute.startsWith( 'localized.' ))
|
|
1011
1014
|
standard( art, parent, prop, spec, name );
|
|
1012
1015
|
else
|
|
1013
1016
|
throw new InternalConsistencyError( `Expected definition${ at( [ art, parent ], prop, name ) }` );
|
|
@@ -1016,11 +1019,11 @@ function assertConsistency( model, stage ) {
|
|
|
1016
1019
|
|
|
1017
1020
|
function isScope( node, parent, prop ) {
|
|
1018
1021
|
// artifact refs in CDL have scope:0 in XSN
|
|
1019
|
-
if (Number.isInteger(node))
|
|
1022
|
+
if (Number.isInteger( node ))
|
|
1020
1023
|
return;
|
|
1021
1024
|
const validValues = [ 'typeOf', 'global', 'param' ];
|
|
1022
|
-
if (!validValues.includes(node))
|
|
1023
|
-
throw new InternalConsistencyError( `Property '${ prop }' must be either "${ validValues.join('", "') }" or a number but was "${ node }"` );
|
|
1025
|
+
if (!validValues.includes( node ))
|
|
1026
|
+
throw new InternalConsistencyError( `Property '${ prop }' must be either "${ validValues.join( '", "' ) }" or a number but was "${ node }"` );
|
|
1024
1027
|
}
|
|
1025
1028
|
|
|
1026
1029
|
function TODO() { /* no-op */ }
|
package/lib/compiler/base.js
CHANGED
|
@@ -29,7 +29,11 @@ const kindProperties = {
|
|
|
29
29
|
$inline: { normalized: 'element' }, // column with inline property
|
|
30
30
|
event: { elements: true, include: true },
|
|
31
31
|
type: { elements: propExists, enum: propExists, include: true },
|
|
32
|
-
aspect: {
|
|
32
|
+
aspect: {
|
|
33
|
+
elements: propExists,
|
|
34
|
+
actions: ( _p, parent ) => propExists( 'elements', parent ),
|
|
35
|
+
include: true,
|
|
36
|
+
},
|
|
33
37
|
annotation: { elements: propExists, enum: propExists },
|
|
34
38
|
enum: { normalized: 'element', dict: 'enum' },
|
|
35
39
|
element: { elements: propExists, enum: propExists, dict: 'elements' },
|
|
@@ -110,7 +114,7 @@ function getMemberNameProp( elem, kind ) {
|
|
|
110
114
|
obj = obj.items;
|
|
111
115
|
if (obj.elements || obj.enum)
|
|
112
116
|
return 'element';
|
|
113
|
-
throw new CompilerAssertion( `Member not found in parent properties ${ Object.keys( obj ).join('+') }` );
|
|
117
|
+
throw new CompilerAssertion( `Member not found in parent properties ${ Object.keys( obj ).join( '+' ) }` );
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
module.exports = {
|
package/lib/compiler/builtins.js
CHANGED
|
@@ -235,7 +235,7 @@ const numberRegEx = /^[ \t]*[-+]?(\d+(\.\d*)?|\.\d+)(e[-+]\d+)?[ \t]*$/i;
|
|
|
235
235
|
const quotedLiteralPatterns = {
|
|
236
236
|
x: {
|
|
237
237
|
test_variant: 'uneven-hex',
|
|
238
|
-
test_fn: (str => Number.isInteger(str.length / 2)),
|
|
238
|
+
test_fn: (str => Number.isInteger( str.length / 2 )),
|
|
239
239
|
unexpected_variant: 'invalid-hex',
|
|
240
240
|
unexpected_char: /[^0-9a-f]/i,
|
|
241
241
|
json_type: 'string',
|
|
@@ -293,12 +293,12 @@ const quotedLiteralPatterns = {
|
|
|
293
293
|
*/
|
|
294
294
|
function checkDate( year, month, day ) {
|
|
295
295
|
// Negative years are allowed
|
|
296
|
-
year = Math.abs(Number.parseInt(year, 10));
|
|
297
|
-
month = Number.parseInt(month, 10);
|
|
298
|
-
day = Number.parseInt(day, 10);
|
|
296
|
+
year = Math.abs( Number.parseInt( year, 10 ) );
|
|
297
|
+
month = Number.parseInt( month, 10 );
|
|
298
|
+
day = Number.parseInt( day, 10 );
|
|
299
299
|
// If any is NaN, the condition will be false.
|
|
300
300
|
// Year 0 does not exist, but ISO 8601 allows it and defines it as 1 BC.
|
|
301
|
-
return !Number.isNaN(year) && month > 0 && month < 13 && day > 0 && day < 32;
|
|
301
|
+
return !Number.isNaN( year ) && month > 0 && month < 13 && day > 0 && day < 32;
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
/**
|
|
@@ -308,9 +308,9 @@ function checkDate( year, month, day ) {
|
|
|
308
308
|
* @returns {boolean} True if the date is valid.
|
|
309
309
|
*/
|
|
310
310
|
function checkTime( hour, minutes, seconds ) {
|
|
311
|
-
hour = Number.parseInt(hour, 10);
|
|
312
|
-
minutes = Number.parseInt(minutes, 10);
|
|
313
|
-
seconds = seconds ? Number.parseInt(seconds, 10) : 0;
|
|
311
|
+
hour = Number.parseInt( hour, 10 );
|
|
312
|
+
minutes = Number.parseInt( minutes, 10 );
|
|
313
|
+
seconds = seconds ? Number.parseInt( seconds, 10 ) : 0;
|
|
314
314
|
if (hour === 24) // allow 24:00:00 (ISO 8601 version earlier than 2019)
|
|
315
315
|
return minutes === 0 && seconds === 0;
|
|
316
316
|
// If any is NaN, the condition will be false.
|
|
@@ -332,47 +332,47 @@ const typeCategories = {
|
|
|
332
332
|
geo: [],
|
|
333
333
|
};
|
|
334
334
|
// Fill type categories with `cds.*` types
|
|
335
|
-
Object.keys(core).forEach((type) => {
|
|
335
|
+
Object.keys( core ).forEach( (type) => {
|
|
336
336
|
if (core[type].category)
|
|
337
|
-
typeCategories[core[type].category].push(`cds.${ type }`);
|
|
338
|
-
});
|
|
337
|
+
typeCategories[core[type].category].push( `cds.${ type }` );
|
|
338
|
+
} );
|
|
339
339
|
// Fill type categories with `cds.hana.*` types
|
|
340
|
-
Object.keys(coreHana).forEach((type) => {
|
|
340
|
+
Object.keys( coreHana ).forEach( (type) => {
|
|
341
341
|
if (coreHana[type].category)
|
|
342
|
-
typeCategories[coreHana[type].category].push(`cds.hana.${ type }`);
|
|
343
|
-
});
|
|
342
|
+
typeCategories[coreHana[type].category].push( `cds.hana.${ type }` );
|
|
343
|
+
} );
|
|
344
344
|
|
|
345
345
|
/** @param {string} typeName */
|
|
346
346
|
function isIntegerTypeName( typeName ) {
|
|
347
|
-
return typeCategories.integer.includes(typeName);
|
|
347
|
+
return typeCategories.integer.includes( typeName );
|
|
348
348
|
}
|
|
349
349
|
/** @param {string} typeName */
|
|
350
350
|
function isDecimalTypeName( typeName ) {
|
|
351
|
-
return typeCategories.decimal.includes(typeName);
|
|
351
|
+
return typeCategories.decimal.includes( typeName );
|
|
352
352
|
}
|
|
353
353
|
/** @param {string} typeName */
|
|
354
354
|
function isNumericTypeName( typeName ) {
|
|
355
|
-
return isIntegerTypeName(typeName) || isDecimalTypeName(typeName);
|
|
355
|
+
return isIntegerTypeName( typeName ) || isDecimalTypeName( typeName );
|
|
356
356
|
}
|
|
357
357
|
/** @param {string} typeName */
|
|
358
358
|
function isStringTypeName( typeName ) {
|
|
359
|
-
return typeCategories.string.includes(typeName);
|
|
359
|
+
return typeCategories.string.includes( typeName );
|
|
360
360
|
}
|
|
361
361
|
/** @param {string} typeName */
|
|
362
362
|
function isDateOrTimeTypeName( typeName ) {
|
|
363
|
-
return typeCategories.dateTime.includes(typeName);
|
|
363
|
+
return typeCategories.dateTime.includes( typeName );
|
|
364
364
|
}
|
|
365
365
|
/** @param {string} typeName */
|
|
366
366
|
function isBooleanTypeName( typeName ) {
|
|
367
|
-
return typeCategories.boolean.includes(typeName);
|
|
367
|
+
return typeCategories.boolean.includes( typeName );
|
|
368
368
|
}
|
|
369
369
|
/** @param {string} typeName */
|
|
370
370
|
function isBinaryTypeName( typeName ) {
|
|
371
|
-
return typeCategories.binary.includes(typeName);
|
|
371
|
+
return typeCategories.binary.includes( typeName );
|
|
372
372
|
}
|
|
373
373
|
/** @param {string} typeName */
|
|
374
374
|
function isGeoTypeName( typeName ) {
|
|
375
|
-
return typeCategories.geo.includes(typeName);
|
|
375
|
+
return typeCategories.geo.includes( typeName );
|
|
376
376
|
}
|
|
377
377
|
/**
|
|
378
378
|
* Whether the given type name is a relation, i.e. an association or composition.
|
|
@@ -380,7 +380,7 @@ function isGeoTypeName( typeName ) {
|
|
|
380
380
|
* @param {string} typeName
|
|
381
381
|
*/
|
|
382
382
|
function isRelationTypeName( typeName ) {
|
|
383
|
-
return typeCategories.relation.includes(typeName);
|
|
383
|
+
return typeCategories.relation.includes( typeName );
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
/**
|
|
@@ -390,10 +390,10 @@ function isRelationTypeName( typeName ) {
|
|
|
390
390
|
* @returns {boolean}
|
|
391
391
|
*/
|
|
392
392
|
function isInReservedNamespace( absolute ) {
|
|
393
|
-
return absolute === 'cds' || absolute.startsWith( 'cds.') &&
|
|
394
|
-
!absolute.match(/^cds\.foundation(\.|$)/) &&
|
|
395
|
-
!absolute.match(/^cds\.outbox(\.|$)/) && // Requested by Node runtime
|
|
396
|
-
!absolute.match(/^cds\.xt(\.|$)/); // Requested by Mtx
|
|
393
|
+
return absolute === 'cds' || absolute.startsWith( 'cds.' ) &&
|
|
394
|
+
!absolute.match( /^cds\.foundation(\.|$)/ ) &&
|
|
395
|
+
!absolute.match( /^cds\.outbox(\.|$)/ ) && // Requested by Node runtime
|
|
396
|
+
!absolute.match( /^cds\.xt(\.|$)/ ); // Requested by Mtx
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
/**
|
|
@@ -408,7 +408,7 @@ function isInReservedNamespace( absolute ) {
|
|
|
408
408
|
* @returns {boolean}
|
|
409
409
|
*/
|
|
410
410
|
function isBuiltinType( type ) {
|
|
411
|
-
return typeof type === 'string' && isInReservedNamespace(type);
|
|
411
|
+
return typeof type === 'string' && isInReservedNamespace( type );
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
/**
|
|
@@ -446,7 +446,7 @@ function initBuiltins( model ) {
|
|
|
446
446
|
builtin,
|
|
447
447
|
location: builtinLocation(),
|
|
448
448
|
};
|
|
449
|
-
setProp( art, '_subArtifacts', Object.create(null) );
|
|
449
|
+
setProp( art, '_subArtifacts', Object.create( null ) );
|
|
450
450
|
return art;
|
|
451
451
|
}
|
|
452
452
|
|
|
@@ -460,7 +460,7 @@ function initBuiltins( model ) {
|
|
|
460
460
|
* @returns {object} Artifacts dictionary with the builtin artifacts without prefixes.
|
|
461
461
|
*/
|
|
462
462
|
function env( builtins, prefix, parent ) {
|
|
463
|
-
const artifacts = Object.create(null);
|
|
463
|
+
const artifacts = Object.create( null );
|
|
464
464
|
for (const name of Object.keys( builtins )) {
|
|
465
465
|
const absolute = prefix + name;
|
|
466
466
|
// TODO: reconsider whether to set a type to itself - looks wrong
|
|
@@ -481,7 +481,7 @@ function initBuiltins( model ) {
|
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
function setMagicVariables( builtins ) {
|
|
484
|
-
const artifacts = Object.create(null);
|
|
484
|
+
const artifacts = Object.create( null );
|
|
485
485
|
for (const name in builtins) {
|
|
486
486
|
const magic = builtins[name];
|
|
487
487
|
// TODO: rename to $builtinFunction
|
|
@@ -510,9 +510,9 @@ function initBuiltins( model ) {
|
|
|
510
510
|
if (!elements)
|
|
511
511
|
return;
|
|
512
512
|
|
|
513
|
-
const names = Object.keys(elements);
|
|
513
|
+
const names = Object.keys( elements );
|
|
514
514
|
if (names.length > 0 && !art.elements)
|
|
515
|
-
art.elements = Object.create(null);
|
|
515
|
+
art.elements = Object.create( null );
|
|
516
516
|
|
|
517
517
|
for (const n of names) {
|
|
518
518
|
const magic = {
|
|
@@ -525,7 +525,7 @@ function initBuiltins( model ) {
|
|
|
525
525
|
setProp( magic, '_parent', art );
|
|
526
526
|
// setProp( magic, '_effectiveType', magic );
|
|
527
527
|
if (elements[n] && typeof elements[n] === 'object')
|
|
528
|
-
createMagicElements(magic, elements[n]);
|
|
528
|
+
createMagicElements( magic, elements[n] );
|
|
529
529
|
|
|
530
530
|
art.elements[n] = magic;
|
|
531
531
|
}
|