@sap/cds-compiler 2.4.4 → 2.10.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 +241 -1
- package/bin/.eslintrc.json +17 -0
- package/bin/cds_update_identifiers.js +8 -7
- package/bin/cdsc.js +180 -132
- package/bin/cdshi.js +18 -11
- package/bin/cdsse.js +38 -32
- package/bin/cdsv2m.js +8 -7
- package/doc/CHANGELOG_BETA.md +36 -1
- package/lib/api/main.js +81 -100
- package/lib/api/options.js +17 -11
- package/lib/api/validate.js +12 -8
- package/lib/backends.js +0 -81
- package/lib/base/keywords.js +32 -2
- package/lib/base/location.js +2 -2
- package/lib/base/message-registry.js +66 -4
- package/lib/base/messages.js +84 -27
- package/lib/base/model.js +2 -61
- package/lib/checks/arrayOfs.js +0 -1
- package/lib/checks/defaultValues.js +27 -2
- package/lib/checks/elements.js +1 -6
- package/lib/checks/enricher.js +8 -2
- 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 +27 -9
- package/lib/checks/selectItems.js +25 -2
- package/lib/checks/types.js +26 -2
- package/lib/checks/unknownMagic.js +38 -0
- package/lib/checks/utils.js +61 -0
- package/lib/checks/validator.js +66 -13
- package/lib/compiler/assert-consistency.js +24 -12
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +6 -4
- package/lib/compiler/definer.js +101 -39
- package/lib/compiler/index.js +88 -59
- package/lib/compiler/resolver.js +455 -209
- package/lib/compiler/shared.js +57 -33
- package/lib/edm/annotations/genericTranslation.js +183 -187
- package/lib/edm/csn2edm.js +128 -99
- package/lib/edm/edm.js +18 -21
- package/lib/edm/edmPreprocessor.js +361 -127
- package/lib/edm/edmUtils.js +103 -33
- package/lib/gen/Dictionary.json +74 -28
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +18 -4
- package/lib/gen/language.tokens +124 -118
- package/lib/gen/languageLexer.interp +13 -1
- package/lib/gen/languageLexer.js +870 -839
- package/lib/gen/languageLexer.tokens +116 -111
- package/lib/gen/languageParser.js +5894 -5614
- package/lib/json/from-csn.js +152 -67
- package/lib/json/to-csn.js +334 -135
- package/lib/language/antlrParser.js +4 -3
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +24 -14
- package/lib/language/language.g4 +188 -128
- package/lib/main.d.ts +435 -0
- package/lib/main.js +31 -7
- package/lib/model/api.js +78 -0
- package/lib/model/csnRefs.js +463 -187
- package/lib/model/csnUtils.js +280 -136
- package/lib/model/enrichCsn.js +75 -4
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/modelCompare/compare.js +70 -25
- package/lib/optionProcessor.js +13 -10
- package/lib/render/.eslintrc.json +4 -1
- package/lib/render/DuplicateChecker.js +8 -5
- package/lib/render/toCdl.js +123 -40
- package/lib/render/toHdbcds.js +156 -65
- package/lib/render/toSql.js +87 -11
- package/lib/render/utils/common.js +55 -9
- package/lib/render/utils/sql.js +3 -3
- package/lib/sql-identifier.js +6 -1
- package/lib/transform/{sql → db}/.eslintrc.json +0 -0
- package/lib/transform/{sql → db}/assertUnique.js +7 -8
- package/lib/transform/{sql → db}/constraints.js +35 -20
- package/lib/transform/db/draft.js +353 -0
- package/lib/transform/db/expansion.js +582 -0
- package/lib/transform/db/flattening.js +325 -0
- package/lib/transform/{sql → db}/groupByOrderBy.js +8 -16
- package/lib/transform/{sql → db}/helpers.js +0 -0
- package/lib/transform/{sql → db}/transformExists.js +256 -60
- package/lib/transform/forHanaNew.js +216 -765
- package/lib/transform/forOdataNew.js +60 -56
- package/lib/transform/localized.js +48 -26
- package/lib/transform/odata/attachPath.js +19 -4
- package/lib/transform/odata/expandStructKeysInAssociations.js +2 -2
- package/lib/transform/odata/generateForeignKeyElements.js +13 -12
- package/lib/transform/odata/referenceFlattener.js +60 -36
- package/lib/transform/odata/sortByAssociationDependency.js +4 -4
- package/lib/transform/odata/structuralPath.js +76 -0
- package/lib/transform/odata/structureFlattener.js +21 -22
- package/lib/transform/odata/toFinalBaseType.js +5 -5
- package/lib/transform/odata/typesExposure.js +27 -17
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +141 -77
- package/lib/transform/translateAssocsToJoins.js +17 -14
- package/lib/transform/universalCsnEnricher.js +67 -0
- package/lib/utils/file.js +0 -11
- package/lib/utils/moduleResolve.js +6 -8
- package/lib/utils/timetrace.js +6 -1
- package/package.json +2 -1
- package/lib/base/deepCopy.js +0 -66
- package/lib/json/walker.js +0 -26
- 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,
|
|
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,19 +114,21 @@ 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);
|
|
110
129
|
});
|
|
111
130
|
that.artifact = artifact;
|
|
112
|
-
if (memberValidators.length
|
|
113
|
-
(!iterateOptions.filterArtifact || iterateOptions.filterArtifact(artifact))) {
|
|
131
|
+
if (memberValidators.length) {
|
|
114
132
|
forEachMemberRecursively( artifact,
|
|
115
133
|
memberValidators.map(v => v.bind(that)),
|
|
116
134
|
path,
|
|
@@ -119,20 +137,52 @@ function _validate(csn, that,
|
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
if (queryValidators.length && getNormalizedQuery(artifact).query)
|
|
122
|
-
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' ]));
|
|
123
141
|
}, iterateOptions);
|
|
124
142
|
|
|
125
143
|
return cleanup;
|
|
126
144
|
}
|
|
127
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
|
+
|
|
128
178
|
/**
|
|
129
179
|
* @param {CSN.Model} csn CSN to check
|
|
130
180
|
* @param {object} that Will be provided to the validators via "this"
|
|
131
|
-
*
|
|
132
181
|
* @returns {Function} the validator function with the respective checks for the HANA backend
|
|
133
182
|
*/
|
|
134
183
|
function forHana(csn, that) {
|
|
135
184
|
return _validate(csn, that,
|
|
185
|
+
forHanaCsnValidators,
|
|
136
186
|
forHanaMemberValidators.concat(commonMemberValidators),
|
|
137
187
|
forHanaArtifactValidators.concat(commonArtifactValidators).concat(
|
|
138
188
|
// why is this hana exclusive
|
|
@@ -146,7 +196,7 @@ function forHana(csn, that) {
|
|
|
146
196
|
),
|
|
147
197
|
forHanaQueryValidators.concat(commonQueryValidators),
|
|
148
198
|
{
|
|
149
|
-
|
|
199
|
+
skipArtifact: artifact => artifact.abstract || hasAnnotationValue(artifact, '@cds.persistence.skip'),
|
|
150
200
|
skip: [
|
|
151
201
|
'action',
|
|
152
202
|
'function',
|
|
@@ -158,11 +208,11 @@ function forHana(csn, that) {
|
|
|
158
208
|
/**
|
|
159
209
|
* @param {CSN.Model} csn CSN to check
|
|
160
210
|
* @param {object} that Will be provided to the validators via "this"
|
|
161
|
-
*
|
|
162
211
|
* @returns {Function} the validator function with the respective checks for the OData backend
|
|
163
212
|
*/
|
|
164
213
|
function forOdata(csn, that) {
|
|
165
214
|
return _validate(csn, that,
|
|
215
|
+
forOdataCsnValidators,
|
|
166
216
|
forOdataMemberValidators.concat(commonMemberValidators),
|
|
167
217
|
forOdataArtifactValidators.concat(commonArtifactValidators).concat(
|
|
168
218
|
(artifact, artifactName) => {
|
|
@@ -176,7 +226,10 @@ function forOdata(csn, that) {
|
|
|
176
226
|
}
|
|
177
227
|
}
|
|
178
228
|
),
|
|
179
|
-
forOdataQueryValidators.concat(commonQueryValidators)
|
|
229
|
+
forOdataQueryValidators.concat(commonQueryValidators),
|
|
230
|
+
{
|
|
231
|
+
skipArtifact: this.isExternalServiceMember,
|
|
232
|
+
});
|
|
180
233
|
}
|
|
181
234
|
|
|
182
235
|
module.exports = { forHana, forOdata };
|
|
@@ -97,6 +97,7 @@ function assertConsistency( model, stage ) {
|
|
|
97
97
|
'_entities', '$entity',
|
|
98
98
|
'$blocks',
|
|
99
99
|
'$newfeatures',
|
|
100
|
+
'$messageFunctions',
|
|
100
101
|
],
|
|
101
102
|
},
|
|
102
103
|
':parser': { // top-level from parser
|
|
@@ -111,6 +112,7 @@ function assertConsistency( model, stage ) {
|
|
|
111
112
|
'meta',
|
|
112
113
|
'@sql_mapping', // TODO: it is time that a 'header' attribute replaces 'version'
|
|
113
114
|
'$withLocalized',
|
|
115
|
+
'$sources',
|
|
114
116
|
],
|
|
115
117
|
},
|
|
116
118
|
location: { // location req if at least one property:
|
|
@@ -121,8 +123,8 @@ function assertConsistency( model, stage ) {
|
|
|
121
123
|
schema: {
|
|
122
124
|
line: { test: isNumber },
|
|
123
125
|
col: { test: isNumber },
|
|
124
|
-
endLine: { test: isNumber },
|
|
125
|
-
endCol: { test: isNumber },
|
|
126
|
+
endLine: { test: isNumber, also: [ undefined ] },
|
|
127
|
+
endCol: { test: isNumber, also: [ undefined ] },
|
|
126
128
|
$notFound: { test: isBoolean },
|
|
127
129
|
},
|
|
128
130
|
},
|
|
@@ -244,8 +246,8 @@ function assertConsistency( model, stage ) {
|
|
|
244
246
|
optional: [
|
|
245
247
|
'name', '$parens', 'quantifier', 'mixin', 'excludingDict', 'columns', 'elements', '_deps',
|
|
246
248
|
'where', 'groupBy', 'having', 'orderBy', '$orderBy', 'limit',
|
|
247
|
-
'_projections', '_block', '_parent', '_main', '_effectiveType',
|
|
248
|
-
'$tableAliases', 'kind', '_$next', '_combined',
|
|
249
|
+
'_projections', '_block', '_parent', '_main', '_effectiveType', '$expand',
|
|
250
|
+
'$tableAliases', 'kind', '_$next', '_combined', '$inlines',
|
|
249
251
|
],
|
|
250
252
|
},
|
|
251
253
|
none: { optional: () => true }, // parse error
|
|
@@ -286,8 +288,8 @@ function assertConsistency( model, stage ) {
|
|
|
286
288
|
},
|
|
287
289
|
columns: {
|
|
288
290
|
kind: [ 'extend' ],
|
|
289
|
-
inherits: 'definitions',
|
|
290
291
|
test: isArray( column ),
|
|
292
|
+
optional: thoseWithKind,
|
|
291
293
|
enum: [ '*' ],
|
|
292
294
|
requires: [ 'location' ],
|
|
293
295
|
// schema: { kind: { isRequired: () => {} } } // kind not required
|
|
@@ -295,6 +297,7 @@ function assertConsistency( model, stage ) {
|
|
|
295
297
|
expand: { kind: [ 'element' ], inherits: 'columns' },
|
|
296
298
|
inline: { kind: [ 'element' ], inherits: 'columns' },
|
|
297
299
|
excludingDict: {
|
|
300
|
+
kind: 'element',
|
|
298
301
|
test: isDictionary( definition ), // definition since redef
|
|
299
302
|
requires: [ 'location', 'name' ],
|
|
300
303
|
optional: [ '$annotations' ], // TODO: get rid of annos: []
|
|
@@ -308,6 +311,7 @@ function assertConsistency( model, stage ) {
|
|
|
308
311
|
rows: { inherits: 'value' },
|
|
309
312
|
offset: { inherits: 'value' },
|
|
310
313
|
_combined: { test: TODO },
|
|
314
|
+
$inlines: { test: TODO },
|
|
311
315
|
type: {
|
|
312
316
|
kind: true,
|
|
313
317
|
requires: [ 'location', 'path' ],
|
|
@@ -320,7 +324,7 @@ function assertConsistency( model, stage ) {
|
|
|
320
324
|
requires: [ 'location' ],
|
|
321
325
|
optional: [
|
|
322
326
|
'path', 'elements', '_outer',
|
|
323
|
-
'scope', '_artifact', '$inferred',
|
|
327
|
+
'scope', '_artifact', '$inferred', '$expand',
|
|
324
328
|
'_effectiveType', // by propagation
|
|
325
329
|
],
|
|
326
330
|
},
|
|
@@ -347,6 +351,7 @@ function assertConsistency( model, stage ) {
|
|
|
347
351
|
$delimited: { parser: true, test: isBoolean },
|
|
348
352
|
scope: { test: isScope },
|
|
349
353
|
func: { test: TODO },
|
|
354
|
+
suffix: { test: TODO },
|
|
350
355
|
kind: {
|
|
351
356
|
isRequired: !stageParser && (() => true),
|
|
352
357
|
// required to be set by Core Compiler even with parse errors
|
|
@@ -394,6 +399,7 @@ function assertConsistency( model, stage ) {
|
|
|
394
399
|
optional: [
|
|
395
400
|
'args',
|
|
396
401
|
'func',
|
|
402
|
+
'suffix',
|
|
397
403
|
'quantifier',
|
|
398
404
|
'$inferred',
|
|
399
405
|
'$parens',
|
|
@@ -422,7 +428,7 @@ function assertConsistency( model, stage ) {
|
|
|
422
428
|
struct: { inherits: 'val', test: isDictionary( definition ) }, // def because double @
|
|
423
429
|
args: {
|
|
424
430
|
inherits: 'value',
|
|
425
|
-
optional: [ 'name', '$duplicate', '$expected' ],
|
|
431
|
+
optional: [ 'name', '$duplicate', '$expected', 'args', 'suffix' ],
|
|
426
432
|
test: args,
|
|
427
433
|
},
|
|
428
434
|
on: { kind: true, inherits: 'value', test: expression },
|
|
@@ -525,11 +531,11 @@ function assertConsistency( model, stage ) {
|
|
|
525
531
|
// query specific
|
|
526
532
|
'op', 'from', 'elements',
|
|
527
533
|
'_combined',
|
|
528
|
-
'$tableAliases',
|
|
534
|
+
'$tableAliases', '$inlines',
|
|
529
535
|
],
|
|
530
536
|
optional: [
|
|
531
537
|
'_effectiveType', '$parens',
|
|
532
|
-
'_deps',
|
|
538
|
+
'_deps', '$expand',
|
|
533
539
|
// query specific
|
|
534
540
|
'where', 'columns', 'mixin', 'quantifier', 'offset',
|
|
535
541
|
'orderBy', '$orderBy', 'groupBy', 'excludingDict', 'having',
|
|
@@ -539,7 +545,7 @@ function assertConsistency( model, stage ) {
|
|
|
539
545
|
_leadingQuery: { kind: true, test: TODO },
|
|
540
546
|
$replacement: { kind: true, test: TODO }, // for smart * in queries
|
|
541
547
|
_origin: { kind: [ 'entity' ], test: TODO },
|
|
542
|
-
_pathHead: { kind: [ 'element' ], test: TODO },
|
|
548
|
+
_pathHead: { kind: [ 'element', undefined ], test: TODO }, // column or * (wildcard)
|
|
543
549
|
_from: { kind: true, test: TODO }, // all table refs necessary to compute elements
|
|
544
550
|
// array of $tableAlias (or includes) for explicit and implicit redirection:
|
|
545
551
|
_redirected: { kind: true, test: TODO },
|
|
@@ -570,12 +576,18 @@ function assertConsistency( model, stage ) {
|
|
|
570
576
|
$duplicates: { parser: true, kind: true, test: TODO }, // array of arts or true
|
|
571
577
|
$extension: { kind: true, test: TODO }, // TODO: introduce $applied instead or $status
|
|
572
578
|
$inferred: { parser: true, kind: true, test: isString },
|
|
573
|
-
|
|
579
|
+
|
|
580
|
+
// Helper property for the XSN-to-CSN transformation, see function setExpandStatus():
|
|
581
|
+
// client, universal: render expanded elements? gensrc: produce annotate statements?
|
|
582
|
+
$expand: { kind: true, test: isString }, // TODO: rename it to $elementsExpand ?
|
|
583
|
+
|
|
574
584
|
$autoexpose: { kind: [ 'entity' ], test: isBoolean, also: [ null, 'Composition' ] },
|
|
575
585
|
$a2j: { kind: true, enumerable: true, test: TODO },
|
|
576
586
|
$extra: { parser: true, test: TODO }, // for unexpected properties in CSN
|
|
577
587
|
$withLocalized: { test: isBoolean },
|
|
588
|
+
$sources: { parser: true, test: isArray( isString ) },
|
|
578
589
|
$expected: { parser: true, test: isString },
|
|
590
|
+
$messageFunctions: { test: TODO },
|
|
579
591
|
};
|
|
580
592
|
let _noSyntaxErrors = null;
|
|
581
593
|
assertProp( model, null, stageParser ? ':parser' : ':model', null, true );
|
|
@@ -806,7 +818,7 @@ function assertConsistency( model, stage ) {
|
|
|
806
818
|
return function valWithLocation( node, parent, prop, spec, name ) {
|
|
807
819
|
const valSchema = { val: Object.assign( {}, spec, { test: func } ) };
|
|
808
820
|
const requires = [ 'val', 'location' ];
|
|
809
|
-
const optional = [ 'literal', '$inferred' ];
|
|
821
|
+
const optional = [ 'literal', '$inferred', '_pathHead' ];
|
|
810
822
|
standard( node, parent, prop, { schema: valSchema, requires, optional }, name );
|
|
811
823
|
};
|
|
812
824
|
}
|
package/lib/compiler/builtins.js
CHANGED
|
@@ -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
|
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) {
|