@sap/cds-compiler 5.8.2 → 5.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 +31 -0
- package/bin/cds_remove_invalid_whitespace.js +5 -3
- package/bin/cds_update_identifiers.js +9 -6
- package/bin/cdsc.js +79 -59
- package/bin/cdsse.js +14 -10
- package/bin/cdsv2m.js +3 -1
- package/lib/api/options.js +28 -6
- package/lib/base/message-registry.js +15 -4
- package/lib/checks/validator.js +3 -0
- package/lib/compiler/base.js +1 -1
- package/lib/compiler/checks.js +70 -50
- package/lib/compiler/extend.js +1 -1
- package/lib/compiler/generate.js +8 -2
- package/lib/compiler/index.js +1 -1
- package/lib/compiler/lsp-api.js +1 -1
- package/lib/compiler/propagator.js +2 -2
- package/lib/compiler/resolve.js +78 -31
- package/lib/compiler/shared.js +3 -3
- package/lib/compiler/tweak-assocs.js +1 -1
- package/lib/compiler/utils.js +10 -0
- package/lib/compiler/xpr-rewrite.js +1 -1
- package/lib/edm/annotations/edmJson.js +42 -39
- package/lib/edm/annotations/genericTranslation.js +55 -55
- package/lib/edm/annotations/preprocessAnnotations.js +5 -5
- package/lib/edm/csn2edm.js +21 -16
- package/lib/edm/edm.js +62 -62
- package/lib/edm/edmAnnoPreprocessor.js +2 -2
- package/lib/edm/edmInboundChecks.js +1 -1
- package/lib/edm/edmPreprocessor.js +32 -32
- package/lib/edm/edmUtils.js +8 -8
- package/lib/gen/CdlGrammar.checksum +1 -1
- package/lib/gen/CdlParser.js +77 -81
- package/lib/gen/Dictionary.json +3062 -3072
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1238 -1236
- package/lib/json/from-csn.js +1 -1
- package/lib/json/to-csn.js +30 -3
- package/lib/language/genericAntlrParser.js +16 -0
- package/lib/main.d.ts +79 -1
- package/lib/model/csnRefs.js +12 -5
- package/lib/model/xprAsTree.js +71 -0
- package/lib/modelCompare/utils/filter.js +1 -1
- package/lib/optionProcessor.js +46 -32
- package/lib/parsers/CdlGrammar.g4 +33 -28
- package/lib/parsers/Lexer.js +1 -1
- package/lib/parsers/XprTree.js +25 -16
- package/lib/render/toCdl.js +902 -414
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +8 -0
- package/lib/render/utils/common.js +2 -2
- package/lib/render/utils/operators.js +160 -0
- package/lib/render/utils/pretty.js +337 -0
- package/lib/sql-identifier.js +7 -9
- package/lib/transform/addTenantFields.js +39 -41
- package/lib/transform/db/applyTransformations.js +4 -4
- package/lib/transform/db/assertUnique.js +6 -5
- package/lib/transform/db/associations.js +3 -3
- package/lib/transform/db/assocsToQueries/transformExists.js +13 -13
- package/lib/transform/db/assocsToQueries/utils.js +8 -0
- package/lib/transform/db/backlinks.js +19 -14
- package/lib/transform/db/constraints.js +6 -6
- package/lib/transform/db/expansion.js +1 -1
- package/lib/transform/db/flattening.js +2 -2
- package/lib/transform/db/groupByOrderBy.js +1 -1
- package/lib/transform/db/processSqlServices.js +3 -3
- package/lib/transform/db/rewriteCalculatedElements.js +2 -2
- package/lib/transform/db/temporal.js +7 -9
- package/lib/transform/db/views.js +6 -6
- package/lib/transform/draft/odata.js +2 -0
- package/lib/transform/effective/annotations.js +1 -1
- package/lib/transform/effective/associations.js +1 -1
- package/lib/transform/effective/main.js +1 -0
- package/lib/transform/effective/service.js +2 -2
- package/lib/transform/forRelationalDB.js +11 -5
- package/lib/transform/localized.js +2 -0
- package/lib/transform/odata/adaptAnnotationRefs.js +10 -9
- package/lib/transform/parseExpr.js +2 -2
- package/lib/transform/transformUtils.js +9 -7
- package/lib/transform/translateAssocsToJoins.js +0 -2
- package/lib/transform/universalCsn/coreComputed.js +2 -2
- package/lib/utils/moduleResolve.js +7 -5
- package/package.json +1 -1
- package/share/messages/def-upcoming-virtual-change.md +55 -0
- package/share/messages/file-unexpected-case-mismatch.md +61 -0
- package/share/messages/message-explanations.json +2 -0
- package/lib/transform/braceExpression.js +0 -77
package/CHANGELOG.md
CHANGED
|
@@ -7,12 +7,43 @@
|
|
|
7
7
|
Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
|
|
10
|
+
## Version 5.9.0 - 2025-03-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- compiler:
|
|
15
|
+
+ Generated entities for compositions of named aspects now have an `include` on the named aspect,
|
|
16
|
+
inheriting actions from the aspect. This can be disabled via option `compositionIncludes: false`.
|
|
17
|
+
+ A warning is emitted for selected elements that are explicitly `virtual`, whose
|
|
18
|
+
behavior will change in cds-compiler v6.
|
|
19
|
+
+ New warning for structures having a scalar default value.
|
|
20
|
+
+ New warning for localized structures, as they are not fully supported by the compiler.
|
|
21
|
+
+ The new parser (`newParser: true`) now supports operator `==`.
|
|
22
|
+
- to.cdl:
|
|
23
|
+
+ Definitions can now be rendered nested in services. A common namespace can be extracted, too.
|
|
24
|
+
To use it, enabled options `renderCdlDefinitionNesting` and `renderCdlCommonNamespace`.
|
|
25
|
+
+ Annotation array values are pretty-printed to reduce whitespace.
|
|
26
|
+
- for.effective: Property `namespace` is no longer part of effective CSN.
|
|
27
|
+
- for.sql/hdi:
|
|
28
|
+
- The new operator `==` is rendered as `IS NOT DISTINCT FROM` or an equivalent expression.
|
|
29
|
+
- Using option `booleanEquality`, operator `!=` is rendered as `IS DISTINCT FROM` or an equivalent expression.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Update OData vocabularies: 'Common', 'Hierarchy'
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- to.odata: Annotation expressions using `LabeledElement` were not correctly rendered into EDMX.
|
|
38
|
+
|
|
39
|
+
|
|
10
40
|
## Version 5.8.2 - 2025-03-07
|
|
11
41
|
|
|
12
42
|
### Fixed
|
|
13
43
|
|
|
14
44
|
- for.odata: Generate foreign key elements for events again.
|
|
15
45
|
|
|
46
|
+
|
|
16
47
|
## Version 5.8.0 - 2025-02-27
|
|
17
48
|
|
|
18
49
|
### Added
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
// Note that you need to update the path to this script in the commands above.
|
|
22
22
|
//
|
|
23
23
|
|
|
24
|
+
/* eslint no-process-exit: 0, no-console: 0 */
|
|
25
|
+
|
|
24
26
|
'use strict';
|
|
25
27
|
|
|
26
28
|
const parsers = require('../lib/parsers');
|
|
@@ -36,7 +38,7 @@ if (filepath === '--help' || filepath === '-h')
|
|
|
36
38
|
exitError();
|
|
37
39
|
|
|
38
40
|
if (cliArgs.length !== 1)
|
|
39
|
-
exitError(`Expected exactly one argument, ${cliArgs.length} given`);
|
|
41
|
+
exitError(`Expected exactly one argument, ${ cliArgs.length } given`);
|
|
40
42
|
|
|
41
43
|
if (!filepath)
|
|
42
44
|
exitError('Expected non-empty filepath as argument!');
|
|
@@ -70,7 +72,7 @@ function modernizeWhitespace( source, filename ) {
|
|
|
70
72
|
errors.forEach((msg) => {
|
|
71
73
|
console.error(msg.toString());
|
|
72
74
|
});
|
|
73
|
-
console.error(`Found ${errors.length} errors! \n`);
|
|
75
|
+
console.error(`Found ${ errors.length } errors! \n`);
|
|
74
76
|
exitError('The CDS parser emitted errors. Fix them first and try again.');
|
|
75
77
|
}
|
|
76
78
|
|
|
@@ -132,5 +134,5 @@ function exitError( msg ) {
|
|
|
132
134
|
|
|
133
135
|
function usage() {
|
|
134
136
|
console.error('');
|
|
135
|
-
console.error(`usage: ${path.basename(process.argv[1])} <filename>`);
|
|
137
|
+
console.error(`usage: ${ path.basename(process.argv[1]) } <filename>`);
|
|
136
138
|
}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
// Note that you need to update the path to this script in the commands above.
|
|
21
21
|
//
|
|
22
22
|
|
|
23
|
+
/* eslint no-process-exit: 0, no-console: 0 */
|
|
24
|
+
|
|
23
25
|
'use strict';
|
|
24
26
|
|
|
25
27
|
const parsers = require('../lib/parsers');
|
|
@@ -35,7 +37,7 @@ if (filepath === '--help' || filepath === '-h')
|
|
|
35
37
|
exitError();
|
|
36
38
|
|
|
37
39
|
if (cliArgs.length !== 1)
|
|
38
|
-
exitError(`Expected exactly one argument, ${cliArgs.length} given`);
|
|
40
|
+
exitError(`Expected exactly one argument, ${ cliArgs.length } given`);
|
|
39
41
|
|
|
40
42
|
if (!filepath)
|
|
41
43
|
exitError('Expected non-empty filepath as argument!');
|
|
@@ -68,7 +70,7 @@ function modernizeIdentifierStyle( source, filename ) {
|
|
|
68
70
|
errors.forEach((msg) => {
|
|
69
71
|
console.error(msg.toString());
|
|
70
72
|
});
|
|
71
|
-
console.error(`Found ${errors.length} errors! \n`);
|
|
73
|
+
console.error(`Found ${ errors.length } errors! \n`);
|
|
72
74
|
exitError('The CDS parser emitted errors. Fix them first and try again.');
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -88,10 +90,11 @@ function modernizeIdentifierStyle( source, filename ) {
|
|
|
88
90
|
const newIdentText = toNewIdentStyle(identToken.text);
|
|
89
91
|
|
|
90
92
|
if (!identToken.stop)
|
|
91
|
-
throw new Error(`INTERNAL ERROR: Identifier at ${identToken.start} has no end!`);
|
|
93
|
+
throw new Error(`INTERNAL ERROR: Identifier at ${ identToken.start } has no end!`);
|
|
92
94
|
|
|
93
95
|
const start = identToken.start + currentOffset;
|
|
94
|
-
|
|
96
|
+
// 'end' points at the position *before* the character
|
|
97
|
+
const end = identToken.stop + currentOffset + 1;
|
|
95
98
|
|
|
96
99
|
source = replaceSliceInSource(source, start, end, newIdentText);
|
|
97
100
|
|
|
@@ -105,7 +108,7 @@ function modernizeIdentifierStyle( source, filename ) {
|
|
|
105
108
|
ident = ident.replace(/""/g, '"');
|
|
106
109
|
ident = ident.replace(/]/g, ']]');
|
|
107
110
|
|
|
108
|
-
return `![${ident}]`;
|
|
111
|
+
return `![${ ident }]`;
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
|
|
@@ -136,5 +139,5 @@ function exitError( msg ) {
|
|
|
136
139
|
|
|
137
140
|
function usage() {
|
|
138
141
|
console.error('');
|
|
139
|
-
console.error(`usage: ${path.basename(process.argv[1])} <filename>`);
|
|
142
|
+
console.error(`usage: ${ path.basename(process.argv[1]) } <filename>`);
|
|
140
143
|
}
|
package/bin/cdsc.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const compiler = require('../lib/compiler');
|
|
19
19
|
const main = require('../lib/main');
|
|
20
|
-
const { for_sql, for_hdi, for_hdbcds } = require('../lib/api/main');
|
|
20
|
+
const { for_sql: forSql, for_hdi: forHdi, for_hdbcds: forHdbcds } = require('../lib/api/main');
|
|
21
21
|
const { compactModel } = require('../lib/json/to-csn');
|
|
22
22
|
const { toRename: _toRename } = require('../lib/render/toRename');
|
|
23
23
|
const util = require('util');
|
|
@@ -48,7 +48,7 @@ class ProcessExitError extends Error {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
|
-
|
|
51
|
+
cdscMain();
|
|
52
52
|
}
|
|
53
53
|
catch (err) {
|
|
54
54
|
// This whole try/catch is only here because process.exit does not work in combination with
|
|
@@ -85,7 +85,7 @@ function remapCmdOptions( options, command ) {
|
|
|
85
85
|
delete options[command];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function
|
|
88
|
+
function cdscMain() {
|
|
89
89
|
if (process.argv.some(arg => arg === '-i' || arg === '--stdin'))
|
|
90
90
|
optionProcessor.makePositionalArgumentsOptional();
|
|
91
91
|
|
|
@@ -94,13 +94,13 @@ function cdsc_main() {
|
|
|
94
94
|
|
|
95
95
|
// Deal with '--version' explicitly
|
|
96
96
|
if (cmdLine.options.version) {
|
|
97
|
-
process.stdout.write(`${main.version()}\n`);
|
|
97
|
+
process.stdout.write(`${ main.version() }\n`);
|
|
98
98
|
throw new ProcessExitError(0);
|
|
99
99
|
}
|
|
100
100
|
// Deal with '--help' explicitly
|
|
101
101
|
if (cmdLine.command) {
|
|
102
102
|
// Command specific help
|
|
103
|
-
if (cmdLine.options.help || cmdLine.options[cmdLine.command]
|
|
103
|
+
if (cmdLine.options.help || cmdLine.options[cmdLine.command]?.help)
|
|
104
104
|
displayUsage(null, optionProcessor.commands[cmdLine.command].helpText, 0);
|
|
105
105
|
}
|
|
106
106
|
else if (cmdLine.options.help) {
|
|
@@ -111,7 +111,7 @@ function cdsc_main() {
|
|
|
111
111
|
if (cmdLine.unknownOptions.length > 0) {
|
|
112
112
|
// Print an INFO message about unknown options but
|
|
113
113
|
// continue with defaults and do not abort execution.
|
|
114
|
-
cmdLine.unknownOptions.forEach(msg => process.stderr.write(`cdsc: INFO: ${msg}\n`));
|
|
114
|
+
cmdLine.unknownOptions.forEach(msg => process.stderr.write(`cdsc: INFO: ${ msg }\n`));
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// Report complaints if any
|
|
@@ -175,18 +175,19 @@ function cdsc_main() {
|
|
|
175
175
|
|
|
176
176
|
const to = cmdLine.options.toSql ? 'toSql' : 'toHana';
|
|
177
177
|
if (cmdLine.options[to]) {
|
|
178
|
+
const opt = cmdLine.options[to];
|
|
178
179
|
// remap string values in options to boolean
|
|
179
|
-
if (
|
|
180
|
-
(
|
|
181
|
-
|
|
180
|
+
if (opt.assertIntegrity &&
|
|
181
|
+
(opt.assertIntegrity === 'true' ||
|
|
182
|
+
opt.assertIntegrity === 'false')
|
|
182
183
|
)
|
|
183
|
-
|
|
184
|
+
opt.assertIntegrity = opt.assertIntegrity === 'true';
|
|
184
185
|
|
|
185
|
-
if (
|
|
186
|
-
|
|
186
|
+
if (opt.withHanaAssociations)
|
|
187
|
+
opt.withHanaAssociations = opt.withHanaAssociations !== 'false';
|
|
187
188
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
189
|
+
if (opt.betterSqliteSessionVariables)
|
|
190
|
+
opt.betterSqliteSessionVariables = opt.betterSqliteSessionVariables === 'true';
|
|
190
191
|
}
|
|
191
192
|
|
|
192
193
|
// Enable all beta-flags if betaMode is set to true
|
|
@@ -199,7 +200,7 @@ function cdsc_main() {
|
|
|
199
200
|
cmdLine.options.testMode = (num > 0)
|
|
200
201
|
? num
|
|
201
202
|
: Math.floor( Math.random() * 4294967296 ) + 1;
|
|
202
|
-
console.error( `Running ‘${cmdLine.command}’ with test-mode shuffle ${cmdLine.options.testMode} …` );
|
|
203
|
+
console.error( `Running ‘${ cmdLine.command }’ with test-mode shuffle ${ cmdLine.options.testMode } …` );
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
// If set through CLI (and not options file), `deprecated` and `moduleLookupDirectories`
|
|
@@ -218,10 +219,16 @@ function cdsc_main() {
|
|
|
218
219
|
cmdLine.options.fallbackParser ??= 'auto!';
|
|
219
220
|
|
|
220
221
|
if (cmdLine.options[cmdLine.command]?.transitiveLocalizedViews) {
|
|
221
|
-
cmdLine.options.fewerLocalizedViews
|
|
222
|
+
cmdLine.options.fewerLocalizedViews
|
|
223
|
+
= !cmdLine.options[cmdLine.command].transitiveLocalizedViews;
|
|
222
224
|
delete cmdLine.options[cmdLine.command].transitiveLocalizedViews;
|
|
223
225
|
}
|
|
224
226
|
|
|
227
|
+
if (cmdLine.options.noCompositionIncludes) {
|
|
228
|
+
cmdLine.options.compositionIncludes = false;
|
|
229
|
+
delete cmdLine.options.noCompositionIncludes;
|
|
230
|
+
}
|
|
231
|
+
|
|
225
232
|
parseSeverityOptions(cmdLine);
|
|
226
233
|
|
|
227
234
|
// Do the work for the selected command
|
|
@@ -239,11 +246,11 @@ function cdsc_main() {
|
|
|
239
246
|
*/
|
|
240
247
|
function validateDirectBackendOption( command, options, args ) {
|
|
241
248
|
if (![ 'toCdl', 'toOdata', 'toHana', 'toCsn', 'toSql', 'forJava' ].includes(command)) {
|
|
242
|
-
displayUsage(`Option '--direct-backend' can't be used with command '${command}'`,
|
|
249
|
+
displayUsage(`Option '--direct-backend' can't be used with command '${ command }'`,
|
|
243
250
|
optionProcessor.helpText, 2);
|
|
244
251
|
}
|
|
245
252
|
if (!options.stdin && (!args.files || args.files.length !== 1)) {
|
|
246
|
-
displayUsage(`Option '--direct-backend' expects exactly one JSON file, but ${args.files?.length || 'none'} given`,
|
|
253
|
+
displayUsage(`Option '--direct-backend' expects exactly one JSON file, but ${ args.files?.length || 'none' } given`,
|
|
247
254
|
optionProcessor.helpText, 2);
|
|
248
255
|
}
|
|
249
256
|
const filename = args.files?.[0];
|
|
@@ -258,14 +265,14 @@ function displayUsage( error, helpText, code ) {
|
|
|
258
265
|
// Display non-error output (like help) to stdout
|
|
259
266
|
const out = (code === 0 && !error) ? process.stdout : process.stderr;
|
|
260
267
|
// Display help text first, error at the end (more readable, no scrolling)
|
|
261
|
-
out.write(`${helpText}\n`);
|
|
268
|
+
out.write(`${ helpText }\n`);
|
|
262
269
|
if (error) {
|
|
263
270
|
if (error instanceof Array) {
|
|
264
|
-
const errors = error.map(err => `cdsc: ERROR: ${err}`).join('\n');
|
|
265
|
-
out.write(`${errors}\n`);
|
|
271
|
+
const errors = error.map(err => `cdsc: ERROR: ${ err }`).join('\n');
|
|
272
|
+
out.write(`${ errors }\n`);
|
|
266
273
|
}
|
|
267
274
|
else {
|
|
268
|
-
out.write(`cdsc: ERROR: ${error}\n`);
|
|
275
|
+
out.write(`cdsc: ERROR: ${ error }\n`);
|
|
269
276
|
}
|
|
270
277
|
}
|
|
271
278
|
throw new ProcessExitError(code);
|
|
@@ -284,7 +291,8 @@ async function createTemporaryFileFromStdin() {
|
|
|
284
291
|
return file;
|
|
285
292
|
}
|
|
286
293
|
|
|
287
|
-
// Executes a command line that has been translated to 'command' (what to do),
|
|
294
|
+
// Executes a command line that has been translated to 'command' (what to do),
|
|
295
|
+
// 'options' (how) and 'args' (which files)
|
|
288
296
|
async function executeCommandLine( command, options, args ) {
|
|
289
297
|
const normalizeFilename = options.testMode && process.platform === 'win32';
|
|
290
298
|
const messageLevels = {
|
|
@@ -319,7 +327,7 @@ async function executeCommandLine( command, options, args ) {
|
|
|
319
327
|
};
|
|
320
328
|
|
|
321
329
|
if (!commands[command] && !commandsWithoutCompilation[command])
|
|
322
|
-
throw new Error(`Missing implementation for command ${command}`);
|
|
330
|
+
throw new Error(`Missing implementation for command ${ command }`);
|
|
323
331
|
|
|
324
332
|
remapCmdOptions( options, command );
|
|
325
333
|
|
|
@@ -352,13 +360,16 @@ async function executeCommandLine( command, options, args ) {
|
|
|
352
360
|
const csn = options.directBackend ? model : compactModel(model, options);
|
|
353
361
|
const cdlResult = main.to.cdl(csn, options);
|
|
354
362
|
for (const name in cdlResult)
|
|
355
|
-
writeToFileOrDisplay(options.out, `${name}.cds`, cdlResult[name]);
|
|
363
|
+
writeToFileOrDisplay(options.out, `${ name }.cds`, cdlResult[name]);
|
|
356
364
|
|
|
357
365
|
return model;
|
|
358
366
|
}
|
|
359
367
|
|
|
360
368
|
function forEffective( model ) {
|
|
361
|
-
const features = [
|
|
369
|
+
const features = [
|
|
370
|
+
'resolveSimpleTypes', 'resolveProjections',
|
|
371
|
+
'remapOdataAnnotations', 'keepLocalized',
|
|
372
|
+
];
|
|
362
373
|
for (const feature of features) {
|
|
363
374
|
if (options[feature]) // map to boolean equivalent
|
|
364
375
|
options[feature] = options[feature] === 'true';
|
|
@@ -408,7 +419,7 @@ async function executeCommandLine( command, options, args ) {
|
|
|
408
419
|
const csn = options.directBackend ? model : compactModel(model, options);
|
|
409
420
|
|
|
410
421
|
if (options.csn) {
|
|
411
|
-
displayNamedCsn(
|
|
422
|
+
displayNamedCsn(forHdbcds(csn, options), 'hana_csn');
|
|
412
423
|
}
|
|
413
424
|
else {
|
|
414
425
|
const hanaResult = main.to.hdbcds(csn, options);
|
|
@@ -438,12 +449,12 @@ async function executeCommandLine( command, options, args ) {
|
|
|
438
449
|
else if (options.json) {
|
|
439
450
|
const result = main.to.edm.all(csn, options);
|
|
440
451
|
for (const serviceName in result)
|
|
441
|
-
writeToFileOrDisplay(options.out, `${serviceName}.json`, result[serviceName]);
|
|
452
|
+
writeToFileOrDisplay(options.out, `${ serviceName }.json`, result[serviceName]);
|
|
442
453
|
}
|
|
443
454
|
else {
|
|
444
455
|
const result = main.to.edmx.all(csn, options);
|
|
445
456
|
for (const serviceName in result)
|
|
446
|
-
writeToFileOrDisplay(options.out, `${serviceName}.xml`, result[serviceName]);
|
|
457
|
+
writeToFileOrDisplay(options.out, `${ serviceName }.xml`, result[serviceName]);
|
|
447
458
|
}
|
|
448
459
|
return model;
|
|
449
460
|
}
|
|
@@ -457,13 +468,13 @@ async function executeCommandLine( command, options, args ) {
|
|
|
457
468
|
const csn = options.directBackend ? model : compactModel(model, options);
|
|
458
469
|
const messageFunctions = makeMessageFunction(csn, options, 'to.rename');
|
|
459
470
|
const renameResult = _toRename(csn, options, messageFunctions);
|
|
460
|
-
let storedProcedure = `PROCEDURE RENAME_${renameResult.options.sqlMapping.toUpperCase()}_TO_PLAIN LANGUAGE SQLSCRIPT AS BEGIN\n`;
|
|
471
|
+
let storedProcedure = `PROCEDURE RENAME_${ renameResult.options.sqlMapping.toUpperCase() }_TO_PLAIN LANGUAGE SQLSCRIPT AS BEGIN\n`;
|
|
461
472
|
for (const name in renameResult.rename) {
|
|
462
|
-
storedProcedure += ` --\n -- ${name}\n --\n`;
|
|
473
|
+
storedProcedure += ` --\n -- ${ name }\n --\n`;
|
|
463
474
|
storedProcedure += renameResult.rename[name];
|
|
464
475
|
}
|
|
465
476
|
storedProcedure += 'END;\n';
|
|
466
|
-
writeToFileOrDisplay(options.out, `storedProcedure_${renameResult.options.sqlMapping}_to_plain.sql`, storedProcedure, true);
|
|
477
|
+
writeToFileOrDisplay(options.out, `storedProcedure_${ renameResult.options.sqlMapping }_to_plain.sql`, storedProcedure, true);
|
|
467
478
|
return model;
|
|
468
479
|
}
|
|
469
480
|
|
|
@@ -476,9 +487,9 @@ async function executeCommandLine( command, options, args ) {
|
|
|
476
487
|
Object.keys(alterConstraintsResult).forEach((id) => {
|
|
477
488
|
const renderedConstraintStatement = alterConstraintsResult[id];
|
|
478
489
|
if (src === 'hdi')
|
|
479
|
-
writeToFileOrDisplay(options.out, `${id}.hdbconstraint`, renderedConstraintStatement);
|
|
490
|
+
writeToFileOrDisplay(options.out, `${ id }.hdbconstraint`, renderedConstraintStatement);
|
|
480
491
|
else
|
|
481
|
-
writeToFileOrDisplay(options.out, `${id}.sql`, renderedConstraintStatement);
|
|
492
|
+
writeToFileOrDisplay(options.out, `${ id }.sql`, renderedConstraintStatement);
|
|
482
493
|
});
|
|
483
494
|
}
|
|
484
495
|
|
|
@@ -488,7 +499,7 @@ async function executeCommandLine( command, options, args ) {
|
|
|
488
499
|
const csn = options.directBackend ? model : compactModel(model, options);
|
|
489
500
|
if (options.src === 'hdi') {
|
|
490
501
|
if (options.csn) {
|
|
491
|
-
displayNamedCsn(
|
|
502
|
+
displayNamedCsn(forHdi(csn, options), 'hdi_csn');
|
|
492
503
|
}
|
|
493
504
|
else {
|
|
494
505
|
const hdiResult = main.to.hdi(csn, options);
|
|
@@ -497,7 +508,7 @@ async function executeCommandLine( command, options, args ) {
|
|
|
497
508
|
}
|
|
498
509
|
}
|
|
499
510
|
else if (options.csn) {
|
|
500
|
-
displayNamedCsn(
|
|
511
|
+
displayNamedCsn(forSql(csn, options), 'sql_csn');
|
|
501
512
|
}
|
|
502
513
|
else {
|
|
503
514
|
const sqlResult = main.to.sql(csn, options);
|
|
@@ -513,7 +524,7 @@ async function executeCommandLine( command, options, args ) {
|
|
|
513
524
|
}
|
|
514
525
|
|
|
515
526
|
if (!hasMessageExplanation(args.messageId))
|
|
516
|
-
console.error(`Message '${args.messageId}' does not have an explanation!`);
|
|
527
|
+
console.error(`Message '${ args.messageId }' does not have an explanation!`);
|
|
517
528
|
else
|
|
518
529
|
console.log(explainMessage(args.messageId));
|
|
519
530
|
}
|
|
@@ -597,12 +608,13 @@ async function executeCommandLine( command, options, args ) {
|
|
|
597
608
|
else {
|
|
598
609
|
let hasAtLeastOneExplanation = false;
|
|
599
610
|
messages.filter(msg => messageLevels[msg.severity] <= options.warning).forEach((msg) => {
|
|
600
|
-
hasAtLeastOneExplanation = hasAtLeastOneExplanation ||
|
|
611
|
+
hasAtLeastOneExplanation = hasAtLeastOneExplanation ||
|
|
612
|
+
main.hasMessageExplanation(msg.messageId);
|
|
601
613
|
log(main.messageStringMultiline(msg, msgConfig));
|
|
602
614
|
log(); // newline
|
|
603
615
|
});
|
|
604
616
|
if (!options.noMessageId && hasAtLeastOneExplanation)
|
|
605
|
-
log(`${colorTerm.asHelp('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
|
|
617
|
+
log(`${ colorTerm.asHelp('help') }: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
|
|
606
618
|
}
|
|
607
619
|
return model;
|
|
608
620
|
}
|
|
@@ -613,9 +625,9 @@ async function executeCommandLine( command, options, args ) {
|
|
|
613
625
|
// written in raw form to '<name>_raw.txt'.
|
|
614
626
|
function displayNamedXsn( xsn, name ) {
|
|
615
627
|
if (options.rawOutput)
|
|
616
|
-
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
|
|
628
|
+
writeToFileOrDisplay(options.out, `${ name }_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
|
|
617
629
|
else if (options.internalMsg)
|
|
618
|
-
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null }), true);
|
|
630
|
+
writeToFileOrDisplay(options.out, `${ name }_raw.txt`, util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null }), true);
|
|
619
631
|
else if (!options.parseOnly) // no output if parseOnly but not rawOutput
|
|
620
632
|
displayNamedCsn(compactModel(xsn, options), name);
|
|
621
633
|
}
|
|
@@ -639,29 +651,37 @@ async function executeCommandLine( command, options, args ) {
|
|
|
639
651
|
if (options.enrichCsn)
|
|
640
652
|
enrichCsn( csn, options );
|
|
641
653
|
|
|
642
|
-
if (options.internalMsg)
|
|
643
|
-
writeToFileOrDisplay(options.out, `${name}_raw.txt`, options.messages, true);
|
|
644
|
-
|
|
645
|
-
else if (!options.internalMsg)
|
|
646
|
-
writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
|
|
647
|
-
}
|
|
654
|
+
if (options.internalMsg)
|
|
655
|
+
writeToFileOrDisplay(options.out, `${ name }_raw.txt`, options.messages, true);
|
|
656
|
+
|
|
657
|
+
else if (!options.internalMsg)
|
|
658
|
+
writeToFileOrDisplay(options.out, `${ name }.json`, csn, true);
|
|
648
659
|
}
|
|
649
660
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
661
|
+
/**
|
|
662
|
+
* Write the result 'content' to a file 'filename' in directory 'dir', except if 'dir' is '-'.
|
|
663
|
+
* In that case, display 'content' to stdout.
|
|
664
|
+
* If 'content' is not a string, JSON-stringify it
|
|
665
|
+
* If displaying to stdout, prepend a headline containing 'filename',
|
|
666
|
+
* unless 'omitHeadline' is set.
|
|
667
|
+
* For filenames, illegal characters (slash, backslash, colon) are replaced by '_'.
|
|
668
|
+
*
|
|
669
|
+
* @param {string} dir
|
|
670
|
+
* @param {string} fileName
|
|
671
|
+
* @param {string} content
|
|
672
|
+
* @param {boolean} [omitHeadline]
|
|
673
|
+
*/
|
|
655
674
|
function writeToFileOrDisplay( dir, fileName, content, omitHeadline = false ) {
|
|
656
675
|
if (options.internalMsg)
|
|
657
676
|
return;
|
|
658
677
|
fileName = fileName.replace(/[:/\\]/g, '_');
|
|
659
678
|
|
|
660
|
-
// replace all dots with underscore to get deployable .hdbcds sources
|
|
679
|
+
// replace all dots with underscore to get deployable .hdbcds sources
|
|
680
|
+
// (except the one before the file extension)
|
|
661
681
|
if (options.transformation === 'hdbcds')
|
|
662
682
|
fileName = fileName.replace(/\.(?=.*?\.)/g, '_');
|
|
663
683
|
|
|
664
|
-
if (
|
|
684
|
+
if (typeof content !== 'string')
|
|
665
685
|
content = JSON.stringify(content, null, 2);
|
|
666
686
|
|
|
667
687
|
if (dir === '-') {
|
|
@@ -672,10 +692,10 @@ async function executeCommandLine( command, options, args ) {
|
|
|
672
692
|
sql: true, hdbconstraint: true, hdbtable: true, hdbview: true,
|
|
673
693
|
};
|
|
674
694
|
const commentStarter = fileName.split('.').pop() in sqlTypes ? '--$' : '//';
|
|
675
|
-
process.stdout.write(`${commentStarter} ------------------- ${fileName} -------------------\n`);
|
|
695
|
+
process.stdout.write(`${ commentStarter } ------------------- ${ fileName } -------------------\n`);
|
|
676
696
|
}
|
|
677
697
|
|
|
678
|
-
process.stdout.write(`${content}\n`);
|
|
698
|
+
process.stdout.write(`${ content }\n`);
|
|
679
699
|
if (!omitHeadline)
|
|
680
700
|
process.stdout.write('\n');
|
|
681
701
|
}
|
|
@@ -730,8 +750,9 @@ function parseSeverityOptions({ options }) {
|
|
|
730
750
|
debug: 'Debug',
|
|
731
751
|
};
|
|
732
752
|
|
|
733
|
-
// Note: We use a for loop to ensure that the order of the options on
|
|
734
|
-
//
|
|
753
|
+
// Note: We use a for loop to ensure that the order of the options on
|
|
754
|
+
// the command line is respected, i.e. `--warn id --error id` would
|
|
755
|
+
// lead to `id` being reclassified as an error and not a warning.
|
|
735
756
|
for (const key in options) {
|
|
736
757
|
switch (key) {
|
|
737
758
|
case 'error':
|
|
@@ -754,4 +775,3 @@ function parseSeverityOptions({ options }) {
|
|
|
754
775
|
}
|
|
755
776
|
}
|
|
756
777
|
}
|
|
757
|
-
|
package/bin/cdsse.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
// capabilities supported at the moments is: complete, find, lint.
|
|
11
11
|
// Syntax highlighting is supported by ./cdshi.js.
|
|
12
12
|
|
|
13
|
-
/* eslint no-console:
|
|
13
|
+
/* eslint @stylistic/js/max-len: 0, no-console: 0 */
|
|
14
|
+
|
|
14
15
|
// @ts-nocheck
|
|
15
16
|
|
|
16
17
|
'use strict';
|
|
@@ -28,8 +29,8 @@ const { availableBetaFlags: beta } = require('../lib/base/model');
|
|
|
28
29
|
|
|
29
30
|
const { argv } = process;
|
|
30
31
|
const cmd = commands[argv[2]];
|
|
31
|
-
const line = Number.parseInt( argv[3] );
|
|
32
|
-
const column = Number.parseInt( argv[4] );
|
|
32
|
+
const line = Number.parseInt( argv[3], 10 );
|
|
33
|
+
const column = Number.parseInt( argv[4], 10 );
|
|
33
34
|
const file = argv[5];
|
|
34
35
|
const frel = path.relative( '', file || '' );
|
|
35
36
|
// TODO: proper realname
|
|
@@ -72,10 +73,11 @@ function complete( err, buf ) {
|
|
|
72
73
|
hasId = tokensAt( buf, off.prefix, off.col, true );
|
|
73
74
|
}
|
|
74
75
|
if (hasId) {
|
|
75
|
-
const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
|
|
76
|
+
const src = `${ buf.substring( 0, off.prefix ) }__NO_SUCH_ID__${ buf.substring( off.cursor ) }`;
|
|
76
77
|
const fname = path.resolve( '', file );
|
|
77
78
|
compiler.compileX( [ file ], '', {
|
|
78
|
-
newParser: true, attachValidNames: true, lintMode: true, beta, messages
|
|
79
|
+
newParser: true, attachValidNames: true, lintMode: true, beta, messages,
|
|
80
|
+
}, { [fname]: src } )
|
|
79
81
|
.then( ident, ident );
|
|
80
82
|
}
|
|
81
83
|
return true;
|
|
@@ -97,7 +99,7 @@ const autoNavigateKinds = {
|
|
|
97
99
|
$navElement: art => art._origin,
|
|
98
100
|
$tableAlias: art => art._origin,
|
|
99
101
|
using: () => true,
|
|
100
|
-
}
|
|
102
|
+
};
|
|
101
103
|
|
|
102
104
|
// For finding the definition for reference under cursor, do the following
|
|
103
105
|
// * replace identifier under cursor by an undefined name
|
|
@@ -112,7 +114,7 @@ function find( err, buf ) {
|
|
|
112
114
|
if (off.prefix === off.cursor) // not at name
|
|
113
115
|
return true;
|
|
114
116
|
const messages = [];
|
|
115
|
-
const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
|
|
117
|
+
const src = `${ buf.substring( 0, off.prefix ) }__NO_SUCH_ID__${ buf.substring( off.cursor ) }`;
|
|
116
118
|
const fname = path.resolve( '', file );
|
|
117
119
|
compiler.compileX( [ file ], '', {
|
|
118
120
|
newParser: true, attachValidNames: true, lintMode: true, beta, messages,
|
|
@@ -130,7 +132,7 @@ function find( err, buf ) {
|
|
|
130
132
|
// TODO: why no _effectiveType for $navElement ?
|
|
131
133
|
// TODO: display both the (first) inferred _and_ the "final" one
|
|
132
134
|
if (art)
|
|
133
|
-
console.log( `${locationString( art.name.location || art.location )}: Definition` );
|
|
135
|
+
console.log( `${ locationString( art.name.location || art.location ) }: Definition` );
|
|
134
136
|
return true;
|
|
135
137
|
}
|
|
136
138
|
}
|
|
@@ -140,7 +142,9 @@ function lint( err, buf ) {
|
|
|
140
142
|
return usage( err );
|
|
141
143
|
const messages = [];
|
|
142
144
|
const fname = path.resolve( '', file );
|
|
143
|
-
compiler.compileX( [ file ], '', {
|
|
145
|
+
compiler.compileX( [ file ], '', {
|
|
146
|
+
newParser: true, lintMode: true, beta, messages,
|
|
147
|
+
}, { [fname]: buf } )
|
|
144
148
|
.then( display, display );
|
|
145
149
|
return true;
|
|
146
150
|
|
|
@@ -155,7 +159,7 @@ function lint( err, buf ) {
|
|
|
155
159
|
|
|
156
160
|
function tokensAt( buf, _offset, col, symbol ) {
|
|
157
161
|
const messages = [];
|
|
158
|
-
const src = `${buf.substring( 0, _offset )}≠${buf.substring( _offset )}`;
|
|
162
|
+
const src = `${ buf.substring( 0, _offset ) }≠${ buf.substring( _offset ) }`;
|
|
159
163
|
compiler.parseX( src, frel, { newParser: true, messages } );
|
|
160
164
|
const et = messageAt( messages, 'expectedTokens', col ) || [];
|
|
161
165
|
for (const n of et) {
|
package/bin/cdsv2m.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
/* eslint @stylistic/js/max-len: 0, no-console: 0 */
|
|
4
|
+
|
|
3
5
|
'use strict';
|
|
4
6
|
|
|
5
7
|
// Very simple command-line interface to support model migration
|
|
@@ -45,6 +47,6 @@ function ria() {
|
|
|
45
47
|
}
|
|
46
48
|
for (const name in annotates) {
|
|
47
49
|
const escaped = name.split('.').map(part => smartId(part)).join('.');
|
|
48
|
-
console.log(`annotate ${escaped} with @cds.redirection.target: false;`);
|
|
50
|
+
console.log(`annotate ${ escaped } with @cds.redirection.target: false;`);
|
|
49
51
|
}
|
|
50
52
|
}
|