@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
@@ -72,7 +72,6 @@ function beautifyExprArray(tokens) {
72
72
  return result;
73
73
  }
74
74
 
75
-
76
75
  /**
77
76
  * Get the part that is really the name of this artifact and not just prefix caused by a context/service
78
77
  *
@@ -86,7 +85,6 @@ function getRealName(csn, artifactName) {
86
85
  if (parts.length === 1)
87
86
  return artifactName;
88
87
 
89
-
90
88
  const namespace = getNamespace(csn, artifactName);
91
89
  const startIndex = namespace ? namespace.split('.').length : 0;
92
90
  let indexOfLastParent = startIndex;
@@ -129,7 +127,6 @@ function getParentContextName(csn, artifactName) {
129
127
  if (art && (art.kind === 'context' || art.kind === 'service'))
130
128
  return name;
131
129
  }
132
-
133
130
  return null;
134
131
  }
135
132
 
@@ -404,8 +401,7 @@ function getSqlSnippets(options, obj) {
404
401
  *
405
402
  * @callback renderPart
406
403
  * @param {object|array} expression
407
- * @param {CdlRenderEnvironment} env
408
- * @this {{inline: Boolean, nestedExpr: Boolean}}
404
+ * @this {ExpressionRenderer}
409
405
  * @returns {string}
410
406
  */
411
407
 
@@ -415,7 +411,27 @@ function getSqlSnippets(options, obj) {
415
411
  *
416
412
  * @typedef {object} ExpressionConfiguration
417
413
  * @property {(x: any) => string} finalize The final function to call on the expression(-string) before returning
418
- * @property {renderPart} explicitTypeCast
414
+ * @property {renderPart} typeCast
415
+ * @property {renderPart} val
416
+ * @property {renderPart} enum
417
+ * @property {renderPart} ref
418
+ * @property {renderPart} aliasOnly
419
+ * @property {renderPart} windowFunction
420
+ * @property {renderPart} func
421
+ * @property {renderPart} xpr
422
+ * @property {renderPart} SELECT
423
+ * @property {renderPart} SET
424
+ * @property {Function} [visitExpr]
425
+ * @property {Function} [renderExpr]
426
+ * @property {Function} [renderSubExpr]
427
+ * @property {boolean} [isNestedXpr]
428
+ * @property {CdlRenderEnvironment} [env]
429
+ */
430
+
431
+ /**
432
+ * @typedef {object} ExpressionRenderer
433
+ * @property {(x: any) => string} finalize The final function to call on the expression(-string) before returning
434
+ * @property {renderPart} typeCast
419
435
  * @property {renderPart} val
420
436
  * @property {renderPart} enum
421
437
  * @property {renderPart} ref
@@ -425,94 +441,128 @@ function getSqlSnippets(options, obj) {
425
441
  * @property {renderPart} xpr
426
442
  * @property {renderPart} SELECT
427
443
  * @property {renderPart} SET
428
- * @property {boolean} [inline]
429
- * @property {boolean} [nestedExpr]
444
+ * @property {Function} visitExpr
445
+ * @property {Function} renderExpr
446
+ * @property {Function} renderSubExpr
447
+ * @property {boolean} isNestedXpr
448
+ * @property {CdlRenderEnvironment} env
430
449
  */
431
450
 
451
+ /**
452
+ * If `xpr` has a `cast` property, return a copy without it, otherwise return `xpr`.
453
+ * Useful for removing e.g. top-level CDL-style casts that should not be rendered as CAST().
454
+ *
455
+ * @param xpr
456
+ */
457
+ function withoutCast(xpr) {
458
+ return !xpr.cast ? xpr : { ...xpr, cast: undefined };
459
+ }
460
+
432
461
  /**
433
462
  * Render an expression (including paths and values) or condition 'x'.
434
463
  * (no trailing LF, don't indent if inline)
435
464
  *
436
- * @param {ExpressionConfiguration} renderer
437
- * @returns {Function} Rendered expression
465
+ * @param {ExpressionConfiguration} rendererBase
466
+ * @returns {ExpressionRenderer} Expression rendering utility
438
467
  */
439
- function getExpressionRenderer(renderer) {
468
+ function createExpressionRenderer(rendererBase) {
469
+ const renderer = Object.create(rendererBase);
470
+ renderer.visitExpr = visitExpr;
440
471
  /**
441
- * Render an expression (including paths and values) or condition 'x'.
442
- * (no trailing LF, don't indent if inline)
443
- *
444
- * @todo Reuse this with toCdl
445
- * @param {Array|object|string} expr Expression to render
446
- * @param {object} env Render environment
447
- * @param {boolean} [inline=true] Whether to render the expression inline
448
- * @param {boolean} [nestedExpr=false] Whether to treat the expression as nested
449
- * @param {boolean} [alwaysRenderCast=false] Whether to _always_ render SQL-style casts, even if `nestedExpr === false`.
450
- * Note: This is a hack for casts() inside groupBy.
451
- * @returns {string} Rendered expression
472
+ * @param {any} x
473
+ * @param {CdlRenderEnvironment} env
452
474
  */
453
- return function renderExpr(expr, env, inline = true, nestedExpr = false, alwaysRenderCast = false) {
454
- // Compound expression
455
- if (Array.isArray(expr)) {
456
- const tokens = expr.map(item => renderExpr(item, env, inline, nestedExpr));
457
- return beautifyExprArray(tokens);
458
- }
459
- else if (typeof expr === 'object' && expr !== null) {
460
- if ((nestedExpr || alwaysRenderCast) && expr.cast && expr.cast.type && !expr.cast.target)
461
- return renderer.explicitTypeCast.call({ inline, nestedExpr }, expr, env);
462
- return renderExprObject(expr);
463
- }
475
+ renderer.renderExpr = function renderExpr(x, env) {
476
+ /** @type {ExpressionRenderer} */
477
+ const renderObj = Object.create(renderer);
478
+ renderObj.env = env || this?.env;
479
+ // The outermost expression is not nested. All `.xpr` inside `expr`
480
+ // are nested. This information is used for adding parentheses around
481
+ // expressions (see `this.xpr()`).
482
+ renderObj.isNestedXpr = false;
483
+ return renderObj.visitExpr(x);
484
+ };
485
+ /**
486
+ * @param {any} x
487
+ * @param {CdlRenderEnvironment} env
488
+ */
489
+ renderer.renderSubExpr = function renderSubExpr(x, env) {
490
+ /** @type {ExpressionRenderer} */
491
+ const renderObj = Object.create(renderer);
492
+ renderObj.env = env || this?.env;
493
+ renderObj.isNestedXpr = true;
494
+ return renderObj.visitExpr(x);
495
+ };
496
+
497
+ return renderer;
498
+ }
499
+
500
+
501
+ /**
502
+ * Render an expression (including paths and values) or condition 'x'.
503
+ * (no trailing LF, don't indent if inline)
504
+ *
505
+ * `this` must refer to an object of type `ExpressionRenderer`, see
506
+ * `createExpressionRenderer()`
507
+ *
508
+ * @param {any} x (Sub-)Expression to render
509
+ *
510
+ * @this ExpressionRenderer
511
+ * @returns {string} Rendered expression
512
+ */
513
+ function visitExpr(x) {
514
+ if (Array.isArray(x)) {
515
+ // Compound expression, e.g. for on- or where-conditions.
516
+ // If xpr is part of an array, it's always a nested xpr,
517
+ // e.g. CSN for `(1=1 or 2=2) and 3=3`.
518
+ const tokens = x.map(item => this.renderSubExpr(item));
519
+ return beautifyExprArray(tokens);
520
+ }
521
+ else if (typeof x !== 'object' || x === null) {
464
522
  // Not a literal value but part of an operator, function etc - just leave as it is
465
- // FIXME: For the sake of simplicity, we should get away from all this uppercasing in toSql
466
- return renderer.finalize.call({ inline, nestedExpr }, expr, env);
467
-
468
-
469
- /**
470
- * Various special cases represented as objects
471
- *
472
- * @param {object} x Expression
473
- * @returns {string} String representation of the expression
474
- */
475
- function renderExprObject(x) {
476
- if (x.list) { // TODO: Does this still exist?
477
- return `(${x.list.map(item => renderExpr(item, env, inline, false)).join(', ')})`;
478
- }
479
- else if (x.val !== undefined) {
480
- return renderer.val.call({ inline, nestedExpr }, x, env);
481
- }
482
- // Enum symbol
483
- else if (x['#']) {
484
- return renderer.enum.call({ inline, nestedExpr }, x, env);
485
- }
486
- // Reference: Array of path steps, possibly preceded by ':'
487
- else if (x.ref) {
488
- return renderer.ref.call({ inline, nestedExpr }, x, env);
489
- }
490
- // Function call, possibly with args (use '=>' for named args)
491
- else if (x.func) {
492
- if (x.xpr)
493
- return renderer.windowFunction.call({ inline, nestedExpr }, x, env);
494
- return renderer.func.call({ inline, nestedExpr }, x, env);
495
- }
496
- // Nested expression
497
- else if (x.xpr) {
498
- return renderer.xpr.call({ inline, nestedExpr }, x, env);
499
- }
500
- // Sub-select
501
- else if (x.SELECT) {
502
- return renderer.SELECT.call({ inline, nestedExpr }, x, env);
503
- }
504
- else if (x.SET) {
505
- return renderer.SET.call({ inline, nestedExpr }, x, env);
506
- }
507
- else if (x.as && x.cast && x.cast.type && x.cast.target) {
508
- return renderer.aliasOnly.call({ inline, nestedExpr }, x, env);
509
- }
523
+ return this.finalize(x);
524
+ }
525
+ else if (x.cast?.type && !x.cast.target) {
526
+ return this.typeCast(x);
527
+ }
528
+ else if (x.list) {
529
+ // Render as non-nested expr.
530
+ return `(${x.list.map(item => this.renderExpr(item)).join(', ')})`;
531
+ }
532
+ else if (x.val !== undefined) {
533
+ return this.val(x);
534
+ }
535
+ else if (x['#']) {
536
+ // Enum symbol
537
+ return this.enum(x);
538
+ }
539
+ else if (x.ref) {
540
+ // Reference: Array of path steps, possibly preceded by ':'
541
+ return this.ref(x);
542
+ }
543
+ else if (x.func) {
544
+ // Function call, possibly with args (use '=>' for named args)
545
+ if (x.xpr)
546
+ return this.windowFunction(x);
547
+ return this.func(x);
548
+ }
549
+ else if (x.xpr) {
550
+ return this.xpr(x);
551
+ }
552
+ else if (x.SELECT) {
553
+ return this.SELECT(x);
554
+ }
555
+ else if (x.SET) {
556
+ return this.SET(x);
557
+ }
558
+ else if (x.as) {
559
+ return this.aliasOnly(x);
560
+ }
510
561
 
511
- throw new ModelError(`Unknown expression: ${JSON.stringify(x)}`);
512
- }
513
- };
562
+ throw new ModelError(`renderExpr(): Unknown expression: ${JSON.stringify(x)}`);
514
563
  }
515
564
 
565
+
516
566
  /**
517
567
  * @typedef CdlRenderEnvironment Rendering environment used throughout the render process.
518
568
  *
@@ -531,8 +581,7 @@ function getExpressionRenderer(renderer) {
531
581
 
532
582
  module.exports = {
533
583
  renderFunc,
534
- getExpressionRenderer,
535
- beautifyExprArray,
584
+ createExpressionRenderer,
536
585
  getNamespace,
537
586
  getRealName,
538
587
  addIntermediateContexts,
@@ -544,4 +593,5 @@ module.exports = {
544
593
  findElement,
545
594
  funcWithoutParen,
546
595
  getSqlSnippets,
596
+ withoutCast,
547
597
  };
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Encapsulate all the functions needed to render SQL ALTER/DROP/ADD statements.
5
+ */
6
+ class DeltaRenderer {
7
+ constructor(options, scopedFunctions) {
8
+ this.options = options;
9
+ this.scopedFunctions = scopedFunctions;
10
+ }
11
+
12
+ /**
13
+ * Render column additions as SQL. Checks for duplicate elements.
14
+ */
15
+ addColumnsFromElementStrings(artifactName, eltStrings) {
16
+ return eltStrings.map(eltString => `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ADD ${eltString};`);
17
+ }
18
+
19
+ /**
20
+ * Render column additions as SQL. Checks for duplicate elements.
21
+ */
22
+ addColumnsFromElementsObj(artifactName, elementsObj, env, duplicateChecker) {
23
+ // Only extend with 'ADD' for elements/associations
24
+ // TODO: May also include 'RENAME' at a later stage
25
+ const alterEnv = this.scopedFunctions.activateAlterMode(env);
26
+ const elements = Object.entries(elementsObj)
27
+ .map(([ name, elt ]) => this.scopedFunctions.renderElement(artifactName, name, elt, duplicateChecker, null, alterEnv))
28
+ .filter(s => s !== '');
29
+
30
+ if (elements.length)
31
+ return this.addColumnsFromElementStrings(artifactName, elements);
32
+
33
+ return [];
34
+ }
35
+
36
+ /**
37
+ * By default, we don't support rendering association-alters - only for HANA
38
+ */
39
+ addAssociations() {
40
+ return [];
41
+ }
42
+
43
+ /**
44
+ * Render key addition as SQL.
45
+ */
46
+ addKey(artifactName, elementsObj) {
47
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ADD ${this.primaryKey(elementsObj)};` ];
48
+ }
49
+
50
+ /**
51
+ * Render column removals as SQL.
52
+ */
53
+ dropColumns(artifactName, sqlIds) {
54
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP ${sqlIds.join(', ')};` ];
55
+ }
56
+
57
+ /**
58
+ * No associations by default - only for HANA.
59
+ */
60
+ dropAssociation() {
61
+ return [];
62
+ }
63
+
64
+ /**
65
+ * Render primary-key removals as SQL.
66
+ */
67
+ dropKey(artifactName) {
68
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP PRIMARY KEY;` ];
69
+ }
70
+
71
+ /**
72
+ * Render column modifications as SQL.
73
+ */
74
+ alterColumns(artifactName, columnName, delta, definitionsStr) {
75
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER (${definitionsStr});` ];
76
+ }
77
+
78
+ /**
79
+ * Render primary keys as SQL.
80
+ */
81
+ primaryKey(elementsObj) {
82
+ const primaryKeys = Object.keys(elementsObj)
83
+ .filter(name => elementsObj[name].key && !elementsObj[name].virtual)
84
+ .map(name => this.scopedFunctions.quoteSqlId(name))
85
+ .join(', ');
86
+ return primaryKeys && `PRIMARY KEY(${primaryKeys})`;
87
+ }
88
+
89
+ /**
90
+ * Render entity-comment modifications as SQL.
91
+ */
92
+ alterEntityComment(artifactName, comment) {
93
+ return [ `COMMENT ON TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} IS ${this.comment(comment)};` ];
94
+ }
95
+
96
+ /**
97
+ * Render column-comment modifications as SQL.
98
+ */
99
+ alterColumnComment(artifactName, columnName, comment) {
100
+ return [ `COMMENT ON COLUMN ${this.scopedFunctions.renderArtifactName(artifactName)}.${columnName} IS ${this.comment(comment)};` ];
101
+ }
102
+
103
+ /**
104
+ * Render comment string.
105
+ */
106
+ comment(comment) {
107
+ return comment && this.scopedFunctions.renderStringForSql(this.scopedFunctions.getHanaComment({ doc: comment }), this.options.sqlDialect) || 'NULL';
108
+ }
109
+
110
+ /**
111
+ * Alter SQL snippet for entity.
112
+ */
113
+ alterEntitySqlSnippet(artifactName, snippet) {
114
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ${snippet};` ];
115
+ }
116
+
117
+ /**
118
+ * Concatenate multiple statements which are to be treated as one by the API caller.
119
+ */
120
+ concat(...statements) {
121
+ return [ statements.join('\n') ];
122
+ }
123
+ }
124
+
125
+ class DeltaRendererHana extends DeltaRenderer {
126
+ /**
127
+ * Render column additions as HANA SQL. Checks for duplicate elements.
128
+ */
129
+ addColumnsFromElementStrings(artifactName, eltStrings) {
130
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ADD (${eltStrings.join(', ')});` ];
131
+ }
132
+
133
+ /**
134
+ * Render association additions as HANA SQL.
135
+ * TODO duplicity check
136
+ */
137
+ addAssociations(artifactName, elementsObj, env) {
138
+ return Object.entries(elementsObj)
139
+ .map(([ name, elt ]) => this.scopedFunctions.renderAssociationElement(name, elt, env))
140
+ .filter(s => s !== '')
141
+ .map(eltStr => `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ADD ASSOCIATION (${eltStr});`);
142
+ }
143
+
144
+ /**
145
+ * Render column removals as HANA SQL.
146
+ */
147
+ dropColumns(artifactName, sqlIds) {
148
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP (${sqlIds.join(', ')});` ];
149
+ }
150
+
151
+ /**
152
+ * Render association removals as HANA SQL.
153
+ */
154
+ dropAssociation(artifactName, sqlId) {
155
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP ASSOCIATION ${sqlId};` ];
156
+ }
157
+ }
158
+
159
+ class DeltaRendererPostgres extends DeltaRenderer {
160
+ /**
161
+ * Render primary-key removals as SQL.
162
+ * @todo tableName is escaped - we cannot simply add _pkey
163
+ */
164
+ dropKey(artifactName) {
165
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP CONSTRAINT ${this.scopedFunctions.renderArtifactName(`${artifactName}_pkey`)};` ];
166
+ }
167
+
168
+ /**
169
+ * Render column removals as SQL.
170
+ */
171
+ dropColumns(artifactName, sqlIds) {
172
+ return sqlIds.map(sqlId => `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} DROP ${sqlId};`);
173
+ }
174
+
175
+ /**
176
+ * Render column modifications as Postgres SQL - no ( ), special NOT NULL.
177
+ */
178
+ alterColumns(artifactName, columnName, delta, definitionsStr) {
179
+ const sqls = [];
180
+ if (delta.new.notNull === true || delta.new.key === true)
181
+ definitionsStr = definitionsStr.replace(' NOT NULL', ''); // TODO: Is this robust enough?
182
+ else if (delta.new.notNull === false || delta.new.$notNull === false)
183
+ definitionsStr = definitionsStr.replace(' NULL', ''); // TODO: Is this robust enough?
184
+
185
+ sqls.push(`ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER ${definitionsStr};`);
186
+ if (delta.new.notNull && !delta.old.notNull)
187
+ sqls.push(`ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER ${columnName} SET NOT NULL;`);
188
+ else if (delta.old.notNull && !delta.new.notNull)
189
+ sqls.push(`ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER ${columnName} DROP NOT NULL;`);
190
+
191
+ return sqls;
192
+ }
193
+ }
194
+
195
+ class DeltaRendererH2 extends DeltaRenderer {
196
+ /**
197
+ * Render column modifications as H2 SQL - no ().
198
+ */
199
+ alterColumns(artifactName, columnName, delta, definitionsStr) {
200
+ return [ `ALTER TABLE ${this.scopedFunctions.renderArtifactName(artifactName)} ALTER ${definitionsStr};` ];
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Return an object encapsulating the render-functions for ALTER/DROP for a given db dialect.
206
+ *
207
+ * @param {CSN.Options} options
208
+ * @param {object} scopedFunctions
209
+ * @returns {DeltaRenderer}
210
+ */
211
+ function getDeltaRenderer(options, scopedFunctions) {
212
+ switch (options.sqlDialect) {
213
+ case 'hana':
214
+ return new DeltaRendererHana(options, scopedFunctions);
215
+ case 'h2':
216
+ return new DeltaRendererH2(options, scopedFunctions);
217
+ case 'postgres':
218
+ return new DeltaRendererPostgres(options, scopedFunctions);
219
+ default:
220
+ return new DeltaRenderer(options, scopedFunctions);
221
+ }
222
+ }
223
+
224
+
225
+ module.exports = {
226
+ getDeltaRenderer,
227
+ };
@@ -10,6 +10,8 @@
10
10
  "template-curly-spacing":["error", "never"],
11
11
  "complexity": ["warn", 40],
12
12
  "max-len": "off",
13
+ // there seem to be false positives
14
+ "jsdoc/require-returns-check": "off",
13
15
  // Don't enforce stupid descriptions
14
16
  "jsdoc/require-param-description": "off",
15
17
  "jsdoc/require-returns-description": "off",
@@ -1,38 +1,4 @@
1
1
  {
2
2
  "root": true,
3
- "plugins": ["sonarjs", "jsdoc"],
4
- "extends": ["../../../.eslintrc-ydkjsi.json", "plugin:sonarjs/recommended", "plugin:jsdoc/recommended"],
5
- "rules": {
6
- "prefer-const": "error",
7
- "quotes": ["error", "single", "avoid-escape"],
8
- "prefer-template": "error",
9
- "no-trailing-spaces": "error",
10
- "template-curly-spacing":["error", "never"],
11
- "complexity": ["warn", 30],
12
- "max-len": "off",
13
- // Don't enforce stupid descriptions
14
- "jsdoc/require-param-description": "off",
15
- "jsdoc/require-returns-description": "off",
16
- // Sometimes if-else's are more specific
17
- "sonarjs/prefer-single-boolean-return": "off",
18
- // Very whiny and nitpicky
19
- "sonarjs/cognitive-complexity": "off",
20
- // Does not recognize TS types
21
- "jsdoc/no-undefined-types": "off",
22
- // Whiny and annoying
23
- "sonarjs/no-duplicate-string": "off"
24
- },
25
- "parserOptions": {
26
- "ecmaVersion": 2020,
27
- "sourceType": "script"
28
- },
29
- "env": {
30
- "es2020": true,
31
- "node": true
32
- },
33
- "settings": {
34
- "jsdoc": {
35
- "mode": "typescript"
36
- }
37
- }
3
+ "extends": ["../db/.eslintrc.json"]
38
4
  }
@@ -213,14 +213,14 @@ function transform4odataWithCsn(inputModel, options) {
213
213
  const skipPersNameKinds = {'service':1, 'context':1, 'namespace':1, 'annotation':1, 'action':1, 'function':1};
214
214
  forEachDefinition(csn, (def, defName) => {
215
215
  // Resolve annotation shorthands for entities, types, annotations, ...
216
- renameShorthandAnnotations(def);
216
+ renameShorthandAnnotations(def, ['definitions', defName ]);
217
217
 
218
218
  // Annotate artifacts with their DB names if requested.
219
219
  // Skip artifacts that have no DB equivalent anyway
220
220
  if (options.sqlMapping && !(def.kind in skipPersNameKinds))
221
221
  def['@cds.persistence.name'] = getArtifactDatabaseNameOf(defName, options.sqlMapping, csn, 'hana'); // hana to allow naming mode "hdbcds"
222
222
 
223
- forEachMemberRecursively(def, (member, memberName, propertyName) => {
223
+ forEachMemberRecursively(def, (member, memberName, propertyName, path) => {
224
224
  // Annotate elements, foreign keys, parameters, etc. with their DB names if requested
225
225
  // Only these are actually required and don't annotate virtual elements in entities or types
226
226
  // as they have no DB representation (although in views)
@@ -233,7 +233,7 @@ function transform4odataWithCsn(inputModel, options) {
233
233
  annotateCoreComputed(member);
234
234
 
235
235
  // Resolve annotation shorthands for elements, actions, action parameters
236
- renameShorthandAnnotations(member);
236
+ renameShorthandAnnotations(member, path);
237
237
 
238
238
  // - If the association target is annotated with @cds.odata.valuelist, annotate the
239
239
  // association with @Common.ValueList.viaAssociation
@@ -298,7 +298,7 @@ function transform4odataWithCsn(inputModel, options) {
298
298
 
299
299
  // Rename shorthand annotations within artifact or element 'node' according to a builtin
300
300
  // list.
301
- function renameShorthandAnnotations(node) {
301
+ function renameShorthandAnnotations(node, path) {
302
302
  // FIXME: Verify this list - are they all still required? Do we need any more?
303
303
  const mappings = {
304
304
  '@label': '@Common.Label',
@@ -368,22 +368,29 @@ function transform4odataWithCsn(inputModel, options) {
368
368
  if(!node.enum && node.type && !isBuiltinType(node.type))
369
369
  typeDef = csn.definitions[node.type];
370
370
  if(typeDef.enum) {
371
- let enumValue = Object.keys(typeDef.enum).map(enumSymbol => {
371
+ const enumValue = [];
372
+ for(const enumSymbol in typeDef.enum) {
372
373
  const enumSymbolDef = typeDef.enum[enumSymbol];
373
- let result = { '@Core.SymbolicName': enumSymbol };
374
- if (enumSymbolDef.val !== undefined)
375
- result.Value = enumSymbolDef.val;
376
- else if (node.type && node.type === 'cds.String')
377
- // the symbol is used as value only for type 'cds.String'
378
- result.Value = enumSymbol;
379
- // Can't rely that @description has already been renamed to @Core.Description
380
- // Eval description according to precedence (doc comment must be considered already in Odata transformer
381
- // as in contrast to the other doc commments as it is used to annotate the @Validation.AllowedValues)
382
- const desc = enumSymbolDef['@Core.Description'] || enumSymbolDef['@description'] || enumSymbolDef.doc;
383
- if (desc)
384
- result['@Core.Description'] = desc;
385
- return result;
386
- });
374
+ if(enumSymbolDef.val === null)
375
+ info('odata-enum-value-type', path,
376
+ {name: enumSymbol, value: null, anno: '@Valiation.AllowedValues' },
377
+ 'Value $(VALUE) for enum element $(NAME) not added to $(ANNO)');
378
+ else {
379
+ const result = { '@Core.SymbolicName': enumSymbol };
380
+ if (enumSymbolDef.val !== undefined)
381
+ result.Value = enumSymbolDef.val;
382
+ else if (node.type && node.type === 'cds.String')
383
+ // the symbol is used as value only for type 'cds.String'
384
+ result.Value = enumSymbol;
385
+ // Can't rely that @description has already been renamed to @Core.Description
386
+ // Eval description according to precedence (doc comment must be considered already in Odata transformer
387
+ // as in contrast to the other doc commments as it is used to annotate the @Validation.AllowedValues)
388
+ const desc = enumSymbolDef['@Core.Description'] || enumSymbolDef['@description'] || enumSymbolDef.doc;
389
+ if (desc)
390
+ result['@Core.Description'] = desc;
391
+ enumValue.push(result);
392
+ }
393
+ }
387
394
  setAnnotation(node, '@Validation.AllowedValues', enumValue);
388
395
  }
389
396
  }