@sap/cds-compiler 3.7.2 → 3.8.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.
- package/CHANGELOG.md +63 -4
- package/bin/cdsc.js +3 -0
- package/doc/CHANGELOG_ARCHIVE.md +6 -6
- package/doc/CHANGELOG_BETA.md +15 -0
- package/doc/DeprecatedOptions_v2.md +1 -1
- package/doc/NameResolution.md +1 -1
- package/lib/api/main.js +61 -22
- package/lib/api/options.js +1 -0
- package/lib/api/validate.js +5 -0
- package/lib/base/dictionaries.js +5 -3
- package/lib/base/keywords.js +2 -0
- package/lib/base/message-registry.js +64 -22
- package/lib/base/messages.js +12 -7
- package/lib/base/model.js +3 -2
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/defaultValues.js +1 -1
- package/lib/checks/hasPersistedElements.js +1 -1
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/onConditions.js +9 -6
- package/lib/checks/sql-snippets.js +2 -2
- package/lib/checks/types.js +1 -2
- package/lib/compiler/assert-consistency.js +24 -5
- package/lib/compiler/base.js +49 -2
- package/lib/compiler/builtins.js +15 -6
- package/lib/compiler/checks.js +4 -4
- package/lib/compiler/define.js +59 -80
- package/lib/compiler/extend.js +701 -498
- package/lib/compiler/finalize-parse-cdl.js +4 -3
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/kick-start.js +2 -2
- package/lib/compiler/populate.js +17 -9
- package/lib/compiler/propagator.js +12 -5
- package/lib/compiler/resolve.js +26 -173
- package/lib/compiler/shared.js +12 -53
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/utils.js +2 -2
- package/lib/edm/annotations/genericTranslation.js +124 -46
- package/lib/edm/csn2edm.js +22 -1
- package/lib/edm/edmPreprocessor.js +41 -21
- package/lib/gen/Dictionary.json +4 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/languageLexer.js +1 -1
- package/lib/gen/languageParser.js +4810 -4482
- package/lib/inspect/inspectPropagation.js +20 -36
- package/lib/json/from-csn.js +55 -5
- package/lib/json/to-csn.js +71 -110
- package/lib/language/errorStrategy.js +1 -0
- package/lib/language/genericAntlrParser.js +47 -8
- package/lib/language/language.g4 +88 -62
- package/lib/language/textUtils.js +13 -0
- package/lib/main.d.ts +43 -3
- package/lib/main.js +4 -2
- package/lib/model/csnRefs.js +14 -2
- package/lib/model/csnUtils.js +11 -74
- package/lib/model/revealInternalProperties.js +3 -0
- package/lib/optionProcessor.js +3 -0
- package/lib/render/toCdl.js +203 -104
- package/lib/render/toHdbcds.js +0 -1
- package/lib/render/toRename.js +14 -51
- package/lib/transform/braceExpression.js +6 -0
- package/lib/transform/db/rewriteCalculatedElements.js +55 -14
- package/lib/transform/forOdataNew.js +20 -15
- package/lib/transform/forRelationalDB.js +21 -14
- package/lib/transform/parseExpr.js +2 -0
- package/lib/transform/transformUtilsNew.js +36 -9
- package/lib/transform/translateAssocsToJoins.js +11 -4
- package/lib/transform/universalCsn/coreComputed.js +15 -7
- package/lib/transform/universalCsn/universalCsnEnricher.js +4 -4
- package/package.json +2 -1
package/lib/model/csnUtils.js
CHANGED
|
@@ -63,7 +63,6 @@ function getUtils( model, universalReady ) {
|
|
|
63
63
|
addStringAnnotationTo,
|
|
64
64
|
getServiceName,
|
|
65
65
|
hasAnnotationValue,
|
|
66
|
-
cloneWithTransformations,
|
|
67
66
|
getFinalBaseTypeWithProps,
|
|
68
67
|
get$combined,
|
|
69
68
|
getQueryPrimarySource,
|
|
@@ -81,7 +80,7 @@ function getUtils( model, universalReady ) {
|
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
/**
|
|
84
|
-
* Get the union of all elements from the from clause
|
|
83
|
+
* Get the union of all elements from the "from" clause
|
|
85
84
|
* - descend into unions, following the lead query
|
|
86
85
|
* - merge all queries in case of joins
|
|
87
86
|
* - follow subqueries
|
|
@@ -93,7 +92,7 @@ function getUtils( model, universalReady ) {
|
|
|
93
92
|
function getSources( query, isSubquery = false ) {
|
|
94
93
|
// Remark CW: better just a while along query.SET.args[0]
|
|
95
94
|
if (query.SET) {
|
|
96
|
-
if (query.SET.args[0].SELECT
|
|
95
|
+
if (query.SET.args[0].SELECT?.elements)
|
|
97
96
|
return mergeElementsIntoMap(Object.create(null), query.SET.args[0].SELECT.elements, query.SET.args[0].$location);
|
|
98
97
|
|
|
99
98
|
return getSources(query.SET.args[0], isSubquery);
|
|
@@ -111,9 +110,12 @@ function getUtils( model, universalReady ) {
|
|
|
111
110
|
if (isSubquery && !query.SELECT.elements)
|
|
112
111
|
throw new ModelError('Expected subquery to have .elements');
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
const elements = isSubquery ? query.SELECT.elements : art.elements;
|
|
114
|
+
// sub-queries also have an alias that is reachable by outer queries, in contrast to `from.as`.
|
|
115
|
+
const parent = query.as || query.SELECT.from.as || implicitAs(query.SELECT.from.ref);
|
|
116
|
+
// for better error messages, we refer to the actual reference name first
|
|
117
|
+
const errorParent = implicitAs(query.SELECT.from.ref);
|
|
118
|
+
return mergeElementsIntoMap(Object.create(null), elements, art.$location, parent, errorParent);
|
|
117
119
|
}
|
|
118
120
|
else if (query.SELECT.from.SET || query.SELECT.from.SELECT) {
|
|
119
121
|
return getSources(query.SELECT.from, true);
|
|
@@ -131,7 +133,7 @@ function getUtils( model, universalReady ) {
|
|
|
131
133
|
}
|
|
132
134
|
else if (arg.ref) {
|
|
133
135
|
const art = artifactRef(arg);
|
|
134
|
-
elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || arg.ref
|
|
136
|
+
elements = mergeElementsIntoMap(elements, art.elements, art.$location, arg.as || implicitAs(arg.ref), implicitAs(arg.ref) || arg.as);
|
|
135
137
|
}
|
|
136
138
|
else if (arg.SELECT || arg.SET) {
|
|
137
139
|
elements = mergeElementMaps(elements, getSources(arg));
|
|
@@ -176,27 +178,13 @@ function getUtils( model, universalReady ) {
|
|
|
176
178
|
existingMap[elementName] = [];
|
|
177
179
|
|
|
178
180
|
existingMap[elementName].push({
|
|
179
|
-
element, name: elementName, source: $location, parent
|
|
181
|
+
element, name: elementName, source: $location, parent, errorParent,
|
|
180
182
|
});
|
|
181
183
|
}
|
|
182
184
|
|
|
183
185
|
return existingMap;
|
|
184
186
|
}
|
|
185
187
|
|
|
186
|
-
/**
|
|
187
|
-
* Return the name part of the artifact name - no namespace etc.
|
|
188
|
-
* @param {string|object} name Absolute name of the artifact
|
|
189
|
-
*/
|
|
190
|
-
function getBaseName( name ) {
|
|
191
|
-
if (!name)
|
|
192
|
-
return name;
|
|
193
|
-
|
|
194
|
-
if (name.id)
|
|
195
|
-
return name.id.substring( name.id.lastIndexOf('.') + 1 );
|
|
196
|
-
|
|
197
|
-
return name.substring( name.lastIndexOf('.') + 1 );
|
|
198
|
-
}
|
|
199
|
-
|
|
200
188
|
/**
|
|
201
189
|
* Return the left-most, primary source of the given query.
|
|
202
190
|
* @param {*} query Definition's query object
|
|
@@ -341,57 +329,6 @@ function getUtils( model, universalReady ) {
|
|
|
341
329
|
}
|
|
342
330
|
}
|
|
343
331
|
|
|
344
|
-
/**
|
|
345
|
-
* Clone 'node', transforming nodes therein recursively. Object 'transformers' is expected
|
|
346
|
-
* to contain a mapping of property 'key' names to transformer functions. The node's properties
|
|
347
|
-
* are walked recursively, calling each transformer function on its corresponding property
|
|
348
|
-
* 'key' of 'node', replacing 'value' in 'resultNode' with the function's return value
|
|
349
|
-
* (returning 'undefined' will delete the property).
|
|
350
|
-
* If no transformation function is found for 'key', the first letter of 'key' is tried
|
|
351
|
-
* instead (this seems to be intended for handling annotations that start with '@' ?)
|
|
352
|
-
*
|
|
353
|
-
* Regardless of their names, transformers are never applied to dictionary elements.
|
|
354
|
-
*
|
|
355
|
-
* The transformer functions are called with the following signature:
|
|
356
|
-
* transformer(value, node, resultNode, key)
|
|
357
|
-
*
|
|
358
|
-
* @param {any} rootNode Node to transform
|
|
359
|
-
* @param {any} transformers Object defining transformer functions
|
|
360
|
-
* @returns {object}
|
|
361
|
-
*/
|
|
362
|
-
function cloneWithTransformations( rootNode, transformers ) {
|
|
363
|
-
return transformNode(rootNode);
|
|
364
|
-
|
|
365
|
-
// This general transformation function will be applied to each node recursively
|
|
366
|
-
function transformNode( node ) {
|
|
367
|
-
// Return primitive values and null unchanged, but let objects and dictionaries through
|
|
368
|
-
// (Note that 'node instanceof Object' would be false for dictionaries).
|
|
369
|
-
if (node === null || typeof node !== 'object')
|
|
370
|
-
return node;
|
|
371
|
-
|
|
372
|
-
// Simply return if node is to be ignored
|
|
373
|
-
if (node === undefined || node._ignore)
|
|
374
|
-
return undefined;
|
|
375
|
-
// Transform arrays element-wise
|
|
376
|
-
if (Array.isArray(node))
|
|
377
|
-
return node.map(transformNode);
|
|
378
|
-
|
|
379
|
-
// Things not having 'proto' are dictionaries
|
|
380
|
-
const proto = Object.getPrototypeOf(node);
|
|
381
|
-
// Iterate own properties of 'node' and transform them into 'resultNode'
|
|
382
|
-
const resultNode = Object.create(proto);
|
|
383
|
-
for (const key of Object.keys(node)) {
|
|
384
|
-
// Dictionary always use transformNode(), other objects their transformer according to key
|
|
385
|
-
const transformer = (proto === null || proto === undefined) ? transformNode : transformers[key] || transformers[key.charAt(0)];
|
|
386
|
-
// Apply transformer, or use transformNode() if there is none
|
|
387
|
-
const resultValue = (transformer || transformNode)(node[key], node, resultNode, key);
|
|
388
|
-
if (resultValue !== undefined)
|
|
389
|
-
resultNode[key] = resultValue;
|
|
390
|
-
}
|
|
391
|
-
return resultNode;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
332
|
/**
|
|
396
333
|
* Resolve to the final type of a type, that means follow type chains, references, etc.
|
|
397
334
|
* Input is a fully qualified type name, i.e. string, or type ref, i.e. `{ ref: [...] }`.
|
|
@@ -931,7 +868,7 @@ function getUnderscoredName( startIndex, parts, csn ) {
|
|
|
931
868
|
for (let i = startIndex; i < parts.length; i++) {
|
|
932
869
|
const namePart = parts.slice(0, i).join('.');
|
|
933
870
|
const art = csn.definitions[namePart];
|
|
934
|
-
if (art && !(art.kind === '
|
|
871
|
+
if (art && !(art.kind === 'context' || art.kind === 'service')) {
|
|
935
872
|
const prefix = parts.slice(0, i - 1).join('.');
|
|
936
873
|
const suffix = parts.slice(i - 1).join('_');
|
|
937
874
|
const result = [];
|
|
@@ -61,6 +61,7 @@ function tableAliasAsLink( art, parent, name ) {
|
|
|
61
61
|
* @param {string} [nameOrPath]
|
|
62
62
|
*/
|
|
63
63
|
function revealInternalProperties( model, nameOrPath ) {
|
|
64
|
+
// return model;
|
|
64
65
|
const transformers = {
|
|
65
66
|
messages: m => m,
|
|
66
67
|
name: shortenName,
|
|
@@ -71,6 +72,7 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
71
72
|
artifacts: artifactDictionary,
|
|
72
73
|
definitions: artifactDictionary,
|
|
73
74
|
vocabularies: dictionary,
|
|
75
|
+
$lateExtensions: dictionary,
|
|
74
76
|
elements,
|
|
75
77
|
columns,
|
|
76
78
|
expand: columns,
|
|
@@ -95,6 +97,7 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
95
97
|
$compositionTargets: d => d, // dictionary( boolean )
|
|
96
98
|
_extend: reveal,
|
|
97
99
|
_annotate: reveal,
|
|
100
|
+
_annotateS: artifactIdentifier,
|
|
98
101
|
_deps: dependencyInfo,
|
|
99
102
|
_status: primOrString, // is a string anyway
|
|
100
103
|
$annotations: as => as.map( $annotation ),
|
package/lib/optionProcessor.js
CHANGED
|
@@ -226,6 +226,7 @@ optionProcessor.command('O, toOdata')
|
|
|
226
226
|
.option(' --odata-x-service-refs')
|
|
227
227
|
.option(' --odata-foreign-keys')
|
|
228
228
|
.option(' --odata-v2-partial-constr')
|
|
229
|
+
.option(' --odata-voc-refs <list>')
|
|
229
230
|
.option('-c, --csn')
|
|
230
231
|
.option('-f, --odata-format <format>', ['flat', 'structured'])
|
|
231
232
|
.option('-n, --sql-mapping <style>', ['plain', 'quoted', 'hdbcds'], { aliases: [ '--names' ] })
|
|
@@ -254,6 +255,8 @@ optionProcessor.command('O, toOdata')
|
|
|
254
255
|
--odata-foreign-keys Render foreign keys in structured format (V4 only)
|
|
255
256
|
--odata-v2-partial-constr Render referential constraints also for partial principal key tuple
|
|
256
257
|
(Not spec compliant and V2 only)
|
|
258
|
+
--odata-voc-refs <list> JSON array of adhoc vocabulary definitions
|
|
259
|
+
[ { alias, ns, uri }, ... ]
|
|
257
260
|
-n, --sql-mapping <style> Annotate artifacts and elements with "@cds.persistence.name", which is
|
|
258
261
|
the corresponding database name (see "--sql-mapping" for "toHana or "toSql")
|
|
259
262
|
plain : (default) Names in uppercase and flattened with underscores
|