@sap/cds-compiler 3.4.2 → 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.
Files changed (57) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/bin/cdsc.js +3 -4
  3. package/bin/cdshi.js +19 -6
  4. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  5. package/lib/api/main.js +6 -3
  6. package/lib/base/message-registry.js +60 -37
  7. package/lib/base/messages.js +7 -3
  8. package/lib/checks/.eslintrc.json +2 -0
  9. package/lib/compiler/.eslintrc.json +4 -1
  10. package/lib/compiler/assert-consistency.js +8 -6
  11. package/lib/compiler/builtins.js +13 -13
  12. package/lib/compiler/checks.js +50 -33
  13. package/lib/compiler/define.js +9 -6
  14. package/lib/compiler/extend.js +71 -45
  15. package/lib/compiler/finalize-parse-cdl.js +3 -3
  16. package/lib/compiler/populate.js +16 -5
  17. package/lib/compiler/resolve.js +2 -15
  18. package/lib/compiler/shared.js +4 -4
  19. package/lib/compiler/utils.js +14 -0
  20. package/lib/edm/annotations/genericTranslation.js +68 -56
  21. package/lib/edm/csn2edm.js +214 -174
  22. package/lib/edm/edmAnnoPreprocessor.js +5 -5
  23. package/lib/edm/edmInboundChecks.js +2 -2
  24. package/lib/edm/edmPreprocessor.js +1 -1
  25. package/lib/edm/edmUtils.js +3 -3
  26. package/lib/gen/Dictionary.json +176 -8
  27. package/lib/gen/language.checksum +1 -1
  28. package/lib/gen/language.interp +2 -1
  29. package/lib/gen/languageParser.js +4776 -4513
  30. package/lib/json/from-csn.js +21 -16
  31. package/lib/json/to-csn.js +37 -41
  32. package/lib/language/.eslintrc.json +4 -1
  33. package/lib/language/antlrParser.js +5 -2
  34. package/lib/language/docCommentParser.js +6 -6
  35. package/lib/language/errorStrategy.js +43 -23
  36. package/lib/language/genericAntlrParser.js +54 -95
  37. package/lib/language/language.g4 +92 -66
  38. package/lib/language/multiLineStringParser.js +2 -2
  39. package/lib/language/textUtils.js +2 -2
  40. package/lib/model/csnRefs.js +5 -0
  41. package/lib/modelCompare/compare.js +2 -2
  42. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  43. package/lib/modelCompare/utils/filter.js +99 -0
  44. package/lib/render/.eslintrc.json +1 -0
  45. package/lib/render/toCdl.js +96 -127
  46. package/lib/render/toHdbcds.js +38 -35
  47. package/lib/render/toSql.js +75 -161
  48. package/lib/render/utils/common.js +133 -83
  49. package/lib/render/utils/delta.js +227 -0
  50. package/lib/transform/db/.eslintrc.json +2 -0
  51. package/lib/transform/draft/.eslintrc.json +1 -35
  52. package/lib/transform/forOdataNew.js +26 -19
  53. package/lib/transform/localized.js +9 -8
  54. package/lib/transform/odata/typesExposure.js +26 -4
  55. package/lib/transform/transformUtilsNew.js +15 -8
  56. package/package.json +2 -3
  57. package/lib/modelCompare/filter.js +0 -83
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@
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
+
10
18
  ## Version 3.4.2 - 2022-11-11
11
19
 
12
20
  ### Fixed
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.location && msg.location.file;
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.location.col) {
518
- // A message context only makes sense, if we have at least a medium precision,
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
- const cat = tok.isIdentifier;
41
- if (cat && tok.start >= 0) {
42
- if (cat !== 'ref' || chars[tok.start] !== '$')
43
- chars[tok.start] = categoryChars[cat] || cat.charAt(0);
44
- if (tok.stop > tok.start) // stop in ANTLR at last char, not behind
45
- chars[tok.start + 1] = '_';
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)
@@ -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 `local`.
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 &&
@@ -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: true },
144
- 'syntax-unexpected-property': { severity: 'Error' },
145
- 'syntax-deprecated-ident': { severity: 'Error', configurableFor: true },
146
- 'syntax-fragile-alias': { severity: 'Error', configurableFor: true },
147
- 'syntax-fragile-ident': { severity: 'Error', configurableFor: true },
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
- // 'syntax-duplicate-excluding' (TODO: also CDL)
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 at prefix references',
245
- doc: 'Doc comments can\'t be used at prefix references',
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 for name must not be empty', // TODO: use
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 - default: Error ------------------------------
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-invalid-extend': 'Can\'t extend an element with $(KIND)',
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 $(NAME) is not supported',
283
- positional: 'Positional parameter $(NAME) is not supported',
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'.
@@ -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 => '![' + n + ']', // TODO: use quote.single around?
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
- return (name) ? quote.double( name ) : quote.angle( '?' ); // TODO: failure in --test-mode, then remove
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
- args[p] = (t) ? t( params[p], args, params, texts ) : params[p];
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,
@@ -1,4 +1,7 @@
1
1
  {
2
2
  "root": true,
3
- "extends": "../../.eslintrc-ydkjsi.json"
3
+ "extends": "../../.eslintrc-ydkjsi.json",
4
+ "rules": {
5
+ "cds-compiler/space-in-func-decl": "error"
6
+ }
4
7
  }
@@ -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', '$duplicate', 'upTo',
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: { kind: true, test: locationVal( isStringOrNull ) }, // doc comment
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;
@@ -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