@sap/cds-compiler 2.5.2 → 2.11.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 +235 -9
- package/bin/cdsc.js +44 -27
- package/bin/cdsse.js +1 -0
- package/doc/CHANGELOG_BETA.md +37 -3
- package/lib/api/.eslintrc.json +2 -0
- package/lib/api/main.js +37 -123
- package/lib/api/options.js +27 -15
- package/lib/api/validate.js +34 -9
- package/lib/backends.js +9 -89
- package/lib/base/dictionaries.js +2 -1
- package/lib/base/keywords.js +32 -2
- package/lib/base/message-registry.js +73 -11
- package/lib/base/messages.js +86 -30
- package/lib/base/model.js +6 -6
- package/lib/base/optionProcessorHelper.js +56 -22
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/foreignKeys.js +0 -6
- package/lib/checks/managedWithoutKeys.js +17 -0
- package/lib/checks/nonexpandableStructured.js +38 -0
- package/lib/checks/onConditions.js +9 -45
- package/lib/checks/queryNoDbArtifacts.js +25 -7
- package/lib/checks/selectItems.js +29 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +41 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +60 -7
- package/lib/compiler/assert-consistency.js +23 -7
- package/lib/compiler/base.js +65 -0
- package/lib/compiler/builtins.js +30 -1
- package/lib/compiler/checks.js +8 -5
- package/lib/compiler/definer.js +157 -133
- package/lib/compiler/index.js +89 -31
- package/lib/compiler/propagator.js +5 -2
- package/lib/compiler/resolver.js +375 -185
- package/lib/compiler/shared.js +49 -202
- package/lib/compiler/utils.js +173 -0
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +104 -108
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +388 -146
- package/lib/edm/edmUtils.js +104 -34
- package/lib/gen/Dictionary.json +22 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +28 -1
- package/lib/gen/language.tokens +79 -69
- package/lib/gen/languageLexer.interp +28 -1
- package/lib/gen/languageLexer.js +879 -805
- package/lib/gen/languageLexer.tokens +71 -62
- package/lib/gen/languageParser.js +5330 -4300
- package/lib/json/from-csn.js +110 -52
- package/lib/json/to-csn.js +434 -120
- package/lib/language/antlrParser.js +15 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +93 -26
- package/lib/language/language.g4 +172 -31
- package/lib/main.d.ts +216 -19
- package/lib/main.js +32 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +413 -149
- package/lib/model/csnUtils.js +286 -75
- package/lib/model/enrichCsn.js +50 -6
- package/lib/model/revealInternalProperties.js +22 -5
- package/lib/modelCompare/compare.js +39 -21
- package/lib/optionProcessor.js +35 -18
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +9 -6
- package/lib/render/toCdl.js +121 -36
- package/lib/render/toHdbcds.js +148 -98
- package/lib/render/toSql.js +114 -43
- package/lib/render/utils/common.js +8 -13
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/db/assertUnique.js +5 -6
- package/lib/transform/db/constraints.js +281 -106
- package/lib/transform/db/draft.js +11 -8
- package/lib/transform/db/expansion.js +584 -0
- package/lib/transform/db/flattening.js +341 -0
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/transformExists.js +345 -65
- package/lib/transform/db/views.js +438 -0
- package/lib/transform/forHanaNew.js +131 -793
- package/lib/transform/forOdataNew.js +30 -24
- package/lib/transform/localized.js +39 -10
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/generateForeignKeyElements.js +11 -10
- package/lib/transform/odata/referenceFlattener.js +60 -39
- package/lib/transform/odata/sortByAssociationDependency.js +2 -2
- package/lib/transform/odata/structuralPath.js +72 -0
- package/lib/transform/odata/structureFlattener.js +19 -18
- package/lib/transform/odata/typesExposure.js +22 -12
- package/lib/transform/transformUtilsNew.js +144 -78
- package/lib/transform/translateAssocsToJoins.js +22 -27
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +5 -14
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/term.js +65 -42
- package/lib/utils/timetrace.js +48 -26
- package/package.json +1 -1
- package/lib/json/walker.js +0 -26
- package/lib/transform/sqlite +0 -0
- package/lib/utils/string.js +0 -17
package/lib/checks/validator.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
forEachDefinition, forEachMemberRecursively, forAllQueries,
|
|
5
|
-
forEachMember, getNormalizedQuery, hasAnnotationValue,
|
|
5
|
+
forEachMember, getNormalizedQuery, hasAnnotationValue, applyTransformations,
|
|
6
6
|
} = require('../model/csnUtils');
|
|
7
7
|
const enrich = require('./enricher');
|
|
8
8
|
|
|
9
9
|
// forHana
|
|
10
|
-
const validateSelectItems = require('./selectItems');
|
|
11
|
-
const { rejectParamDefaultsInHanaCds } = require('./defaultValues');
|
|
10
|
+
const { validateSelectItems } = require('./selectItems');
|
|
11
|
+
const { rejectParamDefaultsInHanaCds, warnAboutDefaultOnAssociationForHanaCds } = require('./defaultValues');
|
|
12
12
|
const validateCdsPersistenceAnnotation = require('./cdsPersistence');
|
|
13
13
|
const checkUsedTypesForAnonymousAspectComposition = require('./managedInType');
|
|
14
14
|
const checkForEmptyOrOnlyVirtual = require('./emptyOrOnlyVirtual');
|
|
@@ -23,19 +23,28 @@ const {
|
|
|
23
23
|
// both
|
|
24
24
|
const { validateOnCondition, validateMixinOnCondition } = require('./onConditions');
|
|
25
25
|
const validateForeignKeys = require('./foreignKeys');
|
|
26
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
checkTypeDefinitionHasType, checkElementTypeDefinitionHasType,
|
|
28
|
+
checkTypeIsScalar, checkDecimalScale,
|
|
29
|
+
} = require('./types');
|
|
27
30
|
const { checkPrimaryKey, checkVirtualElement, checkManagedAssoc } = require('./elements');
|
|
28
31
|
const checkForInvalidTarget = require('./invalidTarget');
|
|
29
32
|
const { validateAssociationsInItems } = require('./arrayOfs');
|
|
30
33
|
const checkQueryForNoDBArtifacts = require('./queryNoDbArtifacts');
|
|
31
34
|
const checkExplicitlyNullableKeys = require('./nullableKeys');
|
|
35
|
+
const nonexpandableStructuredInExpression = require('./nonexpandableStructured');
|
|
36
|
+
const unknownMagic = require('./unknownMagic');
|
|
37
|
+
const managedWithoutKeys = require('./managedWithoutKeys');
|
|
32
38
|
|
|
33
39
|
const forHanaMemberValidators
|
|
34
40
|
= [
|
|
35
41
|
// For HANA CDS specifically, reject any default parameter values, as these are not supported.
|
|
36
42
|
rejectParamDefaultsInHanaCds,
|
|
37
43
|
checkTypeIsScalar,
|
|
44
|
+
checkDecimalScale,
|
|
38
45
|
checkExplicitlyNullableKeys,
|
|
46
|
+
managedWithoutKeys,
|
|
47
|
+
warnAboutDefaultOnAssociationForHanaCds,
|
|
39
48
|
];
|
|
40
49
|
|
|
41
50
|
const forHanaArtifactValidators
|
|
@@ -46,8 +55,11 @@ const forHanaArtifactValidators
|
|
|
46
55
|
checkForEmptyOrOnlyVirtual,
|
|
47
56
|
];
|
|
48
57
|
|
|
49
|
-
const
|
|
50
|
-
|
|
58
|
+
const forHanaCsnValidators = [ nonexpandableStructuredInExpression, unknownMagic ];
|
|
59
|
+
/**
|
|
60
|
+
* @type {Array<(query: CSN.Query, path: CSN.Path) => void>}
|
|
61
|
+
*/
|
|
62
|
+
const forHanaQueryValidators = [
|
|
51
63
|
// TODO reason why this is forHana exclusive
|
|
52
64
|
validateSelectItems,
|
|
53
65
|
checkQueryForNoDBArtifacts,
|
|
@@ -57,6 +69,7 @@ const forOdataMemberValidators
|
|
|
57
69
|
= [
|
|
58
70
|
// OData allows only simple values, no expressions or functions
|
|
59
71
|
validateDefaultValues,
|
|
72
|
+
managedWithoutKeys,
|
|
60
73
|
];
|
|
61
74
|
|
|
62
75
|
const forOdataArtifactValidators
|
|
@@ -75,6 +88,8 @@ const forOdataArtifactValidators
|
|
|
75
88
|
checkReadOnlyAndInsertOnly,
|
|
76
89
|
];
|
|
77
90
|
|
|
91
|
+
const forOdataCsnValidators = [ nonexpandableStructuredInExpression ];
|
|
92
|
+
|
|
78
93
|
const forOdataQueryValidators = [];
|
|
79
94
|
|
|
80
95
|
const commonMemberValidators
|
|
@@ -91,6 +106,7 @@ const commonQueryValidators = [ validateMixinOnCondition ];
|
|
|
91
106
|
*
|
|
92
107
|
* @param {CSN.Model} csn CSN to check
|
|
93
108
|
* @param {object} that Will be provided to the validators via "this"
|
|
109
|
+
* @param {object[]} [csnValidators=[]] Validations on whole CSN using applyTransformations
|
|
94
110
|
* @param {Function[]} [memberValidators=[]] Validations on member-level
|
|
95
111
|
* @param {Function[]} [artifactValidators=[]] Validations on artifact-level
|
|
96
112
|
* @param {Function[]} [queryValidators=[]] Validations on query-level
|
|
@@ -98,12 +114,15 @@ const commonQueryValidators = [ validateMixinOnCondition ];
|
|
|
98
114
|
* @returns {Function} Function taking no parameters, that cleans up the attached helpers
|
|
99
115
|
*/
|
|
100
116
|
function _validate(csn, that,
|
|
117
|
+
csnValidators = [],
|
|
101
118
|
memberValidators = [],
|
|
102
119
|
artifactValidators = [],
|
|
103
120
|
queryValidators = [],
|
|
104
121
|
iterateOptions = {}) {
|
|
105
122
|
const { cleanup } = enrich(csn);
|
|
106
123
|
|
|
124
|
+
applyTransformations(csn, mergeCsnValidators(csnValidators, that), [], true, { drillRef: true });
|
|
125
|
+
|
|
107
126
|
forEachDefinition(csn, (artifact, artifactName, prop, path) => {
|
|
108
127
|
artifactValidators.forEach((artifactValidator) => {
|
|
109
128
|
artifactValidator.bind(that)(artifact, artifactName, prop, path);
|
|
@@ -118,12 +137,44 @@ function _validate(csn, that,
|
|
|
118
137
|
}
|
|
119
138
|
|
|
120
139
|
if (queryValidators.length && getNormalizedQuery(artifact).query)
|
|
121
|
-
forAllQueries(getNormalizedQuery(artifact).query, queryValidators.map(v => v.bind(that)), path.concat([ 'query' ]));
|
|
140
|
+
forAllQueries(getNormalizedQuery(artifact).query, queryValidators.map(v => v.bind(that)), path.concat([ artifact.projection ? 'projection' : 'query' ]));
|
|
122
141
|
}, iterateOptions);
|
|
123
142
|
|
|
124
143
|
return cleanup;
|
|
125
144
|
}
|
|
126
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Ensure the CSN validators adhere to the applyTransformation format - also, supply correct this value for each subfunction
|
|
148
|
+
*
|
|
149
|
+
* @param {object[]} csnValidators Validators
|
|
150
|
+
* @param {object} that Value for this
|
|
151
|
+
* @returns {object} Remapped validators.
|
|
152
|
+
*/
|
|
153
|
+
function mergeCsnValidators(csnValidators, that) {
|
|
154
|
+
const remapped = {};
|
|
155
|
+
for (const validator of csnValidators) {
|
|
156
|
+
for (const [ n, fns ] of Object.entries(validator)) {
|
|
157
|
+
if (!remapped[n])
|
|
158
|
+
remapped[n] = [];
|
|
159
|
+
|
|
160
|
+
if (Array.isArray(fns)) {
|
|
161
|
+
remapped[n].push((parent, name, prop, path) => fns.forEach(
|
|
162
|
+
fn => fn.bind(that)(parent, name, prop, path)
|
|
163
|
+
));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
remapped[n].push((parent, name, prop, path) => fns.bind(that)(parent, name, prop, path));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const [ n, fns ] of Object.entries(remapped))
|
|
172
|
+
remapped[n] = (parent, name, prop, path) => fns.forEach(fn => fn.bind(that)(parent, name, prop, path));
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
return remapped;
|
|
176
|
+
}
|
|
177
|
+
|
|
127
178
|
/**
|
|
128
179
|
* @param {CSN.Model} csn CSN to check
|
|
129
180
|
* @param {object} that Will be provided to the validators via "this"
|
|
@@ -131,6 +182,7 @@ function _validate(csn, that,
|
|
|
131
182
|
*/
|
|
132
183
|
function forHana(csn, that) {
|
|
133
184
|
return _validate(csn, that,
|
|
185
|
+
forHanaCsnValidators,
|
|
134
186
|
forHanaMemberValidators.concat(commonMemberValidators),
|
|
135
187
|
forHanaArtifactValidators.concat(commonArtifactValidators).concat(
|
|
136
188
|
// why is this hana exclusive
|
|
@@ -160,6 +212,7 @@ function forHana(csn, that) {
|
|
|
160
212
|
*/
|
|
161
213
|
function forOdata(csn, that) {
|
|
162
214
|
return _validate(csn, that,
|
|
215
|
+
forOdataCsnValidators,
|
|
163
216
|
forOdataMemberValidators.concat(commonMemberValidators),
|
|
164
217
|
forOdataArtifactValidators.concat(commonArtifactValidators).concat(
|
|
165
218
|
(artifact, artifactName) => {
|
|
@@ -97,6 +97,9 @@ function assertConsistency( model, stage ) {
|
|
|
97
97
|
'_entities', '$entity',
|
|
98
98
|
'$blocks',
|
|
99
99
|
'$newfeatures',
|
|
100
|
+
'$messageFunctions',
|
|
101
|
+
'$functions',
|
|
102
|
+
'$volatileFunctions',
|
|
100
103
|
],
|
|
101
104
|
},
|
|
102
105
|
':parser': { // top-level from parser
|
|
@@ -245,8 +248,8 @@ function assertConsistency( model, stage ) {
|
|
|
245
248
|
optional: [
|
|
246
249
|
'name', '$parens', 'quantifier', 'mixin', 'excludingDict', 'columns', 'elements', '_deps',
|
|
247
250
|
'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit',
|
|
248
|
-
'_projections', '_block', '_parent', '_main', '_effectiveType',
|
|
249
|
-
'$tableAliases', 'kind', '_$next', '_combined',
|
|
251
|
+
'_projections', '_block', '_parent', '_main', '_effectiveType', '$expand',
|
|
252
|
+
'$tableAliases', 'kind', '_$next', '_combined', '$inlines',
|
|
250
253
|
],
|
|
251
254
|
},
|
|
252
255
|
none: { optional: () => true }, // parse error
|
|
@@ -310,6 +313,7 @@ function assertConsistency( model, stage ) {
|
|
|
310
313
|
rows: { inherits: 'value' },
|
|
311
314
|
offset: { inherits: 'value' },
|
|
312
315
|
_combined: { test: TODO },
|
|
316
|
+
$inlines: { test: TODO },
|
|
313
317
|
type: {
|
|
314
318
|
kind: true,
|
|
315
319
|
requires: [ 'location', 'path' ],
|
|
@@ -322,7 +326,7 @@ function assertConsistency( model, stage ) {
|
|
|
322
326
|
requires: [ 'location' ],
|
|
323
327
|
optional: [
|
|
324
328
|
'path', 'elements', '_outer',
|
|
325
|
-
'scope', '_artifact', '$inferred',
|
|
329
|
+
'scope', '_artifact', '$inferred', '$expand',
|
|
326
330
|
'_effectiveType', // by propagation
|
|
327
331
|
],
|
|
328
332
|
},
|
|
@@ -349,6 +353,7 @@ function assertConsistency( model, stage ) {
|
|
|
349
353
|
$delimited: { parser: true, test: isBoolean },
|
|
350
354
|
scope: { test: isScope },
|
|
351
355
|
func: { test: TODO },
|
|
356
|
+
suffix: { test: TODO },
|
|
352
357
|
kind: {
|
|
353
358
|
isRequired: !stageParser && (() => true),
|
|
354
359
|
// required to be set by Core Compiler even with parse errors
|
|
@@ -396,6 +401,7 @@ function assertConsistency( model, stage ) {
|
|
|
396
401
|
optional: [
|
|
397
402
|
'args',
|
|
398
403
|
'func',
|
|
404
|
+
'suffix',
|
|
399
405
|
'quantifier',
|
|
400
406
|
'$inferred',
|
|
401
407
|
'$parens',
|
|
@@ -424,7 +430,7 @@ function assertConsistency( model, stage ) {
|
|
|
424
430
|
struct: { inherits: 'val', test: isDictionary( definition ) }, // def because double @
|
|
425
431
|
args: {
|
|
426
432
|
inherits: 'value',
|
|
427
|
-
optional: [ 'name', '$duplicate', '$expected' ],
|
|
433
|
+
optional: [ 'name', '$duplicate', '$expected', 'args', 'suffix' ],
|
|
428
434
|
test: args,
|
|
429
435
|
},
|
|
430
436
|
on: { kind: true, inherits: 'value', test: expression },
|
|
@@ -475,6 +481,7 @@ function assertConsistency( model, stage ) {
|
|
|
475
481
|
},
|
|
476
482
|
items: {
|
|
477
483
|
kind: true,
|
|
484
|
+
also: [ 0 ], // 0 for cyclic expansions
|
|
478
485
|
requires: [ 'location' ],
|
|
479
486
|
optional: [
|
|
480
487
|
'enum',
|
|
@@ -527,11 +534,11 @@ function assertConsistency( model, stage ) {
|
|
|
527
534
|
// query specific
|
|
528
535
|
'op', 'from', 'elements',
|
|
529
536
|
'_combined',
|
|
530
|
-
'$tableAliases',
|
|
537
|
+
'$tableAliases', '$inlines',
|
|
531
538
|
],
|
|
532
539
|
optional: [
|
|
533
540
|
'_effectiveType', '$parens',
|
|
534
|
-
'_deps',
|
|
541
|
+
'_deps', '$expand',
|
|
535
542
|
// query specific
|
|
536
543
|
'where', 'columns', 'mixin', 'quantifier', 'offset',
|
|
537
544
|
'orderBy', '$orderBy', 'groupBy', 'excludingDict', 'having',
|
|
@@ -572,13 +579,20 @@ function assertConsistency( model, stage ) {
|
|
|
572
579
|
$duplicates: { parser: true, kind: true, test: TODO }, // array of arts or true
|
|
573
580
|
$extension: { kind: true, test: TODO }, // TODO: introduce $applied instead or $status
|
|
574
581
|
$inferred: { parser: true, kind: true, test: isString },
|
|
575
|
-
|
|
582
|
+
|
|
583
|
+
// Helper property for the XSN-to-CSN transformation, see function setExpandStatus():
|
|
584
|
+
// client, universal: render expanded elements? gensrc: produce annotate statements?
|
|
585
|
+
$expand: { kind: true, test: isString }, // TODO: rename it to $elementsExpand ?
|
|
586
|
+
|
|
576
587
|
$autoexpose: { kind: [ 'entity' ], test: isBoolean, also: [ null, 'Composition' ] },
|
|
577
588
|
$a2j: { kind: true, enumerable: true, test: TODO },
|
|
578
589
|
$extra: { parser: true, test: TODO }, // for unexpected properties in CSN
|
|
579
590
|
$withLocalized: { test: isBoolean },
|
|
580
591
|
$sources: { parser: true, test: isArray( isString ) },
|
|
581
592
|
$expected: { parser: true, test: isString },
|
|
593
|
+
$messageFunctions: { test: TODO },
|
|
594
|
+
$functions: { test: TODO },
|
|
595
|
+
$volatileFunctions: { test: TODO },
|
|
582
596
|
};
|
|
583
597
|
let _noSyntaxErrors = null;
|
|
584
598
|
assertProp( model, null, stageParser ? ':parser' : ':model', null, true );
|
|
@@ -650,6 +664,8 @@ function assertConsistency( model, stage ) {
|
|
|
650
664
|
}
|
|
651
665
|
|
|
652
666
|
function standard( node, parent, prop, spec, name ) {
|
|
667
|
+
if (spec.also && spec.also.includes( node ))
|
|
668
|
+
return;
|
|
653
669
|
isObject( node, parent, prop, spec, name );
|
|
654
670
|
|
|
655
671
|
const names = Object.getOwnPropertyNames( node );
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Base Definitions for the Core Compiler
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const dictKinds = {
|
|
7
|
+
definitions: 'absolute',
|
|
8
|
+
elements: 'element',
|
|
9
|
+
enum: 'enum',
|
|
10
|
+
foreignKeys: 'key',
|
|
11
|
+
actions: 'action',
|
|
12
|
+
params: 'param',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const kindProperties = {
|
|
16
|
+
// TODO: also foreignKeys ?
|
|
17
|
+
namespace: { artifacts: true }, // on-the-fly context
|
|
18
|
+
context: { artifacts: true, normalized: 'namespace' },
|
|
19
|
+
service: { artifacts: true, normalized: 'namespace' },
|
|
20
|
+
entity: { elements: true, actions: true, params: () => false },
|
|
21
|
+
select: { normalized: 'select', elements: true },
|
|
22
|
+
$join: { normalized: 'select' },
|
|
23
|
+
$tableAlias: { normalized: 'alias' }, // table alias in select
|
|
24
|
+
$self: { normalized: 'alias' }, // table alias in select
|
|
25
|
+
$navElement: { normalized: 'element' },
|
|
26
|
+
$inline: { normalized: 'element' }, // column with inline property
|
|
27
|
+
event: { elements: true },
|
|
28
|
+
type: { elements: propExists, enum: propExists },
|
|
29
|
+
aspect: { elements: propExists },
|
|
30
|
+
annotation: { elements: propExists, enum: propExists },
|
|
31
|
+
enum: { normalized: 'element' },
|
|
32
|
+
element: { elements: propExists, enum: propExists, dict: 'elements' },
|
|
33
|
+
mixin: { normalized: 'alias' },
|
|
34
|
+
action: {
|
|
35
|
+
params: () => false, elements: () => false, enum: () => false, dict: 'actions',
|
|
36
|
+
}, // no extend params, only annotate
|
|
37
|
+
function: {
|
|
38
|
+
params: () => false, elements: () => false, enum: () => false, normalized: 'action',
|
|
39
|
+
}, // no extend params, only annotate
|
|
40
|
+
key: { normalized: 'element' },
|
|
41
|
+
param: { elements: () => false, enum: () => false, dict: 'params' },
|
|
42
|
+
source: { artifacts: true }, // TODO -> $source
|
|
43
|
+
using: {},
|
|
44
|
+
extend: {
|
|
45
|
+
isExtension: true,
|
|
46
|
+
noDep: 'special',
|
|
47
|
+
elements: true, /* only for parse-cdl */
|
|
48
|
+
actions: true, /* only for parse-cdl */
|
|
49
|
+
},
|
|
50
|
+
annotate: {
|
|
51
|
+
isExtension: true, noDep: 'special', elements: true, enum: true, actions: true, params: true,
|
|
52
|
+
},
|
|
53
|
+
builtin: {}, // = CURRENT_DATE, TODO: improve
|
|
54
|
+
$parameters: {}, // $parameters in query entities
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function propExists( prop, parent ) {
|
|
58
|
+
const obj = parent.returns || parent;
|
|
59
|
+
return (obj.items || obj.targetAspect || obj)[prop];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
dictKinds,
|
|
64
|
+
kindProperties,
|
|
65
|
+
};
|
package/lib/compiler/builtins.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const { forEachInDict } = require('../base/dictionaries');
|
|
6
6
|
const { builtinLocation } = require('../base/location');
|
|
7
|
-
const { setProp } = require('
|
|
7
|
+
const { setProp } = require('./utils');
|
|
8
8
|
|
|
9
9
|
const core = {
|
|
10
10
|
String: { parameters: [ 'length' ], category: 'string' },
|
|
@@ -83,6 +83,8 @@ const specialFunctions = {
|
|
|
83
83
|
const magicVariables = {
|
|
84
84
|
$user: {
|
|
85
85
|
elements: { id: {}, locale: {} },
|
|
86
|
+
// Allow $user.<any>
|
|
87
|
+
$uncheckedElements: true,
|
|
86
88
|
// Allow shortcut in CDL: `$user` becomes `$user.id` in CSN.
|
|
87
89
|
$autoElement: 'id',
|
|
88
90
|
}, // CDS-specific, not part of SQL
|
|
@@ -165,6 +167,31 @@ function isRelationTypeName(typeName) {
|
|
|
165
167
|
return typeCategories.relation.includes(typeName);
|
|
166
168
|
}
|
|
167
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Checks whether the given absolute path is inside a reserved namespace.
|
|
172
|
+
*
|
|
173
|
+
* @param {string} absolute
|
|
174
|
+
* @returns {boolean}
|
|
175
|
+
*/
|
|
176
|
+
function isInReservedNamespace(absolute) {
|
|
177
|
+
return absolute.startsWith( 'cds.') &&
|
|
178
|
+
!absolute.match(/^cds\.foundation(\.|$)/) &&
|
|
179
|
+
!absolute.match(/^cds\.outbox(\.|$)/); // Requested by Node runtime
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Tell if a type is (directly) a builtin type
|
|
184
|
+
* Note that in CSN builtins are not in the definition of the model, so we can only
|
|
185
|
+
* check against their absolute names. Builtin types are "cds.<something>", i.e. they
|
|
186
|
+
* are directly in 'cds', but not for example in 'cds.foundation'.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} type
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/
|
|
191
|
+
function isBuiltinType(type) {
|
|
192
|
+
return typeof type === 'string' && isInReservedNamespace(type);
|
|
193
|
+
}
|
|
194
|
+
|
|
168
195
|
/**
|
|
169
196
|
* Add CDS builtins like the `cds` namespace with types like `cds.Integer` to
|
|
170
197
|
* `definitions` of the XSN model as well as to `$builtins`.
|
|
@@ -267,6 +294,8 @@ module.exports = {
|
|
|
267
294
|
functionsWithoutParens,
|
|
268
295
|
specialFunctions,
|
|
269
296
|
initBuiltins,
|
|
297
|
+
isInReservedNamespace,
|
|
298
|
+
isBuiltinType,
|
|
270
299
|
isIntegerTypeName,
|
|
271
300
|
isDecimalTypeName,
|
|
272
301
|
isNumericTypeName,
|
package/lib/compiler/checks.js
CHANGED
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
|
-
const { makeMessageFunction } = require('../base/messages');
|
|
17
16
|
// const { hasArtifactTypeInformation } = require('../model/csnUtils')
|
|
18
17
|
const builtins = require('../compiler/builtins');
|
|
19
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
forEachGeneric, forEachDefinition, forEachMember,
|
|
20
|
+
} = require('../base/model');
|
|
20
21
|
|
|
21
22
|
function check( model ) { // = XSN
|
|
22
|
-
const { options } = model;
|
|
23
23
|
const {
|
|
24
24
|
error, warning, message,
|
|
25
|
-
} =
|
|
25
|
+
} = model.$messageFunctions;
|
|
26
26
|
forEachDefinition( model, checkArtifact );
|
|
27
27
|
return;
|
|
28
28
|
|
|
@@ -66,6 +66,8 @@ function check( model ) { // = XSN
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
function checkName( construct ) {
|
|
69
|
+
if (model.options.$skipNameCheck)
|
|
70
|
+
return;
|
|
69
71
|
// TODO: Move a corrected version of this check to definer (but do not rely
|
|
70
72
|
// on it!): The code below misses to consider CSN input.
|
|
71
73
|
if (construct.name.id && construct.name.id.indexOf('.') !== -1) {
|
|
@@ -630,8 +632,9 @@ function check( model ) { // = XSN
|
|
|
630
632
|
* @returns {void}
|
|
631
633
|
*/
|
|
632
634
|
function checkTokenStreamExpression(xpr, allowAssocTail) {
|
|
635
|
+
const args = Array.isArray(xpr.args) ? xpr.args : Object.values(xpr.args || {});
|
|
633
636
|
// Check for illegal argument usage within the expression
|
|
634
|
-
for (const arg of
|
|
637
|
+
for (const arg of args) {
|
|
635
638
|
if (isVirtualElement(arg))
|
|
636
639
|
error(null, arg.location, 'Virtual elements can\'t be used in an expression');
|
|
637
640
|
|