@sap/cds-compiler 3.4.2 → 3.5.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 +80 -0
- package/README.md +1 -0
- package/bin/cds_update_identifiers.js +5 -5
- package/bin/cdsc.js +15 -16
- package/bin/cdshi.js +19 -6
- package/doc/CHANGELOG_ARCHIVE.md +2 -2
- package/doc/CHANGELOG_BETA.md +9 -1
- package/doc/CHANGELOG_DEPRECATED.md +2 -0
- package/lib/api/main.js +61 -59
- package/lib/api/options.js +4 -2
- package/lib/api/validate.js +2 -2
- package/lib/base/cleanSymbols.js +2 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +6 -6
- package/lib/base/location.js +11 -12
- package/lib/base/message-registry.js +177 -58
- package/lib/base/messages.js +252 -180
- package/lib/base/model.js +14 -11
- package/lib/base/node-helpers.js +9 -10
- package/lib/base/optionProcessorHelper.js +138 -129
- package/lib/checks/.eslintrc.json +2 -0
- package/lib/checks/actionsFunctions.js +5 -5
- package/lib/checks/annotationsOData.js +4 -4
- package/lib/checks/arrayOfs.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +3 -3
- package/lib/checks/defaultValues.js +3 -3
- package/lib/checks/elements.js +7 -7
- package/lib/checks/emptyOrOnlyVirtual.js +2 -2
- package/lib/checks/foreignKeys.js +1 -1
- package/lib/checks/invalidTarget.js +4 -4
- package/lib/checks/managedInType.js +1 -1
- package/lib/checks/managedWithoutKeys.js +1 -1
- package/lib/checks/nonexpandableStructured.js +5 -3
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +5 -6
- package/lib/checks/parameters.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -2
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +4 -4
- package/lib/checks/types.js +7 -7
- package/lib/checks/utils.js +4 -4
- package/lib/checks/validator.js +16 -13
- package/lib/compiler/.eslintrc.json +4 -1
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/builtins.js +14 -14
- package/lib/compiler/checks.js +123 -48
- package/lib/compiler/define.js +12 -13
- package/lib/compiler/extend.js +266 -60
- package/lib/compiler/finalize-parse-cdl.js +10 -5
- package/lib/compiler/index.js +17 -14
- package/lib/compiler/populate.js +14 -6
- package/lib/compiler/propagator.js +2 -0
- package/lib/compiler/resolve.js +2 -15
- package/lib/compiler/shared.js +27 -16
- package/lib/compiler/tweak-assocs.js +5 -6
- package/lib/compiler/utils.js +20 -0
- package/lib/edm/annotations/genericTranslation.js +604 -358
- package/lib/edm/annotations/preprocessAnnotations.js +39 -35
- package/lib/edm/csn2edm.js +275 -222
- package/lib/edm/edm.js +17 -3
- package/lib/edm/edmAnnoPreprocessor.js +6 -6
- package/lib/edm/edmInboundChecks.js +2 -2
- package/lib/edm/edmPreprocessor.js +107 -77
- package/lib/edm/edmUtils.js +44 -5
- package/lib/gen/Dictionary.json +210 -8
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +67 -63
- package/lib/gen/language.tokens +81 -81
- package/lib/gen/languageLexer.interp +4 -10
- package/lib/gen/languageLexer.js +854 -869
- package/lib/gen/languageLexer.tokens +79 -81
- package/lib/gen/languageParser.js +14309 -13832
- package/lib/inspect/inspectModelStatistics.js +2 -2
- package/lib/inspect/inspectPropagation.js +6 -6
- package/lib/inspect/inspectUtils.js +2 -2
- package/lib/json/from-csn.js +102 -55
- package/lib/json/to-csn.js +119 -198
- package/lib/language/antlrParser.js +5 -2
- package/lib/language/docCommentParser.js +6 -6
- package/lib/language/errorStrategy.js +43 -23
- package/lib/language/genericAntlrParser.js +113 -133
- package/lib/language/language.g4 +1550 -1506
- package/lib/language/multiLineStringParser.js +3 -3
- package/lib/language/textUtils.js +2 -2
- package/lib/main.js +3 -3
- package/lib/model/csnRefs.js +5 -0
- package/lib/model/csnUtils.js +130 -122
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/model/sortViews.js +4 -6
- package/lib/modelCompare/compare.js +2 -2
- package/lib/modelCompare/utils/.eslintrc.json +22 -0
- package/lib/modelCompare/utils/filter.js +100 -0
- package/lib/optionProcessor.js +5 -0
- package/lib/render/.eslintrc.json +1 -0
- package/lib/render/DuplicateChecker.js +1 -1
- package/lib/render/manageConstraints.js +12 -12
- package/lib/render/toCdl.js +311 -276
- package/lib/render/toHdbcds.js +97 -94
- package/lib/render/toRename.js +5 -5
- package/lib/render/toSql.js +127 -223
- package/lib/render/utils/common.js +141 -108
- package/lib/render/utils/delta.js +227 -0
- package/lib/render/utils/sql.js +22 -6
- package/lib/render/utils/stringEscapes.js +3 -3
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/db/applyTransformations.js +3 -3
- package/lib/transform/db/assertUnique.js +13 -12
- package/lib/transform/db/associations.js +5 -5
- package/lib/transform/db/cdsPersistence.js +10 -8
- package/lib/transform/db/constraints.js +14 -14
- package/lib/transform/db/expansion.js +20 -22
- package/lib/transform/db/flattening.js +24 -42
- package/lib/transform/db/groupByOrderBy.js +3 -3
- package/lib/transform/db/temporal.js +6 -6
- package/lib/transform/db/transformExists.js +23 -23
- package/lib/transform/db/views.js +16 -16
- package/lib/transform/draft/.eslintrc.json +1 -35
- package/lib/transform/draft/db.js +10 -10
- package/lib/transform/draft/odata.js +2 -2
- package/lib/transform/forOdataNew.js +8 -29
- package/lib/transform/forRelationalDB.js +16 -6
- package/lib/transform/localized.js +11 -10
- package/lib/transform/odata/toFinalBaseType.js +41 -27
- package/lib/transform/odata/typesExposure.js +113 -47
- package/lib/transform/parseExpr.js +209 -106
- package/lib/transform/transformUtilsNew.js +17 -10
- package/lib/transform/translateAssocsToJoins.js +24 -19
- package/lib/transform/universalCsn/coreComputed.js +10 -10
- package/lib/transform/universalCsn/universalCsnEnricher.js +26 -26
- package/lib/transform/universalCsn/utils.js +3 -3
- package/lib/utils/file.js +5 -5
- package/lib/utils/moduleResolve.js +13 -13
- package/lib/utils/objectUtils.js +6 -6
- package/lib/utils/term.js +5 -2
- package/lib/utils/timetrace.js +51 -24
- package/package.json +5 -8
- package/share/messages/check-proper-type-of.md +1 -1
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/redirected-to-complex.md +4 -4
- package/share/messages/{syntax-expecting-integer.md → syntax-expecting-unsigned-int.md} +7 -4
- package/lib/modelCompare/filter.js +0 -83
package/lib/api/main.js
CHANGED
|
@@ -12,11 +12,12 @@ const forOdataNew = lazyload('../transform/forOdataNew.js');
|
|
|
12
12
|
const toSql = lazyload('../render/toSql');
|
|
13
13
|
const toCdl = require('../render/toCdl');
|
|
14
14
|
const modelCompare = lazyload('../modelCompare/compare');
|
|
15
|
-
const diffFilter = lazyload('../modelCompare/filter');
|
|
15
|
+
const diffFilter = lazyload('../modelCompare/utils/filter');
|
|
16
16
|
const sortViews = lazyload('../model/sortViews');
|
|
17
17
|
const csnUtils = lazyload('../model/csnUtils');
|
|
18
18
|
const timetrace = lazyload('../utils/timetrace');
|
|
19
19
|
const forRelationalDB = lazyload('../transform/forRelationalDB');
|
|
20
|
+
const sqlUtils = lazyload('../render/utils/sql');
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Return the artifact name for use for the hdbresult object
|
|
@@ -26,15 +27,14 @@ const forRelationalDB = lazyload('../transform/forRelationalDB');
|
|
|
26
27
|
* @param {CSN.Model} csn SQL transformed model
|
|
27
28
|
* @returns {string} Name with . replaced as _ in some places
|
|
28
29
|
*/
|
|
29
|
-
function getFileName(artifactName, csn) {
|
|
30
|
+
function getFileName( artifactName, csn ) {
|
|
30
31
|
return csnUtils.getResultingName(csn, 'quoted', artifactName);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
const { cloneCsnNonDict } = require('../model/csnUtils');
|
|
34
34
|
const { toHdbcdsSource } = require('../render/toHdbcds');
|
|
35
35
|
const { ModelError } = require('../base/error');
|
|
36
36
|
const { forEach, forEachKey } = require('../utils/objectUtils');
|
|
37
|
-
const { checkRemovedDeprecatedFlags
|
|
37
|
+
const { checkRemovedDeprecatedFlags } = require('../base/model');
|
|
38
38
|
const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
|
|
39
39
|
|
|
40
40
|
const relevantGeneralOptions = [ /* for future generic options */ ];
|
|
@@ -50,8 +50,8 @@ const warnAboutMismatchOdata = [ 'odataVersion' ];
|
|
|
50
50
|
* @param {string[]} relevantOptionNames Option names that are defining characteristics
|
|
51
51
|
* @param {string[]} [optionalOptionNames=[]] Option names that should be attached as a fyi
|
|
52
52
|
*/
|
|
53
|
-
function attachTransformerCharacteristics(csn, transformation, options,
|
|
54
|
-
|
|
53
|
+
function attachTransformerCharacteristics( csn, transformation, options,
|
|
54
|
+
relevantOptionNames, optionalOptionNames = [] ) {
|
|
55
55
|
const relevant = {};
|
|
56
56
|
for (const name of relevantOptionNames ) {
|
|
57
57
|
if (options[name] !== undefined)
|
|
@@ -85,7 +85,7 @@ function attachTransformerCharacteristics(csn, transformation, options,
|
|
|
85
85
|
* @param {string[]} warnAboutMismatch Option names to warn about, but not error on
|
|
86
86
|
* @param {string} module Name of the module that calls this function, e.g. `for.odata`
|
|
87
87
|
*/
|
|
88
|
-
function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMismatch, module) {
|
|
88
|
+
function checkPreTransformedCsn( csn, options, relevantOptionNames, warnAboutMismatch, module ) {
|
|
89
89
|
if (!csn.meta) {
|
|
90
90
|
// Not able to check
|
|
91
91
|
return;
|
|
@@ -93,7 +93,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
93
93
|
const { error, warning, throwWithAnyError } = messages.makeMessageFunction(csn, options, module);
|
|
94
94
|
|
|
95
95
|
for (const name of relevantOptionNames ) {
|
|
96
|
-
if (options[name] !== csn.meta.options[name]) {
|
|
96
|
+
if (options[name] !== csn.meta.options?.[name]) {
|
|
97
97
|
error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
|
|
98
98
|
'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
|
|
99
99
|
}
|
|
@@ -118,7 +118,7 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
|
|
|
118
118
|
* @param {string} transformation Name of the transformation
|
|
119
119
|
* @returns {boolean} Return true if it is pre-transformed
|
|
120
120
|
*/
|
|
121
|
-
function isPreTransformed(csn, transformation) {
|
|
121
|
+
function isPreTransformed( csn, transformation ) {
|
|
122
122
|
return csn && csn.meta && csn.meta.transformation === transformation;
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -129,7 +129,7 @@ function isPreTransformed(csn, transformation) {
|
|
|
129
129
|
* @param {object} internalOptions processed options
|
|
130
130
|
* @returns {object} Return an oData-pre-processed CSN
|
|
131
131
|
*/
|
|
132
|
-
function odataInternal(csn, internalOptions) {
|
|
132
|
+
function odataInternal( csn, internalOptions ) {
|
|
133
133
|
const oDataCsn = forOdataNew.transform4odataWithCsn(csn, internalOptions);
|
|
134
134
|
attachTransformerCharacteristics(oDataCsn, 'odata', internalOptions, relevantOdataOptions, warnAboutMismatchOdata);
|
|
135
135
|
return oDataCsn;
|
|
@@ -142,7 +142,7 @@ function odataInternal(csn, internalOptions) {
|
|
|
142
142
|
* @param {ODataOptions} [options={}] Options
|
|
143
143
|
* @returns {oDataCSN} Return an oData-pre-processed CSN
|
|
144
144
|
*/
|
|
145
|
-
function odata(csn, options = {}) {
|
|
145
|
+
function odata( csn, options = {} ) {
|
|
146
146
|
const internalOptions = prepareOptions.for.odata(options);
|
|
147
147
|
return odataInternal(csn, internalOptions);
|
|
148
148
|
}
|
|
@@ -154,9 +154,9 @@ function odata(csn, options = {}) {
|
|
|
154
154
|
* @param {object} [externalOptions={}] Options
|
|
155
155
|
* @returns {object} { model: string, namespace: string }
|
|
156
156
|
*/
|
|
157
|
-
function cdl(csn, externalOptions = {}) {
|
|
157
|
+
function cdl( csn, externalOptions = {} ) {
|
|
158
158
|
const internalOptions = prepareOptions.to.cdl(externalOptions);
|
|
159
|
-
return toCdl.csnToCdl(
|
|
159
|
+
return toCdl.csnToCdl(csn, internalOptions);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
@@ -167,7 +167,7 @@ function cdl(csn, externalOptions = {}) {
|
|
|
167
167
|
* @returns {CSN.Model} CSN transformed like to.sql
|
|
168
168
|
* @private
|
|
169
169
|
*/
|
|
170
|
-
function forSql(csn, options = {}) {
|
|
170
|
+
function forSql( csn, options = {} ) {
|
|
171
171
|
const internalOptions = prepareOptions.to.sql(options);
|
|
172
172
|
internalOptions.transformation = 'sql';
|
|
173
173
|
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.sql');
|
|
@@ -182,7 +182,7 @@ function forSql(csn, options = {}) {
|
|
|
182
182
|
* @returns {CSN.Model} CSN transformed like to.hdi
|
|
183
183
|
* @private
|
|
184
184
|
*/
|
|
185
|
-
function forHdi(csn, options = {}) {
|
|
185
|
+
function forHdi( csn, options = {} ) {
|
|
186
186
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
187
187
|
internalOptions.transformation = 'sql';
|
|
188
188
|
const transformedCsn = forRelationalDB.transformForRelationalDBWithCsn(csn, internalOptions, 'to.hdi');
|
|
@@ -197,7 +197,7 @@ function forHdi(csn, options = {}) {
|
|
|
197
197
|
* @returns {CSN.Model} CSN transformed like to.hdbcds
|
|
198
198
|
* @private
|
|
199
199
|
*/
|
|
200
|
-
function forHdbcds(csn, options = {}) {
|
|
200
|
+
function forHdbcds( csn, options = {} ) {
|
|
201
201
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
202
202
|
internalOptions.transformation = 'hdbcds';
|
|
203
203
|
|
|
@@ -213,7 +213,7 @@ function forHdbcds(csn, options = {}) {
|
|
|
213
213
|
* @param {SqlOptions} [options={}] Options
|
|
214
214
|
* @returns {SQL[]} Array of SQL statements, tables first, views second
|
|
215
215
|
*/
|
|
216
|
-
function sql(csn, options = {}) {
|
|
216
|
+
function sql( csn, options = {} ) {
|
|
217
217
|
const internalOptions = prepareOptions.to.sql(options);
|
|
218
218
|
internalOptions.transformation = 'sql';
|
|
219
219
|
|
|
@@ -243,7 +243,7 @@ function sql(csn, options = {}) {
|
|
|
243
243
|
* multiple statements concatenated as a multi-line string in case the change e.g.
|
|
244
244
|
* consists of a column drop and add).
|
|
245
245
|
*/
|
|
246
|
-
function mtx(csn, deltaCsn, options = {}) {
|
|
246
|
+
function mtx( csn, deltaCsn, options = {} ) {
|
|
247
247
|
if (!baseModel.isBetaEnabled(options, 'to.mtx'))
|
|
248
248
|
throw new Error('to.mtx is only available with beta flag `to.mtx`');
|
|
249
249
|
|
|
@@ -277,7 +277,7 @@ function mtx(csn, deltaCsn, options = {}) {
|
|
|
277
277
|
* @param {HdiOptions} [options={}] Options
|
|
278
278
|
* @returns {HDIArtifacts} { <filename>:<content>, ...}
|
|
279
279
|
*/
|
|
280
|
-
function hdi(csn, options = {}) {
|
|
280
|
+
function hdi( csn, options = {} ) {
|
|
281
281
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
282
282
|
|
|
283
283
|
// we need the CSN for view sorting
|
|
@@ -333,7 +333,7 @@ function hdi(csn, options = {}) {
|
|
|
333
333
|
* @param {Function} filter Filter for keys not to remap
|
|
334
334
|
* @returns {object} New result structure
|
|
335
335
|
*/
|
|
336
|
-
function remapNames(dict, csn, filter) {
|
|
336
|
+
function remapNames( dict, csn, filter ) {
|
|
337
337
|
const result = Object.create(null);
|
|
338
338
|
|
|
339
339
|
forEach(dict, (key, value) => {
|
|
@@ -353,7 +353,7 @@ function remapNames(dict, csn, filter) {
|
|
|
353
353
|
* @param {Function} filter Filter for keys not to remap
|
|
354
354
|
* @returns {string} Remapped filename
|
|
355
355
|
*/
|
|
356
|
-
function remapName(key, csn, filter = () => true) {
|
|
356
|
+
function remapName( key, csn, filter = () => true ) {
|
|
357
357
|
if (filter(key)) {
|
|
358
358
|
const lastDot = key.lastIndexOf('.');
|
|
359
359
|
const prefix = key.slice(0, lastDot);
|
|
@@ -379,13 +379,10 @@ function remapName(key, csn, filter = () => true) {
|
|
|
379
379
|
* - drops: An array of SQL statements to drop views/tables
|
|
380
380
|
* - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
|
|
381
381
|
*/
|
|
382
|
-
function sqlMigration(csn, options, beforeImage) {
|
|
382
|
+
function sqlMigration( csn, options, beforeImage ) {
|
|
383
383
|
const internalOptions = prepareOptions.to.sql(options);
|
|
384
384
|
const { error, throwWithError } = messages.makeMessageFunction(csn, options, 'to.sql.migration');
|
|
385
385
|
|
|
386
|
-
if (!isBetaEnabled(internalOptions, 'sqlMigration'))
|
|
387
|
-
throw new Error('Function `to.sql.migration` requires beta-flag `sqlMigration`');
|
|
388
|
-
|
|
389
386
|
// Prepare after-image.
|
|
390
387
|
const afterImage = forSql(csn, options);
|
|
391
388
|
// Compare both images.
|
|
@@ -398,10 +395,12 @@ function sqlMigration(csn, options, beforeImage) {
|
|
|
398
395
|
Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
|
|
399
396
|
}
|
|
400
397
|
|
|
398
|
+
const identifierUtils = sqlUtils.getIdentifierUtils(csn, internalOptions);
|
|
399
|
+
|
|
401
400
|
const drops = {
|
|
402
401
|
creates: {},
|
|
403
402
|
final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
|
|
404
|
-
previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${
|
|
403
|
+
previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.renderArtifactName(name) };`;
|
|
405
404
|
return previous;
|
|
406
405
|
}, {}),
|
|
407
406
|
};
|
|
@@ -417,7 +416,7 @@ function sqlMigration(csn, options, beforeImage) {
|
|
|
417
416
|
(diffArtifact.query || diffArtifact.projection) &&
|
|
418
417
|
(diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
|
|
419
418
|
diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
|
|
420
|
-
drops.creates[artifactName] = `DROP VIEW ${
|
|
419
|
+
drops.creates[artifactName] = `DROP VIEW ${ identifierUtils.renderArtifactName(artifactName) };`;
|
|
421
420
|
} // TODO: What happens with a changed kind -> entity becomes a view?
|
|
422
421
|
else if (diffArtifact &&
|
|
423
422
|
diffArtifact['@cds.persistence.skip'] !== true &&
|
|
@@ -489,7 +488,7 @@ function sqlMigration(csn, options, beforeImage) {
|
|
|
489
488
|
* is known, i.e. for the very first migration step
|
|
490
489
|
* @returns {migration} The migration result
|
|
491
490
|
*/
|
|
492
|
-
function hdiMigration(csn, options, beforeImage) {
|
|
491
|
+
function hdiMigration( csn, options, beforeImage ) {
|
|
493
492
|
const internalOptions = prepareOptions.to.hdi(options);
|
|
494
493
|
|
|
495
494
|
// Prepare after-image.
|
|
@@ -520,7 +519,7 @@ function hdiMigration(csn, options, beforeImage) {
|
|
|
520
519
|
* @param {CSN.Model} afterImage CSN, used to create correct file names in result structure.
|
|
521
520
|
* @returns {object[]} Array of objects, each having: name, suffix and sql
|
|
522
521
|
*/
|
|
523
|
-
function createSqlDefinitions(hdbkinds, afterImage) {
|
|
522
|
+
function createSqlDefinitions( hdbkinds, afterImage ) {
|
|
524
523
|
const result = [];
|
|
525
524
|
forEach(hdbkinds, (kind, artifacts) => {
|
|
526
525
|
const suffix = `.${ kind }`;
|
|
@@ -540,7 +539,7 @@ function createSqlDefinitions(hdbkinds, afterImage) {
|
|
|
540
539
|
* @param {CSN.Model} beforeImage CSN used to create correct file names in result structure.
|
|
541
540
|
* @returns {object[]} Array of objects, each having: name and suffix - only .hdbtable as suffix for now
|
|
542
541
|
*/
|
|
543
|
-
function createSqlDeletions(deletions, beforeImage) {
|
|
542
|
+
function createSqlDeletions( deletions, beforeImage ) {
|
|
544
543
|
const result = [];
|
|
545
544
|
forEach(deletions, name => result.push({ name: getFileName(name, beforeImage), suffix: '.hdbtable' }));
|
|
546
545
|
return result;
|
|
@@ -552,7 +551,7 @@ function createSqlDeletions(deletions, beforeImage) {
|
|
|
552
551
|
* @param {CSN.Model} afterImage CSN used to create correct file names in result structure.
|
|
553
552
|
* @returns {object[]} Array of objects, each having: name, suffix and changeset.
|
|
554
553
|
*/
|
|
555
|
-
function createSqlMigrations(migrations, afterImage) {
|
|
554
|
+
function createSqlMigrations( migrations, afterImage ) {
|
|
556
555
|
const result = [];
|
|
557
556
|
forEach(migrations, (name, changeset) => result.push({ name: getFileName(name, afterImage), suffix: '.hdbmigrationtable', changeset }));
|
|
558
557
|
return result;
|
|
@@ -569,15 +568,13 @@ sql.migration = sqlMigration;
|
|
|
569
568
|
* @param {HdbcdsOptions} [options={}] Options
|
|
570
569
|
* @returns {HDBCDS} { <filename>:<content>, ...}
|
|
571
570
|
*/
|
|
572
|
-
function hdbcds(csn, options = {}) {
|
|
573
|
-
timetrace.timetrace.start('to.hdbcds');
|
|
571
|
+
function hdbcds( csn, options = {} ) {
|
|
574
572
|
const internalOptions = prepareOptions.to.hdbcds(options);
|
|
575
573
|
internalOptions.transformation = 'hdbcds';
|
|
576
574
|
|
|
577
575
|
const hanaCsn = forHdbcds(csn, internalOptions);
|
|
578
576
|
|
|
579
577
|
const result = flattenResultStructure(toHdbcdsSource(hanaCsn, internalOptions));
|
|
580
|
-
timetrace.timetrace.stop();
|
|
581
578
|
return result;
|
|
582
579
|
}
|
|
583
580
|
/**
|
|
@@ -587,7 +584,7 @@ function hdbcds(csn, options = {}) {
|
|
|
587
584
|
* @param {ODataOptions} [options={}] Options
|
|
588
585
|
* @returns {edm} The JSON representation of the service
|
|
589
586
|
*/
|
|
590
|
-
function edm(csn, options = {}) {
|
|
587
|
+
function edm( csn, options = {} ) {
|
|
591
588
|
// If not provided at all, set service to undefined to trigger validation
|
|
592
589
|
const internalOptions = prepareOptions.to.edm(
|
|
593
590
|
// eslint-disable-next-line comma-dangle
|
|
@@ -617,7 +614,7 @@ edm.all = edmall;
|
|
|
617
614
|
* @param {ODataOptions} [options={}] Options
|
|
618
615
|
* @returns {edms} { <service>:<JSON representation>, ...}
|
|
619
616
|
*/
|
|
620
|
-
function edmall(csn, options = {}) {
|
|
617
|
+
function edmall( csn, options = {} ) {
|
|
621
618
|
const internalOptions = prepareOptions.to.edm(options);
|
|
622
619
|
const { error } = messages.makeMessageFunction(csn, internalOptions, 'for.odata');
|
|
623
620
|
|
|
@@ -647,7 +644,7 @@ function edmall(csn, options = {}) {
|
|
|
647
644
|
* @param {ODataOptions} [options={}] Options
|
|
648
645
|
* @returns {edmx} The XML representation of the service
|
|
649
646
|
*/
|
|
650
|
-
function edmx(csn, options = {}) {
|
|
647
|
+
function edmx( csn, options = {} ) {
|
|
651
648
|
// If not provided at all, set service to undefined to trigger validation
|
|
652
649
|
const internalOptions = prepareOptions.to.edmx(
|
|
653
650
|
// eslint-disable-next-line comma-dangle
|
|
@@ -678,7 +675,7 @@ edmx.all = edmxall;
|
|
|
678
675
|
* @param {ODataOptions} [options={}] Options
|
|
679
676
|
* @returns {edmxs} { <service>:<XML representation>, ...}
|
|
680
677
|
*/
|
|
681
|
-
function edmxall(csn, options = {}) {
|
|
678
|
+
function edmxall( csn, options = {} ) {
|
|
682
679
|
const internalOptions = prepareOptions.to.edmx(options);
|
|
683
680
|
|
|
684
681
|
const result = {};
|
|
@@ -710,11 +707,11 @@ function edmxall(csn, options = {}) {
|
|
|
710
707
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
711
708
|
* @returns {object} Rendered EDMX string for the given service.
|
|
712
709
|
*/
|
|
713
|
-
function preparedCsnToEdmx(csn, service, options) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
};
|
|
710
|
+
function preparedCsnToEdmx( csn, service, options ) {
|
|
711
|
+
timetrace.timetrace.start('EDMX rendering');
|
|
712
|
+
const e = csn2edm(csn, service, options)?.toXML('all');
|
|
713
|
+
timetrace.timetrace.stop('EDMX rendering');
|
|
714
|
+
return { edmx: e };
|
|
718
715
|
}
|
|
719
716
|
|
|
720
717
|
/**
|
|
@@ -725,14 +722,13 @@ function preparedCsnToEdmx(csn, service, options) {
|
|
|
725
722
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
726
723
|
* @returns {object} Dictionary of rendered EDMX strings for each service.
|
|
727
724
|
*/
|
|
728
|
-
function preparedCsnToEdmxAll(csn, options) {
|
|
725
|
+
function preparedCsnToEdmxAll( csn, options ) {
|
|
726
|
+
timetrace.timetrace.start('EDMX all rendering');
|
|
729
727
|
const edmxResult = csn2edmAll(csn, options);
|
|
730
728
|
for (const service in edmxResult)
|
|
731
729
|
edmxResult[service] = edmxResult[service].toXML('all');
|
|
732
|
-
|
|
733
|
-
return {
|
|
734
|
-
edmx: edmxResult,
|
|
735
|
-
};
|
|
730
|
+
timetrace.timetrace.stop('EDMX all rendering');
|
|
731
|
+
return { edmx: edmxResult };
|
|
736
732
|
}
|
|
737
733
|
|
|
738
734
|
/**
|
|
@@ -744,13 +740,13 @@ function preparedCsnToEdmxAll(csn, options) {
|
|
|
744
740
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
745
741
|
* @returns {object} Rendered EDM JSON object for of the given service.
|
|
746
742
|
*/
|
|
747
|
-
function preparedCsnToEdm(csn, service, options) {
|
|
743
|
+
function preparedCsnToEdm( csn, service, options ) {
|
|
744
|
+
timetrace.timetrace.start('EDM rendering');
|
|
748
745
|
// Override OData version as edm json is always v4
|
|
749
746
|
options.odataVersion = 'v4';
|
|
750
|
-
const e = csn2edm(csn, service, options);
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
};
|
|
747
|
+
const e = csn2edm(csn, service, options)?.toJSON();
|
|
748
|
+
timetrace.timetrace.stop('EDM rendering');
|
|
749
|
+
return { edmj: e };
|
|
754
750
|
}
|
|
755
751
|
|
|
756
752
|
/**
|
|
@@ -761,13 +757,14 @@ function preparedCsnToEdm(csn, service, options) {
|
|
|
761
757
|
* @param {ODataOptions} options OData / EDMX specific options.
|
|
762
758
|
* @returns {object} Dictionary of rendered EDM JSON objects for each service.
|
|
763
759
|
*/
|
|
764
|
-
function preparedCsnToEdmAll(csn, options) {
|
|
760
|
+
function preparedCsnToEdmAll( csn, options ) {
|
|
761
|
+
timetrace.timetrace.start('EDM all rendering');
|
|
765
762
|
// Override OData version as edm json is always v4
|
|
766
763
|
options.odataVersion = 'v4';
|
|
767
764
|
const edmj = csn2edmAll(csn, options);
|
|
768
765
|
for (const service in edmj)
|
|
769
766
|
edmj[service] = edmj[service].toJSON();
|
|
770
|
-
|
|
767
|
+
timetrace.timetrace.stop('EDM all rendering');
|
|
771
768
|
return {
|
|
772
769
|
edmj,
|
|
773
770
|
};
|
|
@@ -782,7 +779,7 @@ function preparedCsnToEdmAll(csn, options) {
|
|
|
782
779
|
* @param {object} toProcess { <type>: { <name>:<content>, ...}, <type>: ...}
|
|
783
780
|
* @returns {object} { <name.type>:<content> }
|
|
784
781
|
*/
|
|
785
|
-
function flattenResultStructure(toProcess) {
|
|
782
|
+
function flattenResultStructure( toProcess ) {
|
|
786
783
|
const result = {};
|
|
787
784
|
forEach(toProcess, (fileType, artifacts) => {
|
|
788
785
|
if (fileType === 'messages')
|
|
@@ -849,9 +846,14 @@ function publishCsnProcessor( processor, _name ) {
|
|
|
849
846
|
checkRemovedDeprecatedFlags( options, messageFunctions );
|
|
850
847
|
}
|
|
851
848
|
checkOutdatedOptions( options );
|
|
852
|
-
|
|
849
|
+
|
|
850
|
+
timetrace.timetrace.start(_name);
|
|
851
|
+
const result = processor( csn, options, ...args );
|
|
852
|
+
timetrace.timetrace.stop(_name);
|
|
853
|
+
return result;
|
|
853
854
|
}
|
|
854
855
|
catch (err) {
|
|
856
|
+
timetrace.timetrace.reset('Exception in backend triggered');
|
|
855
857
|
if (err instanceof messages.CompilationError || options.noRecompile || isPreTransformed(csn, 'odata')) // we cannot recompile a pre-transformed CSN
|
|
856
858
|
throw err;
|
|
857
859
|
|
|
@@ -882,7 +884,7 @@ const oldBackendOptionNames = [ 'toSql', 'toOdata', 'toHana', 'forHana' ];
|
|
|
882
884
|
*
|
|
883
885
|
* @param {CSN.Options} options Backend options
|
|
884
886
|
*/
|
|
885
|
-
function checkOutdatedOptions(options) {
|
|
887
|
+
function checkOutdatedOptions( options ) {
|
|
886
888
|
const { error, throwWithError } = messages.makeMessageFunction(null, options, 'api');
|
|
887
889
|
|
|
888
890
|
// This error has been emitted once, we don't need to emit it again.
|
|
@@ -920,7 +922,7 @@ function checkOutdatedOptions(options) {
|
|
|
920
922
|
* @param {string} moduleName Name of the module to load - like with require
|
|
921
923
|
* @returns {object} A Proxy that handles the on-demand loading
|
|
922
924
|
*/
|
|
923
|
-
function lazyload(moduleName) {
|
|
925
|
+
function lazyload( moduleName ) {
|
|
924
926
|
let module;
|
|
925
927
|
return new Proxy(((...args) => {
|
|
926
928
|
if (!module) // eslint-disable-next-line global-require
|
package/lib/api/options.js
CHANGED
|
@@ -15,6 +15,7 @@ const publicOptionsNewAPI = [
|
|
|
15
15
|
'severities',
|
|
16
16
|
'messages',
|
|
17
17
|
'withLocations',
|
|
18
|
+
'structXpr',
|
|
18
19
|
'defaultBinaryLength',
|
|
19
20
|
'defaultStringLength',
|
|
20
21
|
'csnFlavor',
|
|
@@ -30,6 +31,7 @@ const publicOptionsNewAPI = [
|
|
|
30
31
|
'odataVersion',
|
|
31
32
|
'odataFormat',
|
|
32
33
|
'odataContainment',
|
|
34
|
+
'odataCapabilitiesPullup',
|
|
33
35
|
'odataForeignKeys',
|
|
34
36
|
'odataProxies',
|
|
35
37
|
'odataXServiceRefs',
|
|
@@ -75,8 +77,8 @@ const overallOptions = publicOptionsNewAPI.concat(privateOptions);
|
|
|
75
77
|
* @param {string} moduleName The called module, e.g. 'for.odata', 'to.hdi'. Needed to initialize the message functions
|
|
76
78
|
* @returns {TranslatedOptions} General cds options
|
|
77
79
|
*/
|
|
78
|
-
function translateOptions(input = {}, defaults = {}, hardRequire = {},
|
|
79
|
-
|
|
80
|
+
function translateOptions( input = {}, defaults = {}, hardRequire = {},
|
|
81
|
+
customValidators = {}, combinationValidators = [], moduleName = '' ) {
|
|
80
82
|
const options = Object.assign({}, defaults);
|
|
81
83
|
for (const name of overallOptions) {
|
|
82
84
|
// Ensure that arrays are not passed as a reference!
|
package/lib/api/validate.js
CHANGED
|
@@ -31,7 +31,7 @@ const booleanValidator = {
|
|
|
31
31
|
* @param {any} availableValues Available values
|
|
32
32
|
* @returns {Validator} Return a validator for a string in an expected range
|
|
33
33
|
*/
|
|
34
|
-
function generateStringValidator(availableValues) {
|
|
34
|
+
function generateStringValidator( availableValues ) {
|
|
35
35
|
return {
|
|
36
36
|
validate: val => typeof val === 'string' && availableValues.some( av => av.toLowerCase() === val.toLowerCase() ),
|
|
37
37
|
expected: (val) => {
|
|
@@ -152,7 +152,7 @@ const allCombinationValidators = {
|
|
|
152
152
|
* @returns {void}
|
|
153
153
|
* @throws {CompilationError} Throws in case of invalid option usage
|
|
154
154
|
*/
|
|
155
|
-
function validate(options, moduleName, customValidators = {}, combinationValidators = []) {
|
|
155
|
+
function validate( options, moduleName, customValidators = {}, combinationValidators = [] ) {
|
|
156
156
|
// TODO: issuing messages in this function looks very strange...
|
|
157
157
|
{
|
|
158
158
|
const messageCollector = { messages: [] };
|
package/lib/base/cleanSymbols.js
CHANGED
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* @param {object} obj
|
|
8
8
|
* @param {...any} symbols
|
|
9
9
|
*/
|
|
10
|
-
function cleanSymbols(obj, ...symbols) {
|
|
11
|
-
for (const symbol of symbols)
|
|
10
|
+
function cleanSymbols( obj, ...symbols ) {
|
|
11
|
+
for (const symbol of symbols)
|
|
12
12
|
delete obj[symbol];
|
|
13
|
-
}
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
module.exports = {
|
package/lib/base/dictionaries.js
CHANGED
|
@@ -20,7 +20,7 @@ function dictAdd( dict, name, entry, duplicateCallback ) {
|
|
|
20
20
|
}
|
|
21
21
|
found.$duplicates.push( entry );
|
|
22
22
|
if (Array.isArray( entry.$duplicates ))
|
|
23
|
-
found.$duplicates.push( ...entry.$duplicates )
|
|
23
|
+
found.$duplicates.push( ...entry.$duplicates );
|
|
24
24
|
else if (duplicateCallback && name) // do not complain with empty name ''
|
|
25
25
|
duplicateCallback( name, entry.name.location, entry );
|
|
26
26
|
entry.$duplicates = true;
|
|
@@ -48,7 +48,7 @@ function dictForEach( dict, callback ) {
|
|
|
48
48
|
// `entry.name.location`. If this is the first duplicate entry and if the
|
|
49
49
|
// `filename`s are different, call the callback again on `found.name.location`.
|
|
50
50
|
function dictAddArray( dict, name, entry, messageCallback ) {
|
|
51
|
-
|
|
51
|
+
const found = dict[name];
|
|
52
52
|
if (!found || found.builtin) { // do not replace a builtin definition
|
|
53
53
|
dict[name] = entry; // also ok if array (redefined)
|
|
54
54
|
return entry;
|
|
@@ -86,12 +86,12 @@ function pushToDict( dict, name, entry ) {
|
|
|
86
86
|
if (dict[name])
|
|
87
87
|
dict[name].push( entry );
|
|
88
88
|
else
|
|
89
|
-
dict[name] = [entry];
|
|
89
|
+
dict[name] = [ entry ];
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
module.exports = {
|
|
93
|
-
dictAdd,
|
|
93
|
+
dictAdd,
|
|
94
|
+
dictForEach,
|
|
94
95
|
dictAddArray,
|
|
95
96
|
pushToDict,
|
|
96
|
-
}
|
|
97
|
-
|
|
97
|
+
};
|
package/lib/base/error.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
class CompilerAssertion extends Error {
|
|
8
8
|
constructor(message) {
|
|
9
|
-
super(`cds-compiler assertion failed: ${message}`);
|
|
9
|
+
super(`cds-compiler assertion failed: ${ message }`);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ class CompilerAssertion extends Error {
|
|
|
16
16
|
*/
|
|
17
17
|
class ModelError extends Error {
|
|
18
18
|
constructor(message) {
|
|
19
|
-
super(`cds-compiler model error: ${message}`);
|
|
19
|
+
super(`cds-compiler model error: ${ message }`);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
package/lib/base/keywords.js
CHANGED
|
@@ -185,7 +185,7 @@ module.exports = {
|
|
|
185
185
|
'WHERE',
|
|
186
186
|
'WINDOW',
|
|
187
187
|
'WITH',
|
|
188
|
-
'WITHOUT'
|
|
188
|
+
'WITHOUT',
|
|
189
189
|
],
|
|
190
190
|
// SAP HANA keywords, used for smart quoting in to-hdi.plain
|
|
191
191
|
// See './scripts/keywords/hana/generateSqlKeywords.js'
|
|
@@ -706,7 +706,7 @@ module.exports = {
|
|
|
706
706
|
'WITH',
|
|
707
707
|
'WITHIN',
|
|
708
708
|
'XMLTABLE',
|
|
709
|
-
'YEAR'
|
|
709
|
+
'YEAR',
|
|
710
710
|
],
|
|
711
711
|
// SAP HANA CDS keywords, used for smart quoting in to-hdbcds.plain
|
|
712
712
|
hdbcds: [
|
|
@@ -841,7 +841,7 @@ module.exports = {
|
|
|
841
841
|
'WHEN',
|
|
842
842
|
'WHERE',
|
|
843
843
|
'WINDOW',
|
|
844
|
-
'WITH'
|
|
844
|
+
'WITH',
|
|
845
845
|
],
|
|
846
846
|
// H2 keywords, used for smart quoting in to-sql.plain.postgres
|
|
847
847
|
// Taken from http://www.h2database.com/html/advanced.html#keywords
|
|
@@ -945,6 +945,6 @@ module.exports = {
|
|
|
945
945
|
'WINDOW',
|
|
946
946
|
'WITH',
|
|
947
947
|
'YEAR',
|
|
948
|
-
'_ROWID_'
|
|
949
|
-
]
|
|
950
|
-
}
|
|
948
|
+
'_ROWID_',
|
|
949
|
+
],
|
|
950
|
+
};
|
package/lib/base/location.js
CHANGED
|
@@ -39,7 +39,7 @@ function combinedLocation( start, end ) {
|
|
|
39
39
|
*
|
|
40
40
|
* TODO: make this function redundant (XSN sparse locations project)
|
|
41
41
|
*/
|
|
42
|
-
function emptyLocation(filename) {
|
|
42
|
+
function emptyLocation( filename ) {
|
|
43
43
|
return {
|
|
44
44
|
file: filename,
|
|
45
45
|
line: 1,
|
|
@@ -58,7 +58,7 @@ function emptyLocation(filename) {
|
|
|
58
58
|
*
|
|
59
59
|
* TODO: make this function redundant (XSN sparse locations project)
|
|
60
60
|
*/
|
|
61
|
-
function emptyWeakLocation(filename) {
|
|
61
|
+
function emptyWeakLocation( filename ) {
|
|
62
62
|
return {
|
|
63
63
|
file: filename,
|
|
64
64
|
line: 1,
|
|
@@ -90,9 +90,9 @@ function locationString( location, normalizeFilename ) {
|
|
|
90
90
|
if (!location)
|
|
91
91
|
return '<???>';
|
|
92
92
|
const loc = location;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
const filename = (loc.file && normalizeFilename)
|
|
94
|
+
? loc.file.replace( /\\/g, '/' )
|
|
95
|
+
: loc.file;
|
|
96
96
|
if (!(loc instanceof Object))
|
|
97
97
|
return loc;
|
|
98
98
|
if (!loc.line) {
|
|
@@ -100,14 +100,13 @@ function locationString( location, normalizeFilename ) {
|
|
|
100
100
|
}
|
|
101
101
|
else if (!loc.endLine) {
|
|
102
102
|
return (loc.col)
|
|
103
|
-
? `${filename}:${loc.line}:${loc.col}`
|
|
104
|
-
: `${filename}:${loc.line}`;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
return (loc.line === loc.endLine)
|
|
108
|
-
? `${filename}:${loc.line}:${loc.col}-${loc.endCol}`
|
|
109
|
-
: `${filename}:${loc.line}.${loc.col}-${loc.endLine}.${loc.endCol}`;
|
|
103
|
+
? `${ filename }:${ loc.line }:${ loc.col }`
|
|
104
|
+
: `${ filename }:${ loc.line }`;
|
|
110
105
|
}
|
|
106
|
+
|
|
107
|
+
return (loc.line === loc.endLine)
|
|
108
|
+
? `${ filename }:${ loc.line }:${ loc.col }-${ loc.endCol }`
|
|
109
|
+
: `${ filename }:${ loc.line }.${ loc.col }-${ loc.endLine }.${ loc.endCol }`;
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
/**
|