@sap/cds-compiler 2.15.8 → 3.1.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -0,0 +1,4 @@
1
+ {
2
+ "root": true,
3
+ "extends": "../../.eslintrc-ydkjsi.json"
4
+ }
@@ -0,0 +1,14 @@
1
+ // cds-compiler Inspect Module
2
+ // Used by `cdsc inspect` to gather details about the model such as statistics, etc.
3
+
4
+ 'use strict';
5
+
6
+ const { inspectModelStatistics } = require('./inspectModelStatistics');
7
+ const { inspectPropagation } = require('./inspectPropagation');
8
+ const { stringRefToPath } = require('./inspectUtils');
9
+
10
+ module.exports = {
11
+ inspectModelStatistics,
12
+ inspectPropagation,
13
+ stringRefToPath,
14
+ };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ const { forEach } = require('../utils/objectUtils');
4
+ const { term } = require('../utils/term');
5
+
6
+ /**
7
+ * Return a string representation of the inspected results.
8
+ *
9
+ * @param {XSN.Model} xsn
10
+ * @param {CSN.Options} options
11
+ * @returns {string}
12
+ */
13
+ function inspectModelStatistics(xsn, options) {
14
+ let result = '';
15
+
16
+ // Default color mode is 'auto'
17
+ const color = term(options.color || 'auto');
18
+
19
+ const defCount = countDefinitionKinds(xsn);
20
+ const sources = {
21
+ cdl: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'cdl').length,
22
+ csn: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'csn').length,
23
+ };
24
+
25
+ result += `cds-compiler model statistics:
26
+
27
+ ${ color.underline('files') }: ${ Object.keys(xsn.sources).length }
28
+ cdl sources: ${ sources.cdl }
29
+ csn sources: ${ sources.csn }
30
+
31
+ ${ color.underline('definitions') }: ${ defCount.definitions }
32
+ entities: ${ defCount.entity }
33
+ queries: ${ defCount.view }
34
+ aspects: ${ defCount.aspect }
35
+ events: ${ defCount.event }
36
+ types: ${ defCount.type }
37
+ services: ${ defCount.service }
38
+ context: ${ defCount.context }
39
+ actions: ${ defCount.action }
40
+ functions: ${ defCount.function }
41
+ namespaces: ${ defCount.namespace } (explicitly in CDL)
42
+
43
+ ${ color.underline('vocabularies') }: ${ Object.keys(xsn.vocabularies || {}).length }
44
+ `;
45
+ return result;
46
+ }
47
+
48
+ function countDefinitionKinds(xsn) {
49
+ const result = {
50
+ definitions: 0,
51
+ entity: 0,
52
+ action: 0,
53
+ function: 0,
54
+ aspect: 0,
55
+ event: 0,
56
+ type: 0,
57
+ service: 0,
58
+ context: 0,
59
+ namespace: 0,
60
+ // non-kind
61
+ view: 0,
62
+ };
63
+ forEach(xsn.definitions || {}, (name, def) => {
64
+ if (def.builtin)
65
+ return;
66
+ ++result.definitions;
67
+
68
+ if (def.query || def.projection)
69
+ ++result.view;
70
+ else if (result[def.kind] !== undefined)
71
+ ++result[def.kind];
72
+ else
73
+ throw new Error(`Unhandled kind: ${ def.kind } for ${ name }`);
74
+ });
75
+ return result;
76
+ }
77
+
78
+
79
+ module.exports = {
80
+ inspectModelStatistics,
81
+ };
@@ -0,0 +1,189 @@
1
+ 'use strict';
2
+
3
+ const { createMessageFunctions } = require('../base/messages');
4
+ const { locationString } = require('../base/location');
5
+ const { findArtifact, stringRefToPath } = require('./inspectUtils');
6
+ const { term } = require('../utils/term');
7
+
8
+ /**
9
+ * @param {XSN.Model} xsn
10
+ * @param {CSN.Options} options
11
+ * @param {string} artifactName
12
+ * @returns {string|null}
13
+ */
14
+ function inspectPropagation(xsn, options, artifactName) {
15
+ const { error } = createMessageFunctions(options, 'inspect', xsn);
16
+ const result = [];
17
+
18
+ // Default color mode is 'auto'
19
+ const color = term(options.color || 'auto');
20
+
21
+ const path = stringRefToPath(artifactName);
22
+ if (!path) {
23
+ error(null, null, { name: artifactName },
24
+ 'Artifact $(NAME) is not a valid path; expected format `<def>[:element]`');
25
+ return null;
26
+ }
27
+
28
+ const artifactXsn = findArtifact(xsn, path);
29
+
30
+ if (!artifactXsn) {
31
+ error(null, null, { name: artifactName },
32
+ // eslint-disable-next-line max-len
33
+ 'Artifact $(NAME) not found, only top-level artifacts and their elements are supported for now');
34
+ return null;
35
+ }
36
+ result.push(color.underline('analyzing propagation for artifact:'));
37
+ result.push(` name: ${ artifactXsn.name.id }`);
38
+ result.push(` kind: ${ artifactXsn.kind }`);
39
+
40
+ if (artifactXsn.$inferred)
41
+ result.push(` inferred: ${ artifactXsn.$inferred }`);
42
+
43
+ result.push('');
44
+ result.push(` ${ color.underline('annotation propagation:') }`);
45
+ result.push(..._indent(_inspectAnnotations(artifactXsn)));
46
+
47
+ result.push('');
48
+ result.push(` ${ color.underline('element propagation:') }`);
49
+ result.push(..._indent(_inspectElements(artifactXsn)));
50
+
51
+ return result.join('\n');
52
+ }
53
+
54
+ /**
55
+ @param {string[]} lines
56
+ @param {string} indent
57
+ * @returns {string[]}
58
+ */
59
+ function _indent(lines, indent = ' ') {
60
+ return lines.map(str => `${ indent }${ str }`);
61
+ }
62
+
63
+ /**
64
+ * @param {XSN.Artifact} artifactXsn
65
+ * @returns {string[]}
66
+ * @private
67
+ */
68
+ function _inspectAnnotations(artifactXsn) {
69
+ const result = [];
70
+ const annos = Object.keys(artifactXsn).filter(str => str.startsWith('@')).sort();
71
+
72
+ if (annos.length === 0)
73
+ return [ 'no annotations' ];
74
+
75
+ let maxAnnoLength = 30; // chosen arbitrarily, hopefully average
76
+ for (const anno of annos) {
77
+ const annoXsn = artifactXsn[anno];
78
+ const loc = locationString(annoXsn.name.location);
79
+ let origin;
80
+ switch (annoXsn.$priority) {
81
+ case false:
82
+ if (annoXsn.$inferred)
83
+ origin = 'propagation';
84
+ else
85
+ origin = 'direct';
86
+ break;
87
+
88
+ case 'extend':
89
+ case 'annotate':
90
+ origin = annoXsn.$priority;
91
+ break;
92
+
93
+ case undefined:
94
+ if (annoXsn.$inferred === '$generated') {
95
+ origin = 'generated';
96
+ break;
97
+ }
98
+ // fallthrough
99
+ default:
100
+ throw new Error(`inspect anno: Unhandled Case: ${ annoXsn.$priority }`);
101
+ }
102
+
103
+ maxAnnoLength = Math.max(maxAnnoLength, anno.length);
104
+
105
+ // origin: assume max length 11 of 'propagation'
106
+ // anno: use max length of all annotations till now
107
+ result.push([ origin.padStart(11), anno.padEnd(maxAnnoLength), loc ].join(' | '));
108
+ }
109
+ return result;
110
+ }
111
+
112
+ /**
113
+ * @param {XSN.Artifact} artifactXsn
114
+ * @returns {string[]}
115
+ * @private
116
+ */
117
+ function _inspectElements(artifactXsn) {
118
+ if (!artifactXsn.elements)
119
+ return [ 'does not have elements' ];
120
+
121
+ const result = [];
122
+ const elements = Object.keys(artifactXsn.elements);
123
+
124
+ let maxElemLength = 12;
125
+
126
+ const inferredNiceOutput = {
127
+ '*': 'wildcard',
128
+ 'expand-element': 'expanded',
129
+ 'expand-param': 'expanded',
130
+ 'aspect-composition': 'composition',
131
+ };
132
+
133
+ for (const element of elements) {
134
+ const elementXsn = artifactXsn.elements[element];
135
+ const loc = locationString(_origin(elementXsn).name.location);
136
+ let origin;
137
+
138
+ if (elementXsn.$inferred) {
139
+ // Use nice(r) output for known $inferred
140
+ if (inferredNiceOutput[elementXsn.$inferred])
141
+ origin = inferredNiceOutput[elementXsn.$inferred];
142
+ else
143
+ origin = elementXsn.$inferred;
144
+ }
145
+ else if (!isContainedInParentLocation(elementXsn, artifactXsn)) {
146
+ // just a heuristic
147
+ origin = 'extend';
148
+ }
149
+ else {
150
+ origin = 'direct';
151
+ }
152
+
153
+ maxElemLength = Math.max(maxElemLength, element.length);
154
+
155
+ // origin: assume max length 11 of 'composition'
156
+ // element: assume average length of 30, chosen randomly
157
+ result.push([ origin.padStart(11), element.padEnd(maxElemLength), loc ].join(' | '));
158
+ }
159
+ return result;
160
+ }
161
+
162
+ function _origin(elementXsn) {
163
+ while (elementXsn._origin)
164
+ elementXsn = elementXsn._origin;
165
+ return elementXsn;
166
+ }
167
+
168
+ /**
169
+ * Returns true if `art` is contained in `parent` according to its location.
170
+ *
171
+ * @param art
172
+ * @param parent
173
+ * @returns {boolean}
174
+ */
175
+ function isContainedInParentLocation(art, parent) {
176
+ const artLoc = art.location;
177
+ const parentLoc = parent.location;
178
+ if (artLoc.file !== parentLoc.file)
179
+ return false;
180
+ if (artLoc.line < parentLoc.line || artLoc.line > parentLoc.endLine)
181
+ return false;
182
+ // Good enough for now
183
+ // TODO: Check columns
184
+ return true;
185
+ }
186
+
187
+ module.exports = {
188
+ inspectPropagation,
189
+ };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Reference (string) to path (array) that can be used to identify an artifact
5
+ * @param str
6
+ * @returns {*[]|*}
7
+ */
8
+ function stringRefToPath(str) {
9
+ // e.g. `ns.service.E:sub.elem.structured`
10
+ const path = str.split(':');
11
+ if (path.length === 1)
12
+ return path;
13
+ if (path.length > 2)
14
+ return null;
15
+ return [ path[0], ...path[1].split('.') ];
16
+ }
17
+
18
+ /**
19
+ * @param {XSN.Model} xsn
20
+ * @param {string} path
21
+ * @private
22
+ */
23
+ function findArtifact(xsn, path) {
24
+ const segments = [ ...path ];
25
+ const topLevelName = segments[0];
26
+ let art = (xsn.definitions && xsn.definitions[topLevelName]) ||
27
+ (xsn.vocabularies && xsn.vocabularies[topLevelName]);
28
+ if (!art)
29
+ return null;
30
+ segments.shift();
31
+ if (segments.length === 0)
32
+ return art;
33
+ while (segments.length && art) {
34
+ const segment = segments.shift();
35
+ art = (art.items?.elements || art.elements)?.[segment];
36
+ }
37
+ return art || null;
38
+ }
39
+
40
+
41
+ module.exports = {
42
+ stringRefToPath,
43
+ findArtifact,
44
+ };