@sap/cds-compiler 3.8.2 → 3.9.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 +53 -0
- package/bin/cdsc.js +2 -2
- package/doc/CHANGELOG_BETA.md +26 -5
- package/lib/api/.eslintrc.json +3 -2
- package/lib/api/options.js +3 -1
- package/lib/api/validate.js +1 -1
- package/lib/base/message-registry.js +27 -18
- package/lib/base/messages.js +6 -1
- package/lib/base/model.js +2 -2
- package/lib/checks/.eslintrc.json +1 -0
- package/lib/checks/actionsFunctions.js +6 -6
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/elements.js +28 -17
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/onConditions.js +11 -6
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/types.js +1 -1
- package/lib/checks/utils.js +1 -1
- package/lib/checks/validator.js +3 -2
- package/lib/compiler/assert-consistency.js +7 -2
- package/lib/compiler/base.js +8 -4
- package/lib/compiler/builtins.js +7 -0
- package/lib/compiler/checks.js +73 -6
- package/lib/compiler/define.js +10 -5
- package/lib/compiler/extend.js +910 -1711
- package/lib/compiler/finalize-parse-cdl.js +1 -1
- package/lib/compiler/generate.js +838 -0
- package/lib/compiler/index.js +2 -0
- package/lib/compiler/populate.js +2 -2
- package/lib/compiler/propagator.js +20 -8
- package/lib/compiler/resolve.js +3 -3
- package/lib/compiler/shared.js +3 -1
- package/lib/edm/annotations/genericTranslation.js +6 -6
- package/lib/edm/csn2edm.js +1 -1
- package/lib/edm/edm.js +25 -11
- package/lib/edm/edmPreprocessor.js +47 -23
- package/lib/edm/edmUtils.js +37 -9
- package/lib/gen/Dictionary.json +5 -7
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -1
- package/lib/gen/language.tokens +24 -23
- package/lib/gen/languageLexer.interp +4 -1
- package/lib/gen/languageLexer.js +792 -784
- package/lib/gen/languageLexer.tokens +12 -11
- package/lib/gen/languageParser.js +3564 -3493
- package/lib/json/from-csn.js +26 -4
- package/lib/json/to-csn.js +10 -6
- package/lib/language/antlrParser.js +11 -3
- package/lib/language/genericAntlrParser.js +2 -1
- package/lib/language/language.g4 +14 -3
- package/lib/model/csnRefs.js +10 -5
- package/lib/model/csnUtils.js +41 -76
- package/lib/modelCompare/utils/.eslintrc.json +1 -1
- package/lib/optionProcessor.js +7 -4
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/toCdl.js +244 -168
- package/lib/render/toHdbcds.js +18 -10
- package/lib/render/toSql.js +24 -2
- package/lib/transform/db/.eslintrc.json +4 -3
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/expansion.js +11 -6
- package/lib/transform/db/flattening.js +22 -15
- package/lib/transform/db/rewriteCalculatedElements.js +50 -29
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/db/views.js +1 -1
- package/lib/transform/draft/db.js +1 -1
- package/lib/transform/draft/odata.js +3 -4
- package/lib/transform/forOdataNew.js +5 -6
- package/lib/transform/forRelationalDB.js +7 -7
- package/lib/transform/odata/toFinalBaseType.js +6 -6
- package/lib/transform/odata/typesExposure.js +12 -3
- package/lib/transform/odata/utils.js +3 -0
- package/lib/transform/transformUtilsNew.js +11 -26
- package/lib/transform/translateAssocsToJoins.js +9 -9
- package/lib/transform/universalCsn/.eslintrc.json +3 -2
- package/lib/transform/universalCsn/coreComputed.js +1 -1
- package/lib/transform/universalCsn/universalCsnEnricher.js +6 -4
- package/package.json +1 -1
|
@@ -244,7 +244,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
244
244
|
}
|
|
245
245
|
});
|
|
246
246
|
|
|
247
|
-
processCalculatedElementsInEntities(csn
|
|
247
|
+
processCalculatedElementsInEntities(csn);
|
|
248
248
|
|
|
249
249
|
timetrace.start('Transform CSN')
|
|
250
250
|
|
|
@@ -272,7 +272,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
272
272
|
]);
|
|
273
273
|
|
|
274
274
|
// eliminate the doA2J in the functions 'handleManagedAssociationFKs' and 'createForeignKeyElements'
|
|
275
|
-
doA2J && flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, pathDelimiter, true, csnUtils, { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') });
|
|
275
|
+
doA2J && flattening.handleManagedAssociationsAndCreateForeignKeys(csn, options, error, warning, pathDelimiter, true, csnUtils, { skipDict: { actions: true }, allowArtifact: artifact => (artifact.kind === 'entity') });
|
|
276
276
|
|
|
277
277
|
doA2J && forEachDefinition(csn, flattenIndexes);
|
|
278
278
|
// Managed associations get an on-condition - in views and entities
|
|
@@ -613,7 +613,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
613
613
|
function doit(dict, subPath) {
|
|
614
614
|
for (const elemName in dict) {
|
|
615
615
|
const elem = dict[elemName];
|
|
616
|
-
if (
|
|
616
|
+
if (elem.on && isAssocOrComposition(elem))
|
|
617
617
|
processBacklinkAssoc(elem, elemName, artifact, artifactName, subPath.concat([ elemName, 'on' ]));
|
|
618
618
|
}
|
|
619
619
|
}
|
|
@@ -636,16 +636,16 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
636
636
|
// For HANA: Report an error on
|
|
637
637
|
// - view with parameters that has an element of type association/composition
|
|
638
638
|
// - association that points to entity with parameters
|
|
639
|
-
if (options.sqlDialect === 'hana' && member.target && isAssocOrComposition(member
|
|
639
|
+
if (options.sqlDialect === 'hana' && member.target && isAssocOrComposition(member) && !isBetaEnabled(options, 'assocsWithParams')) {
|
|
640
640
|
if (artifact.params) {
|
|
641
641
|
// HANA does not allow 'WITH ASSOCIATIONS' on something with parameters:
|
|
642
642
|
// SAP DBTech JDBC: [7]: feature not supported: parameterized sql view cannot support association: line 1 col 1 (at pos 0)
|
|
643
|
-
message('def-unexpected-paramview-assoc', path, { '#': '
|
|
643
|
+
message('def-unexpected-paramview-assoc', path, { '#': 'source' });
|
|
644
644
|
}
|
|
645
645
|
else if(artifact['@cds.persistence.udf'] || artifact['@cds.persistence.calcview']) {
|
|
646
646
|
// UDF/CVs w/o params don't support 'WITH ASSOCIATIONS'
|
|
647
647
|
const anno = artifact['@cds.persistence.udf'] ? '@cds.persistence.udf' : '@cds.persistence.calcview';
|
|
648
|
-
message('def-unexpected-calcview-assoc', path, { '#': '
|
|
648
|
+
message('def-unexpected-calcview-assoc', path, { '#': 'source', anno });
|
|
649
649
|
}
|
|
650
650
|
if (csn.definitions[member.target].params) {
|
|
651
651
|
// HANA does not allow association targets with parameters or to UDFs/CVs w/o parameters:
|
|
@@ -660,7 +660,7 @@ function transformForRelationalDBWithCsn(inputModel, options, moduleName) {
|
|
|
660
660
|
// CREATE TABLE Y ( id INTEGER NOT NULL, toUDF_id INTEGER) WITH ASSOCIATIONS (MANY TO ONE JOIN UDF AS toUDF ON (toUDF.id = toUDF_id));
|
|
661
661
|
// CREATE VIEW U AS SELECT id, toUDF.a FROM Y;
|
|
662
662
|
const anno = csn.definitions[member.target]['@cds.persistence.udf'] ? '@cds.persistence.udf' : '@cds.persistence.calcview';
|
|
663
|
-
message('def-unexpected-calcview-assoc', path, { '#': 'target
|
|
663
|
+
message('def-unexpected-calcview-assoc', path, { '#': 'target', anno });
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
666
|
}, [ 'definitions', artifactName ]);
|
|
@@ -27,7 +27,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
27
27
|
/*
|
|
28
28
|
If the definition('def' variable) is a type definition and the assigned type of this very same definition('def' variable)
|
|
29
29
|
is structured type, e.g.:
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
type Struct1 {
|
|
32
32
|
a : Integer;
|
|
33
33
|
b : Integer;
|
|
@@ -48,7 +48,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
48
48
|
"a": { "type": "cds.Integer" },
|
|
49
49
|
"b": { "type": "cds.Integer" }
|
|
50
50
|
} } ...
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
"S.Struct2" should looks just like "S.Struct1" => the "type": "S.Struct1" property has to be removed
|
|
53
53
|
*/
|
|
54
54
|
if (def.kind === 'type' && def.type && !isBuiltinType(def.type) && !def.type.ref) {
|
|
@@ -83,7 +83,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
83
83
|
// type Foo: array of { qux: Integer };
|
|
84
84
|
function expandFirstLevelOfArrayed(def) {
|
|
85
85
|
if (def.items.type && !isBuiltinType(def.items.type)) {
|
|
86
|
-
let finalBaseType = csnUtils.
|
|
86
|
+
let finalBaseType = csnUtils.getFinalTypeInfo(def.items.type);
|
|
87
87
|
if (finalBaseType?.elements) {
|
|
88
88
|
def.items.elements = cloneCsnDictionary(finalBaseType.elements, options);
|
|
89
89
|
delete def.items.type;
|
|
@@ -102,7 +102,7 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
102
102
|
if (node.kind === 'event') return;
|
|
103
103
|
|
|
104
104
|
if(node.type && !isBuiltinType(node.type)) {
|
|
105
|
-
const finalBaseType = csnUtils.
|
|
105
|
+
const finalBaseType = csnUtils.getFinalTypeInfo(node.type);
|
|
106
106
|
if(!finalBaseType) {
|
|
107
107
|
/*
|
|
108
108
|
type could not be resolved, set it to null
|
|
@@ -179,8 +179,8 @@ function expandToFinalBaseType(csn, transformers, csnUtils, services, options, i
|
|
|
179
179
|
// handle array of defined via a named type
|
|
180
180
|
// example in actions: 'action act() return Primitive; type Primitive: array of String;'
|
|
181
181
|
const currService = csnUtils.getServiceName(defName);
|
|
182
|
-
const isArrayOfBuiltin = finalBaseType.items &&
|
|
183
|
-
isBuiltinType(csnUtils.
|
|
182
|
+
const isArrayOfBuiltin = finalBaseType.items &&
|
|
183
|
+
isBuiltinType(csnUtils.getFinalTypeInfo(finalBaseType.items.type)?.type)
|
|
184
184
|
if (isArrayOfBuiltin && (!isArtifactInService(node.type, currService) || !isV4)) {
|
|
185
185
|
node.items = finalBaseType.items;
|
|
186
186
|
delete node.type;
|
|
@@ -162,7 +162,7 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
|
|
|
162
162
|
isKey = false;
|
|
163
163
|
// in case this was a named type and if the openess does not match the type definition
|
|
164
164
|
// expose the type as a new one not changing the original definition.
|
|
165
|
-
if(elements &&
|
|
165
|
+
if(elements && !!node['@open'] !== !!typeDef['@open'])
|
|
166
166
|
fullQualifiedNewTypeName += node['@open'] ? '_open' : '_closed';
|
|
167
167
|
}
|
|
168
168
|
// check if that type is already defined
|
|
@@ -381,8 +381,17 @@ function typesExposure(csn, whatsMyServiceName, requestedServiceNames, fallBackS
|
|
|
381
381
|
Object.entries(elements).forEach(([elemName, element]) => {
|
|
382
382
|
let cloned = cloneCsnNonDict(element, options);
|
|
383
383
|
// if this was an anonymous sub element of a key, mark it as not nullable
|
|
384
|
-
if(isAnonymous && isKey && !cloned.key
|
|
385
|
-
cloned.
|
|
384
|
+
if(isAnonymous && isKey && !cloned.key) {
|
|
385
|
+
if(cloned.target) {
|
|
386
|
+
if(cloned.cardinality === undefined)
|
|
387
|
+
cloned.cardinality = {};
|
|
388
|
+
cloned.cardinality.min = 1;
|
|
389
|
+
}
|
|
390
|
+
// if odata-spec-violation-key-null is checking on min>1, this can
|
|
391
|
+
// be an else if
|
|
392
|
+
if(cloned.notNull === undefined)
|
|
393
|
+
cloned.notNull = true;
|
|
394
|
+
}
|
|
386
395
|
type.elements[elemName] = cloned;
|
|
387
396
|
});
|
|
388
397
|
return type;
|
|
@@ -13,6 +13,9 @@ function defNameWithoutServiceOrContextName(name, srvOrCtx) {
|
|
|
13
13
|
* By the given name of an artifact 'artName 'and an array 'services'
|
|
14
14
|
* containing all the service names part of the model, return the service
|
|
15
15
|
* name where the given artifact resides
|
|
16
|
+
*
|
|
17
|
+
* @todo: This function does not take nested services into account => longest match
|
|
18
|
+
*
|
|
16
19
|
* @param {string} artName
|
|
17
20
|
* @param {string[]} services
|
|
18
21
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// different backends.
|
|
5
5
|
// The sibling of model/transform/TransformUtil.js which works with compacted new CSN.
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { makeMessageFunction } = require('../base/messages');
|
|
8
8
|
const { setProp } = require('../base/model');
|
|
9
9
|
|
|
10
10
|
const { copyAnnotations, applyTransformations } = require('../model/csnUtils');
|
|
@@ -25,7 +25,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
25
25
|
const csnUtils = getUtils(model);
|
|
26
26
|
const {
|
|
27
27
|
getCsnDef,
|
|
28
|
-
|
|
28
|
+
getFinalTypeInfo,
|
|
29
29
|
hasAnnotationValue,
|
|
30
30
|
inspectRef,
|
|
31
31
|
isStructured,
|
|
@@ -142,12 +142,6 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
142
142
|
// FIXME: Duplicate code
|
|
143
143
|
// Assemble foreign key element name from assoc name, '_' and foreign key name/alias
|
|
144
144
|
const foreignKeyElementName = `${assocName.replace(/\./g, pathDelimiter)}${pathDelimiter}${foreignKey.as || foreignKey.ref.join(pathDelimiter)}`;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// In case of compiler errors the foreign key might be missing
|
|
148
|
-
if (!fkArtifact && hasErrors(options.messages)) {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
145
|
return [ foreignKeyElementName, createRealFK(fkArtifact, assoc, assocName, foreignKey, path, foreignKeyElementName) ];
|
|
152
146
|
}
|
|
153
147
|
|
|
@@ -168,21 +162,11 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
168
162
|
|
|
169
163
|
|
|
170
164
|
let fkArtifact = inspectRef(path).art;
|
|
171
|
-
|
|
172
|
-
// In case of compiler errors the foreign key might be missing
|
|
173
|
-
if (!fkArtifact && hasErrors(options.messages)) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
newForeignKey(fkArtifact,foreignKeyElementName);
|
|
165
|
+
newForeignKey(fkArtifact, foreignKeyElementName);
|
|
178
166
|
|
|
179
167
|
function processAssociationOrComposition(fkArtifact,foreignKeyElementName) {
|
|
180
168
|
fkArtifact.keys.forEach(iKey => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (!iKeyArtifact && hasErrors(options.messages)) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
169
|
+
const iKeyArtifact = inspectRef(iKey.$path).art;
|
|
186
170
|
if(iKey.ref.length>1)
|
|
187
171
|
throw new CompilerAssertion(`createForeignKeyElement(${artifactName},${assocName},${iKey.$path.join('/')}) unexpected reference: `+ iKey.ref)
|
|
188
172
|
newForeignKey(iKeyArtifact,foreignKeyElementName+'_'+iKey.ref[0])
|
|
@@ -242,7 +226,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
242
226
|
// for type of 'x' -> elem.type is an object, not a string -> use directly
|
|
243
227
|
let elemType;
|
|
244
228
|
if (!elem.elements) // structures do not have final base type
|
|
245
|
-
elemType =
|
|
229
|
+
elemType = getFinalTypeInfo(elem.type);
|
|
246
230
|
|
|
247
231
|
const struct = elemType ? elemType.elements : elem.elements;
|
|
248
232
|
|
|
@@ -419,11 +403,12 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
419
403
|
typeRef = resolved.get(type)?.art
|
|
420
404
|
// The cached entry may not be resolved, yet.
|
|
421
405
|
if (typeRef.type && !isBuiltinType(typeRef.type))
|
|
422
|
-
typeRef =
|
|
406
|
+
typeRef = getFinalTypeInfo(typeRef.type);
|
|
423
407
|
} else {
|
|
424
|
-
typeRef =
|
|
408
|
+
typeRef = getFinalTypeInfo(type);
|
|
425
409
|
}
|
|
426
|
-
|
|
410
|
+
if(!typeRef)
|
|
411
|
+
return;
|
|
427
412
|
if (typeRef.elements || typeRef.items) {
|
|
428
413
|
// Copy elements/items and we're finished. No need to look up actual base type,
|
|
429
414
|
// since it must also be structured and must contain at least as many elements,
|
|
@@ -1188,9 +1173,9 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
1188
1173
|
'$(PREFIX): Sub path $(NAME) not found in $(ALIAS)');
|
|
1189
1174
|
}
|
|
1190
1175
|
else {
|
|
1191
|
-
error(null, location,
|
|
1176
|
+
error(null, location,
|
|
1192
1177
|
{
|
|
1193
|
-
prefix: prefix(lhs, op, rhs),
|
|
1178
|
+
prefix: prefix(lhs, op, rhs),
|
|
1194
1179
|
name: (x.lhs ? lhs : rhs).ref.join('.'),
|
|
1195
1180
|
alias: (x.lhs ? rhs : lhs).ref.join('.')
|
|
1196
1181
|
},
|
|
@@ -1303,8 +1303,8 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1303
1303
|
path = tail;
|
|
1304
1304
|
}
|
|
1305
1305
|
// assocStack eventually undefined => head is not Assoc
|
|
1306
|
-
// assoc prefix can be something
|
|
1307
|
-
// compiler decides if it
|
|
1306
|
+
// assoc prefix can be something structured or just the id, the core
|
|
1307
|
+
// compiler decides if it wants to add 'element' or only 'id' to the XSN
|
|
1308
1308
|
// we need to unambiguously identify the target side with the full assoc prefix.
|
|
1309
1309
|
// If the path is on the target side, strip the prefix of and treat src/tgt
|
|
1310
1310
|
// paths uniformly.
|
|
@@ -1313,19 +1313,19 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1313
1313
|
path.forEach((ps) => {
|
|
1314
1314
|
/* checks for all path steps */
|
|
1315
1315
|
if(ps.args) {
|
|
1316
|
-
error(null, pathDict.location,
|
|
1316
|
+
error(null, [pathDict.location, lead],
|
|
1317
1317
|
{ name: lead.name.absolute, id: ps.id },
|
|
1318
1318
|
'$(NAME): $(ID) must not have parameters');
|
|
1319
1319
|
pathDict.$check = false;
|
|
1320
1320
|
}
|
|
1321
1321
|
if(ps.where) {
|
|
1322
|
-
error(null, pathDict.location,
|
|
1322
|
+
error(null, [pathDict.location, lead],
|
|
1323
1323
|
{ name: lead.name.absolute, id: ps.id },
|
|
1324
1324
|
'$(NAME): $(ID) must not have a filter');
|
|
1325
1325
|
pathDict.$check = false;
|
|
1326
1326
|
}
|
|
1327
1327
|
if(ps._artifact.virtual) {
|
|
1328
|
-
error(null, pathDict.location,
|
|
1328
|
+
error(null, [pathDict.location, lead],
|
|
1329
1329
|
{ name: lead.name.absolute, id: ps.id },
|
|
1330
1330
|
'$(NAME): $(ID) must not be virtual');
|
|
1331
1331
|
pathDict.$check = false;
|
|
@@ -1338,7 +1338,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1338
1338
|
if(la1) {
|
|
1339
1339
|
if(ps._artifact.on)
|
|
1340
1340
|
{
|
|
1341
|
-
error(null, pathDict.location,
|
|
1341
|
+
error(null, [pathDict.location, lead],
|
|
1342
1342
|
{ name: lead.name.absolute, id: ps.id, alias: pathAsStr(pathDict.path) },
|
|
1343
1343
|
'$(NAME): $(ID) in path $(ALIAS)" must not be an unmanaged association');
|
|
1344
1344
|
pathDict.$check = false;
|
|
@@ -1346,7 +1346,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1346
1346
|
else if(ps._artifact.$fkPathPrefixTree)// must be managed
|
|
1347
1347
|
{
|
|
1348
1348
|
if(!ps._artifact.$fkPathPrefixTree.children[la1.id]) {
|
|
1349
|
-
error(null, pathDict.location,
|
|
1349
|
+
error(null, [pathDict.location, lead],
|
|
1350
1350
|
{ art: lead.name.absolute, id: la1.id, name: ps.id, alias: pathAsStr(pathDict.path) },
|
|
1351
1351
|
'$(ART): $(ID) is not foreign key of managed association $(NAME) in path $(ALIAS)' );
|
|
1352
1352
|
pathDict.$check = false;
|
|
@@ -1355,7 +1355,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1355
1355
|
}
|
|
1356
1356
|
else {
|
|
1357
1357
|
// it is the last path step => no association
|
|
1358
|
-
error(null, pathDict.location,
|
|
1358
|
+
error(null, [pathDict.location, lead],
|
|
1359
1359
|
{ art: lead.name.absolute, id: ps.id, alias: pathAsStr(pathDict.path) },
|
|
1360
1360
|
'$(ART): $(ID) in path $(ALIAS) must not be an association');
|
|
1361
1361
|
pathDict.$check = false;
|
|
@@ -1366,7 +1366,7 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
1366
1366
|
const lastSegment = path[path.length - 1];
|
|
1367
1367
|
const artifact = lastSegment && lastSegment._artifact && lastSegment._artifact.type && lastSegment._artifact.type._artifact && lastSegment._artifact.type._artifact;
|
|
1368
1368
|
if (artifact && artifact.elements) {
|
|
1369
|
-
error(null, pathDict.location,
|
|
1369
|
+
error(null, [pathDict.location, lead],
|
|
1370
1370
|
{ art: lead.name.absolute, id: lastSegment.id },
|
|
1371
1371
|
'$(ART): $(ID) must have scalar type');
|
|
1372
1372
|
pathDict.$check = false;
|
|
@@ -17,15 +17,16 @@
|
|
|
17
17
|
"sonarjs/cognitive-complexity": "off",
|
|
18
18
|
// Does not recognize TS types
|
|
19
19
|
"jsdoc/no-undefined-types": "off",
|
|
20
|
+
"jsdoc/tag-lines": "off",
|
|
20
21
|
// Just annoying as hell
|
|
21
22
|
"sonarjs/no-duplicate-string": "off"
|
|
22
23
|
},
|
|
23
24
|
"parserOptions": {
|
|
24
|
-
"ecmaVersion":
|
|
25
|
+
"ecmaVersion": 2022,
|
|
25
26
|
"sourceType": "script"
|
|
26
27
|
},
|
|
27
28
|
"env": {
|
|
28
|
-
"
|
|
29
|
+
"es2022": true,
|
|
29
30
|
"node": true
|
|
30
31
|
},
|
|
31
32
|
"settings": {
|
|
@@ -155,7 +155,7 @@ function setCoreComputedOnViewsAndCalculatedElements( csn, csnUtils ) {
|
|
|
155
155
|
(
|
|
156
156
|
column.xpr || column.list || column.func || column.val !== undefined || column.param ||
|
|
157
157
|
column.SELECT || column.SET ||
|
|
158
|
-
column.ref && [ '$at', '$now', '$user', '$session' ].includes(column.ref[0])
|
|
158
|
+
column.ref && [ '$at', '$valid', '$now', '$user', '$session' ].includes(column.ref[0])
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp } = require('../../base/model');
|
|
3
|
+
const { setProp, isBetaEnabled } = require('../../base/model');
|
|
4
4
|
const shuffleGen = require('../../base/shuffle');
|
|
5
5
|
const { setAnnotationIfNotDefined, makeClientCompatible } = require('./utils');
|
|
6
6
|
const {
|
|
@@ -23,6 +23,7 @@ const { setCoreComputedOnViewsAndCalculatedElements } = require('./coreComputed'
|
|
|
23
23
|
* @param {CSN.Options} options
|
|
24
24
|
*/
|
|
25
25
|
module.exports = (csn, options) => {
|
|
26
|
+
const propagateToReturns = isBetaEnabled( options, 'v4preview' );
|
|
26
27
|
const csnUtils = getUtils(csn, 'init-all');
|
|
27
28
|
const {
|
|
28
29
|
initDefinition, getOrigin, getQueryPrimarySource, artifactRef, getColumn,
|
|
@@ -174,7 +175,8 @@ module.exports = (csn, options) => {
|
|
|
174
175
|
setTargetAspectIfRequired(parent);
|
|
175
176
|
},
|
|
176
177
|
type: ( parent, prop, type, path, grandParent, parentProp ) => {
|
|
177
|
-
|
|
178
|
+
// annos are not propagated to `returns` (<=v3) and `items`
|
|
179
|
+
if (parentProp === 'returns' && !propagateToReturns)
|
|
178
180
|
return;
|
|
179
181
|
const annotationsForBuiltinType = extensions[type];
|
|
180
182
|
Object.assign( parent, annotationsForBuiltinType );
|
|
@@ -292,7 +294,7 @@ module.exports = (csn, options) => {
|
|
|
292
294
|
});
|
|
293
295
|
},
|
|
294
296
|
returns: (parent, prop, returns) => {
|
|
295
|
-
propagateMemberPropsFromOrigin(returns, { items: true, '@':
|
|
297
|
+
propagateMemberPropsFromOrigin(returns, { items: true, '@': !propagateToReturns, elements: true });
|
|
296
298
|
if (returns.target)
|
|
297
299
|
calculateForeignKeys(returns);
|
|
298
300
|
},
|
|
@@ -618,7 +620,7 @@ function copyProperties( from, to, getCustomRule, except = null, force = null )
|
|
|
618
620
|
const keys = Object.keys(from);
|
|
619
621
|
// Copy over properties from the origin element to the target.
|
|
620
622
|
for (const key of keys) {
|
|
621
|
-
if (except && !(force && force[key]) && (key.charAt(0)
|
|
623
|
+
if (except && !(force && force[key]) && (except[key] || except[key.charAt(0)]))
|
|
622
624
|
continue;
|
|
623
625
|
if (!(key in to)) {
|
|
624
626
|
const func = force && force[key] ? force[key] : getCustomRule(key);
|