@sap/cds-compiler 5.3.2 → 5.4.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.
- package/CHANGELOG.md +29 -2
- package/bin/cdsc.js +1 -1
- package/doc/CHANGELOG_BETA.md +2 -2
- package/lib/api/options.js +4 -2
- package/lib/base/builtins.js +0 -10
- package/lib/base/keywords.js +3 -31
- package/lib/base/message-registry.js +23 -5
- package/lib/base/messages.js +1 -1
- package/lib/checks/existsMustEndInAssoc.js +7 -2
- package/lib/checks/foreignKeys.js +12 -7
- package/lib/compiler/assert-consistency.js +11 -3
- package/lib/compiler/builtins.js +2 -0
- package/lib/compiler/checks.js +88 -38
- package/lib/compiler/define.js +2 -2
- package/lib/compiler/shared.js +9 -10
- package/lib/compiler/xpr-rewrite.js +11 -0
- package/lib/compiler/xsn-model.js +1 -1
- package/lib/edm/csn2edm.js +2 -0
- package/lib/edm/edm.js +2 -1
- package/lib/edm/edmPreprocessor.js +14 -1
- package/lib/edm/edmUtils.js +17 -2
- package/lib/gen/BaseParser.js +291 -197
- package/lib/gen/CdlParser.js +1631 -1605
- package/lib/gen/Dictionary.json +74 -6
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1808 -1804
- package/lib/language/antlrParser.js +8 -4
- package/lib/language/genericAntlrParser.js +3 -3
- package/lib/model/csnUtils.js +6 -1
- package/lib/optionProcessor.js +4 -0
- package/lib/parsers/AstBuildingParser.js +172 -108
- package/lib/parsers/CdlGrammar.g4 +154 -134
- package/lib/parsers/Lexer.js +3 -3
- package/lib/parsers/identifiers.js +59 -0
- package/lib/render/toCdl.js +5 -5
- package/lib/render/utils/common.js +5 -0
- package/lib/render/utils/delta.js +23 -5
- package/lib/transform/db/expansion.js +2 -1
- package/lib/transform/db/transformExists.js +10 -9
- package/lib/transform/effective/annotations.js +147 -0
- package/lib/transform/effective/main.js +16 -2
- package/lib/transform/forOdata.js +53 -10
- package/lib/transform/forRelationalDB.js +7 -0
- package/lib/transform/odata/createForeignKeys.js +180 -0
- package/lib/transform/odata/flattening.js +135 -19
- package/lib/transform/odata/typesExposure.js +4 -3
- package/lib/transform/transformUtils.js +6 -6
- package/package.json +1 -1
package/lib/compiler/shared.js
CHANGED
|
@@ -481,6 +481,7 @@ function fns( model ) {
|
|
|
481
481
|
artifact[par] = args[i];
|
|
482
482
|
}
|
|
483
483
|
args = args.slice( parameters.length );
|
|
484
|
+
// TODO: we could issue syntax-unexpected-argument here
|
|
484
485
|
}
|
|
485
486
|
else if (args.length > 0 && !typeArtifact?.builtin) {
|
|
486
487
|
// One or two arguments are interpreted as either length or precision/scale.
|
|
@@ -503,13 +504,10 @@ function fns( model ) {
|
|
|
503
504
|
// Warn about left-over arguments.
|
|
504
505
|
if (args.length > 0) {
|
|
505
506
|
const loc = [ args[0].location, user ];
|
|
506
|
-
if (typeArtifact?.builtin)
|
|
507
|
+
if (typeArtifact?.builtin)
|
|
507
508
|
message( 'type-ignoring-argument', loc, { art: typeArtifact } );
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
// Ensure: parser reports error and sets $typeArgs to undefined if more than 2 parameter
|
|
511
|
-
throw new CompilerAssertion( 'More than 2 type arguments set by parser' );
|
|
512
|
-
}
|
|
509
|
+
// when the parser exits rule unsuccessfully/prematurely, $typeArgs might
|
|
510
|
+
// still have a length > 2 → no testMode dump
|
|
513
511
|
}
|
|
514
512
|
artifact.$typeArgs = undefined;
|
|
515
513
|
}
|
|
@@ -751,9 +749,10 @@ function fns( model ) {
|
|
|
751
749
|
}
|
|
752
750
|
case '$parameters': {
|
|
753
751
|
// TODO: if ref.scope='param' is handled, test that here, too ?
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
752
|
+
const id = path[1]?.id;
|
|
753
|
+
const code = id ? `$parameters.${ id }` : '$parameters';
|
|
754
|
+
const newcode = id ? `:${ id }` : ':‹param›';
|
|
755
|
+
message( 'ref-obsolete-parameters', [ head.location, user ], { code, newcode },
|
|
757
756
|
'Obsolete $(CODE) - replace by $(NEWCODE)' );
|
|
758
757
|
return art;
|
|
759
758
|
}
|
|
@@ -1632,7 +1631,7 @@ function fns( model ) {
|
|
|
1632
1631
|
|
|
1633
1632
|
for (let set = query._main.query; set.op; set = set.args[0]) {
|
|
1634
1633
|
const right = set.args[1];
|
|
1635
|
-
if (query.name.id >= (right._leadingQuery || right).name
|
|
1634
|
+
if (query.name.id >= ((right._leadingQuery || right).name?.id ?? 0))
|
|
1636
1635
|
return { txt: 'setQuery', op: set.op.val };
|
|
1637
1636
|
}
|
|
1638
1637
|
throw new CompilerAssertion( 'Did we pass the leading query as argument?' );
|
|
@@ -152,6 +152,7 @@ const {
|
|
|
152
152
|
} = require('./utils');
|
|
153
153
|
const { CompilerAssertion } = require('../base/error');
|
|
154
154
|
const { isBetaEnabled } = require('../base/model');
|
|
155
|
+
const { isSimpleCdlIdentifier } = require('../parsers/identifiers');
|
|
155
156
|
|
|
156
157
|
// Config object passed around all "rewrite" functions.
|
|
157
158
|
class AnnoRewriteConfig {
|
|
@@ -319,6 +320,16 @@ function xprRewriteFns( model ) {
|
|
|
319
320
|
}
|
|
320
321
|
}
|
|
321
322
|
|
|
323
|
+
if (expr.$tokenTexts === true) {
|
|
324
|
+
// TODO: do not do with Universal-CSN (and gensrc, but that does not matter)
|
|
325
|
+
// We rewrite the string value for backward compatibility with "old-school" tools that
|
|
326
|
+
// only understand the string representation. But we only do so for simple strings, which
|
|
327
|
+
// is the case if this path expression has $tokenTexts. It then is of the form `@a: (path)`.
|
|
328
|
+
const isSimpleStep = step => !step.where && !step.args && isSimpleCdlIdentifier( step.id );
|
|
329
|
+
if (expr.path.every(isSimpleStep))
|
|
330
|
+
expr.$tokenTexts = expr.path.map( step => step.id ).join('.');
|
|
331
|
+
}
|
|
332
|
+
|
|
322
333
|
if (model.options.testMode) {
|
|
323
334
|
// re-resolve the modified path; all paths steps must match what we rewrote
|
|
324
335
|
const ref = { ...expr, path: [ ...expr.path.map(item => ({ ...item })) ] };
|
package/lib/edm/csn2edm.js
CHANGED
|
@@ -328,6 +328,8 @@ function csn2edmAll( _csn, _options, serviceNames, messageFunctions ) {
|
|
|
328
328
|
href._jsonOnlyAttributes['Edm.String'] = 'https://cap.cloud.sap';
|
|
329
329
|
const watermark = new Edm.Annotation(v, 'Core.Links', new Edm.Collection(v, new Edm.Record(v, rel, href)));
|
|
330
330
|
// watermark._edmAttributes['Qualifier'] = 'CAP';
|
|
331
|
+
if (options.isV2())
|
|
332
|
+
watermark._xmlOnlyAttributes.xmlns = 'http://docs.oasis-open.org/odata/ns/edm';
|
|
331
333
|
return watermark;
|
|
332
334
|
}
|
|
333
335
|
|
package/lib/edm/edm.js
CHANGED
|
@@ -1239,7 +1239,8 @@ function getEdm( options, messageFunctions ) {
|
|
|
1239
1239
|
class Annotations extends AnnotationBase {
|
|
1240
1240
|
constructor(version, target) {
|
|
1241
1241
|
super(version, { Target: target });
|
|
1242
|
-
|
|
1242
|
+
if (this.v2)
|
|
1243
|
+
this._xmlOnlyAttributes.xmlns = 'http://docs.oasis-open.org/odata/ns/edm';
|
|
1243
1244
|
}
|
|
1244
1245
|
|
|
1245
1246
|
toJSONattributes(json) {
|
|
@@ -107,9 +107,19 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
107
107
|
/*
|
|
108
108
|
Enrich the CSN by de-anonymizing and exposing types that are required to make the service self contained.
|
|
109
109
|
*/
|
|
110
|
+
// add cds.Map structured type into definitions to allow types exposure to pull in this type
|
|
111
|
+
if (options.isV4() && csn.definitions['cds.Map'] == null) {
|
|
112
|
+
const cdsMap = { '@open': true, elements: Object.create(null) };
|
|
113
|
+
setProp(cdsMap, '$emtpyMapType', true);
|
|
114
|
+
csn.definitions['cds.Map'] = cdsMap;
|
|
115
|
+
}
|
|
116
|
+
|
|
110
117
|
const schemas = typesExposure(csn, whatsMyServiceRootName, requestedServiceNames,
|
|
111
118
|
fallBackSchemaName, options, csnUtils, { error });
|
|
112
119
|
|
|
120
|
+
if (options.isV4() && csn.definitions['cds.Map']?.$emptyMapType)
|
|
121
|
+
csn.definitions['cds.Map'] = undefined;
|
|
122
|
+
|
|
113
123
|
// Get an overview about all schemas (including the services)
|
|
114
124
|
const schemaNames = [ ...serviceRootNames ];
|
|
115
125
|
schemaNames.push(...Object.keys(schemas));
|
|
@@ -2159,7 +2169,10 @@ function initializeModel( csn, _options, messageFunctions, requestedServiceNames
|
|
|
2159
2169
|
|
|
2160
2170
|
|
|
2161
2171
|
function mapCdsToEdmProp( obj ) {
|
|
2162
|
-
if (
|
|
2172
|
+
if (edmUtils.convertMapToOpenStruct(obj, _options.odataVersion === 'v4')) {
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
else if (obj.type && isBuiltinType(obj.type) && !obj.target && !obj.targetAspect) {
|
|
2163
2176
|
const edmType = edmUtils.mapCdsToEdmType(obj, messageFunctions, _options.odataVersion === 'v2', obj['@Core.MediaType']);
|
|
2164
2177
|
edmUtils.assignProp(obj, '_edmType', edmType);
|
|
2165
2178
|
}
|
package/lib/edm/edmUtils.js
CHANGED
|
@@ -92,6 +92,7 @@ function isParameterizedEntity( artifact ) {
|
|
|
92
92
|
// Return true if 'artifact' is structured (i.e. has elements, like a structured type or an entity)
|
|
93
93
|
function isStructuredArtifact( artifact ) {
|
|
94
94
|
// FIXME: No derived types etc yet
|
|
95
|
+
// FIXME: Don't forget cds.Map; maybe use csnUtils.isStructured()?
|
|
95
96
|
return (artifact.items && artifact.items.elements || artifact.elements);
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -553,8 +554,10 @@ function mapCdsToEdmType( csn, messageFunctions, isV2 = false, isMediaType = fal
|
|
|
553
554
|
*/
|
|
554
555
|
}[cdsType];
|
|
555
556
|
if (!edmType) {
|
|
556
|
-
error('ref-unsupported-type', location,
|
|
557
|
-
|
|
557
|
+
error('ref-unsupported-type', location,
|
|
558
|
+
{ type: cdsType, version: (isV2 ? '2.0' : '4.0'), '#': 'odata' });
|
|
559
|
+
// return a version compatible type to avoid later compatibility failures
|
|
560
|
+
edmType = isV2 ? 'Edm.String' : 'Edm.PrimitiveType';
|
|
558
561
|
}
|
|
559
562
|
|
|
560
563
|
|
|
@@ -873,8 +876,20 @@ function createSchemaRef( serviceRoots, targetSchemaName ) {
|
|
|
873
876
|
}
|
|
874
877
|
}
|
|
875
878
|
|
|
879
|
+
// convert cds.Map without elements into empty open struct for a (type) definition
|
|
880
|
+
function convertMapToOpenStruct( node, isV4 ) {
|
|
881
|
+
const typeDef = node.items || node;
|
|
882
|
+
if (node.kind && isV4 && typeDef.type === 'cds.Map' && typeDef.elements == null) {
|
|
883
|
+
typeDef.elements = Object.create(null);
|
|
884
|
+
typeDef.type = undefined;
|
|
885
|
+
assignAnnotation(node, '@open', true);
|
|
886
|
+
return true;
|
|
887
|
+
}
|
|
888
|
+
return false;
|
|
889
|
+
}
|
|
876
890
|
|
|
877
891
|
module.exports = {
|
|
892
|
+
convertMapToOpenStruct,
|
|
878
893
|
assignAnnotation,
|
|
879
894
|
assignProp,
|
|
880
895
|
createSchemaRef,
|