@sap/cds-compiler 2.15.8 → 3.1.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 +102 -1590
- package/bin/.eslintrc.json +2 -1
- package/bin/cdsc.js +61 -46
- package/doc/API.md +11 -0
- package/doc/CHANGELOG_ARCHIVE.md +1592 -0
- package/doc/CHANGELOG_BETA.md +26 -5
- package/doc/CHANGELOG_DEPRECATED.md +55 -1
- package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
- package/doc/Versioning.md +20 -1
- package/lib/api/.eslintrc.json +2 -2
- package/lib/api/main.js +282 -156
- package/lib/api/options.js +17 -88
- package/lib/api/validate.js +6 -10
- package/lib/base/keywords.js +280 -110
- package/lib/base/message-registry.js +85 -25
- package/lib/base/messages.js +119 -89
- package/lib/base/model.js +46 -2
- package/lib/base/optionProcessorHelper.js +53 -21
- package/lib/checks/actionsFunctions.js +15 -12
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -0
- package/lib/checks/elements.js +6 -6
- package/lib/checks/invalidTarget.js +1 -1
- package/lib/checks/nonexpandableStructured.js +1 -1
- package/lib/checks/queryNoDbArtifacts.js +2 -1
- package/lib/checks/selectItems.js +101 -15
- package/lib/checks/types.js +7 -8
- package/lib/checks/utils.js +2 -2
- package/lib/checks/validator.js +3 -3
- package/lib/compiler/assert-consistency.js +78 -21
- package/lib/compiler/base.js +6 -4
- package/lib/compiler/builtins.js +177 -10
- package/lib/compiler/checks.js +1 -1
- package/lib/compiler/define.js +28 -23
- package/lib/compiler/extend.js +75 -18
- package/lib/compiler/finalize-parse-cdl.js +25 -18
- package/lib/compiler/index.js +27 -11
- package/lib/compiler/moduleLayers.js +7 -0
- package/lib/compiler/populate.js +26 -39
- package/lib/compiler/propagator.js +12 -7
- package/lib/compiler/resolve.js +207 -236
- package/lib/compiler/shared.js +100 -93
- package/lib/compiler/tweak-assocs.js +13 -20
- package/lib/compiler/utils.js +20 -6
- package/lib/edm/annotations/preprocessAnnotations.js +12 -13
- package/lib/edm/csn2edm.js +35 -37
- package/lib/edm/edm.js +22 -13
- package/lib/edm/edmAnnoPreprocessor.js +349 -0
- package/lib/edm/edmInboundChecks.js +85 -0
- package/lib/edm/edmPreprocessor.js +338 -689
- package/lib/edm/edmUtils.js +97 -67
- package/lib/gen/Dictionary.json +29 -9
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +8 -31
- package/lib/gen/language.tokens +105 -114
- package/lib/gen/languageLexer.interp +1 -34
- package/lib/gen/languageLexer.js +892 -1007
- package/lib/gen/languageLexer.tokens +95 -106
- package/lib/gen/languageParser.js +20629 -22474
- package/lib/inspect/.eslintrc.json +4 -0
- package/lib/inspect/index.js +14 -0
- package/lib/inspect/inspectModelStatistics.js +81 -0
- package/lib/inspect/inspectPropagation.js +189 -0
- package/lib/inspect/inspectUtils.js +44 -0
- package/lib/json/from-csn.js +74 -69
- package/lib/json/to-csn.js +17 -14
- package/lib/language/antlrParser.js +2 -2
- package/lib/language/docCommentParser.js +61 -38
- package/lib/language/errorStrategy.js +52 -40
- package/lib/language/genericAntlrParser.js +424 -292
- package/lib/language/language.g4 +604 -687
- package/lib/language/multiLineStringParser.js +14 -42
- package/lib/language/textUtils.js +44 -0
- package/lib/main.d.ts +28 -42
- package/lib/main.js +104 -81
- package/lib/model/api.js +1 -1
- package/lib/model/csnRefs.js +57 -30
- package/lib/model/csnUtils.js +189 -287
- package/lib/model/revealInternalProperties.js +32 -10
- package/lib/model/sortViews.js +32 -31
- package/lib/modelCompare/compare.js +3 -0
- package/lib/optionProcessor.js +91 -57
- package/lib/render/.eslintrc.json +1 -1
- package/lib/render/DuplicateChecker.js +4 -7
- package/lib/render/manageConstraints.js +70 -2
- package/lib/render/toCdl.js +387 -367
- package/lib/render/toHdbcds.js +20 -16
- package/lib/render/toRename.js +44 -22
- package/lib/render/toSql.js +81 -59
- package/lib/render/utils/common.js +16 -3
- package/lib/render/utils/sql.js +20 -19
- package/lib/sql-identifier.js +6 -0
- package/lib/transform/db/.eslintrc.json +3 -2
- package/lib/transform/db/associations.js +43 -35
- package/lib/transform/db/cdsPersistence.js +5 -16
- package/lib/transform/db/constraints.js +1 -1
- package/lib/transform/db/expansion.js +7 -6
- package/lib/transform/db/flattening.js +16 -18
- package/lib/transform/db/transformExists.js +7 -5
- package/lib/transform/db/views.js +3 -3
- package/lib/transform/draft/.eslintrc.json +2 -2
- package/lib/transform/draft/db.js +6 -6
- package/lib/transform/draft/odata.js +6 -7
- package/lib/transform/forHanaNew.js +30 -24
- package/lib/transform/forOdataNew.js +14 -16
- package/lib/transform/localized.js +35 -25
- package/lib/transform/odata/toFinalBaseType.js +10 -10
- package/lib/transform/odata/typesExposure.js +17 -8
- package/lib/transform/odata/utils.js +1 -38
- package/lib/transform/transformUtilsNew.js +63 -77
- package/lib/transform/translateAssocsToJoins.js +2 -2
- package/lib/transform/universalCsn/.eslintrc.json +2 -2
- package/lib/transform/universalCsn/coreComputed.js +11 -6
- package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
- package/lib/utils/file.js +31 -21
- package/lib/utils/moduleResolve.js +0 -1
- package/lib/utils/timetrace.js +20 -21
- package/package.json +34 -4
- package/share/messages/syntax-expected-integer.md +9 -8
- package/doc/ApiMigration.md +0 -237
- package/doc/CommandLineMigration.md +0 -58
- package/doc/ErrorMessages.md +0 -175
- package/doc/FioriAnnotations.md +0 -94
- package/doc/ODataTransformation.md +0 -273
- package/lib/backends.js +0 -529
- package/lib/checks/unknownMagic.js +0 -41
- package/lib/fix_antlr4-8_warning.js +0 -56
package/lib/backends.js
DELETED
|
@@ -1,529 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// API functions for backends (i.e. functions that take a compiled
|
|
4
|
-
// augmented CSN and generate something from it)
|
|
5
|
-
|
|
6
|
-
const { transformForHanaWithCsn } = require('./transform/forHanaNew');
|
|
7
|
-
const { compactModel, sortCsn } = require('./json/to-csn')
|
|
8
|
-
const { toCdsSourceCsn } = require('./render/toCdl');
|
|
9
|
-
const { toSqlDdl } = require('./render/toSql');
|
|
10
|
-
const { toRenameDdl } = require('./render/toRename');
|
|
11
|
-
const { manageConstraints, listReferentialIntegrityViolations } = require('./render/manageConstraints');
|
|
12
|
-
const { transform4odataWithCsn } = require('./transform/forOdataNew');
|
|
13
|
-
const { csn2edm, csn2edmAll } = require('./edm/csn2edm');
|
|
14
|
-
const { mergeOptions } = require('./model/csnUtils');
|
|
15
|
-
const { isBetaEnabled } = require('./base/model');
|
|
16
|
-
const { optionProcessor } = require('./optionProcessor')
|
|
17
|
-
const { timetrace } = require('./utils/timetrace');
|
|
18
|
-
const { makeMessageFunction } = require('./base/messages');
|
|
19
|
-
const { forEachDefinition } = require('./model/csnUtils');
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Generate ODATA for `csn` using `options`.
|
|
23
|
-
* The twin of the toOdata function but using CSN
|
|
24
|
-
*
|
|
25
|
-
* @param {CSN.Model} csn
|
|
26
|
-
* @param {CSN.Options} [options]
|
|
27
|
-
*/
|
|
28
|
-
function toOdataWithCsn(csn, options) {
|
|
29
|
-
// In case of API usage the options are in the 'options' argument
|
|
30
|
-
// put the OData specific options under the 'options.toOdata' wrapper
|
|
31
|
-
// and leave the rest under 'options'
|
|
32
|
-
if (options && !options.toOdata) {
|
|
33
|
-
_wrapRelevantOptionsForCmd(options, 'toOdata');
|
|
34
|
-
}
|
|
35
|
-
// Provide defaults and merge options with those from csn
|
|
36
|
-
options = mergeOptions({ toOdata : getDefaultBackendOptions().toOdata }, options);
|
|
37
|
-
|
|
38
|
-
// Provide something to generate if nothing else was given (conditional default)
|
|
39
|
-
if (!options.toOdata.xml && !options.toOdata.json && !options.toOdata.csn) {
|
|
40
|
-
options.toOdata.xml = true;
|
|
41
|
-
}
|
|
42
|
-
if (!options.toOdata.separate && !options.toOdata.combined) {
|
|
43
|
-
options.toOdata.combined = true;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const { error, warning } = makeMessageFunction(csn, options, 'for.odata');
|
|
47
|
-
|
|
48
|
-
// Verify options
|
|
49
|
-
optionProcessor.verifyOptions(options, 'toOdata', true).forEach(complaint => warning(null, null, `${complaint}`));
|
|
50
|
-
|
|
51
|
-
// Prepare model for ODATA processing
|
|
52
|
-
let forOdataCSN = transform4odataWithCsn(csn, options);
|
|
53
|
-
// Assemble result object
|
|
54
|
-
let result = {
|
|
55
|
-
services: Object.create(null),
|
|
56
|
-
}
|
|
57
|
-
if (options.toOdata.csn) {
|
|
58
|
-
result.csn = forOdataCSN;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Create annotations and metadata once per service
|
|
62
|
-
if (options.toOdata.xml || options.toOdata.json) {
|
|
63
|
-
let allServices = csn2edmAll(forOdataCSN, options);
|
|
64
|
-
for(let serviceName in allServices) {
|
|
65
|
-
let l_edm = allServices[serviceName];
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
result.services[serviceName] = {};
|
|
69
|
-
if (options.toOdata.xml) {
|
|
70
|
-
if (options.toOdata.separate) {
|
|
71
|
-
result.services[serviceName].annotations = l_edm.toXML('annotations');
|
|
72
|
-
result.services[serviceName].metadata = l_edm.toXML('metadata');
|
|
73
|
-
}
|
|
74
|
-
if (options.toOdata.combined) {
|
|
75
|
-
result.services[serviceName].combined = l_edm.toXML('all');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (options.toOdata.json) {
|
|
79
|
-
// JSON output is not available for ODATA V2
|
|
80
|
-
if (options.toOdata.version === 'v2') {
|
|
81
|
-
error(null, null, `OData JSON output is not available for OData V2`);
|
|
82
|
-
}
|
|
83
|
-
// FIXME: Why only metadata_json - isn't this rather a 'combined_json' ? If so, rename it!
|
|
84
|
-
result.services[serviceName].metadata_json = l_edm.toJSON();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Generate edmx for given 'service' based on 'csn' (new-style compact, already prepared for OData)
|
|
93
|
-
// using 'options'
|
|
94
|
-
function preparedCsnToEdmx(csn, service, options) {
|
|
95
|
-
const e = csn2edm(csn, service, options)
|
|
96
|
-
return {
|
|
97
|
-
edmx: (e ? e.toXML('all') : undefined)
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Generate edmx for given 'service' based on 'csn' (new-style compact, already prepared for OData)
|
|
102
|
-
// using 'options'
|
|
103
|
-
function preparedCsnToEdmxAll(csn, options) {
|
|
104
|
-
let edmx = csn2edmAll(csn, options);
|
|
105
|
-
for(const service in edmx){
|
|
106
|
-
edmx[service] = edmx[service].toXML('all');
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
edmx,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Generate edm-json for given 'service' based on 'csn' (new-style compact, already prepared for OData)
|
|
114
|
-
// using 'options'
|
|
115
|
-
function preparedCsnToEdm(csn, service, options) {
|
|
116
|
-
// Merge options; override OData version as edm json is always v4
|
|
117
|
-
options = mergeOptions(options, { toOdata : { version : 'v4' }});
|
|
118
|
-
const e = csn2edm(csn, service, options);
|
|
119
|
-
return {
|
|
120
|
-
edmj: (e ? e.toJSON() : undefined)
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Generate edm-json for given 'service' based on 'csn' (new-style compact, already prepared for OData)
|
|
125
|
-
// using 'options'
|
|
126
|
-
function preparedCsnToEdmAll(csn, options) {
|
|
127
|
-
// Merge options; override OData version as edm json is always v4
|
|
128
|
-
options = mergeOptions(options, { toOdata : { version : 'v4' }});
|
|
129
|
-
let edmj = csn2edmAll(csn, options);
|
|
130
|
-
for(const service in edmj){
|
|
131
|
-
edmj[service] = edmj[service].toJSON();
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
edmj,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ----------- toCdl -----------
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* @param {XSN.Model | CSN.Model} model
|
|
142
|
-
* @param {CSN.Options} options
|
|
143
|
-
* @param {boolean} [silent]
|
|
144
|
-
*/
|
|
145
|
-
function handleToCdlOptions(model, options, silent=false){
|
|
146
|
-
// In case of API usage the options are in the 'options' argument
|
|
147
|
-
// put the OData specific options under the 'options.toCdl' wrapper
|
|
148
|
-
// and leave the rest under 'options'
|
|
149
|
-
if (options && !options.toCdl) {
|
|
150
|
-
_wrapRelevantOptionsForCmd(options, 'toCdl');
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Merge options with those from XSN model
|
|
154
|
-
options = mergeOptions({ toCdl : true }, model.options, options);
|
|
155
|
-
|
|
156
|
-
const { warning } = makeMessageFunction(model, options, 'to.cdl');
|
|
157
|
-
|
|
158
|
-
// Verify options
|
|
159
|
-
optionProcessor.verifyOptions(options, 'toCdl', silent).forEach(complaint => warning(null, null, `${complaint}`));
|
|
160
|
-
|
|
161
|
-
return options;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Generate CDS source text for CSN model.
|
|
166
|
-
|
|
167
|
-
* One source is created per top-level artifact.
|
|
168
|
-
* Returns an object with a `result` dictionary of top-level artifacts
|
|
169
|
-
* by their names, like this:
|
|
170
|
-
*
|
|
171
|
-
* {
|
|
172
|
-
* "foo" : "using XY; context foo {...};",
|
|
173
|
-
* "bar.wiz" : "namespace bar; entity wiz {...};"
|
|
174
|
-
* }
|
|
175
|
-
*
|
|
176
|
-
* Throws a CompilationError on errors.
|
|
177
|
-
*
|
|
178
|
-
* @param {CSN.Model} csn
|
|
179
|
-
* @param {CSN.Options} options
|
|
180
|
-
*/
|
|
181
|
-
function toCdlWithCsn(csn, options) {
|
|
182
|
-
options = handleToCdlOptions(csn, options, true);
|
|
183
|
-
const result = toCdsSourceCsn(csn, options);
|
|
184
|
-
return { result, options };
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// ----------- toSql -----------
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Generate SQL DDL statements for augmented CSN 'model'.
|
|
191
|
-
* The following options control what is actually generated (see help above):
|
|
192
|
-
* options : {
|
|
193
|
-
* toSql.names
|
|
194
|
-
* toSql.dialect
|
|
195
|
-
* toSql.user.id
|
|
196
|
-
* toSql.user.locale
|
|
197
|
-
* toSql.src
|
|
198
|
-
* toSql.csn
|
|
199
|
-
* }
|
|
200
|
-
* Options provided here are merged with (and take precedence over) options from 'model'.
|
|
201
|
-
* If neither 'toSql.src' nor 'toSql.csn' are provided, the default is to generate only SQL DDL
|
|
202
|
-
* source files.
|
|
203
|
-
* If all provided options are part of 'toSql', the 'toSql' wrapper can be omitted.
|
|
204
|
-
* The result object contains the generation results as follows (as enabled in 'options'):
|
|
205
|
-
* result : {
|
|
206
|
-
* csn : the (compact) transformed CSN model
|
|
207
|
-
* sql : a dictionary of top-level artifact names, containing for each name 'X':
|
|
208
|
-
* <X> : a string with SQL DDL statements for artifact 'X', terminated with ';'.
|
|
209
|
-
* Please note that the name of 'X' may contain characters that are not
|
|
210
|
-
* legal for filenames on all operating systems (e.g. ':', '\' or '/').
|
|
211
|
-
* }
|
|
212
|
-
* Throws a CompilationError on errors.
|
|
213
|
-
*
|
|
214
|
-
* @param {CSN.Model} model
|
|
215
|
-
* @param {CSN.Options} [options]
|
|
216
|
-
*/
|
|
217
|
-
function toSqlWithCsn(model, options) {
|
|
218
|
-
timetrace.start('toSqlWithCsn');
|
|
219
|
-
|
|
220
|
-
const transformedOptions = transformSQLOptions(model, options);
|
|
221
|
-
const mergedOptions = mergeOptions(transformedOptions.options, { forHana : transformedOptions.forHanaOptions });
|
|
222
|
-
const forSqlCsn = transformForHanaWithCsn(model, mergedOptions, 'to.sql');
|
|
223
|
-
|
|
224
|
-
// Assemble result
|
|
225
|
-
/** @type {object} */
|
|
226
|
-
let result = {};
|
|
227
|
-
if (transformedOptions.options.toSql.src) {
|
|
228
|
-
result = toSqlDdl(forSqlCsn, mergedOptions);
|
|
229
|
-
}
|
|
230
|
-
if (transformedOptions.options.toSql.csn) {
|
|
231
|
-
result.csn = options.testMode ? sortCsn(forSqlCsn, options) : forSqlCsn;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
timetrace.stop();
|
|
235
|
-
return result;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function transformSQLOptions(model, options) {
|
|
239
|
-
// when toSql is invoked via the CLI - toSql options are under model.options
|
|
240
|
-
// ensure the desired format of the user option
|
|
241
|
-
if (model.options && model.options.toSql &&(model.options.toSql.user || model.options.toSql.locale)) {
|
|
242
|
-
transformUserOption(model.options.toSql);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// In case of API usage the options are in the 'options' argument
|
|
246
|
-
// put the OData specific options under the 'options.toSql' wrapper
|
|
247
|
-
// and leave the rest under 'options'
|
|
248
|
-
if (options && !options.toSql) {
|
|
249
|
-
_wrapRelevantOptionsForCmd(options, 'toSql');
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// when the API function is used directly - toSql options are in options
|
|
253
|
-
// ensure the desired format of the user option
|
|
254
|
-
if (options && (options.toSql.user || options.toSql.locale)){
|
|
255
|
-
transformUserOption(options.toSql);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Provide defaults and merge options with those from model
|
|
259
|
-
options = mergeOptions({ toSql : getDefaultBackendOptions().toSql }, model.options, options);
|
|
260
|
-
|
|
261
|
-
// Provide something to generate if nothing else was given (conditional default)
|
|
262
|
-
if (!options.toSql.src && !options.toSql.csn) {
|
|
263
|
-
options.toSql.src = 'sql';
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const { warning, error } = makeMessageFunction(model, options, 'to.sql');
|
|
267
|
-
|
|
268
|
-
// Verify options
|
|
269
|
-
optionProcessor.verifyOptions(options, 'toSql', true).forEach(complaint => warning(null, null, `${complaint}`));
|
|
270
|
-
|
|
271
|
-
// FIXME: Currently, '--to-sql' implies transformation for HANA (transferring the options to forHana)
|
|
272
|
-
let forHanaOptions = options.toSql;
|
|
273
|
-
|
|
274
|
-
// Special case: For naming variant 'hdbcds' in combination with 'toSql', 'forHana' must leave
|
|
275
|
-
// namespaces alone (but must still flatten structs because we need the leaf element names).
|
|
276
|
-
if (options.toSql.names === 'hdbcds') {
|
|
277
|
-
forHanaOptions.keepNamespaces = true;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if(options.toSql.dialect !== 'hana') {
|
|
281
|
-
// CDXCORE-465, 'quoted' and 'hdbcds' are to be used in combination with dialect 'hana' only
|
|
282
|
-
if (options.toSql.names === 'quoted' || options.toSql.names === 'hdbcds') {
|
|
283
|
-
error(null, null, `Option "{ toSql.dialect: '${options.toSql.dialect}' }" can't be combined with "{ toSql.names: '${options.toSql.names}' }"`);
|
|
284
|
-
}
|
|
285
|
-
// No non-HANA SQL for HDI
|
|
286
|
-
if(options.toSql.src === 'hdi') {
|
|
287
|
-
error(null, null, `Option "{ toSql.dialect: '${options.toSql.dialect}' }" can't be combined with "{ toSql.src: '${options.toSql.src}' }"`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// FIXME: Should not be necessary
|
|
292
|
-
forHanaOptions.alwaysResolveDerivedTypes = true;
|
|
293
|
-
|
|
294
|
-
return {options, forHanaOptions};
|
|
295
|
-
|
|
296
|
-
// If among the options user, user.id or user.locale are specified via the CLI or
|
|
297
|
-
// via the API, then ensure that at the end there is a user option, which is an object and has(have)
|
|
298
|
-
// "id" and/or "locale" prop(s)
|
|
299
|
-
function transformUserOption(userOptions) {
|
|
300
|
-
// move the user option value under user.id if specified as a string
|
|
301
|
-
if (userOptions.user && typeof userOptions.user === 'string' || userOptions.user instanceof String) {
|
|
302
|
-
userOptions.user = { id: userOptions.user };
|
|
303
|
-
}
|
|
304
|
-
// move the locale option(if provided) under user.locale
|
|
305
|
-
if (userOptions.locale) {
|
|
306
|
-
userOptions.user = userOptions.user
|
|
307
|
-
? Object.assign(userOptions.user, { locale: userOptions.locale })
|
|
308
|
-
: { locale: userOptions.locale };
|
|
309
|
-
delete userOptions.locale;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Render the given CSN - assuming that it was correctly transformed for toSQL
|
|
316
|
-
* @param {CSN.Model} csn SQL-transformed CSN
|
|
317
|
-
* @param {object} options Options - same as for toSQLWithCSN
|
|
318
|
-
*/
|
|
319
|
-
function renderSqlWithCsn(csn, options){
|
|
320
|
-
const transformedOptions = transformSQLOptions(csn, options);
|
|
321
|
-
options = transformedOptions.options;
|
|
322
|
-
// Make the options passed to the renderer just like the original toSQLWithCSN
|
|
323
|
-
return toSqlDdl(csn, mergeOptions(options, { forHana : transformedOptions.forHanaOptions } ));
|
|
324
|
-
}
|
|
325
|
-
// ----------- toRenameWithCsn -----------
|
|
326
|
-
|
|
327
|
-
// FIXME: Not yet supported, only in beta mode
|
|
328
|
-
// Generate SQL DDL rename statements for a migration, renaming existing tables and their
|
|
329
|
-
// columns so that they match the result of "toHana" or "toSql" with the "{ names: 'plain' }
|
|
330
|
-
// option.
|
|
331
|
-
// Expects the naming convention of the existing tables to be either 'quoted' or 'hdbcds' (default).
|
|
332
|
-
// The following options control what is actually generated (see help above):
|
|
333
|
-
// options : {
|
|
334
|
-
// toRename.names
|
|
335
|
-
// }
|
|
336
|
-
// Return a dictionary of top-level artifacts by their names, like this:
|
|
337
|
-
// { "foo" : "RENAME TABLE \"foo\" ...",
|
|
338
|
-
// "bar::wiz" : "RENAME VIEW \"bar::wiz\" ..."
|
|
339
|
-
// }
|
|
340
|
-
// Options provided here are merged with (and take precedence over) options from 'model'.
|
|
341
|
-
// If all provided options are part of 'toRename', the 'toRename' wrapper can be omitted.
|
|
342
|
-
// The result object contains the generation results as follows:
|
|
343
|
-
// result : {
|
|
344
|
-
// rename : a dictionary of top-level artifact names, containing for each name 'X':
|
|
345
|
-
// <X> : a string with SQL DDL statements for artifact 'X', terminated with ';'.
|
|
346
|
-
// Please note that the name of 'X' may contain characters that are not
|
|
347
|
-
// legal for filenames on all operating systems (e.g. ':', '\' or '/').
|
|
348
|
-
// }
|
|
349
|
-
// Throws a CompilationError on errors.
|
|
350
|
-
function toRenameWithCsn(csn, options) {
|
|
351
|
-
const { error, warning } = makeMessageFunction(csn, options, 'to.rename');
|
|
352
|
-
|
|
353
|
-
// In case of API usage the options are in the 'options' argument
|
|
354
|
-
// put the OData specific options under the 'options.toRename' wrapper
|
|
355
|
-
// and leave the rest under 'options'
|
|
356
|
-
if (options && !options.toRename) {
|
|
357
|
-
_wrapRelevantOptionsForCmd(options, 'toRename');
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Provide defaults and merge options
|
|
361
|
-
options = mergeOptions({ toRename : getDefaultBackendOptions().toRename }, options);
|
|
362
|
-
|
|
363
|
-
// Backward compatibility for old naming modes
|
|
364
|
-
// FIXME: Remove after a few releases
|
|
365
|
-
if (options.toRename.names === 'flat') {
|
|
366
|
-
warning(null, null, `Option "{ toRename.names: 'flat' }" is deprecated, use "{ toRename.names: 'plain' }" instead`);
|
|
367
|
-
options.toRename.names = 'plain';
|
|
368
|
-
}
|
|
369
|
-
else if (options.toRename.names === 'deep') {
|
|
370
|
-
warning(null, null, `Option "{ toRename.names: 'deep' }" is deprecated, use "{ toRename.names: 'quoted' }" instead`);
|
|
371
|
-
options.toRename.names = 'quoted';
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Verify options
|
|
375
|
-
optionProcessor.verifyOptions(options, 'toRename').forEach(complaint => warning(null, null, `${complaint}`));
|
|
376
|
-
|
|
377
|
-
// Requires beta mode
|
|
378
|
-
if (!isBetaEnabled(options, 'toRename')) {
|
|
379
|
-
error(null, null, `Generation of SQL rename statements is not supported yet (only in beta mode)`);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Special case: For naming variant 'hdbcds' in combination with 'toRename', 'forHana' must leave
|
|
383
|
-
// namespaces alone (but must still flatten structs because we need the leaf element names).
|
|
384
|
-
if (options.toRename.names === 'hdbcds') {
|
|
385
|
-
options = mergeOptions(options, { forHana : { keepNamespaces: true } });
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// FIXME: Currently, 'toRename' implies transformation for HANA (transferring the options to forHana)
|
|
389
|
-
let forHanaCsn = transformForHanaWithCsn(csn, mergeOptions(options, { forHana : options.toRename } ), 'to.rename');
|
|
390
|
-
// forHanaCsn looses empty contexts and services, add them again so that toRename can calculate the namespaces
|
|
391
|
-
forEachDefinition(csn, (artifact, artifactName) => {
|
|
392
|
-
if((artifact.kind === 'context' || artifact.kind === 'service') && forHanaCsn.definitions[artifactName] === undefined) {
|
|
393
|
-
forHanaCsn.definitions[artifactName] = artifact;
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
// Assemble result
|
|
398
|
-
return {
|
|
399
|
-
rename : toRenameDdl(forHanaCsn, options),
|
|
400
|
-
options
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function alterConstraintsWithCsn(csn, options) {
|
|
405
|
-
const { error } = makeMessageFunction(csn, options, 'manageConstraints');
|
|
406
|
-
|
|
407
|
-
const {
|
|
408
|
-
drop, alter, names, src, violations
|
|
409
|
-
} = options.manageConstraints || {};
|
|
410
|
-
|
|
411
|
-
if(drop && alter)
|
|
412
|
-
error(null, null, 'Option “--drop” can\'t be combined with “--alter”');
|
|
413
|
-
|
|
414
|
-
options.toSql = {
|
|
415
|
-
dialect: 'hana',
|
|
416
|
-
names: names || 'plain'
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Also set new-style options
|
|
420
|
-
options.sqlDialect = 'hana';
|
|
421
|
-
options.sqlMapping = names || 'plain';
|
|
422
|
-
|
|
423
|
-
// Of course we want the database constraints
|
|
424
|
-
options.assertIntegrityType = 'DB';
|
|
425
|
-
|
|
426
|
-
const transformedOptions = transformSQLOptions(csn, options);
|
|
427
|
-
const mergedOptions = mergeOptions(transformedOptions.options, { forHana : transformedOptions.forHanaOptions });
|
|
428
|
-
const forSqlCsn = transformForHanaWithCsn(csn, mergedOptions, 'to.sql');
|
|
429
|
-
|
|
430
|
-
if (violations && src && src !== 'sql')
|
|
431
|
-
error(null, null, `Option “--violations“ can't be combined with source style “${src}“`);
|
|
432
|
-
|
|
433
|
-
let intermediateResult;
|
|
434
|
-
if (violations)
|
|
435
|
-
intermediateResult = listReferentialIntegrityViolations(forSqlCsn, mergedOptions);
|
|
436
|
-
else
|
|
437
|
-
intermediateResult = manageConstraints(forSqlCsn, mergedOptions);
|
|
438
|
-
|
|
439
|
-
return intermediateResult;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// ----------- toCsn -----------
|
|
443
|
-
// TODO: delete
|
|
444
|
-
|
|
445
|
-
// Generate compact CSN for augmented CSN 'model'
|
|
446
|
-
// The following options control what is actually generated:
|
|
447
|
-
// options : {
|
|
448
|
-
// testMode : if true, the result is extra-stable for automated tests (sorted, no 'version')
|
|
449
|
-
// toCsn.flavor : if 'gensrc', the result CSN is only suitable for use as a source, e.g. for combination with
|
|
450
|
-
// additional extend/annotate statements, but not for consumption by clients or backends
|
|
451
|
-
// (default is to produce 'client' CSN with all properties propagated and inferred as required
|
|
452
|
-
// by consumers and backends)
|
|
453
|
-
// }
|
|
454
|
-
// Options provided here are merged with (and take precedence over) options from 'model'.
|
|
455
|
-
// Throws a CompilationError on errors.
|
|
456
|
-
function toCsn(model, options) {
|
|
457
|
-
const { warning } = makeMessageFunction(model, options, 'to.csn');
|
|
458
|
-
// In case of API usage the options are in the 'options' argument
|
|
459
|
-
// put the OData specific options under the 'options.toCsn' wrapper
|
|
460
|
-
// and leave the rest under 'options'
|
|
461
|
-
if (options && !options.toCsn) {
|
|
462
|
-
_wrapRelevantOptionsForCmd(options, 'toCsn');
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Merge options with those from XSN model
|
|
466
|
-
options = mergeOptions({ toCsn : {} }, model.options, options);
|
|
467
|
-
|
|
468
|
-
// Verify options
|
|
469
|
-
optionProcessor.verifyOptions(options, 'toCsn').forEach(complaint => warning(null, null, `${complaint}`));
|
|
470
|
-
|
|
471
|
-
return compactModel(model, options);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Return a set of options containing the defaults that would be applied by the backends.
|
|
476
|
-
* Note that this only contains simple mergeable default values, not conditional defaults
|
|
477
|
-
* that depend in any way on other options (e.g. toSql provides 'src' if neither 'src' nor
|
|
478
|
-
* 'csn' is given: this is a conditional default).
|
|
479
|
-
*
|
|
480
|
-
* @returns {CSN.Options}
|
|
481
|
-
*/
|
|
482
|
-
function getDefaultBackendOptions() {
|
|
483
|
-
return {
|
|
484
|
-
toHana: {
|
|
485
|
-
names : 'plain'
|
|
486
|
-
},
|
|
487
|
-
toOdata: {
|
|
488
|
-
version : 'v4',
|
|
489
|
-
odataFormat: 'flat'
|
|
490
|
-
},
|
|
491
|
-
toRename: {
|
|
492
|
-
names: 'hdbcds'
|
|
493
|
-
},
|
|
494
|
-
toSql: {
|
|
495
|
-
names : 'plain',
|
|
496
|
-
dialect: 'plain'
|
|
497
|
-
},
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// Internal function moving command specific options under a command
|
|
502
|
-
// wrapper in the options object
|
|
503
|
-
function _wrapRelevantOptionsForCmd(options, command) {
|
|
504
|
-
// take the command's specific options
|
|
505
|
-
let cmdOptions = optionProcessor.camelOptionsForCommand(command);
|
|
506
|
-
if (!options[command])
|
|
507
|
-
options[command] = Object.create(null);
|
|
508
|
-
for (let opt in options) {
|
|
509
|
-
if (cmdOptions.includes(opt)) {
|
|
510
|
-
Object.assign(options[command], { [opt]: options[opt] });
|
|
511
|
-
delete options[opt];
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
module.exports = {
|
|
517
|
-
toOdataWithCsn,
|
|
518
|
-
preparedCsnToEdmx,
|
|
519
|
-
preparedCsnToEdmxAll,
|
|
520
|
-
preparedCsnToEdm,
|
|
521
|
-
preparedCsnToEdmAll,
|
|
522
|
-
toCdlWithCsn,
|
|
523
|
-
toSqlWithCsn,
|
|
524
|
-
renderSqlWithCsn,
|
|
525
|
-
toCsn,
|
|
526
|
-
getDefaultBackendOptions,
|
|
527
|
-
toRenameWithCsn,
|
|
528
|
-
alterConstraintsWithCsn
|
|
529
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { getVariableReplacement } = require('../model/csnUtils');
|
|
4
|
-
|
|
5
|
-
// We only care about the "wild" ones - $at is validated by the compiler
|
|
6
|
-
const magicVariables = {
|
|
7
|
-
$user: [
|
|
8
|
-
'id', // $user.id
|
|
9
|
-
'locale', // $user.locale
|
|
10
|
-
],
|
|
11
|
-
$session: [
|
|
12
|
-
// no valid ways for this
|
|
13
|
-
],
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Check that the given ref does not use magic variables for which we don't have
|
|
18
|
-
* a valid way of rendering.
|
|
19
|
-
*
|
|
20
|
-
* Valid ways:
|
|
21
|
-
* - We know what to do -> $user.id on HANA
|
|
22
|
-
* - The user tells us what to do -> options.variableReplacements
|
|
23
|
-
*
|
|
24
|
-
* @param {object} parent Object with the ref as a property
|
|
25
|
-
* @param {string} name Name of the ref property on parent
|
|
26
|
-
* @param {Array} ref to check
|
|
27
|
-
*/
|
|
28
|
-
function unknownMagicVariable(parent, name, ref) {
|
|
29
|
-
if (parent.$scope && parent.$scope === '$magic') {
|
|
30
|
-
const [ head, ...rest ] = ref;
|
|
31
|
-
const tail = rest.join('.');
|
|
32
|
-
const magicVariable = magicVariables[head];
|
|
33
|
-
if (magicVariable && magicVariable.indexOf(tail) === -1 &&
|
|
34
|
-
getVariableReplacement(ref, this.options) === null)
|
|
35
|
-
this.error('ref-missing-replacement', parent.$location, { elemref: parent }, 'Missing replacement for variable $(ELEMREF)');
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = {
|
|
40
|
-
ref: unknownMagicVariable,
|
|
41
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// ANTLR 4.8 has a circular dependency bug.
|
|
4
|
-
// NodeJS 14 warns about this on _every_ call to cds-compiler.
|
|
5
|
-
//
|
|
6
|
-
// Because we can't update to ANTLR 4.9, yet, since it requires NodeJS 14 and
|
|
7
|
-
// we need to support NodeJS 12, this script is run as a postinstall step to
|
|
8
|
-
// fix the ANTLR circular dependency bug.
|
|
9
|
-
//
|
|
10
|
-
// THIS SCRIPT MODIFIES ANOTHER NODEJS MODULE!
|
|
11
|
-
//
|
|
12
|
-
// We look for `require()` calls to `INVALID_ALT_NUMBER` and replace it
|
|
13
|
-
// with its underlying value.
|
|
14
|
-
|
|
15
|
-
const path = require('path');
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
|
|
18
|
-
const antlrIndexFile = require.resolve('antlr4');
|
|
19
|
-
|
|
20
|
-
if (!antlrIndexFile) {
|
|
21
|
-
errorAndExit('Could not find antlr4 dependency');
|
|
22
|
-
}
|
|
23
|
-
if (!fs.existsSync(antlrIndexFile)) {
|
|
24
|
-
errorAndExit('Could not find antlr4\'s index.js');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const antlr_path = path.dirname(antlrIndexFile);
|
|
28
|
-
const files = [
|
|
29
|
-
path.join(antlr_path, 'RuleContext.js'),
|
|
30
|
-
path.join(antlr_path, 'tree/Trees.js'),
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const search = /var INVALID_ALT_NUMBER = require\('[^']+'\)\.INVALID_ALT_NUMBER;/;
|
|
34
|
-
const replacement = 'var INVALID_ALT_NUMBER = 0;'
|
|
35
|
-
|
|
36
|
-
for (const file of files) {
|
|
37
|
-
try {
|
|
38
|
-
let contents = fs.readFileSync(file, 'utf-8');
|
|
39
|
-
contents = contents.replace(search, replacement);
|
|
40
|
-
fs.writeFileSync(file, contents);
|
|
41
|
-
|
|
42
|
-
} catch(e) {
|
|
43
|
-
errorAndExit('Could NOT fix Antlr\'s circular dependency');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
success('Successfully fixed Antlr\'s circular dependency');
|
|
48
|
-
|
|
49
|
-
function errorAndExit(err) {
|
|
50
|
-
console.error(`postinstall cds-compiler: ${err}`);
|
|
51
|
-
// Emit "success" return code. After all, this script is _optional_.
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
function success(msg) {
|
|
55
|
-
console.error(`postinstall cds-compiler: ${msg}`);
|
|
56
|
-
}
|