@sap/cds-compiler 3.3.2 → 3.4.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 +21 -0
- package/bin/cdsc.js +3 -1
- package/doc/CHANGELOG_BETA.md +17 -0
- package/lib/api/main.js +147 -18
- package/lib/api/validate.js +8 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/keywords.js +104 -0
- package/lib/base/message-registry.js +136 -67
- package/lib/base/messages.js +59 -48
- package/lib/base/model.js +1 -0
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +13 -8
- package/lib/checks/defaultValues.js +3 -1
- package/lib/checks/elements.js +1 -1
- package/lib/checks/parameters.js +4 -2
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/sql-snippets.js +12 -10
- package/lib/checks/validator.js +14 -4
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/checks.js +30 -20
- package/lib/compiler/define.js +89 -25
- package/lib/compiler/extend.js +21 -18
- package/lib/compiler/finalize-parse-cdl.js +14 -9
- package/lib/compiler/populate.js +30 -8
- package/lib/compiler/propagator.js +4 -2
- package/lib/compiler/resolve.js +11 -5
- package/lib/compiler/shared.js +66 -48
- package/lib/compiler/tweak-assocs.js +2 -3
- package/lib/compiler/utils.js +11 -0
- package/lib/edm/annotations/genericTranslation.js +7 -4
- package/lib/edm/csn2edm.js +1 -1
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3565 -3544
- package/lib/json/csnVersion.js +13 -13
- package/lib/json/from-csn.js +140 -158
- package/lib/json/to-csn.js +23 -5
- package/lib/language/.eslintrc.json +4 -0
- package/lib/language/antlrParser.js +7 -10
- package/lib/language/docCommentParser.js +1 -2
- package/lib/language/errorStrategy.js +54 -27
- package/lib/language/genericAntlrParser.js +115 -84
- package/lib/language/language.g4 +29 -25
- package/lib/language/multiLineStringParser.js +75 -63
- package/lib/main.js +1 -0
- package/lib/model/csnRefs.js +4 -3
- package/lib/model/csnUtils.js +39 -7
- package/lib/model/sortViews.js +7 -3
- package/lib/modelCompare/compare.js +49 -15
- package/lib/modelCompare/filter.js +83 -0
- package/lib/optionProcessor.js +5 -1
- package/lib/render/manageConstraints.js +9 -5
- package/lib/render/toCdl.js +120 -62
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +6 -2
- package/lib/render/utils/common.js +7 -0
- package/lib/sql-identifier.js +7 -0
- package/lib/transform/db/assertUnique.js +27 -38
- package/lib/transform/db/expansion.js +11 -4
- package/lib/transform/db/temporal.js +3 -1
- package/lib/transform/db/transformExists.js +7 -1
- package/lib/transform/db/views.js +42 -13
- package/lib/transform/draft/db.js +2 -2
- package/lib/transform/forRelationalDB.js +12 -6
- package/lib/transform/localized.js +1 -1
- package/lib/transform/odata/typesExposure.js +2 -1
- package/lib/transform/parseExpr.js +245 -0
- package/lib/transform/transformUtilsNew.js +23 -14
- package/lib/transform/translateAssocsToJoins.js +12 -12
- package/lib/utils/term.js +5 -5
- package/package.json +2 -2
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +1 -1
|
@@ -37,7 +37,11 @@ const { createDict } = require("../utils/objectUtils");
|
|
|
37
37
|
* Central register of messages and their configuration.
|
|
38
38
|
* Group by id-category.
|
|
39
39
|
*
|
|
40
|
-
* configurableFor:
|
|
40
|
+
* configurableFor: truthy = error can be downgraded in certain situations
|
|
41
|
+
* - true = can always be downgraded, we do not really care
|
|
42
|
+
* - [‹module›, …] = can be downgraded in compiler function ‹module›
|
|
43
|
+
* - 'deprecated' = severity can only be changed with deprecated.downgradableErrors
|
|
44
|
+
* - 'v3' = currently like true, but should be 'deprecated' in v4
|
|
41
45
|
*
|
|
42
46
|
* @type {Object<string, MessageConfig>}
|
|
43
47
|
*/
|
|
@@ -74,12 +78,11 @@ const centralMessages = {
|
|
|
74
78
|
|
|
75
79
|
'empty-type': { severity: 'Info' }, // only still an error in old transformers
|
|
76
80
|
|
|
77
|
-
// Structured types were warned about but made CSN un-recompilable.
|
|
78
|
-
'enum-invalid-type': { severity: 'Error', configurableFor: 'deprecated' },
|
|
79
|
-
|
|
80
81
|
// TODO: rename to ref-expected-XYZ
|
|
81
82
|
'expected-type': { severity: 'Error' },
|
|
82
83
|
'ref-sloppy-type': { severity: 'Error' },
|
|
84
|
+
'ref-unexpected-self': { severity: 'Error' },
|
|
85
|
+
'ref-expecting-bare-aspect': { severity: 'Error' },
|
|
83
86
|
'type-unexpected-typeof': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: make it non-config
|
|
84
87
|
'type-ignoring-argument': { severity: 'Error', configurableFor: true },
|
|
85
88
|
'type-expected-builtin': { severity: 'Error', configurableFor: true },
|
|
@@ -124,13 +127,10 @@ const centralMessages = {
|
|
|
124
127
|
'ref-rejected-on': { severity: 'Error' },
|
|
125
128
|
'ref-expected-element': { severity: 'Error' },
|
|
126
129
|
|
|
127
|
-
'rewrite-key-not-covered-explicit': { severity: 'Error'
|
|
128
|
-
'rewrite-key-not-covered-implicit': { severity: 'Error'
|
|
129
|
-
'rewrite-key-not-matched-explicit': { severity: 'Error'
|
|
130
|
-
'rewrite-key-not-matched-implicit': { severity: 'Error'
|
|
131
|
-
'rewrite-key-for-unmanaged': { severity: 'Error', configurableFor: 'deprecated' },
|
|
132
|
-
'rewrite-not-supported': { severity: 'Error' },
|
|
133
|
-
'rewrite-on-for-managed': { severity: 'Error', configurableFor: 'deprecated' },
|
|
130
|
+
'rewrite-key-not-covered-explicit': { severity: 'Error' },
|
|
131
|
+
'rewrite-key-not-covered-implicit': { severity: 'Error' },
|
|
132
|
+
'rewrite-key-not-matched-explicit': { severity: 'Error' },
|
|
133
|
+
'rewrite-key-not-matched-implicit': { severity: 'Error' },
|
|
134
134
|
|
|
135
135
|
'service-nested-context': { severity: 'Error', configurableFor: true }, // does not hurt compile, TODO
|
|
136
136
|
'service-nested-service': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
|
|
@@ -141,24 +141,13 @@ const centralMessages = {
|
|
|
141
141
|
// fallback, but then parse.cdl is not supposed to work correctly (it can
|
|
142
142
|
// then either issue an error or produce a CSN missing some annotations):
|
|
143
143
|
'syntax-duplicate-annotate': { severity: 'Error', configurableFor: true },
|
|
144
|
-
'syntax-
|
|
145
|
-
'syntax-expected-length': { severity: 'Error' },
|
|
146
|
-
'syntax-expected-translation': { severity: 'Error' },
|
|
147
|
-
'syntax-required-subproperty': { severity: 'Error' },
|
|
148
|
-
'syntax-unexpected-property': { severity: 'Error', configurableFor: true }, // is the removed
|
|
144
|
+
'syntax-unexpected-property': { severity: 'Error' },
|
|
149
145
|
'syntax-deprecated-ident': { severity: 'Error', configurableFor: true },
|
|
150
146
|
'syntax-fragile-alias': { severity: 'Error', configurableFor: true },
|
|
151
147
|
'syntax-fragile-ident': { severity: 'Error', configurableFor: true },
|
|
152
|
-
|
|
153
|
-
'syntax-invalid-extend': { severity: 'Error' },
|
|
154
|
-
|
|
155
|
-
'syntax-invalid-text-block' : { severity: 'Error' },
|
|
156
148
|
'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
|
|
157
|
-
'syntax-invalid-escape': { severity: 'Error' },
|
|
158
|
-
'syntax-missing-escape': { severity: 'Error' },
|
|
159
149
|
|
|
160
|
-
'syntax-
|
|
161
|
-
'syntax-invalid-masked': { severity: 'Error', configurableFor: true },
|
|
150
|
+
'syntax-unsupported-masked': { severity: 'Error', configurableFor: 'v3' },
|
|
162
151
|
'syntax-unexpected-null': { severity: 'Error', configurableFor: true },
|
|
163
152
|
|
|
164
153
|
'type-managed-composition': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: non-config
|
|
@@ -212,7 +201,10 @@ for (const oldName in oldMessageIds) {
|
|
|
212
201
|
}
|
|
213
202
|
|
|
214
203
|
|
|
215
|
-
// For messageIds, where no text has been provided via code (central def)
|
|
204
|
+
// For messageIds, where no text has been provided via code (central def).
|
|
205
|
+
// DO NOT CHANGE THE VARIABLE NAME!
|
|
206
|
+
// If you change it, keep in sync with scripts/eslint/rules/message-text.js
|
|
207
|
+
|
|
216
208
|
const centralMessageTexts = {
|
|
217
209
|
'api-invalid-option': {
|
|
218
210
|
// TODO: too many different error situations for one message id,
|
|
@@ -239,42 +231,118 @@ const centralMessageTexts = {
|
|
|
239
231
|
'flatten-fkey-gen': 'Duplicate definition of foreign key element $(NAME) for association $(ART)',
|
|
240
232
|
'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
|
|
241
233
|
},
|
|
242
|
-
|
|
234
|
+
|
|
235
|
+
// Syntax messages, both CDL and CSN parser: ----------------------------------
|
|
236
|
+
'syntax-dollar-ident': { // Warning, TODO: make it name-invalid-alias
|
|
237
|
+
std: 'An artifact starting with $(NAME) might shadow a special variable - replace by another name',
|
|
238
|
+
$tableAlias: 'A table alias name starting with $(NAME) might shadow a special variable - replace by another name',
|
|
239
|
+
$tableImplicit: 'The resulting table alias starts with $(NAME) and might shadow a special variable - specify another name with $(KEYWORD)',
|
|
240
|
+
mixin: 'A mixin name starting with $(NAME) might shadow a special variable - replace by another name',
|
|
241
|
+
},
|
|
242
|
+
// 'syntax-duplicate-excluding' (TODO: also CDL)
|
|
243
243
|
'syntax-ignoring-anno': {
|
|
244
244
|
std: 'Annotations can\'t be used at prefix references',
|
|
245
245
|
doc: 'Doc comments can\'t be used at prefix references',
|
|
246
246
|
},
|
|
247
|
+
'syntax-invalid-name': {
|
|
248
|
+
std: 'Identifier for name must not be empty', // TODO: use
|
|
249
|
+
csn: 'Property name in dictionary $(PARENTPROP) must not be empty',
|
|
250
|
+
},
|
|
251
|
+
'syntax-invalid-literal': { // TODO: write texts less CDL specific
|
|
252
|
+
'std': 'Invalid literal',
|
|
253
|
+
'uneven-hex': 'A binary literal must have an even number of characters',
|
|
254
|
+
'invalid-hex': 'A binary literal must only contain characters 0-9, a-f and A-F',
|
|
255
|
+
'time': 'Expecting time\'hh:mm:ss\' where hh, mm and the optional ss are numbers',
|
|
256
|
+
'date': 'Expecting date\'YYYY-MM-DD\' where YYYY, MM and DD are numbers',
|
|
257
|
+
'timestamp': 'Expecting timestamp\'YYYY-MM-DD hh:mm:ss.u…u\' where YYYY, MM, DD, hh, mm, ss and u are numbers (optional 1-7×u)',
|
|
258
|
+
},
|
|
259
|
+
'syntax-missing-ellipsis': 'Expecting an array item $(NEWCODE) after an item with $(CODE)',
|
|
247
260
|
'syntax-unexpected-ellipsis': {
|
|
248
|
-
std: '
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
'syntax-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
'syntax-expected-term': 'Expected non-empty string or object for property $(PROP)',
|
|
257
|
-
'syntax-dollar-ident': {
|
|
258
|
-
std: 'An artifact starting with $(NAME) might shadow a special variable - replace by another name',
|
|
259
|
-
$tableAlias: 'A table alias name starting with $(NAME) might shadow a special variable - replace by another name',
|
|
260
|
-
$tableImplicit: 'The resulting table alias starts with $(NAME) and might shadow a special variable - specify another name with $(KEYWORD)',
|
|
261
|
-
mixin: 'A mixin name starting with $(NAME) might shadow a special variable - replace by another name' ,
|
|
261
|
+
std: 'Unexpected array item $(CODE)',
|
|
262
|
+
duplicate: 'Unexpected array item $(CODE) after previous $(CODE) without $(KEYWORD)',
|
|
263
|
+
'csn-duplicate': 'Unexpected object with property $(PROP) after previous array item $(CODE)',
|
|
264
|
+
'csn-nested': 'Unexpected object with property $(PROP) in nested array',
|
|
265
|
+
},
|
|
266
|
+
'syntax-unsupported-masked': { // configurable Error
|
|
267
|
+
std: 'The keyword $(KEYWORD) is not supported',
|
|
268
|
+
csn: 'The property $(PROP) is not supported',
|
|
262
269
|
},
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
270
|
+
|
|
271
|
+
// Syntax messages, CDL parser - default: Error ------------------------------
|
|
272
|
+
'syntax-duplicate-annotate': 'You can\'t refer to $(NAME) repeatedly with property $(PROP) in the same annotate statement',
|
|
273
|
+
'syntax-duplicate-extend': {
|
|
274
|
+
std: 'You can\'t define and refer to $(NAME) repeatedly in the same extend statement',
|
|
275
|
+
define: 'You can\'t refer to $(NAME) in the same extend statement where it was defined',
|
|
276
|
+
extend: 'You can\'t refer to $(NAME) repeatedly in the same extend statement',
|
|
267
277
|
},
|
|
268
278
|
'syntax-invalid-extend': 'Can\'t extend an element with $(KIND)',
|
|
269
279
|
'syntax-invalid-text-block': 'Missing newline in text block',
|
|
280
|
+
'syntax-unsupported-param': {
|
|
281
|
+
std: 'Parameter not supported', // unused
|
|
282
|
+
dynamic: 'Dynamic parameter $(NAME) is not supported',
|
|
283
|
+
positional: 'Positional parameter $(NAME) is not supported',
|
|
284
|
+
},
|
|
285
|
+
|
|
286
|
+
// Syntax messages, CSN parser - default: Error ------------------------------
|
|
287
|
+
// TODO: use one id with text variants instead of several message ids
|
|
288
|
+
'syntax-deprecated-property': { // Warning
|
|
289
|
+
std: 'Deprecated property $(PROP)', // unused
|
|
290
|
+
'zero': 'Deprecated CSN v0.1.0 property $(PROP) is ignored',
|
|
291
|
+
'zero-replace': 'Replace CSN v0.1.0 property $(PROP) by $(OTHERPROP)',
|
|
292
|
+
},
|
|
293
|
+
'syntax-deprecated-value': { // Warning
|
|
294
|
+
std: 'Deprecated representation of the value in property $(PROP)',
|
|
295
|
+
replace: 'Replace value in $(PROP) by $(VALUE)',
|
|
296
|
+
'zero-parens': 'Deprecated CSN v.0.1.0 representation of expressions in parentheses',
|
|
297
|
+
'zero-replace': 'Replace CSN v0.1.0 value in $(PROP) by $(VALUE)',
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
'syntax-expecting-object': 'Expecting object for property $(PROP)',
|
|
301
|
+
'syntax-expecting-column': 'Expecting object or string \'*\' for property $(PROP)',
|
|
302
|
+
'syntax-expecting-natnum': 'Expecting non-negative number for property $(PROP)',
|
|
303
|
+
'syntax-expecting-cardinality': 'Expecting non-negative number or string \'*\' for property $(PROP)',
|
|
304
|
+
'syntax-expecting-reference': 'Expecting non-empty string or object for property $(PROP)',
|
|
305
|
+
'syntax-expecting-term': 'Expecting non-empty string or object for property $(PROP)',
|
|
306
|
+
// 'syntax-expecting-string', 'syntax-expecting-boolean' (Warning), 'syntax-expecting-scalar',
|
|
307
|
+
// 'syntax-expecting-args', 'syntax-expecting-translation', 'syntax-expecting-array'
|
|
308
|
+
'syntax-incomplete-array': { // location at ']'
|
|
309
|
+
std: 'Expecting array in $(PROP) to have at least $(N) items',
|
|
310
|
+
one: 'Expecting array in $(PROP) to have at least one item',
|
|
311
|
+
suffix: 'With sibling property $(SIBLINGPROP), expecting array in $(PROP) to have at least one item',
|
|
312
|
+
},
|
|
313
|
+
'syntax-incomplete-object': { // location at '}'
|
|
314
|
+
std: 'Object in $(PROP) must have at least one valid CSN property',
|
|
315
|
+
as: 'Object in $(PROP) must have at least one valid CSN property other than $(OTHERPROP)',
|
|
316
|
+
},
|
|
317
|
+
// 'syntax-invalid-ref' (Warning?), 'syntax-invalid-kind', 'syntax-invalid-literal' (Warning)
|
|
318
|
+
'syntax-invalid-string': {
|
|
319
|
+
std: 'Invalid string value in property $(PROP)',
|
|
320
|
+
},
|
|
321
|
+
'syntax-missing-property': { // location at sibling or '}' otherwise
|
|
322
|
+
std: 'Object in $(PARENTPROP) must have the property $(PROP)',
|
|
323
|
+
sibling: 'Object with property $(SIBLINGPROP) must also have a property $(PROP)',
|
|
324
|
+
columns: 'Object in $(PARENTPROP) must have an expression property like $(PROP)',
|
|
325
|
+
extensions: 'Object in $(PARENTPROP) must have the property $(PROP) or $(OTHERPROP)',
|
|
326
|
+
},
|
|
327
|
+
'syntax-unexpected-property': {
|
|
328
|
+
std: 'Unexpected CSN property $(PROP)',
|
|
329
|
+
sibling: 'CSN property $(PROP) is not expected in an object with property $(SIBLINGPROP)',
|
|
330
|
+
prop: 'CSN property $(PROP) is not expected in $(PARENTPROP)',
|
|
331
|
+
top: 'CSN property $(PROP) is not expected top-level',
|
|
332
|
+
kind: 'CSN property $(PROP) is not expected by a definition of kind $(KIND)',
|
|
333
|
+
extend: 'CSN property $(PROP) is not expected by an extend in $(PARENTPROP)',
|
|
334
|
+
annotate: 'CSN property $(PROP) is not expected by an annotate in $(PARENTPROP)',
|
|
335
|
+
},
|
|
336
|
+
// 'syntax-unknown-property' (Warning? Better configurable Error)
|
|
337
|
+
|
|
270
338
|
'syntax-unknown-escape': 'Unknown escape sequence $(CODE)',
|
|
271
339
|
'syntax-invalid-escape': {
|
|
272
340
|
std: 'Invalid escape sequence $(CODE)',
|
|
273
341
|
octal: 'Octal escape sequences are not supported. Use unicode escapes instead',
|
|
274
342
|
whitespace: 'Unknown escape sequence: Can\'t escape whitespace',
|
|
275
343
|
codepoint: 'Undefined code-point for $(CODE)',
|
|
276
|
-
'unicode-hex': '
|
|
277
|
-
'hex-count': '
|
|
344
|
+
'unicode-hex': 'Expecting hexadecimal numbers for unicode escape but found $(CODE)',
|
|
345
|
+
'hex-count': 'Expecting $(NUMBER) hexadecimal numbers for escape sequence but found $(CODE)',
|
|
278
346
|
'unicode-brace': 'Missing closing brace for unicode escape sequence',
|
|
279
347
|
'language-identifier': 'Escape sequences in text-block\'s language identifier are not allowed',
|
|
280
348
|
},
|
|
@@ -282,41 +350,34 @@ const centralMessageTexts = {
|
|
|
282
350
|
std: 'Missing escape. Replace $(CODE) with $(NEWCODE)',
|
|
283
351
|
placeholder: 'Placeholders are not supported. Replace $(CODE) with $(NEWCODE)',
|
|
284
352
|
},
|
|
285
|
-
'syntax-
|
|
353
|
+
'syntax-expecting-integer': {
|
|
286
354
|
std: 'A safe integer is expected here',
|
|
287
355
|
normal: 'An integer number is expected here',
|
|
288
356
|
unsafe: 'The provided integer is too large',
|
|
289
357
|
},
|
|
290
|
-
'syntax-duplicate-argument': {
|
|
358
|
+
'syntax-duplicate-argument': { // TODO: also CDL
|
|
291
359
|
std: 'Unexpected argument $(CODE)',
|
|
292
|
-
unknown: 'Unknown argument $(CODE)',
|
|
360
|
+
unknown: 'Unknown argument $(CODE)', // huh?
|
|
293
361
|
duplicate: 'Duplicate argument $(CODE)',
|
|
294
362
|
},
|
|
295
|
-
'syntax-duplicate-annotate': 'You can\'t refer to $(NAME) repeatedly with property $(PROP) in the same annotate statement',
|
|
296
|
-
'syntax-duplicate-extend': {
|
|
297
|
-
std: 'You can\'t define and refer to $(NAME) repeatedly in the same extend statement',
|
|
298
|
-
define: 'You can\'t refer to $(NAME) in the same extend statement where it was defined',
|
|
299
|
-
extend: 'You can\'t refer to $(NAME) repeatedly in the same extend statement',
|
|
300
|
-
},
|
|
301
|
-
'syntax-invalid-literal': {
|
|
302
|
-
'std': 'Invalid literal',
|
|
303
|
-
'uneven-hex': 'A binary literal must have an even number of characters',
|
|
304
|
-
'invalid-hex': 'A binary literal must only contain characters 0-9, a-f and A-F',
|
|
305
|
-
'time': 'Expected time\'hh:mm:ss\' where hh, mm and the optional ss are numbers',
|
|
306
|
-
'date': 'Expected date\'YYYY-MM-DD\' where YYYY, MM and DD are numbers',
|
|
307
|
-
'timestamp': 'Expected timestamp\'YYYY-MM-DD hh:mm:ss.u…u\' where YYYY, MM, DD, hh, mm, ss and u are numbers (optional 1-7×u)',
|
|
308
|
-
},
|
|
309
363
|
'syntax-unexpected-null': 'Keyword $(KEYWORD) must appear after the enum definition and not before',
|
|
310
364
|
'syntax-unexpected-vocabulary': {
|
|
311
365
|
std: 'Annotations can\'t be defined inside contexts or services',
|
|
312
366
|
service: 'Annotations can\'t be defined inside services',
|
|
313
367
|
context: 'Annotations can\'t be defined inside contexts',
|
|
314
368
|
},
|
|
369
|
+
'syntax-fragile-ident': '$(ID) is a reserved name here - write $(DELIMITED) instead if you want to use it',
|
|
370
|
+
'syntax-unsupported-field': 'Calculated fields are not supported, yet',
|
|
371
|
+
|
|
372
|
+
// Syntax messages for errorneous references ----------------------------------
|
|
373
|
+
// location at errorneous reference (if possible)
|
|
374
|
+
'ref-unexpected-self': 'Unexpected $(ID) reference; is valid only in ON-conditions',
|
|
315
375
|
'ref-undefined-def': {
|
|
316
376
|
std: 'Artifact $(ART) has not been found',
|
|
317
377
|
// TODO: proposal 'No definition of $(NAME) found',
|
|
318
|
-
element: 'Artifact $(ART) has no element $(MEMBER)'
|
|
378
|
+
element: 'Artifact $(ART) has no element $(MEMBER)',
|
|
319
379
|
},
|
|
380
|
+
'ref-undefined-param': 'Entity $(ART) has no parameter $(ID)',
|
|
320
381
|
'ref-undefined-art': 'No artifact has been found with name $(NAME)',
|
|
321
382
|
// TODO: proposal 'No definition found for $(NAME)',
|
|
322
383
|
'ref-undefined-element': {
|
|
@@ -324,6 +385,7 @@ const centralMessageTexts = {
|
|
|
324
385
|
element: 'Artifact $(ART) has no element $(MEMBER)',
|
|
325
386
|
aspect: 'Element $(ID) has not been found in the anonymous target aspect'
|
|
326
387
|
},
|
|
388
|
+
'ref-undefined-var': 'Element or variable $(ID) has not been found',
|
|
327
389
|
'ref-unknown-var': {
|
|
328
390
|
std: 'No replacement found for special variable $(ID)'
|
|
329
391
|
},
|
|
@@ -416,7 +478,8 @@ const centralMessageTexts = {
|
|
|
416
478
|
'expected-target': 'An entity or an aspect is expected here',
|
|
417
479
|
'extend-columns': 'Artifact $(ART) can\'t be extended with columns, only projections can',
|
|
418
480
|
'extend-repeated-intralayer': 'Unstable element order due to repeated extensions in same layer',
|
|
419
|
-
|
|
481
|
+
'extend-unexpected-include': 'Can\'t extend $(KIND) with includes',
|
|
482
|
+
'ref-expecting-bare-aspect': 'An aspect without elements is expected here',
|
|
420
483
|
|
|
421
484
|
'ext-duplicate-extend-type': 'Duplicate type extension for type $(TYPE)',
|
|
422
485
|
'ext-duplicate-extend-type-unrelated-layer': 'Duplicate type extension for type $(TYPE)',
|
|
@@ -424,9 +487,9 @@ const centralMessageTexts = {
|
|
|
424
487
|
std: 'Property $(PROP) can only be extended',
|
|
425
488
|
'new-prop': 'Property $(PROP) can only be extended, not added',
|
|
426
489
|
// eslint-disable-next-line max-len
|
|
427
|
-
smaller: 'Property $(PROP) can only be extended, but $(
|
|
490
|
+
smaller: 'Property $(PROP) can only be extended, but $(VALUE) is smaller than $(NUMBER) of type definition',
|
|
428
491
|
// eslint-disable-next-line max-len
|
|
429
|
-
'ext-smaller': 'Property $(PROP) can only be extended, but extended value $(
|
|
492
|
+
'ext-smaller': 'Property $(PROP) can only be extended, but extended value $(VALUE) is smaller than $(NUMBER) from previous type extension',
|
|
430
493
|
prop: 'Type property $(PROP) can\'t be extended',
|
|
431
494
|
scale: 'If property $(PROP) is increased, then so must $(OTHERPROP)',
|
|
432
495
|
string: 'Only numerical properties can be extended, but found string for $(PROP)',
|
|
@@ -437,6 +500,10 @@ const centralMessageTexts = {
|
|
|
437
500
|
inferred: 'Only direct types can be extended',
|
|
438
501
|
},
|
|
439
502
|
|
|
503
|
+
'query-undefined-element': {
|
|
504
|
+
std: 'Element $(ID) has not been found in the elements of the query',
|
|
505
|
+
redirected: 'Element $(ID) has not been found in the elements of the query; please use REDIRECTED TO with an explicit ON-condition',
|
|
506
|
+
},
|
|
440
507
|
'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
|
|
441
508
|
'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
|
|
442
509
|
'query-ignoring-param-nullability': {
|
|
@@ -530,4 +597,6 @@ const centralMessageTexts = {
|
|
|
530
597
|
* Don't set this property directly! Append to object oldMessageIds instead!
|
|
531
598
|
*/
|
|
532
599
|
|
|
600
|
+
//console.log('FOO')
|
|
601
|
+
|
|
533
602
|
module.exports = { centralMessages, centralMessageTexts, oldMessageIds };
|
package/lib/base/messages.js
CHANGED
|
@@ -42,9 +42,10 @@ function hasErrors( messages ) {
|
|
|
42
42
|
* @param {string} moduleName
|
|
43
43
|
* @returns {boolean}
|
|
44
44
|
*/
|
|
45
|
-
function hasNonDowngradableErrors( messages, moduleName ) {
|
|
46
|
-
return messages &&
|
|
47
|
-
|
|
45
|
+
function hasNonDowngradableErrors( messages, moduleName, deprecatedDowngradable ) {
|
|
46
|
+
return messages &&
|
|
47
|
+
messages.some( m => m.severity === 'Error' &&
|
|
48
|
+
!isDowngradable( m.messageId, moduleName, deprecatedDowngradable ));
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
/**
|
|
@@ -54,10 +55,11 @@ function hasNonDowngradableErrors( messages, moduleName ) {
|
|
|
54
55
|
*
|
|
55
56
|
* @param {string} messageId
|
|
56
57
|
* @param {string} moduleName
|
|
58
|
+
* @param {boolean} deprecatedDowngradable
|
|
57
59
|
* @returns {boolean}
|
|
58
60
|
*/
|
|
59
|
-
function isDowngradable( messageId, moduleName ) {
|
|
60
|
-
if (!centralMessages[messageId])
|
|
61
|
+
function isDowngradable( messageId, moduleName, deprecatedDowngradable ) {
|
|
62
|
+
if (!messageId || !centralMessages[messageId])
|
|
61
63
|
return false;
|
|
62
64
|
|
|
63
65
|
const msg = centralMessages[messageId];
|
|
@@ -66,10 +68,12 @@ function isDowngradable( messageId, moduleName ) {
|
|
|
66
68
|
// the module, it is NEVER downgradable.
|
|
67
69
|
if (msg.errorFor && msg.errorFor.includes(moduleName))
|
|
68
70
|
return false;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
if (msg.severity !== 'Error')
|
|
72
|
+
return true;
|
|
73
|
+
const { configurableFor } = msg;
|
|
74
|
+
return (Array.isArray( configurableFor ))
|
|
75
|
+
? configurableFor.includes( moduleName )
|
|
76
|
+
: configurableFor && (configurableFor !== 'deprecated' || deprecatedDowngradable);
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
/**
|
|
@@ -173,7 +177,7 @@ const severitySpecs = {
|
|
|
173
177
|
* @param {boolean} deprecatedDowngradable
|
|
174
178
|
* @returns {MessageSeverity}
|
|
175
179
|
*/
|
|
176
|
-
function reclassifiedSeverity(msg, options, moduleName, deprecatedDowngradable ) {
|
|
180
|
+
function reclassifiedSeverity( msg, options, moduleName, deprecatedDowngradable ) {
|
|
177
181
|
const spec = centralMessages[msg.messageId] || { severity: msg.severity, configurableFor: null, errorFor: null };
|
|
178
182
|
if (spec.severity === 'Error') {
|
|
179
183
|
const { configurableFor } = spec;
|
|
@@ -350,7 +354,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
350
354
|
|
|
351
355
|
messages.push( msg );
|
|
352
356
|
hasNewError = hasNewError || msg.severity === 'Error' &&
|
|
353
|
-
!(options.testMode &&
|
|
357
|
+
!(options.testMode && isDowngradable( msg.messageId, moduleName, deprecatedDowngradable ));
|
|
354
358
|
if (!hasMessageArray)
|
|
355
359
|
console.error( messageString( msg ) );
|
|
356
360
|
return msg;
|
|
@@ -496,7 +500,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
496
500
|
if (!messages || !messages.length)
|
|
497
501
|
return;
|
|
498
502
|
const hasError = options.testMode ? hasNonDowngradableErrors : hasErrors;
|
|
499
|
-
if (hasError( messages, moduleName ))
|
|
503
|
+
if (hasError( messages, moduleName, deprecatedDowngradable ))
|
|
500
504
|
throw new CompilationError( messages, options.attachValidNames && model );
|
|
501
505
|
}
|
|
502
506
|
|
|
@@ -514,7 +518,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
|
|
|
514
518
|
// Re-set the module regardless of severity, since we reclassified it.
|
|
515
519
|
Object.defineProperty( msg, '$module', { value: moduleName, configurable: true } );
|
|
516
520
|
hasNewError = hasNewError || severity === 'Error' &&
|
|
517
|
-
!(options.testMode &&
|
|
521
|
+
!(options.testMode && isDowngradable( msg.messageId, moduleName, deprecatedDowngradable ));
|
|
518
522
|
}
|
|
519
523
|
}
|
|
520
524
|
}
|
|
@@ -602,7 +606,7 @@ function _check$Severities( id, moduleName, severity ) {
|
|
|
602
606
|
return;
|
|
603
607
|
}
|
|
604
608
|
// now try whether the message could be something less than an Error in the module due to user wishes
|
|
605
|
-
if (!isDowngradable( id, moduleName )) { // always an error in module
|
|
609
|
+
if (!isDowngradable( id, moduleName, true )) { // always an error in module
|
|
606
610
|
if (severity !== 'Error')
|
|
607
611
|
throw new CompilerAssertion( `Inconsistent severity: Expecting "Error", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
|
|
608
612
|
}
|
|
@@ -636,14 +640,12 @@ function _check$Texts( id, prop, value ) {
|
|
|
636
640
|
throw new CompilerAssertion( `Different texts for the same message ID. Expecting "${expected}", not "${value}" for ID "${id}" and text variant "${prop}"`);
|
|
637
641
|
}
|
|
638
642
|
|
|
639
|
-
const quote = {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
// TODO: probably use keyword as function name, but its name would not have length 4 :-(
|
|
646
|
-
word: w => w.toUpperCase(), // keyword
|
|
643
|
+
const quote = { // could be an option in the future
|
|
644
|
+
double: p => `“${ p }”`, // for names, including annotation names (with preceeding `@`)
|
|
645
|
+
single: p => `‘${ p }’`, // for other things cited from the model
|
|
646
|
+
angle: p => `‹${ p }›`, // for tokens like ‹Identifier›, and similar
|
|
647
|
+
number: p => p, // for numbers like 42
|
|
648
|
+
upper: p => p.toUpperCase(), // for keywords reported by ANTLR, use prop.single in v4
|
|
647
649
|
}
|
|
648
650
|
|
|
649
651
|
const paramsTransform = {
|
|
@@ -651,33 +653,38 @@ const paramsTransform = {
|
|
|
651
653
|
name: quoted,
|
|
652
654
|
id: quoted,
|
|
653
655
|
alias: quoted,
|
|
654
|
-
anno: a => (a.charAt(0) === '@' ? quote.
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
656
|
+
anno: a => (a.charAt(0) === '@' ? quote.double( a ) : quote.double( '@' + a )),
|
|
657
|
+
annos: anno => anno.map(paramsTransform.anno).join(', '),
|
|
658
|
+
delimited: n => '![' + n + ']', // TODO: use quote.single around?
|
|
659
|
+
file: quote.single,
|
|
660
|
+
prop: quote.single,
|
|
661
|
+
siblingprop: quote.single,
|
|
662
|
+
parentprop: quote.single,
|
|
663
|
+
otherprop: quote.single,
|
|
664
|
+
code: quote.single,
|
|
665
|
+
newcode: quote.single,
|
|
666
|
+
kind: quote.angle, // consider using text variants instead
|
|
667
|
+
keyword: quote.upper,
|
|
663
668
|
// more complex convenience:
|
|
664
669
|
names: transformManyWith( quoted ),
|
|
665
|
-
number:
|
|
666
|
-
line:
|
|
667
|
-
col:
|
|
668
|
-
|
|
670
|
+
number: quote.number,
|
|
671
|
+
line: quote.number,
|
|
672
|
+
col: quote.number,
|
|
673
|
+
value: n => (typeof n !== 'number' ? quote.single( n ) : quote.number( n )),
|
|
674
|
+
othervalue: n => (typeof n !== 'number' ? quote.single( n ) : quote.number( n )),
|
|
669
675
|
art: transformArg,
|
|
670
676
|
service: transformArg,
|
|
671
677
|
sorted_arts: transformManyWith( transformArg, true ),
|
|
672
678
|
target: transformArg,
|
|
679
|
+
source: transformArg,
|
|
673
680
|
elemref: transformElementRef,
|
|
674
681
|
type: transformArg,
|
|
675
682
|
offending: tokenSymbol,
|
|
676
|
-
op: quote.
|
|
683
|
+
op: quote.single,
|
|
677
684
|
expecting: transformManyWith( tokenSymbol ),
|
|
678
685
|
// msg: m => m,
|
|
679
686
|
$reviewed: ignoreTextTransform,
|
|
680
|
-
version: quote.
|
|
687
|
+
version: quote.single, // TODO delete: just use for OData $(VERSION), with version: 2.0
|
|
681
688
|
};
|
|
682
689
|
|
|
683
690
|
function ignoreTextTransform() {
|
|
@@ -700,20 +707,20 @@ function transformManyWith( t, sorted ) {
|
|
|
700
707
|
}
|
|
701
708
|
|
|
702
709
|
function quoted( name ) {
|
|
703
|
-
return (name) ? quote.
|
|
710
|
+
return (name) ? quote.double( name ) : quote.angle( '?' ); // TODO: failure in --test-mode, then remove
|
|
704
711
|
}
|
|
705
712
|
|
|
706
713
|
function tokenSymbol( token ) {
|
|
707
714
|
if (token.match( /^[A-Z][A-Z]/ )) // keyword
|
|
708
|
-
return quote.
|
|
715
|
+
return quote.upper( token );
|
|
709
716
|
else if (token.match( /^[A-Z][a-z]/ )) // Number, Identifier, ...
|
|
710
|
-
return quote.
|
|
717
|
+
return quote.angle( token );
|
|
711
718
|
if (token.startsWith("'") && token.endsWith("'")) // operator token symbol
|
|
712
|
-
return quote.
|
|
719
|
+
return quote.single( token.slice( 1, -1 ));
|
|
713
720
|
else if (token === '<EOF>')
|
|
714
|
-
return quote.
|
|
721
|
+
return quote.angle( 'EOF' );
|
|
715
722
|
else
|
|
716
|
-
return quote.
|
|
723
|
+
return quote.single( token ); // should not happen
|
|
717
724
|
}
|
|
718
725
|
|
|
719
726
|
/**
|
|
@@ -1107,7 +1114,7 @@ function shortArtName( art ) {
|
|
|
1107
1114
|
const { name } = art;
|
|
1108
1115
|
if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null || name[n] === 1 ) &&
|
|
1109
1116
|
!name.absolute.includes(':'))
|
|
1110
|
-
return quote.
|
|
1117
|
+
return quote.double( name.element ? `${ name.absolute }:${ name.element }` : name.absolute );
|
|
1111
1118
|
return artName( art );
|
|
1112
1119
|
}
|
|
1113
1120
|
|
|
@@ -1230,11 +1237,15 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
|
|
|
1230
1237
|
|
|
1231
1238
|
let { query } = analyseCsnPath(csnPath, model, false);
|
|
1232
1239
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1240
|
+
const dictName = csnPath.shift();
|
|
1241
|
+
const dict = model[dictName];
|
|
1235
1242
|
const artifactName = csnPath.shift();
|
|
1236
|
-
let currentThing =
|
|
1237
|
-
let result = `${ (currentThing
|
|
1243
|
+
let currentThing = dict ? dict[artifactName] : undefined;
|
|
1244
|
+
let result = `${ (currentThing?.kind)
|
|
1245
|
+
? currentThing.kind
|
|
1246
|
+
: (dictName === 'vocabularies'
|
|
1247
|
+
? 'annotation'
|
|
1248
|
+
: 'artifact') }:${ _quoted(artifactName) }`;
|
|
1238
1249
|
|
|
1239
1250
|
if (!currentThing)
|
|
1240
1251
|
return result;
|
package/lib/base/model.js
CHANGED
|
@@ -22,7 +22,7 @@ function checkActionOrFunction(art, artName, prop, path) {
|
|
|
22
22
|
|
|
23
23
|
const serviceName = this.csnUtils.getServiceName(artName);
|
|
24
24
|
if (!serviceName)
|
|
25
|
-
this.warning(null, path, {},
|
|
25
|
+
this.warning(null, path, {}, 'Functions and actions must be declared in a service');
|
|
26
26
|
|
|
27
27
|
if (art.kind === 'entity') {
|
|
28
28
|
for (const [ actName, act ] of Object.entries(art.actions)) {
|
|
@@ -17,7 +17,7 @@ function validateCdsPersistenceAnnotation(artifact, artifactName, prop, path) {
|
|
|
17
17
|
// TODO: Why not filter over persistenceAnnos, is shorter!
|
|
18
18
|
const TableUdfCv = Object.keys(artifact).filter(p => persistenceAnnos.includes(p) && artifact[p]);
|
|
19
19
|
if (TableUdfCv.length > 1)
|
|
20
|
-
this.error(null, path, {},
|
|
20
|
+
this.error(null, path, { annos: TableUdfCv }, 'Annotations $(ANNOS) can\'t be used in combination');
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -12,26 +12,30 @@ const { isPersistedOnDatabase } = require('../model/csnUtils.js');
|
|
|
12
12
|
*/
|
|
13
13
|
function checkForHanaTypes(parent, name, type, path) {
|
|
14
14
|
const artifact = this.csn.definitions[path[1]];
|
|
15
|
-
if (artifact.kind === 'entity' && isPersistedOnDatabase(artifact) && typeof parent.type === 'string' && parent.type.startsWith('cds.hana.'))
|
|
16
|
-
this.error('ref-unexpected-hana-type', [ ...path, 'type' ], {
|
|
15
|
+
if (artifact.kind === 'entity' && isPersistedOnDatabase(artifact) && typeof parent.type === 'string' && parent.type.startsWith('cds.hana.')) {
|
|
16
|
+
this.error('ref-unexpected-hana-type', [ ...path, 'type' ], { type: 'cds.hana', value: this.options.sqlDialect },
|
|
17
|
+
'Types in the $(TYPE) namespace can\'t be used with sqlDialect $(VALUE)');
|
|
18
|
+
}
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* Check that `cds.UInt8`is not used - we don't have a clear idea how to represent it on postgres
|
|
22
|
+
* Check that `cds.UInt8` is not used - we don't have a clear idea how to represent it on postgres and h2
|
|
21
23
|
*
|
|
22
24
|
* @param {object} parent Object with a type
|
|
23
25
|
* @param {string} name Name of the type property on parent
|
|
24
26
|
* @param {Array} type type to check
|
|
25
27
|
* @param {CSN.Path} path
|
|
26
28
|
*/
|
|
27
|
-
function
|
|
29
|
+
function CheckForUInt8(parent, name, type, path) {
|
|
28
30
|
const artifact = this.csn.definitions[path[1]];
|
|
29
|
-
if (artifact.kind === 'entity' && isPersistedOnDatabase(artifact) && parent.type === 'cds.UInt8')
|
|
30
|
-
this.error('ref-unexpected-type', [ ...path, 'type' ], {
|
|
31
|
+
if (artifact.kind === 'entity' && isPersistedOnDatabase(artifact) && parent.type === 'cds.UInt8') {
|
|
32
|
+
this.error('ref-unexpected-type', [ ...path, 'type' ], { type: 'cds.UInt8', value: this.options.sqlDialect },
|
|
33
|
+
'Type $(TYPE) can\'t be used with sqlDialect $(VALUE)');
|
|
34
|
+
}
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
/**
|
|
34
|
-
* Check types - specifically for postgres
|
|
38
|
+
* Check types - specifically for postgres and h2
|
|
35
39
|
*
|
|
36
40
|
* @param {object} parent Object with a type
|
|
37
41
|
* @param {string} name Name of the type property on parent
|
|
@@ -40,7 +44,8 @@ function checkForUInt8(parent, name, type, path) {
|
|
|
40
44
|
*/
|
|
41
45
|
function checkTypes(parent, name, type, path) {
|
|
42
46
|
checkForHanaTypes.bind(this)(parent, name, type, path);
|
|
43
|
-
|
|
47
|
+
if (this.options.sqlDialect === 'postgres' || this.options.sqlDialect === 'h2')
|
|
48
|
+
CheckForUInt8.bind(this)(parent, name, type, path);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
module.exports = {
|
|
@@ -20,8 +20,10 @@ function validateDefaultValues(member, memberName, prop, path) {
|
|
|
20
20
|
// consume all unary signs
|
|
21
21
|
while (member.default.xpr[i] === '-' || member.default.xpr[i] === '+')
|
|
22
22
|
i++;
|
|
23
|
+
// TODO: This check only counts the number of leading signs, not inbetween (e.g. 1 - - 1).
|
|
24
|
+
// The message also needs to be improved.
|
|
23
25
|
if (i > 1)
|
|
24
|
-
this.error(null, path, {},
|
|
26
|
+
this.error(null, path, {}, 'Illegal number of unary ‘+’/‘-’ operators');
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
}
|
package/lib/checks/elements.js
CHANGED
|
@@ -93,7 +93,7 @@ function checkPrimaryKey(art) {
|
|
|
93
93
|
function checkVirtualElement(member) {
|
|
94
94
|
if (member.virtual) {
|
|
95
95
|
if (this.csnUtils.isAssociation(member.type)) { // or Composition ???
|
|
96
|
-
this.error(null, member.$path, {},
|
|
96
|
+
this.error(null, member.$path, {}, 'Element can\'t be virtual and an association');
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|