@sap/cds-compiler 6.7.3 → 6.9.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 +70 -0
- package/README.md +4 -0
- package/bin/cdsc.js +5 -5
- package/bin/cdshi.js +1 -0
- package/bin/cdsse.js +1 -1
- package/lib/api/main.js +17 -9
- package/lib/api/options.js +5 -2
- package/lib/api/validate.js +1 -1
- package/lib/base/builtins.js +13 -9
- package/lib/{model → base}/csnRefs.js +8 -10
- package/lib/base/error.js +2 -0
- package/lib/base/message-registry.js +68 -4
- package/lib/base/messages.js +4 -2
- package/lib/{optionProcessor.js → base/optionProcessor.js} +5 -3
- package/lib/base/{model.js → specialOptions.js} +16 -39
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/elements.js +1 -1
- package/lib/checks/enricher.js +2 -2
- package/lib/checks/featureFlags.js +54 -24
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/onConditions.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/validator.js +10 -14
- package/lib/compiler/assert-consistency.js +11 -9
- package/lib/compiler/base.js +5 -1
- package/lib/compiler/builtins.js +1 -1
- package/lib/compiler/checks.js +3 -3
- package/lib/compiler/define.js +6 -3
- package/lib/{base → compiler}/dictionaries.js +4 -3
- package/lib/compiler/extend.js +121 -21
- package/lib/compiler/generate.js +2 -2
- package/lib/compiler/index.js +11 -3
- package/lib/compiler/kick-start.js +1 -1
- package/lib/compiler/lsp-api.js +3 -3
- package/lib/compiler/populate.js +6 -7
- package/lib/compiler/resolve.js +53 -36
- package/lib/compiler/shared.js +68 -18
- package/lib/compiler/tweak-assocs.js +2 -2
- package/lib/compiler/utils.js +28 -27
- package/lib/compiler/xpr-rewrite.js +3 -3
- package/lib/edm/EdmPrimitiveTypeDefinitions.js +4 -1
- package/lib/edm/annotations/edmJson.js +2 -4
- package/lib/edm/annotations/genericTranslation.js +51 -7
- package/lib/edm/csn2edm.js +3 -2
- package/lib/edm/edmAnnoPreprocessor.js +1 -1
- package/lib/edm/edmInboundChecks.js +2 -1
- package/lib/edm/edmPreprocessor.js +3 -3
- package/lib/edm/edmUtils.js +2 -2
- package/lib/gen/BaseParser.js +59 -108
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +2052 -1965
- package/lib/gen/Dictionary.json +67 -7
- package/lib/json/from-csn.js +14 -14
- package/lib/json/to-csn.js +77 -38
- package/lib/main.js +3 -3
- package/lib/model/csnUtils.js +2 -2
- package/lib/modelCompare/compare.js +1 -1
- package/lib/modelCompare/utils/filter.js +1 -0
- package/lib/parsers/AstBuildingParser.js +83 -33
- package/lib/parsers/index.js +1 -1
- package/lib/render/manageConstraints.js +1 -1
- package/lib/render/toCdl.js +49 -30
- package/lib/render/toHdbcds.js +2 -2
- package/lib/render/toSql.js +16 -7
- package/lib/render/utils/common.js +11 -3
- package/lib/render/utils/sql.js +14 -5
- package/lib/render/utils/standardDatabaseFunctions.js +108 -99
- package/lib/sql-identifier.js +9 -1
- package/lib/{model → tool-lib}/enrichCsn.js +3 -2
- package/lib/{model → tool-lib}/revealInternalProperties.js +2 -1
- package/lib/transform/addTenantFields.js +1 -1
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/assocsToQueries/transformExists.js +1 -1
- package/lib/transform/db/backlinks.js +2 -2
- package/lib/transform/db/expansion.js +2 -2
- package/lib/transform/db/flattening.js +3 -4
- package/lib/transform/db/killAnnotations.js +1 -0
- package/lib/transform/db/processSqlServices.js +2 -1
- package/lib/transform/db/rewriteCalculatedElements.js +2 -2
- package/lib/transform/db/temporal.js +30 -5
- package/lib/transform/db/views.js +16 -20
- package/lib/transform/draft/db.js +1 -2
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/effective/flattening.js +6 -5
- package/lib/transform/effective/main.js +24 -4
- package/lib/transform/effective/types.js +1 -1
- package/lib/transform/{odata/fioriTreeViews.js → fioriTreeViews.js} +48 -25
- package/lib/transform/forOdata.js +25 -7
- package/lib/transform/forRelationalDB.js +48 -12
- package/lib/transform/localized.js +2 -2
- package/lib/transform/odata/createForeignKeys.js +1 -1
- package/lib/transform/odata/flattening.js +2 -2
- package/lib/transform/odata/toFinalBaseType.js +3 -2
- package/lib/transform/odata/typesExposure.js +3 -2
- package/lib/transform/transformUtils.js +2 -2
- package/lib/transform/translateAssocsToJoins.js +2 -1
- package/lib/transform/tupleExpansion.js +44 -4
- package/lib/transform/universalCsn/universalCsnEnricher.js +7 -3
- package/lib/transform/universalCsn/utils.js +1 -1
- package/lib/{base → utils}/lazyload.js +9 -0
- package/lib/{base → utils}/node-helpers.js +2 -0
- package/lib/utils/objectUtils.js +29 -6
- package/lib/{base → utils}/optionProcessorHelper.js +16 -6
- package/package.json +3 -40
- /package/lib/{model → base}/cloneCsn.js +0 -0
- /package/lib/{model/api.js → base/model-api.js} +0 -0
- /package/lib/{api → base}/trace.js +0 -0
- /package/lib/{model → base}/xprAsTree.js +0 -0
- /package/lib/{inspect → tool-lib}/index.js +0 -0
- /package/lib/{inspect → tool-lib}/inspectModelStatistics.js +0 -0
- /package/lib/{inspect → tool-lib}/inspectPropagation.js +0 -0
- /package/lib/{inspect → tool-lib}/inspectUtils.js +0 -0
- /package/lib/{base → utils}/shuffle.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { isBetaEnabled } = require('../base/
|
|
3
|
+
const { isBetaEnabled } = require('../base/specialOptions');
|
|
4
4
|
const transformUtils = require('./transformUtils');
|
|
5
5
|
const {
|
|
6
6
|
forEachDefinition,
|
|
@@ -16,23 +16,24 @@ const {
|
|
|
16
16
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
17
17
|
const validate = require('../checks/validator');
|
|
18
18
|
const { timetrace } = require('../utils/timetrace');
|
|
19
|
+
const shuffleGen = require('../utils/shuffle');
|
|
19
20
|
const enrichUniversalCsn = require('./universalCsn/universalCsnEnricher');
|
|
20
21
|
|
|
21
22
|
const { isArtifactInSomeService, isLocalizedArtifactInService } = require('./odata/utils');
|
|
22
23
|
const expandToFinalBaseType = require('./odata/toFinalBaseType');
|
|
23
24
|
const flattening = require('./odata/flattening');
|
|
24
25
|
const createForeignKeyElements = require('./odata/createForeignKeys');
|
|
25
|
-
const generateFioriTreeViewAnnotationsAndFields = require('./
|
|
26
|
+
const generateFioriTreeViewAnnotationsAndFields = require('./fioriTreeViews');
|
|
26
27
|
const associations = require('./db/associations');
|
|
27
28
|
const expansion = require('./db/expansion');
|
|
28
29
|
const generateDrafts = require('./draft/odata');
|
|
29
30
|
|
|
30
31
|
const { addTenantFields } = require('./addTenantFields');
|
|
31
32
|
const { addLocalizationViews } = require('./localized');
|
|
32
|
-
const { cloneFullCsn } = require('../
|
|
33
|
-
const { csnRefs } = require('../
|
|
33
|
+
const { cloneFullCsn } = require('../base/cloneCsn');
|
|
34
|
+
const { csnRefs } = require('../base/csnRefs');
|
|
34
35
|
const replaceForeignKeyRefsInExpressionAnnotations = require('./odata/foreignKeyRefsInXprAnnos');
|
|
35
|
-
const { isAnnotationExpression,
|
|
36
|
+
const { isAnnotationExpression, primaryExprProperties } = require('../base/builtins');
|
|
36
37
|
|
|
37
38
|
// Transformation for ODATA. Expects a CSN 'inputModel', processes it for ODATA.
|
|
38
39
|
// The result should be suitable for consumption by EDMX processors (annotations and metadata)
|
|
@@ -123,6 +124,11 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
123
124
|
// @ts-ignore
|
|
124
125
|
const isExternalServiceMember = (art, name) => !!(externalServices.includes(getServiceName(name)) || (art && art['@cds.external'] && art['@cds.external'] !== 2));
|
|
125
126
|
|
|
127
|
+
if (options.testMode && csn.definitions) {
|
|
128
|
+
const { shuffleDict } = shuffleGen(options.testMode);
|
|
129
|
+
csn.definitions = shuffleDict(csn.definitions);
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
if (options.csnFlavor === 'universal' && isBetaEnabled(options, 'enableUniversalCsn'))
|
|
127
133
|
enrichUniversalCsn(csn, options);
|
|
128
134
|
|
|
@@ -295,9 +301,15 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
295
301
|
// Resolve annotation shorthands for entities, types, annotations, ...
|
|
296
302
|
renameShorthandAnnotations(def);
|
|
297
303
|
|
|
304
|
+
if ((def.kind === 'entity' || def.kind === 'aspect') &&
|
|
305
|
+
def['@readonly'] && isAnnotationExpression(def['@readonly'])) {
|
|
306
|
+
message('odata-unexpected-xpr-anno', [ 'definitions', defName, '@readonly' ],
|
|
307
|
+
{ anno: '@readonly', kind: def.kind });
|
|
308
|
+
}
|
|
309
|
+
|
|
298
310
|
// Generate annotations and fields needed for the Fiori Tree Views out of the @hierarchy annotation
|
|
299
311
|
if (def['@hierarchy'])
|
|
300
|
-
generateFioriTreeViewAnnotationsAndFields(def, defName, messageFunctions, csnUtils, transformers);
|
|
312
|
+
generateFioriTreeViewAnnotationsAndFields(def, defName, messageFunctions, csnUtils, transformers, options);
|
|
301
313
|
|
|
302
314
|
// Annotate artifacts with their DB names if requested.
|
|
303
315
|
// Skip artifacts that have no DB equivalent anyway
|
|
@@ -356,6 +368,11 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
356
368
|
if (isBetaEnabled(options, 'odataTerms'))
|
|
357
369
|
forEachGeneric(csn, 'vocabularies', renameShorthandAnnotations);
|
|
358
370
|
|
|
371
|
+
if (!options.testMode) {
|
|
372
|
+
csn.meta ??= {};
|
|
373
|
+
csn.meta.compilerCsnFlavor = 'odata';
|
|
374
|
+
}
|
|
375
|
+
|
|
359
376
|
|
|
360
377
|
cleanup();
|
|
361
378
|
// Throw exception in case of errors
|
|
@@ -424,8 +441,9 @@ function transform4odataWithCsn(inputModel, options, messageFunctions) {
|
|
|
424
441
|
}
|
|
425
442
|
|
|
426
443
|
function getXprFromAnno(anno) {
|
|
427
|
-
const xprProp =
|
|
444
|
+
const xprProp = primaryExprProperties.find(prop => anno[prop] !== undefined);
|
|
428
445
|
const constructResult = {
|
|
446
|
+
// TODO: expression property `param` not handled
|
|
429
447
|
ref: () => {
|
|
430
448
|
const result = { ref: anno.ref };
|
|
431
449
|
if (anno.cast)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { isBetaEnabled } = require('../base/specialOptions');
|
|
4
|
+
const shuffleGen = require('../utils/shuffle');
|
|
4
5
|
const {
|
|
5
6
|
forEachMemberRecursively, forAllQueries, applyTransformationsOnNonDictionary,
|
|
6
7
|
getArtifactDatabaseNameOf, getElementDatabaseNameOf, applyTransformations,
|
|
@@ -10,7 +11,7 @@ const transformUtils = require('./transformUtils');
|
|
|
10
11
|
const { translateAssocsToJoinsCSN } = require('./translateAssocsToJoins');
|
|
11
12
|
const {
|
|
12
13
|
csnRefs, pathId, traverseQuery, columnAlias,
|
|
13
|
-
} = require('../
|
|
14
|
+
} = require('../base/csnRefs');
|
|
14
15
|
const { checkCSNVersion } = require('../json/csnVersion');
|
|
15
16
|
const validate = require('../checks/validator');
|
|
16
17
|
const { rejectManagedAssociationsAndStructuresForHdbcdsNames } = require('../checks/selectItems');
|
|
@@ -18,7 +19,7 @@ const { addTenantFields } = require('../transform/addTenantFields');
|
|
|
18
19
|
const { addLocalizationViewsWithJoins, addLocalizationViews } = require('../transform/localized');
|
|
19
20
|
const { timetrace } = require('../utils/timetrace');
|
|
20
21
|
const { createReferentialConstraints, assertConstraintIdentifierUniqueness } = require('./db/constraints');
|
|
21
|
-
const { forEach } = require('../utils/objectUtils');
|
|
22
|
+
const { setProp, forEach } = require('../utils/objectUtils');
|
|
22
23
|
const handleExists = require('./db/assocsToQueries/transformExists');
|
|
23
24
|
const { rewriteCalculatedElementsInViews, processCalculatedElementsInEntities } = require('./db/rewriteCalculatedElements');
|
|
24
25
|
const replaceAssociationsInGroupByOrderBy = require('./db/groupByOrderBy');
|
|
@@ -35,9 +36,14 @@ const associations = require('./db/associations');
|
|
|
35
36
|
const backlinks = require('./db/backlinks');
|
|
36
37
|
const { getDefaultTypeLengths } = require('../render/utils/common');
|
|
37
38
|
const { featureFlags, removeFeatureFlags } = require('./featureFlags');
|
|
38
|
-
const { cloneCsnNonDict, cloneFullCsn } = require('../
|
|
39
|
+
const { cloneCsnNonDict, cloneFullCsn } = require('../base/cloneCsn');
|
|
39
40
|
const { processSqlServices, createServiceDummy } = require('./db/processSqlServices');
|
|
40
41
|
const { expandWildcard } = require('./db/expansion');
|
|
42
|
+
const removeEnums = require('../checks/enums');
|
|
43
|
+
const {
|
|
44
|
+
getQueryFeatureFlagSetter, getDefinitionFeatureFlagSetter,
|
|
45
|
+
} = require('../checks/featureFlags');
|
|
46
|
+
const generateFioriTreeViews = require('./fioriTreeViews');
|
|
41
47
|
|
|
42
48
|
// By default: Do not process non-entities/views
|
|
43
49
|
function forEachDefinition(csn, cb) {
|
|
@@ -61,6 +67,10 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
61
67
|
csn = cloneFullCsn(csn, options);
|
|
62
68
|
timetrace.stop('Clone CSN');
|
|
63
69
|
|
|
70
|
+
const { shuffleDict } = shuffleGen(options.testMode);
|
|
71
|
+
if (options.testMode && csn.definitions)
|
|
72
|
+
csn.definitions = shuffleDict(csn.definitions);
|
|
73
|
+
|
|
64
74
|
if (options.tenantDiscriminator)
|
|
65
75
|
addTenantFields(csn, options);
|
|
66
76
|
|
|
@@ -92,12 +102,21 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
92
102
|
bindCsnReference();
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
|
|
105
|
+
const setQueryFeatureFlags = getQueryFeatureFlagSetter(csn);
|
|
106
|
+
const setDefinitionFeatureFlags = getDefinitionFeatureFlagSetter(csn, options);
|
|
96
107
|
|
|
108
|
+
// csnRefs cache init, expandWildcards, ensureColumnNames, and feature flags in one loop
|
|
109
|
+
// as preparation for the following transformations and validations
|
|
97
110
|
forEachDefinition(csn, (def) => {
|
|
98
|
-
|
|
99
|
-
if (def.query || def.projection)
|
|
100
|
-
traverseQuery(def.query || def, null, null, query =>
|
|
111
|
+
csnUtils.initDefinition(def);
|
|
112
|
+
if (def.query || def.projection) {
|
|
113
|
+
traverseQuery(def.query || def, null, null, (query) => {
|
|
114
|
+
expandWildcard(query, csnUtils, options);
|
|
115
|
+
ensureColumnNames(query, csnUtils, options);
|
|
116
|
+
setQueryFeatureFlags(query);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
setDefinitionFeatureFlags(def);
|
|
101
120
|
});
|
|
102
121
|
|
|
103
122
|
const dialect = options.sqlDialect;
|
|
@@ -165,6 +184,8 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
165
184
|
$env: killProp,
|
|
166
185
|
$path: killProp,
|
|
167
186
|
$scope: killProp,
|
|
187
|
+
// Remove enums - the compiler already resolved them
|
|
188
|
+
...removeEnums,
|
|
168
189
|
});
|
|
169
190
|
|
|
170
191
|
bindCsnReferenceOnly();
|
|
@@ -197,6 +218,9 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
197
218
|
if (doA2J)
|
|
198
219
|
handleAssocToJoins();
|
|
199
220
|
|
|
221
|
+
if (options.testMode && csn.definitions)
|
|
222
|
+
csn.definitions = shuffleDict(csn.definitions);
|
|
223
|
+
|
|
200
224
|
bindCsnReference();
|
|
201
225
|
|
|
202
226
|
const redoProjections = [];
|
|
@@ -332,10 +356,12 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
332
356
|
// Projections now finally become views
|
|
333
357
|
// Replace managed association in group/order by with foreign keys
|
|
334
358
|
const transformEntityOrViewPass2 = getViewTransformer(csn, options, messageFunctions);
|
|
359
|
+
const { setAnnotation, addElement, createScalarElement } = transformUtils.getTransformers(csn, options, messageFunctions);
|
|
335
360
|
forEachDefinition(csn, [ (artifact, artifactName) => {
|
|
336
361
|
findAndMarkSqlServiceArtifacts(artifact, artifactName);
|
|
337
362
|
if (artifact.$dummyService)
|
|
338
363
|
createServiceDummy(artifact, artifactName, csn, messageFunctions);
|
|
364
|
+
generateFioriTreeViews(artifact, artifactName, messageFunctions, csnUtils, { setAnnotation, addElement, createScalarElement }, options);
|
|
339
365
|
}, transformViews ]);
|
|
340
366
|
|
|
341
367
|
if (!doA2J) {
|
|
@@ -467,6 +493,11 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
467
493
|
redoProjections.forEach(fn => fn());
|
|
468
494
|
removeFeatureFlags(csn);
|
|
469
495
|
|
|
496
|
+
if (!options.testMode) {
|
|
497
|
+
csn.meta ??= {};
|
|
498
|
+
csn.meta.compilerCsnFlavor = '$internal';
|
|
499
|
+
}
|
|
500
|
+
|
|
470
501
|
timetrace.stop('Transform CSN');
|
|
471
502
|
timetrace.stop('HANA transformation');
|
|
472
503
|
return csn;
|
|
@@ -702,12 +733,11 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
702
733
|
break;
|
|
703
734
|
}
|
|
704
735
|
case 'cds.Vector': {
|
|
705
|
-
if (options.sqlDialect
|
|
736
|
+
if (options.sqlDialect === 'plain') {
|
|
706
737
|
error('ref-unsupported-type', path, {
|
|
707
|
-
'#': '
|
|
738
|
+
'#': 'dialect',
|
|
708
739
|
type: node.type,
|
|
709
|
-
value:
|
|
710
|
-
othervalue: options.sqlDialect,
|
|
740
|
+
value: options.sqlDialect,
|
|
711
741
|
});
|
|
712
742
|
}
|
|
713
743
|
else if (options.transformation === 'hdbcds') {
|
|
@@ -715,6 +745,12 @@ function transformForRelationalDBWithCsn(csn, options, messageFunctions) {
|
|
|
715
745
|
'#': 'hdbcds', type: node.type, value: options.sqlDialect,
|
|
716
746
|
});
|
|
717
747
|
}
|
|
748
|
+
// Technical limitation of SQLite vector extension
|
|
749
|
+
else if (options.sqlDialect === 'sqlite' && node.length && node.length % 4 !== 0) {
|
|
750
|
+
error('ref-unexpected-args', path, {
|
|
751
|
+
'#': 'vector_length', elemref: path.at(-1),
|
|
752
|
+
});
|
|
753
|
+
}
|
|
718
754
|
break;
|
|
719
755
|
}
|
|
720
756
|
default:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { makeMessageFunction } = require('../base/messages');
|
|
4
|
-
const { setProp } = require('../
|
|
4
|
+
const { setProp } = require('../utils/objectUtils');
|
|
5
5
|
const { forEachKey } = require('../utils/objectUtils');
|
|
6
6
|
const {
|
|
7
7
|
applyAnnotationsFromExtensions,
|
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
cloneCsnNonDict,
|
|
16
16
|
sortCsnDefinitionsForTests,
|
|
17
17
|
sortCsn,
|
|
18
|
-
} = require('../
|
|
18
|
+
} = require('../base/cloneCsn');
|
|
19
19
|
|
|
20
20
|
const annoPersistenceSkip = '@cds.persistence.skip';
|
|
21
21
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { isBuiltinType } = require('../../base/builtins');
|
|
4
|
-
const { setProp } = require('../../
|
|
4
|
+
const { setProp } = require('../../utils/objectUtils');
|
|
5
5
|
const {
|
|
6
6
|
applyTransformations, implicitAs, copyAnnotations, isDeepEqual,
|
|
7
7
|
} = require('../../model/csnUtils');
|
|
@@ -7,13 +7,13 @@ const {
|
|
|
7
7
|
} = require('../../model/csnUtils');
|
|
8
8
|
const { isBuiltinType, isMagicVariable } = require('../../base/builtins');
|
|
9
9
|
const transformUtils = require('../transformUtils');
|
|
10
|
-
const { setProp } = require('../../
|
|
10
|
+
const { setProp } = require('../../utils/objectUtils');
|
|
11
11
|
const {
|
|
12
12
|
applyTransformationsOnDictionary,
|
|
13
13
|
applyTransformationsOnNonDictionary,
|
|
14
14
|
} = require('../db/applyTransformations.js');
|
|
15
15
|
const { handleManagedAssociationsAndCreateForeignKeys } = require('../db/flattening');
|
|
16
|
-
const { cloneCsnNonDict } = require('../../
|
|
16
|
+
const { cloneCsnNonDict } = require('../../base/cloneCsn');
|
|
17
17
|
const { forEach } = require('../../utils/objectUtils');
|
|
18
18
|
const { assignAnnotation } = require('../../edm/edmUtils');
|
|
19
19
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp
|
|
3
|
+
const { setProp } = require('../../utils/objectUtils.js');
|
|
4
|
+
const { isBetaEnabled } = require('../../base/specialOptions');
|
|
4
5
|
const {
|
|
5
6
|
transformAnnotationExpression,
|
|
6
7
|
forEachDefinition,
|
|
@@ -9,7 +10,7 @@ const {
|
|
|
9
10
|
} = require('../../model/csnUtils');
|
|
10
11
|
const { isBuiltinType } = require('../../base/builtins');
|
|
11
12
|
const { isArtifactInSomeService, isArtifactInService } = require('./utils');
|
|
12
|
-
const { cloneCsnDict, cloneCsnNonDict } = require('../../
|
|
13
|
+
const { cloneCsnDict, cloneCsnNonDict } = require('../../base/cloneCsn');
|
|
13
14
|
|
|
14
15
|
function expandToFinalBaseType(csn, transformers, csnUtils, services, options, error) {
|
|
15
16
|
const isV4 = options.odataVersion === 'v4';
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* @module typesExposure
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const { setProp
|
|
9
|
+
const { setProp } = require('../../utils/objectUtils');
|
|
10
|
+
const { isBetaEnabled } = require('../../base/specialOptions');
|
|
10
11
|
const { defNameWithoutServiceOrContextName, isArtifactInService } = require('./utils');
|
|
11
12
|
const {
|
|
12
13
|
getNamespace, copyAnnotations,
|
|
@@ -14,7 +15,7 @@ const {
|
|
|
14
15
|
} = require('../../model/csnUtils');
|
|
15
16
|
const { isBuiltinType } = require('../../base/builtins');
|
|
16
17
|
const { CompilerAssertion } = require('../../base/error');
|
|
17
|
-
const { cloneCsnNonDict } = require('../../
|
|
18
|
+
const { cloneCsnNonDict } = require('../../base/cloneCsn');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* A given CDS model is a set of n definitions D = {v_1, ..., v_n } spanning a type dependency
|
|
@@ -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 { setProp } = require('../
|
|
7
|
+
const { setProp } = require('../utils/objectUtils');
|
|
8
8
|
|
|
9
9
|
const { copyAnnotations, applyTransformations, isDeepEqual } = require('../model/csnUtils');
|
|
10
10
|
const { getUtils, implicitAs } = require('../model/csnUtils');
|
|
@@ -12,7 +12,7 @@ const { typeParameters } = require('../compiler/builtins');
|
|
|
12
12
|
const { isBuiltinType } = require('../base/builtins');
|
|
13
13
|
const { ModelError, CompilerAssertion } = require('../base/error');
|
|
14
14
|
const { forEach } = require('../utils/objectUtils');
|
|
15
|
-
const { cloneCsnNonDict, cloneCsnDict } = require('../
|
|
15
|
+
const { cloneCsnNonDict, cloneCsnDict } = require('../base/cloneCsn');
|
|
16
16
|
const { addTenantFieldToArt } = require('./addTenantFields');
|
|
17
17
|
const { tupleExpansion } = require('./tupleExpansion');
|
|
18
18
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp
|
|
3
|
+
const { setProp } = require('../utils/objectUtils');
|
|
4
|
+
const { isBetaEnabled } = require('../base/specialOptions');
|
|
4
5
|
const { makeMessageFunction } = require('../base/messages');
|
|
5
6
|
const { recompileX } = require('../compiler/index');
|
|
6
7
|
const {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp } = require('../
|
|
3
|
+
const { setProp } = require('../utils/objectUtils');
|
|
4
4
|
const { applyTransformations, isDollarSelfOrProjectionOperand, implicitAs } = require('../model/csnUtils');
|
|
5
5
|
const { isBuiltinType } = require('../base/builtins');
|
|
6
|
-
const { condAsTree } = require('../
|
|
6
|
+
const { condAsTree } = require('../base/xprAsTree');
|
|
7
7
|
const { pathToMessageString } = require('../base/messages');
|
|
8
|
-
const { pathId } = require('../
|
|
9
|
-
const { cloneCsnNonDict } = require('../
|
|
8
|
+
const { pathId } = require('../base/csnRefs');
|
|
9
|
+
const { cloneCsnNonDict } = require('../base/cloneCsn');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* All relational operators supported by tuple expansion.
|
|
@@ -98,6 +98,10 @@ function tupleExpansion(csn, csnUtils, msgFunctions) {
|
|
|
98
98
|
|
|
99
99
|
expr = expr.map((e, i) => expandStructurizedExpr(e, location.concat(i)));
|
|
100
100
|
|
|
101
|
+
// Handle `(list) in (...)` and `(list) not in (...)` - expand single-leafed structures in list
|
|
102
|
+
if (expr[0]?.list && (expr[1] === 'in' || (expr[1] === 'not' && expr[2] === 'in')))
|
|
103
|
+
return expandStructsInListIn(expr[0], expr, location) ?? expr;
|
|
104
|
+
|
|
101
105
|
if (expr.length === 3 && typeof expr[1] === 'string') // also includes `<lhs> is null`
|
|
102
106
|
return expandBinaryOp(expr[0], [ expr[1] ], expr[2], location) ?? expr;
|
|
103
107
|
|
|
@@ -111,6 +115,42 @@ function tupleExpansion(csn, csnUtils, msgFunctions) {
|
|
|
111
115
|
return expr;
|
|
112
116
|
}
|
|
113
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Expands single-leafed structured elements and managed associations with a single key
|
|
120
|
+
* in `(list) in (...)` and `(list) not in (...)` expressions.
|
|
121
|
+
* If a structured element has more than one leaf, an error is emitted later during tupleExpansion.
|
|
122
|
+
*
|
|
123
|
+
* @param {object} listNode - The `{list: [...]}` node
|
|
124
|
+
* @param {Array} expr - The full expression array
|
|
125
|
+
* @param {CSN.Path} location
|
|
126
|
+
* @returns {Array|null} The (possibly modified) expr, or null on error.
|
|
127
|
+
*/
|
|
128
|
+
function expandStructsInListIn(listNode, expr, location) {
|
|
129
|
+
const listLoc = location.concat(0, 'list');
|
|
130
|
+
const newItems = [];
|
|
131
|
+
for (let i = 0; i < listNode.list.length; i++) {
|
|
132
|
+
const item = listNode.list[i];
|
|
133
|
+
const art = item._art || (item.ref && enrichRef(item, listLoc.concat(i)));
|
|
134
|
+
if (!art || !isExpandable(art)) {
|
|
135
|
+
newItems.push(item);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Expandable - try flattening to leaves
|
|
139
|
+
const paths = flattenPath(item, false, true);
|
|
140
|
+
if (paths.length === 1) {
|
|
141
|
+
// Single leaf - replace with the expanded scalar path
|
|
142
|
+
delete paths[0].comparisonRef;
|
|
143
|
+
newItems.push(paths[0]);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Multiple leaves - rejected later by rejectAnyDirectStructureReference
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
listNode.list = newItems;
|
|
151
|
+
return expr;
|
|
152
|
+
}
|
|
153
|
+
|
|
114
154
|
/**
|
|
115
155
|
* Expands the binary operation `lhs <op> rhs`, where `op` may be one or more tokens,
|
|
116
156
|
* e.g. `is not` for `is not null`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { setProp } = require('../../
|
|
4
|
-
const shuffleGen = require('../../
|
|
3
|
+
const { setProp } = require('../../utils/objectUtils');
|
|
4
|
+
const shuffleGen = require('../../utils/shuffle');
|
|
5
5
|
const { setAnnotationIfNotDefined, makeClientCompatible } = require('./utils');
|
|
6
6
|
const {
|
|
7
7
|
forEachDefinition,
|
|
@@ -98,7 +98,11 @@ module.exports = (csn, options) => {
|
|
|
98
98
|
cardinality: notWithItemsOrElements,
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
-
if (options.testMode) {
|
|
101
|
+
if (!options.testMode) {
|
|
102
|
+
// after enrichment, CSN has flavor 'inferred' (internal name: 'client')
|
|
103
|
+
csn.meta = Object.assign( {}, csn.meta, { compilerCsnFlavor: 'inferred' } );
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
102
106
|
const { shuffleDict } = shuffleGen( options.testMode );
|
|
103
107
|
csn.definitions = shuffleDict( csn.definitions );
|
|
104
108
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// Provide some on-demand `require`
|
|
2
|
+
|
|
3
|
+
// To use:
|
|
4
|
+
// const lazyload = require('./base/lazyload')( module );
|
|
5
|
+
// const My = lazyload('../My/Module'); // replaces `require('../My/Module')`
|
|
6
|
+
//
|
|
7
|
+
// The required module must export an object. Do not def-struct, i.e.
|
|
8
|
+
// const { Foo, bar } = lazyload('../My/Module'); // DO NOT DO THIS
|
|
9
|
+
|
|
1
10
|
'use strict';
|
|
2
11
|
|
|
3
12
|
function createLazyload( callingModule ) {
|
package/lib/utils/objectUtils.js
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
// Utilities for JavaScript objects
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Like `obj.prop = value`, but not serialized.
|
|
8
|
+
* It's important to set `enumerable` explicitly to false (although 'false' is the default),
|
|
9
|
+
* as else, if the property already exists, it keeps the old setting for enumerable.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} obj
|
|
12
|
+
* @param {string} prop
|
|
13
|
+
* @param {any} value
|
|
14
|
+
*/
|
|
15
|
+
function setProp( obj, prop, value ) {
|
|
16
|
+
const descriptor = {
|
|
17
|
+
value, configurable: true, writable: true, enumerable: false,
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty( obj, prop, descriptor );
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
3
24
|
/**
|
|
4
25
|
* Copy "property" from the source object to the target object.
|
|
5
26
|
* Only if it exists in the source object (using "in" operator).
|
|
@@ -14,7 +35,8 @@ function copyPropIfExist( sourceObj, property, targetObj ) {
|
|
|
14
35
|
}
|
|
15
36
|
|
|
16
37
|
/**
|
|
17
|
-
* Loops over all
|
|
38
|
+
* Loops over all properties with their values in an object and
|
|
39
|
+
* calls the specified callback(key,obj)
|
|
18
40
|
*
|
|
19
41
|
* @param {object} obj
|
|
20
42
|
* @param {(key: string, value: object) => void} callback
|
|
@@ -27,8 +49,8 @@ function forEach( obj, callback ) {
|
|
|
27
49
|
}
|
|
28
50
|
|
|
29
51
|
/**
|
|
30
|
-
* Loops over all
|
|
31
|
-
* --> can be used as substitute for `Object.values(…).forEach(…)`
|
|
52
|
+
* Loops over all property values in an object and calls the specified callback(o[key])
|
|
53
|
+
* for each key --> can be used as substitute for `Object.values(…).forEach(…)`
|
|
32
54
|
*
|
|
33
55
|
* @param {object} o the object which values should be iterated
|
|
34
56
|
* @param {Function} callback
|
|
@@ -41,8 +63,8 @@ function forEachValue( o, callback ) {
|
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
/**
|
|
44
|
-
* Loops over all
|
|
45
|
-
* --> can be used as substitute for `Object.keys(…).forEach(…)`
|
|
66
|
+
* Loops over all properties with their values in an object and calls the specified callback(key)
|
|
67
|
+
* for each key --> can be used as substitute for `Object.keys(…).forEach(…)`
|
|
46
68
|
*
|
|
47
69
|
* @param {object} o the object which keys should be iterated
|
|
48
70
|
* @param {Function} callback
|
|
@@ -55,7 +77,7 @@ function forEachKey( o, callback ) {
|
|
|
55
77
|
}
|
|
56
78
|
|
|
57
79
|
/**
|
|
58
|
-
* Sets a property as "hidden" (a.k.a. non-enumerable).
|
|
80
|
+
* Sets a property as "hidden" (a.k.a. non-enumerable). Same as `setProp`.
|
|
59
81
|
*
|
|
60
82
|
* @param {object} obj
|
|
61
83
|
* @param {string} prop
|
|
@@ -80,6 +102,7 @@ function hasNonEnumerable( object, propertyName ) {
|
|
|
80
102
|
}
|
|
81
103
|
|
|
82
104
|
module.exports = {
|
|
105
|
+
setProp,
|
|
83
106
|
copyPropIfExist,
|
|
84
107
|
forEach,
|
|
85
108
|
forEachValue,
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Create "option processor"
|
|
2
|
+
|
|
3
|
+
// Remark: is not just used by cdsc, but also by various scripts.
|
|
4
|
+
|
|
1
5
|
'use strict';
|
|
2
6
|
|
|
3
7
|
/**
|
|
@@ -122,11 +126,14 @@ function createOptionProcessor() {
|
|
|
122
126
|
* Note that you can only call this function once. Only the last invocation sets
|
|
123
127
|
* the positional arguments.
|
|
124
128
|
*
|
|
125
|
-
* @param {string} argumentDefinition Positional arguments,
|
|
126
|
-
*
|
|
129
|
+
* @param {string} argumentDefinition Positional arguments,
|
|
130
|
+
* e.g. '<input> <output>' or '<files...>'
|
|
131
|
+
* @param {object[]} argList Array, to which the parsed arguments will be added.
|
|
132
|
+
* Default is global scope.
|
|
127
133
|
* @private
|
|
128
134
|
*/
|
|
129
|
-
function _setPositionalArguments( argumentDefinition,
|
|
135
|
+
function _setPositionalArguments( argumentDefinition,
|
|
136
|
+
argList = optionProcessor.positionalArguments ) {
|
|
130
137
|
if (argList.find(arg => arg.isDynamic))
|
|
131
138
|
throw new Error('Can\'t add positional arguments after a dynamic one');
|
|
132
139
|
|
|
@@ -397,7 +404,8 @@ function createOptionProcessor() {
|
|
|
397
404
|
|
|
398
405
|
|
|
399
406
|
// Complain about first missing positional arguments
|
|
400
|
-
const missingArg = getCurrentPositionArguments()
|
|
407
|
+
const missingArg = getCurrentPositionArguments()
|
|
408
|
+
.find(arg => arg.required && !result.args[arg.name]);
|
|
401
409
|
if (missingArg) {
|
|
402
410
|
const forCommand = result.command ? ` for '${ result.command }'` : '';
|
|
403
411
|
const errorMsg = `Missing positional argument${ forCommand }: <${ missingArg.name }${ missingArg.isDynamic ? '...' : '' }>`;
|
|
@@ -496,7 +504,8 @@ function createOptionProcessor() {
|
|
|
496
504
|
if (currentCommand) {
|
|
497
505
|
// Not found at all. We dig into the other cdsc commands in order to check if
|
|
498
506
|
// the option expects a parameter and if so to take the next argument as a value
|
|
499
|
-
const otherCmd = Object.keys(optionProcessor.commands)
|
|
507
|
+
const otherCmd = Object.keys(optionProcessor.commands)
|
|
508
|
+
.find(cmd => optionProcessor.commands[cmd].options[arg]);
|
|
500
509
|
const otherCmdOpt = otherCmd && optionProcessor.commands[otherCmd].options[arg];
|
|
501
510
|
if (otherCmdOpt && hasParamForUnknown(otherCmdOpt))
|
|
502
511
|
return 1;
|
|
@@ -567,7 +576,8 @@ function createOptionProcessor() {
|
|
|
567
576
|
* @returns {boolean}
|
|
568
577
|
*/
|
|
569
578
|
function hasParamForUnknown( opt ) {
|
|
570
|
-
return ((!opt || opt.param) &&
|
|
579
|
+
return ((!opt || opt.param) &&
|
|
580
|
+
(i + 1) < argv.length && !argv[i + 1].match('(^[.-])|[.](csn|cdl|cds|json)$'));
|
|
571
581
|
}
|
|
572
582
|
}
|
|
573
583
|
}
|