@sap/cds-compiler 3.4.0 → 3.4.4
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 -1
- package/bin/cdsc.js +3 -4
- package/bin/cdshi.js +19 -6
- package/doc/CHANGELOG_ARCHIVE.md +1 -1
- package/lib/api/main.js +6 -3
- package/lib/base/message-registry.js +61 -38
- package/lib/base/messages.js +7 -3
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/compiler/.eslintrc.json +4 -1
- package/lib/compiler/assert-consistency.js +8 -6
- package/lib/compiler/builtins.js +13 -13
- package/lib/compiler/checks.js +50 -33
- package/lib/compiler/define.js +9 -6
- package/lib/compiler/extend.js +83 -55
- package/lib/compiler/finalize-parse-cdl.js +3 -3
- package/lib/compiler/populate.js +16 -5
- package/lib/compiler/propagator.js +22 -29
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +4 -4
- package/lib/compiler/utils.js +14 -0
- package/lib/edm/annotations/genericTranslation.js +68 -56
- package/lib/edm/csn2edm.js +214 -174
- package/lib/edm/edmAnnoPreprocessor.js +5 -5
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +1 -1
- package/lib/edm/edmUtils.js +3 -3
- package/lib/gen/Dictionary.json +176 -8
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +2 -1
- package/lib/gen/languageParser.js +4776 -4513
- package/lib/json/from-csn.js +21 -16
- package/lib/json/to-csn.js +37 -41
- package/lib/language/.eslintrc.json +4 -1
- package/lib/language/antlrParser.js +5 -2
- package/lib/language/docCommentParser.js +6 -6
- package/lib/language/errorStrategy.js +43 -23
- package/lib/language/genericAntlrParser.js +54 -95
- package/lib/language/language.g4 +92 -66
- package/lib/language/multiLineStringParser.js +2 -2
- package/lib/language/textUtils.js +2 -2
- package/lib/model/csnRefs.js +5 -0
- package/lib/modelCompare/compare.js +2 -2
- package/lib/modelCompare/utils/.eslintrc.json +22 -0
- package/lib/modelCompare/utils/filter.js +99 -0
- package/lib/render/.eslintrc.json +1 -0
- package/lib/render/toCdl.js +96 -127
- package/lib/render/toHdbcds.js +38 -35
- package/lib/render/toSql.js +75 -161
- package/lib/render/utils/common.js +133 -83
- package/lib/render/utils/delta.js +227 -0
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/draft/.eslintrc.json +1 -35
- package/lib/transform/forOdataNew.js +33 -22
- package/lib/transform/forRelationalDB.js +1 -1
- package/lib/transform/localized.js +9 -8
- package/lib/transform/odata/typesExposure.js +26 -4
- package/lib/transform/transformUtilsNew.js +15 -8
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/package.json +2 -3
- package/lib/modelCompare/filter.js +0 -83
package/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,31 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
|
|
11
|
+
## Version 3.4.4 - 2022-11-25
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- compiler: CSN flavor `gensrc` (known as `xtended` in `@sap/cds`) lost annotations
|
|
16
|
+
on enum values and projection columns.
|
|
17
|
+
|
|
18
|
+
## Version 3.4.2 - 2022-11-11
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Don't propagate `@cds.external` (The CDS Importer adds `@cds.external` for all
|
|
23
|
+
imported definitions beginning with cds-dk@6.3.0, see CAP release log).
|
|
24
|
+
- for.odata: Ignore all `@cds.external` definitions.
|
|
25
|
+
- to.sql: For sql dialect `h2`, don't turn a Decimal with length 0 into a Decfloat.
|
|
26
|
+
- Extending a projection with an aspect could result in incorrect auto-redirection.
|
|
27
|
+
- Annotations of aspects were not properly propagated to projections under some order-specific circumstances.
|
|
28
|
+
|
|
10
29
|
## Version 3.4.0 - 2022-10-26
|
|
11
30
|
|
|
12
31
|
### Added
|
|
13
32
|
|
|
14
|
-
- to.sql: Add support for sql dialect `h2`, which renders SQL for H2 2.x
|
|
33
|
+
- to.sql: Add support for sql dialect `h2`, which renders SQL for H2 2.x.
|
|
34
|
+
- Projections can now be extended by annotation-only aspects, e.g. `extend P with MyAspect;`.
|
|
15
35
|
|
|
16
36
|
### Fixed
|
|
17
37
|
|
package/bin/cdsc.js
CHANGED
|
@@ -505,7 +505,7 @@ function executeCommandLine(command, options, args) {
|
|
|
505
505
|
let hasAtLeastOneExplanation = false;
|
|
506
506
|
messages.filter(msg => messageLevels[msg.severity] <= options.warning).forEach((msg) => {
|
|
507
507
|
hasAtLeastOneExplanation = hasAtLeastOneExplanation || main.hasMessageExplanation(msg.messageId);
|
|
508
|
-
const name = msg
|
|
508
|
+
const name = msg.$location && msg.$location.file;
|
|
509
509
|
const fullFilePath = name ? path.resolve('', name) : undefined;
|
|
510
510
|
log(main.messageStringMultiline(msg, {
|
|
511
511
|
normalizeFilename,
|
|
@@ -514,9 +514,8 @@ function executeCommandLine(command, options, args) {
|
|
|
514
514
|
hintExplanation: true,
|
|
515
515
|
color: options.color,
|
|
516
516
|
}));
|
|
517
|
-
if (fullFilePath && msg
|
|
518
|
-
// A message context only makes sense, if we have at least
|
|
519
|
-
// i.e. line and column for start position.
|
|
517
|
+
if (fullFilePath && msg.$location.line) {
|
|
518
|
+
// A message context only makes sense, if we have at least start line
|
|
520
519
|
const context = sourceLines(fullFilePath);
|
|
521
520
|
log(main.messageContext(context, msg, { color: options.color }));
|
|
522
521
|
}
|
package/bin/cdshi.js
CHANGED
|
@@ -37,12 +37,25 @@ function highlight( err, buf ) {
|
|
|
37
37
|
return;
|
|
38
38
|
const chars = [ ...buf ];
|
|
39
39
|
for (const tok of ts.tokens) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
chars[tok.
|
|
40
|
+
if (tok.start < 0)
|
|
41
|
+
continue;
|
|
42
|
+
if (tok.$isSkipped) {
|
|
43
|
+
if (tok.stop > tok.start) {
|
|
44
|
+
chars[tok.start] = (tok.$isSkipped === true ? '\x0f' : '\x16');
|
|
45
|
+
chars[tok.stop] = '\x17';
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
chars[tok.start] = (tok.$isSkipped === true ? '\x0e' : '\x15');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const cat = tok.isIdentifier;
|
|
53
|
+
if (cat) {
|
|
54
|
+
if (cat !== 'ref' || chars[tok.start] !== '$')
|
|
55
|
+
chars[tok.start] = categoryChars[cat] || cat.charAt(0);
|
|
56
|
+
if (tok.stop > tok.start) // stop in ANTLR at last char, not behind
|
|
57
|
+
chars[tok.start + 1] = '_';
|
|
58
|
+
}
|
|
46
59
|
}
|
|
47
60
|
}
|
|
48
61
|
for (const c of chars)
|
package/doc/CHANGELOG_ARCHIVE.md
CHANGED
|
@@ -154,7 +154,7 @@ The compiler behaviour concerning `beta` features can change at any time without
|
|
|
154
154
|
- When the option `addTextsLanguageAssoc` is set to true and
|
|
155
155
|
the model contains an entity `sap.common.Languages` with an element `code`,
|
|
156
156
|
all generated texts entities additionally contain an element `language`
|
|
157
|
-
which is an association to `sap.common.Languages` using element `
|
|
157
|
+
which is an association to `sap.common.Languages` using element `locale`.
|
|
158
158
|
- for.odata:
|
|
159
159
|
+ In `--odata-format=flat`, structured view parameters are flattened like elements.
|
|
160
160
|
- to.hdbcds
|
package/lib/api/main.js
CHANGED
|
@@ -12,11 +12,12 @@ const forOdataNew = lazyload('../transform/forOdataNew.js');
|
|
|
12
12
|
const toSql = lazyload('../render/toSql');
|
|
13
13
|
const toCdl = require('../render/toCdl');
|
|
14
14
|
const modelCompare = lazyload('../modelCompare/compare');
|
|
15
|
-
const diffFilter = lazyload('../modelCompare/filter');
|
|
15
|
+
const diffFilter = lazyload('../modelCompare/utils/filter');
|
|
16
16
|
const sortViews = lazyload('../model/sortViews');
|
|
17
17
|
const csnUtils = lazyload('../model/csnUtils');
|
|
18
18
|
const timetrace = lazyload('../utils/timetrace');
|
|
19
19
|
const forRelationalDB = lazyload('../transform/forRelationalDB');
|
|
20
|
+
const sqlUtils = lazyload('../render/utils/sql');
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -398,10 +399,12 @@ function sqlMigration(csn, options, beforeImage) {
|
|
|
398
399
|
Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
|
|
399
400
|
}
|
|
400
401
|
|
|
402
|
+
const identifierUtils = sqlUtils.getIdentifierUtils(internalOptions);
|
|
403
|
+
|
|
401
404
|
const drops = {
|
|
402
405
|
creates: {},
|
|
403
406
|
final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
|
|
404
|
-
previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ artifact['@cds.persistence.name'] };`;
|
|
407
|
+
previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.quoteSqlId(artifact['@cds.persistence.name']) };`;
|
|
405
408
|
return previous;
|
|
406
409
|
}, {}),
|
|
407
410
|
};
|
|
@@ -417,7 +420,7 @@ function sqlMigration(csn, options, beforeImage) {
|
|
|
417
420
|
(diffArtifact.query || diffArtifact.projection) &&
|
|
418
421
|
(diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
|
|
419
422
|
diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
|
|
420
|
-
drops.creates[artifactName] = `DROP VIEW ${ diffArtifact['@cds.persistence.name'] };`;
|
|
423
|
+
drops.creates[artifactName] = `DROP VIEW ${ identifierUtils.quoteSqlId(diffArtifact['@cds.persistence.name']) };`;
|
|
421
424
|
} // TODO: What happens with a changed kind -> entity becomes a view?
|
|
422
425
|
else if (diffArtifact &&
|
|
423
426
|
diffArtifact['@cds.persistence.skip'] !== true &&
|
|
@@ -98,7 +98,7 @@ const centralMessages = {
|
|
|
98
98
|
'ref-sloppy-target': { severity: 'Warning' },
|
|
99
99
|
|
|
100
100
|
'extend-repeated-intralayer': { severity: 'Warning' },
|
|
101
|
-
'extend-unrelated-layer': { severity: '
|
|
101
|
+
'extend-unrelated-layer': { severity: 'Info' },
|
|
102
102
|
|
|
103
103
|
'ext-duplicate-extend-type': { severity: 'Error' },
|
|
104
104
|
'ext-duplicate-extend-type-unrelated-layer': { severity: 'Error', configurableFor: true },
|
|
@@ -116,6 +116,7 @@ const centralMessages = {
|
|
|
116
116
|
'type-ambiguous-target': { severity: 'Warning' },
|
|
117
117
|
|
|
118
118
|
'ref-autoexposed': { severity: 'Error', configurableFor: 'deprecated' },
|
|
119
|
+
// Published! Used in @sap/cds-lsp; if renamed, add to oldMessageIds and contact colleagues
|
|
119
120
|
'ref-undefined-art': { severity: 'Error' },
|
|
120
121
|
'ref-undefined-def': { severity: 'Error' },
|
|
121
122
|
'ref-undefined-var': { severity: 'Error' },
|
|
@@ -137,20 +138,22 @@ const centralMessages = {
|
|
|
137
138
|
|
|
138
139
|
'expr-unexpected-operator': { severity: 'Error', configurableFor: true },
|
|
139
140
|
|
|
141
|
+
// Published! Used in @sap/cds-lsp; if renamed, add to oldMessageIds and contact colleagues
|
|
142
|
+
// Also used by other projects that rely on double-quotes for delimited identifiers.
|
|
143
|
+
'syntax-deprecated-ident': { severity: 'Error', configurableFor: true },
|
|
140
144
|
// 'syntax-duplicate-annotate' came late with v3 - make it configurable as
|
|
141
145
|
// fallback, but then parse.cdl is not supposed to work correctly (it can
|
|
142
146
|
// then either issue an error or produce a CSN missing some annotations):
|
|
143
|
-
'syntax-duplicate-annotate': { severity: 'Error', configurableFor:
|
|
144
|
-
'syntax-
|
|
145
|
-
'syntax-
|
|
146
|
-
'syntax-
|
|
147
|
-
'syntax-
|
|
147
|
+
'syntax-duplicate-annotate': { severity: 'Error', configurableFor: 'v3' },
|
|
148
|
+
'syntax-invalid-name': { severity: 'Error', configurableFor: 'v3' },
|
|
149
|
+
'syntax-missing-as': { severity: 'Error', configurableFor: true },
|
|
150
|
+
'syntax-unexpected-null': { severity: 'Error', configurableFor: true },
|
|
151
|
+
'syntax-unexpected-reserved-word': { severity: 'Error', configurableFor: true },
|
|
148
152
|
'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
|
|
149
|
-
|
|
150
153
|
'syntax-unsupported-masked': { severity: 'Error', configurableFor: 'v3' },
|
|
151
|
-
'syntax-unexpected-null': { severity: 'Error', configurableFor: true },
|
|
152
154
|
|
|
153
155
|
'type-managed-composition': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: non-config
|
|
156
|
+
'type-unsupported-precision-change': { severity: 'Error'},
|
|
154
157
|
|
|
155
158
|
'def-missing-element': { severity: 'Error' },
|
|
156
159
|
|
|
@@ -231,7 +234,7 @@ const centralMessageTexts = {
|
|
|
231
234
|
'flatten-fkey-gen': 'Duplicate definition of foreign key element $(NAME) for association $(ART)',
|
|
232
235
|
'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
|
|
233
236
|
},
|
|
234
|
-
|
|
237
|
+
|
|
235
238
|
// Syntax messages, both CDL and CSN parser: ----------------------------------
|
|
236
239
|
'syntax-dollar-ident': { // Warning, TODO: make it name-invalid-alias
|
|
237
240
|
std: 'An artifact starting with $(NAME) might shadow a special variable - replace by another name',
|
|
@@ -239,14 +242,25 @@ const centralMessageTexts = {
|
|
|
239
242
|
$tableImplicit: 'The resulting table alias starts with $(NAME) and might shadow a special variable - specify another name with $(KEYWORD)',
|
|
240
243
|
mixin: 'A mixin name starting with $(NAME) might shadow a special variable - replace by another name',
|
|
241
244
|
},
|
|
242
|
-
|
|
245
|
+
|
|
246
|
+
'syntax-deprecated-abstract': 'Abstract entity definitions are deprecated; use aspect definitions instead', // Warning, TODO: also use for CSN
|
|
247
|
+
'syntax-duplicate-excluding': {
|
|
248
|
+
std: 'Duplicate $(NAME) in the $(KEYWORD) clause',
|
|
249
|
+
csn: 'Duplicate $(NAME) in property $(PROP)',
|
|
250
|
+
},
|
|
251
|
+
'syntax-expecting-integer': { // TODO: currently 'syntax-expecting-natnum' in CSN
|
|
252
|
+
std: 'A safe integer is expected here',
|
|
253
|
+
normal: 'An integer number is expected here',
|
|
254
|
+
unsafe: 'The provided integer is too large',
|
|
255
|
+
},
|
|
243
256
|
'syntax-ignoring-anno': {
|
|
244
|
-
std: 'Annotations can\'t be used
|
|
245
|
-
doc: 'Doc comments can\'t be used
|
|
257
|
+
std: 'Annotations can\'t be used in a column with $(CODE)',
|
|
258
|
+
doc: 'Doc comments can\'t be used in a column with $(CODE)',
|
|
246
259
|
},
|
|
247
260
|
'syntax-invalid-name': {
|
|
248
|
-
std: 'Identifier
|
|
261
|
+
std: 'Identifier must consist of at least one character',
|
|
249
262
|
csn: 'Property name in dictionary $(PARENTPROP) must not be empty',
|
|
263
|
+
as: 'String in property $(PROP) must not be empty', // TODO: use
|
|
250
264
|
},
|
|
251
265
|
'syntax-invalid-literal': { // TODO: write texts less CDL specific
|
|
252
266
|
'std': 'Invalid literal',
|
|
@@ -268,20 +282,44 @@ const centralMessageTexts = {
|
|
|
268
282
|
csn: 'The property $(PROP) is not supported',
|
|
269
283
|
},
|
|
270
284
|
|
|
271
|
-
// Syntax messages, CDL parser
|
|
285
|
+
// Syntax messages, CDL parser -----------------------------------------------
|
|
286
|
+
// 'syntax-deprecated-auto-as', 'syntax-deprecated-ident'
|
|
272
287
|
'syntax-duplicate-annotate': 'You can\'t refer to $(NAME) repeatedly with property $(PROP) in the same annotate statement',
|
|
288
|
+
'syntax-duplicate-argument': {
|
|
289
|
+
std: 'Duplicate value for parameter $(NAME)',
|
|
290
|
+
type: 'Duplicate value for type parameter $(NAME)',
|
|
291
|
+
},
|
|
273
292
|
'syntax-duplicate-extend': {
|
|
274
293
|
std: 'You can\'t define and refer to $(NAME) repeatedly in the same extend statement',
|
|
275
294
|
define: 'You can\'t refer to $(NAME) in the same extend statement where it was defined',
|
|
276
295
|
extend: 'You can\'t refer to $(NAME) repeatedly in the same extend statement',
|
|
277
296
|
},
|
|
278
|
-
'syntax-
|
|
297
|
+
// 'syntax-duplicate-anno', 'syntax-duplicate-doc-comment', 'syntax-duplicate-cardinality',
|
|
298
|
+
// 'syntax-duplicate-property'
|
|
299
|
+
'syntax-unexpected-reserved-word': '$(CODE) is a reserved word - write $(DELIMITED) instead if you want to use it as name',
|
|
279
300
|
'syntax-invalid-text-block': 'Missing newline in text block',
|
|
301
|
+
// 'syntax-missing-newline' (Warning), 'syntax-missing-as',
|
|
302
|
+
// 'syntax-missing-token'
|
|
303
|
+
'syntax-unexpected-null': 'Keyword $(KEYWORD) must appear after the enum definition and not before',
|
|
304
|
+
'syntax-unexpected-token': {
|
|
305
|
+
std: 'Mismatched $(OFFENDING), expecting $(EXPECTING)',
|
|
306
|
+
unwanted: 'Extraneous $(OFFENDING), expecting $(EXPECTING)'
|
|
307
|
+
},
|
|
308
|
+
'syntax-unexpected-vocabulary': {
|
|
309
|
+
std: 'Annotations can\'t be defined inside contexts or services', // not used
|
|
310
|
+
service: 'Annotations can\'t be defined inside services',
|
|
311
|
+
context: 'Annotations can\'t be defined inside contexts',
|
|
312
|
+
},
|
|
313
|
+
// 'syntax-unexpected-space', 'syntax-unexpected-doc-comment' (TODO is: -ignoring-, Info)
|
|
314
|
+
// 'syntax-unexpected-alias' (is 'syntax-unexpected-property' in CSN),
|
|
315
|
+
// 'syntax-unexpected-right-paren'
|
|
316
|
+
'syntax-unsupported-calc-field': 'Calculated fields are not supported',
|
|
280
317
|
'syntax-unsupported-param': {
|
|
281
318
|
std: 'Parameter not supported', // unused
|
|
282
|
-
dynamic: 'Dynamic parameter $(
|
|
283
|
-
positional: 'Positional parameter $(
|
|
319
|
+
dynamic: 'Dynamic parameter $(CODE) is not supported',
|
|
320
|
+
positional: 'Positional parameter $(CODE) is not supported',
|
|
284
321
|
},
|
|
322
|
+
// 'syntax-unsupported-method', 'syntax-unsupported-new'
|
|
285
323
|
|
|
286
324
|
// Syntax messages, CSN parser - default: Error ------------------------------
|
|
287
325
|
// TODO: use one id with text variants instead of several message ids
|
|
@@ -314,10 +352,10 @@ const centralMessageTexts = {
|
|
|
314
352
|
std: 'Object in $(PROP) must have at least one valid CSN property',
|
|
315
353
|
as: 'Object in $(PROP) must have at least one valid CSN property other than $(OTHERPROP)',
|
|
316
354
|
},
|
|
317
|
-
// 'syntax-invalid-ref' (Warning?), 'syntax-invalid-kind', 'syntax-invalid-literal' (Warning)
|
|
318
355
|
'syntax-invalid-string': {
|
|
319
356
|
std: 'Invalid string value in property $(PROP)',
|
|
320
357
|
},
|
|
358
|
+
// 'syntax-invalid-ref' (Warning?), 'syntax-invalid-kind', 'syntax-invalid-literal' (Warning)
|
|
321
359
|
'syntax-missing-property': { // location at sibling or '}' otherwise
|
|
322
360
|
std: 'Object in $(PARENTPROP) must have the property $(PROP)',
|
|
323
361
|
sibling: 'Object with property $(SIBLINGPROP) must also have a property $(PROP)',
|
|
@@ -335,6 +373,7 @@ const centralMessageTexts = {
|
|
|
335
373
|
},
|
|
336
374
|
// 'syntax-unknown-property' (Warning? Better configurable Error)
|
|
337
375
|
|
|
376
|
+
// multi-line strings: --------------------------------------------------------
|
|
338
377
|
'syntax-unknown-escape': 'Unknown escape sequence $(CODE)',
|
|
339
378
|
'syntax-invalid-escape': {
|
|
340
379
|
std: 'Invalid escape sequence $(CODE)',
|
|
@@ -350,24 +389,6 @@ const centralMessageTexts = {
|
|
|
350
389
|
std: 'Missing escape. Replace $(CODE) with $(NEWCODE)',
|
|
351
390
|
placeholder: 'Placeholders are not supported. Replace $(CODE) with $(NEWCODE)',
|
|
352
391
|
},
|
|
353
|
-
'syntax-expecting-integer': {
|
|
354
|
-
std: 'A safe integer is expected here',
|
|
355
|
-
normal: 'An integer number is expected here',
|
|
356
|
-
unsafe: 'The provided integer is too large',
|
|
357
|
-
},
|
|
358
|
-
'syntax-duplicate-argument': { // TODO: also CDL
|
|
359
|
-
std: 'Unexpected argument $(CODE)',
|
|
360
|
-
unknown: 'Unknown argument $(CODE)', // huh?
|
|
361
|
-
duplicate: 'Duplicate argument $(CODE)',
|
|
362
|
-
},
|
|
363
|
-
'syntax-unexpected-null': 'Keyword $(KEYWORD) must appear after the enum definition and not before',
|
|
364
|
-
'syntax-unexpected-vocabulary': {
|
|
365
|
-
std: 'Annotations can\'t be defined inside contexts or services',
|
|
366
|
-
service: 'Annotations can\'t be defined inside services',
|
|
367
|
-
context: 'Annotations can\'t be defined inside contexts',
|
|
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
392
|
|
|
372
393
|
// Syntax messages for errorneous references ----------------------------------
|
|
373
394
|
// location at errorneous reference (if possible)
|
|
@@ -543,7 +564,7 @@ const centralMessageTexts = {
|
|
|
543
564
|
// version independent messages
|
|
544
565
|
'odata-spec-violation-key-array': {
|
|
545
566
|
std: 'Unexpected array type for element $(NAME)',
|
|
546
|
-
scalar: 'Unexpected array type'
|
|
567
|
+
scalar: 'Unexpected array type',
|
|
547
568
|
},
|
|
548
569
|
'odata-spec-violation-key-null': {
|
|
549
570
|
std: 'Expected key element $(NAME) to be not nullable', // structured
|
|
@@ -559,6 +580,8 @@ const centralMessageTexts = {
|
|
|
559
580
|
std: 'Expected element to have a type',
|
|
560
581
|
incompatible: 'Unexpected EDM Type $(TYPE) for OData $(VERSION)',
|
|
561
582
|
facet: 'Unexpected EDM Type facet $(NAME) of type $(TYPE) for OData $(VERSION)',
|
|
583
|
+
missing: 'Expected referenced type $(TYPE) to be included in service $(NAME)',
|
|
584
|
+
external: 'Referenced type $(TYPE) marked as $(ANNO) can\'t be rendered as $(CODE) in service $(NAME) for OData $(VERSION)',
|
|
562
585
|
},
|
|
563
586
|
'odata-spec-violation-property-name': 'Expected element name to be different from declaring $(KIND)',
|
|
564
587
|
'odata-spec-violation-namespace': {
|
|
@@ -583,7 +606,7 @@ const centralMessageTexts = {
|
|
|
583
606
|
*
|
|
584
607
|
* @typedef {object} MessageConfig
|
|
585
608
|
* @property {MessageSeverity} severity Default severity for the message.
|
|
586
|
-
* @property {string[]|'deprecated'|true} [configurableFor]
|
|
609
|
+
* @property {string[]|'deprecated'|'v3'|true} [configurableFor]
|
|
587
610
|
* Whether the error can be reclassified to a warning or lower.
|
|
588
611
|
* If not `true` then an array is expected with specified modules in which the error is downgradable.
|
|
589
612
|
* Only has an effect if default severity is 'Error'.
|
package/lib/base/messages.js
CHANGED
|
@@ -655,7 +655,7 @@ const paramsTransform = {
|
|
|
655
655
|
alias: quoted,
|
|
656
656
|
anno: a => (a.charAt(0) === '@' ? quote.double( a ) : quote.double( '@' + a )),
|
|
657
657
|
annos: anno => anno.map(paramsTransform.anno).join(', '),
|
|
658
|
-
delimited: n =>
|
|
658
|
+
delimited: n => quote.single( `![${ n }]` ), // represent as delimited id (TODO: double-']')
|
|
659
659
|
file: quote.single,
|
|
660
660
|
prop: quote.single,
|
|
661
661
|
siblingprop: quote.single,
|
|
@@ -671,6 +671,7 @@ const paramsTransform = {
|
|
|
671
671
|
line: quote.number,
|
|
672
672
|
col: quote.number,
|
|
673
673
|
value: n => (typeof n !== 'number' ? quote.single( n ) : quote.number( n )),
|
|
674
|
+
values: value => value.map(paramsTransform.value).join(', '),
|
|
674
675
|
othervalue: n => (typeof n !== 'number' ? quote.single( n ) : quote.number( n )),
|
|
675
676
|
art: transformArg,
|
|
676
677
|
service: transformArg,
|
|
@@ -707,7 +708,9 @@ function transformManyWith( t, sorted ) {
|
|
|
707
708
|
}
|
|
708
709
|
|
|
709
710
|
function quoted( name ) {
|
|
710
|
-
|
|
711
|
+
if (typeof name === 'string')
|
|
712
|
+
return quote.double( name );
|
|
713
|
+
throw new CompilerAssertion( `Expecting a string, not ${ name }` );
|
|
711
714
|
}
|
|
712
715
|
|
|
713
716
|
function tokenSymbol( token ) {
|
|
@@ -799,7 +802,8 @@ function messageText( texts, params, transform ) {
|
|
|
799
802
|
let args = {};
|
|
800
803
|
for (let p in params) {
|
|
801
804
|
let t = transform && transform[p] || paramsTransform[p];
|
|
802
|
-
|
|
805
|
+
if (params[p] !== undefined)
|
|
806
|
+
args[p] = (t) ? t( params[p], args, params, texts ) : params[p];
|
|
803
807
|
}
|
|
804
808
|
let variant = args['#'];
|
|
805
809
|
return replaceInString( variant && texts[ variant ] || texts.std, args );
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
"jsdoc/require-property": 0,
|
|
15
15
|
// most of the main functions have the normal forEachArtifact/Member signature anyway
|
|
16
16
|
"jsdoc/require-param-description": 0,
|
|
17
|
+
// there seem to be false positives
|
|
18
|
+
"jsdoc/require-returns-check": 0,
|
|
17
19
|
// =airbnb, >eslint:
|
|
18
20
|
"max-len": [ "error", {
|
|
19
21
|
"code": 110,
|
|
@@ -404,7 +404,6 @@ function assertConsistency( model, stage ) {
|
|
|
404
404
|
// TODO: "yes" instead "none": val: true, optional literal/location
|
|
405
405
|
val: {
|
|
406
406
|
requires: [ 'literal', 'location' ],
|
|
407
|
-
// TODO: rename symbol to sym
|
|
408
407
|
// TODO: struct and variant only for annotation assignments
|
|
409
408
|
optional: [
|
|
410
409
|
'val', 'sym', 'name', '$inferred', '$parens',
|
|
@@ -441,7 +440,7 @@ function assertConsistency( model, stage ) {
|
|
|
441
440
|
test: isVal, // the following for array/struct value
|
|
442
441
|
requires: [ 'location' ],
|
|
443
442
|
optional: [
|
|
444
|
-
'literal', 'val', 'sym', 'struct', 'variant', 'path', 'name', '$
|
|
443
|
+
'literal', 'val', 'sym', 'struct', 'variant', 'path', 'name', '$duplicates', 'upTo',
|
|
445
444
|
],
|
|
446
445
|
// TODO: restrict path to #simplePath
|
|
447
446
|
},
|
|
@@ -462,7 +461,10 @@ function assertConsistency( model, stage ) {
|
|
|
462
461
|
join: { test: locationVal( isString ) },
|
|
463
462
|
quantifier: { test: locationVal( isString ) },
|
|
464
463
|
// preliminary -----------------------------------------------------------
|
|
465
|
-
doc: {
|
|
464
|
+
doc: {
|
|
465
|
+
kind: true,
|
|
466
|
+
test: locationVal( isStringOrNull ),
|
|
467
|
+
}, // doc comment
|
|
466
468
|
'@': {
|
|
467
469
|
kind: true,
|
|
468
470
|
inherits: 'value',
|
|
@@ -888,7 +890,7 @@ function assertConsistency( model, stage ) {
|
|
|
888
890
|
return function valWithLocation( node, parent, prop, spec, name ) {
|
|
889
891
|
const valSchema = { val: Object.assign( {}, spec, { test: func } ) };
|
|
890
892
|
const requires = [ 'val', 'location' ];
|
|
891
|
-
const optional = [ 'literal', '$inferred', '_pathHead' ];
|
|
893
|
+
const optional = [ 'literal', '$inferred', '$priority', '_pathHead' ];
|
|
892
894
|
standard( node, parent, prop, { schema: valSchema, requires, optional }, name );
|
|
893
895
|
};
|
|
894
896
|
}
|
|
@@ -912,7 +914,7 @@ function assertConsistency( model, stage ) {
|
|
|
912
914
|
isString(node, parent, prop, spec);
|
|
913
915
|
}
|
|
914
916
|
|
|
915
|
-
function isOneOf(values) {
|
|
917
|
+
function isOneOf( values ) {
|
|
916
918
|
return function isOneOfInner( node, parent, prop ) {
|
|
917
919
|
if (!values.includes(node))
|
|
918
920
|
throw new Error( `Unexpected value '${ node }', expected ${ JSON.stringify(values) }${ at( [ node, parent ], prop ) }` );
|
|
@@ -959,7 +961,7 @@ function assertConsistency( model, stage ) {
|
|
|
959
961
|
}
|
|
960
962
|
}
|
|
961
963
|
|
|
962
|
-
function isScope(node, parent, prop) {
|
|
964
|
+
function isScope( node, parent, prop ) {
|
|
963
965
|
// artifact refs in CDL have scope:0 in XSN
|
|
964
966
|
if (Number.isInteger(node))
|
|
965
967
|
return;
|
package/lib/compiler/builtins.js
CHANGED
|
@@ -259,7 +259,7 @@ const quotedLiteralPatterns = {
|
|
|
259
259
|
*
|
|
260
260
|
* @returns {boolean} True if the date is valid.
|
|
261
261
|
*/
|
|
262
|
-
function checkDate(year, month, day) {
|
|
262
|
+
function checkDate( year, month, day ) {
|
|
263
263
|
// Negative years are allowed
|
|
264
264
|
year = Math.abs(Number.parseInt(year, 10));
|
|
265
265
|
month = Number.parseInt(month, 10);
|
|
@@ -275,7 +275,7 @@ function checkDate(year, month, day) {
|
|
|
275
275
|
*
|
|
276
276
|
* @returns {boolean} True if the date is valid.
|
|
277
277
|
*/
|
|
278
|
-
function checkTime(hour, minutes, seconds) {
|
|
278
|
+
function checkTime( hour, minutes, seconds ) {
|
|
279
279
|
hour = Number.parseInt(hour, 10);
|
|
280
280
|
minutes = Number.parseInt(minutes, 10);
|
|
281
281
|
seconds = seconds ? Number.parseInt(seconds, 10) : 0;
|
|
@@ -311,35 +311,35 @@ Object.keys(coreHana).forEach((type) => {
|
|
|
311
311
|
});
|
|
312
312
|
|
|
313
313
|
/** @param {string} typeName */
|
|
314
|
-
function isIntegerTypeName(typeName) {
|
|
314
|
+
function isIntegerTypeName( typeName ) {
|
|
315
315
|
return typeCategories.integer.includes(typeName);
|
|
316
316
|
}
|
|
317
317
|
/** @param {string} typeName */
|
|
318
|
-
function isDecimalTypeName(typeName) {
|
|
318
|
+
function isDecimalTypeName( typeName ) {
|
|
319
319
|
return typeCategories.decimal.includes(typeName);
|
|
320
320
|
}
|
|
321
321
|
/** @param {string} typeName */
|
|
322
|
-
function isNumericTypeName(typeName) {
|
|
322
|
+
function isNumericTypeName( typeName ) {
|
|
323
323
|
return isIntegerTypeName(typeName) || isDecimalTypeName(typeName);
|
|
324
324
|
}
|
|
325
325
|
/** @param {string} typeName */
|
|
326
|
-
function isStringTypeName(typeName) {
|
|
326
|
+
function isStringTypeName( typeName ) {
|
|
327
327
|
return typeCategories.string.includes(typeName);
|
|
328
328
|
}
|
|
329
329
|
/** @param {string} typeName */
|
|
330
|
-
function isDateOrTimeTypeName(typeName) {
|
|
330
|
+
function isDateOrTimeTypeName( typeName ) {
|
|
331
331
|
return typeCategories.dateTime.includes(typeName);
|
|
332
332
|
}
|
|
333
333
|
/** @param {string} typeName */
|
|
334
|
-
function isBooleanTypeName(typeName) {
|
|
334
|
+
function isBooleanTypeName( typeName ) {
|
|
335
335
|
return typeCategories.boolean.includes(typeName);
|
|
336
336
|
}
|
|
337
337
|
/** @param {string} typeName */
|
|
338
|
-
function isBinaryTypeName(typeName) {
|
|
338
|
+
function isBinaryTypeName( typeName ) {
|
|
339
339
|
return typeCategories.binary.includes(typeName);
|
|
340
340
|
}
|
|
341
341
|
/** @param {string} typeName */
|
|
342
|
-
function isGeoTypeName(typeName) {
|
|
342
|
+
function isGeoTypeName( typeName ) {
|
|
343
343
|
return typeCategories.geo.includes(typeName);
|
|
344
344
|
}
|
|
345
345
|
/**
|
|
@@ -347,7 +347,7 @@ function isGeoTypeName(typeName) {
|
|
|
347
347
|
*
|
|
348
348
|
* @param {string} typeName
|
|
349
349
|
*/
|
|
350
|
-
function isRelationTypeName(typeName) {
|
|
350
|
+
function isRelationTypeName( typeName ) {
|
|
351
351
|
return typeCategories.relation.includes(typeName);
|
|
352
352
|
}
|
|
353
353
|
|
|
@@ -357,7 +357,7 @@ function isRelationTypeName(typeName) {
|
|
|
357
357
|
* @param {string} absolute
|
|
358
358
|
* @returns {boolean}
|
|
359
359
|
*/
|
|
360
|
-
function isInReservedNamespace(absolute) {
|
|
360
|
+
function isInReservedNamespace( absolute ) {
|
|
361
361
|
return absolute.startsWith( 'cds.') &&
|
|
362
362
|
!absolute.match(/^cds\.foundation(\.|$)/) &&
|
|
363
363
|
!absolute.match(/^cds\.outbox(\.|$)/) && // Requested by Node runtime
|
|
@@ -375,7 +375,7 @@ function isInReservedNamespace(absolute) {
|
|
|
375
375
|
* @param {string} type
|
|
376
376
|
* @returns {boolean}
|
|
377
377
|
*/
|
|
378
|
-
function isBuiltinType(type) {
|
|
378
|
+
function isBuiltinType( type ) {
|
|
379
379
|
return typeof type === 'string' && isInReservedNamespace(type);
|
|
380
380
|
}
|
|
381
381
|
|