@sap/cds-compiler 2.12.0 → 2.15.2

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 (128) hide show
  1. package/CHANGELOG.md +221 -15
  2. package/bin/cdsc.js +125 -50
  3. package/bin/cdsse.js +2 -2
  4. package/doc/CHANGELOG_BETA.md +13 -6
  5. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  6. package/doc/NameResolution.md +21 -16
  7. package/lib/api/main.js +47 -84
  8. package/lib/api/options.js +5 -6
  9. package/lib/api/validate.js +6 -11
  10. package/lib/backends.js +15 -23
  11. package/lib/base/dictionaries.js +0 -8
  12. package/lib/base/error.js +26 -0
  13. package/lib/base/keywords.js +7 -17
  14. package/lib/base/location.js +9 -4
  15. package/lib/base/message-registry.js +114 -18
  16. package/lib/base/messages.js +101 -90
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +177 -123
  19. package/lib/checks/annotationsOData.js +12 -33
  20. package/lib/checks/arrayOfs.js +1 -34
  21. package/lib/checks/cdsPersistence.js +2 -1
  22. package/lib/checks/enricher.js +17 -1
  23. package/lib/checks/invalidTarget.js +3 -1
  24. package/lib/checks/managedWithoutKeys.js +3 -1
  25. package/lib/checks/selectItems.js +4 -4
  26. package/lib/checks/sql-snippets.js +27 -26
  27. package/lib/checks/types.js +1 -1
  28. package/lib/checks/validator.js +6 -11
  29. package/lib/compiler/assert-consistency.js +6 -3
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +19 -6
  32. package/lib/compiler/checks.js +23 -60
  33. package/lib/compiler/cycle-detector.js +1 -1
  34. package/lib/compiler/define.js +1151 -0
  35. package/lib/compiler/extend.js +1000 -0
  36. package/lib/compiler/finalize-parse-cdl.js +237 -0
  37. package/lib/compiler/index.js +107 -39
  38. package/lib/compiler/kick-start.js +190 -0
  39. package/lib/compiler/moduleLayers.js +4 -4
  40. package/lib/compiler/populate.js +1227 -0
  41. package/lib/compiler/propagator.js +114 -46
  42. package/lib/compiler/resolve.js +1521 -0
  43. package/lib/compiler/shared.js +126 -65
  44. package/lib/compiler/tweak-assocs.js +535 -0
  45. package/lib/compiler/utils.js +197 -33
  46. package/lib/edm/.eslintrc.json +5 -0
  47. package/lib/edm/annotations/genericTranslation.js +38 -24
  48. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  49. package/lib/edm/csn2edm.js +219 -100
  50. package/lib/edm/edm.js +302 -230
  51. package/lib/edm/edmPreprocessor.js +554 -419
  52. package/lib/edm/edmUtils.js +138 -44
  53. package/lib/gen/Dictionary.json +100 -19
  54. package/lib/gen/language.checksum +1 -1
  55. package/lib/gen/language.interp +11 -1
  56. package/lib/gen/language.tokens +86 -83
  57. package/lib/gen/languageLexer.interp +10 -1
  58. package/lib/gen/languageLexer.js +860 -833
  59. package/lib/gen/languageLexer.tokens +78 -75
  60. package/lib/gen/languageParser.js +5765 -4480
  61. package/lib/json/csnVersion.js +10 -11
  62. package/lib/json/from-csn.js +15 -3
  63. package/lib/json/to-csn.js +126 -68
  64. package/lib/language/docCommentParser.js +4 -4
  65. package/lib/language/genericAntlrParser.js +123 -5
  66. package/lib/language/language.g4 +355 -156
  67. package/lib/language/multiLineStringParser.js +5 -5
  68. package/lib/main.d.ts +486 -59
  69. package/lib/main.js +41 -9
  70. package/lib/model/api.js +3 -1
  71. package/lib/model/csnRefs.js +252 -156
  72. package/lib/model/csnUtils.js +384 -297
  73. package/lib/model/enrichCsn.js +71 -29
  74. package/lib/model/revealInternalProperties.js +29 -8
  75. package/lib/model/sortViews.js +2 -1
  76. package/lib/modelCompare/compare.js +23 -18
  77. package/lib/optionProcessor.js +63 -26
  78. package/lib/render/manageConstraints.js +35 -32
  79. package/lib/render/toCdl.js +897 -947
  80. package/lib/render/toHdbcds.js +205 -257
  81. package/lib/render/toSql.js +264 -225
  82. package/lib/render/utils/common.js +136 -25
  83. package/lib/render/utils/sql.js +4 -3
  84. package/lib/render/utils/stringEscapes.js +111 -0
  85. package/lib/sql-identifier.js +1 -1
  86. package/lib/transform/.eslintrc.json +5 -0
  87. package/lib/transform/db/.eslintrc.json +3 -1
  88. package/lib/transform/db/applyTransformations.js +35 -12
  89. package/lib/transform/db/assertUnique.js +1 -1
  90. package/lib/transform/db/associations.js +104 -306
  91. package/lib/transform/db/cdsPersistence.js +2 -2
  92. package/lib/transform/db/constraints.js +58 -53
  93. package/lib/transform/db/expansion.js +60 -33
  94. package/lib/transform/db/flattening.js +582 -104
  95. package/lib/transform/db/groupByOrderBy.js +3 -1
  96. package/lib/transform/db/transformExists.js +66 -13
  97. package/lib/transform/db/views.js +11 -7
  98. package/lib/transform/draft/.eslintrc.json +38 -0
  99. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  100. package/lib/transform/draft/odata.js +227 -0
  101. package/lib/transform/forHanaNew.js +109 -208
  102. package/lib/transform/forOdataNew.js +59 -212
  103. package/lib/transform/localized.js +46 -26
  104. package/lib/transform/odata/toFinalBaseType.js +85 -11
  105. package/lib/transform/odata/typesExposure.js +147 -199
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +44 -33
  108. package/lib/transform/translateAssocsToJoins.js +3 -20
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +172 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/moduleResolve.js +13 -6
  114. package/lib/utils/objectUtils.js +30 -0
  115. package/package.json +1 -1
  116. package/share/messages/README.md +26 -0
  117. package/share/messages/message-explanations.json +2 -1
  118. package/share/messages/syntax-expected-integer.md +37 -0
  119. package/lib/compiler/definer.js +0 -2361
  120. package/lib/compiler/resolver.js +0 -3079
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -290
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
  128. package/lib/transform/universalCsnEnricher.js +0 -237
@@ -0,0 +1,190 @@
1
+ // Kick-start: prepare to resolve all references
2
+
3
+ 'use strict';
4
+
5
+ const { isBetaEnabled, forEachGeneric } = require('../base/model');
6
+ const { setLink, annotationVal, annotationIsFalse } = require('./utils');
7
+
8
+ function kickStart( model ) {
9
+ const { options } = model;
10
+ const { message } = model.$messageFunctions;
11
+
12
+ const { resolveUncheckedPath, resolvePath } = model.$functions;
13
+ Object.assign( model.$functions, { projectionAncestor } );
14
+
15
+ // Set _service link (sorted to set it on parent first). Could be set
16
+ // directly, but beware a namespace becoming a service later.
17
+ Object.keys( model.definitions ).sort().forEach( setAncestorsAndService );
18
+ forEachGeneric( model, 'definitions', postProcessArtifact );
19
+
20
+ forEachGeneric( model, 'sources', resolveUsings );
21
+ return;
22
+
23
+
24
+ /**
25
+ * Set projection ancestors, and _service link for artifact with absolute name 'name':
26
+ * - not set: internal artifact
27
+ * - null: not within service
28
+ * - service: the artifact of the embedding service
29
+ * This function must be called ordered: parent first
30
+ *
31
+ * @param {string} name Artifact name
32
+ */
33
+ function setAncestorsAndService( name ) {
34
+ const art = model.definitions[name];
35
+ if (!('_parent' in art))
36
+ return; // nothing to do for builtins and redefinitions
37
+ if (art._from && !('_ancestors' in art))
38
+ setProjectionAncestors( art );
39
+
40
+ let parent = art._parent;
41
+ if (parent === model.definitions.localized)
42
+ parent = model.definitions[name.substring( 'localized.'.length )];
43
+ const service = parent && (parent._service || parent.kind === 'service' && parent);
44
+ setLink( art, '_service', service );
45
+ if (!parent || !service)
46
+ return;
47
+ // To be removed when nested services are allowed
48
+ if (!isBetaEnabled(options, 'nestedServices') && art.kind === 'service') {
49
+ while (parent.kind !== 'service')
50
+ parent = parent._parent;
51
+ message( 'service-nested-service', [ art.name.location, art ], { art: parent },
52
+ 'A service can\'t be nested within a service $(ART)' );
53
+ }
54
+ else if (art.kind === 'context') {
55
+ while (parent.kind !== 'service')
56
+ parent = parent._parent;
57
+ // TODO: remove this error
58
+ message( 'service-nested-context', [ art.name.location, art ], { art: parent },
59
+ 'A context can\'t be nested within a service $(ART)' );
60
+ }
61
+ }
62
+
63
+ function setProjectionAncestors( art ) {
64
+ // Must be run after processLocalizedData() as we could have a projection
65
+ // on a generated entity.
66
+
67
+ // TODO: do not do implicit redirection across services, i.e. Service2.E is
68
+ // no redirection target for E if Service2.E = projection on Service1.E and
69
+ // Service1.E = projection on E
70
+ const chain = [];
71
+ const autoexposed = art.$generated || annotationVal( art['@cds.autoexposed'] );
72
+ const preferredRedirectionTarget = annotationVal( art['@cds.redirection.target'] );
73
+ // no need to set preferredRedirectionTarget in the while loop as we would
74
+ // use the projection having @cds.redirection.target anyhow instead of
75
+ // `art` anyway (if we do the no-x-service-implicit-redirection TODO above)
76
+ while (art && !('_ancestors' in art) &&
77
+ art._from && art._from.length === 1 &&
78
+ (preferredRedirectionTarget || !annotationIsFalse( art['@cds.redirection.target'] ) ) &&
79
+ art.query.op && art.query.op.val === 'SELECT') {
80
+ chain.push( art );
81
+ setLink( art, '_ancestors', null ); // avoid infloop with cyclic from
82
+ const name = resolveUncheckedPath( art._from[0], 'include', art ); // TODO: 'include'?
83
+ art = name && projectionAncestor( model.definitions[name], art.params );
84
+ if (autoexposed)
85
+ break; // only direct projection for auto-exposed
86
+ }
87
+ let ancestors = art && (!autoexposed && art._ancestors || []);
88
+ chain.reverse();
89
+ for (const a of chain) {
90
+ ancestors = (ancestors ? [ ...ancestors, art ] : []);
91
+ setLink( a, '_ancestors', ancestors );
92
+ art = a;
93
+ }
94
+ }
95
+
96
+ // Return argument `source` if entity `source` has parameters like `params`
97
+ // - same parameters, although `params` can contain a new optional one (with DEFAULT)
98
+ // - a parameter in `params` can be optional which is not in `source.params`, but not vice versa
99
+ // - exactly the same types (type argument do not matter)
100
+ function projectionAncestor( source, params ) {
101
+ if (!source)
102
+ return source;
103
+ if (!params) // proj has no params => ok if source has no params
104
+ return !source.params && source;
105
+ const sourceParams = source.params || Object.create(null);
106
+ for (const n in sourceParams) {
107
+ if (!(n in params)) // source param is not projection param
108
+ return null; // -> can't be used as implicit redirection target
109
+ }
110
+ for (const n in params) {
111
+ const pp = params[n];
112
+ const sp = sourceParams[n];
113
+ if (sp) {
114
+ if (sp.default && !pp.default) // param DEFAULT clause not supported yet
115
+ return null; // param is not optional anymore
116
+ const pt = pp.type && resolveUncheckedPath( pp.type, 'type', pp );
117
+ const st = sp.type && resolveUncheckedPath( sp.type, 'type', sp );
118
+ if ((pt || null) !== (st || null))
119
+ return null; // params have different type
120
+ }
121
+ else if (!pp.default) {
122
+ return null;
123
+ } // non-optional param in projection, but not source
124
+ }
125
+ return source;
126
+ }
127
+
128
+ function postProcessArtifact( art ) {
129
+ tagCompositionTargets( art );
130
+ if (art.$queries) {
131
+ for (const query of art.$queries) {
132
+ if (query.mixin)
133
+ forEachGeneric( query, 'mixin', tagCompositionTargets );
134
+ }
135
+ }
136
+ if (!art._ancestors || art.kind !== 'entity')
137
+ return; // redirections only to entities
138
+ const service = art._service;
139
+ if (!service)
140
+ return;
141
+ const sname = service.name.absolute;
142
+ art._ancestors.forEach( expose );
143
+ return;
144
+
145
+ function expose( ancestor ) {
146
+ if (ancestor._service === service)
147
+ return;
148
+ const desc = ancestor._descendants ||
149
+ setLink( ancestor, '_descendants', Object.create(null) );
150
+ if (!desc[sname])
151
+ desc[sname] = [ art ];
152
+ else
153
+ desc[sname].push( art );
154
+ }
155
+ }
156
+
157
+ function tagCompositionTargets( elem ) {
158
+ const type = elem.type && elem.type.path;
159
+ if (elem.target && type && type[0] && type[0].id === 'cds.Composition') {
160
+ // A target aspect would have already moved to property `targetAspect` in
161
+ // define.js (hm... more something for kick-start.js...)
162
+ const target = resolvePath( elem.target, 'target', elem );
163
+ if (target)
164
+ model.$compositionTargets[target.name.absolute] = true;
165
+ }
166
+ forEachGeneric( elem, 'elements', tagCompositionTargets );
167
+ }
168
+
169
+ // Resolve the using declarations in `using`. Issue
170
+ // error message if the referenced artifact does not exist.
171
+ function resolveUsings( src, topLevel ) {
172
+ if (!src.usings)
173
+ return;
174
+ for (const def of src.usings) {
175
+ if (def.usings) // using {...}
176
+ resolveUsings( def );
177
+ if (!def.name || !def.name.absolute)
178
+ continue; // using {...}, parse error
179
+ const art = model.definitions[def.name.absolute];
180
+ if (art && art.$duplicates)
181
+ continue;
182
+ const ref = def.extern;
183
+ const from = (topLevel ? def : src).fileDep;
184
+ if (art || !from || from.realname) // no error for non-existing ref with non-existing module
185
+ resolvePath( ref, 'global', def ); // TODO: consider FROM for validNames
186
+ }
187
+ }
188
+ }
189
+
190
+ module.exports = kickStart;
@@ -3,14 +3,14 @@
3
3
  'use strict';
4
4
 
5
5
  const detectCycles = require('./cycle-detector');
6
- const { setProp } = require('../base/model');
6
+ const { setLink } = require('./utils');
7
7
 
8
8
  function setLayers( sources ) {
9
9
  // set dependencies
10
10
  for (const name in sources) {
11
11
  const ast = sources[name];
12
12
  ast.realname = name;
13
- setProp( ast, '_deps', [] );
13
+ setLink( ast, '_deps', [] );
14
14
  for (const d of ast.dependencies || []) {
15
15
  const art = sources[d.realname];
16
16
  if (art)
@@ -24,7 +24,7 @@ function setLayers( sources ) {
24
24
  // It is ensured that the representative is called last in SCC and that
25
25
  // dependent SCCs are called first
26
26
  function setExtends( node, representative, sccDeps = Object.create(null) ) {
27
- setProp( node, '_layerRepresentative', representative );
27
+ setLink( node, '_layerRepresentative', representative );
28
28
  if (layerRepresentative !== representative) {
29
29
  layerRepresentative = representative;
30
30
  ++layerNumber;
@@ -40,7 +40,7 @@ function setLayers( sources ) {
40
40
  if (node === representative) {
41
41
  const exts = Object.keys( sccDeps ).map( name => sccDeps[name]._layerExtends );
42
42
  Object.assign( sccDeps, ...exts );
43
- setProp( representative, '_layerExtends', sccDeps );
43
+ setLink( representative, '_layerExtends', sccDeps );
44
44
  // console.log ('SCC:', node.realname)
45
45
  }
46
46
  return sccDeps;