@sap/cds-compiler 4.8.0 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -4
- package/bin/cds_remove_invalid_whitespace.js +135 -0
- package/bin/cds_update_annotations.js +180 -0
- package/bin/cds_update_identifiers.js +3 -4
- package/bin/cdsc.js +30 -17
- package/doc/CHANGELOG_BETA.md +19 -0
- package/lib/api/main.js +59 -24
- package/lib/api/options.js +12 -1
- package/lib/api/validate.js +1 -5
- package/lib/base/builtins.js +27 -0
- package/lib/base/message-registry.js +38 -21
- package/lib/base/messages.js +51 -20
- package/lib/base/model.js +4 -5
- package/lib/checks/actionsFunctions.js +2 -2
- package/lib/checks/annotationsOData.js +3 -0
- package/lib/checks/defaultValues.js +5 -2
- package/lib/checks/queryNoDbArtifacts.js +3 -2
- package/lib/checks/validator.js +2 -34
- package/lib/compiler/assert-consistency.js +10 -3
- package/lib/compiler/checks.js +44 -18
- package/lib/compiler/define.js +38 -30
- package/lib/compiler/extend.js +33 -10
- package/lib/compiler/index.js +0 -1
- package/lib/compiler/lsp-api.js +5 -0
- package/lib/compiler/populate.js +0 -2
- package/lib/compiler/propagator.js +23 -19
- package/lib/compiler/resolve.js +48 -29
- package/lib/compiler/shared.js +60 -20
- package/lib/compiler/tweak-assocs.js +72 -116
- package/lib/compiler/xpr-rewrite.js +762 -0
- package/lib/edm/annotations/edmJson.js +24 -7
- package/lib/edm/annotations/genericTranslation.js +81 -61
- package/lib/edm/edm.js +4 -4
- package/lib/edm/edmInboundChecks.js +33 -0
- package/lib/edm/edmPreprocessor.js +9 -6
- package/lib/gen/Dictionary.json +129 -14
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1523 -1518
- package/lib/json/from-csn.js +13 -4
- package/lib/json/to-csn.js +12 -12
- package/lib/language/genericAntlrParser.js +14 -6
- package/lib/main.d.ts +67 -14
- package/lib/main.js +1 -0
- package/lib/model/cloneCsn.js +6 -3
- package/lib/model/csnRefs.js +23 -11
- package/lib/model/csnUtils.js +13 -7
- package/lib/model/enrichCsn.js +3 -1
- package/lib/model/revealInternalProperties.js +2 -1
- package/lib/model/sortViews.js +14 -6
- package/lib/modelCompare/compare.js +33 -34
- package/lib/optionProcessor.js +27 -2
- package/lib/render/DuplicateChecker.js +6 -6
- package/lib/render/manageConstraints.js +1 -0
- package/lib/render/toCdl.js +3 -1
- package/lib/transform/db/applyTransformations.js +33 -0
- package/lib/transform/db/constraints.js +75 -28
- package/lib/transform/db/expansion.js +8 -3
- package/lib/transform/db/flattening.js +2 -2
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/temporal.js +6 -3
- package/lib/transform/db/transformExists.js +2 -2
- package/lib/transform/effective/annotations.js +194 -0
- package/lib/transform/effective/main.js +6 -8
- package/lib/transform/effective/misc.js +31 -10
- package/lib/transform/forOdata.js +23 -7
- package/lib/transform/forRelationalDB.js +3 -3
- package/lib/transform/localized.js +7 -6
- package/lib/transform/odata/flattening.js +221 -124
- package/lib/transform/odata/toFinalBaseType.js +1 -1
- package/lib/transform/odata/typesExposure.js +15 -12
- package/lib/transform/parseExpr.js +4 -4
- package/lib/transform/transformUtils.js +47 -42
- package/lib/transform/translateAssocsToJoins.js +47 -47
- package/lib/transform/universalCsn/universalCsnEnricher.js +16 -19
- package/package.json +1 -1
- package/share/messages/anno-missing-rewrite.md +45 -0
- package/share/messages/message-explanations.json +1 -0
- package/bin/.eslintrc.json +0 -17
- package/lib/api/.eslintrc.json +0 -37
- package/lib/checks/.eslintrc.json +0 -31
- package/lib/compiler/.eslintrc.json +0 -8
- package/lib/edm/.eslintrc.json +0 -46
- package/lib/inspect/.eslintrc.json +0 -4
- package/lib/json/.eslintrc.json +0 -4
- package/lib/language/.eslintrc.json +0 -4
- package/lib/model/.eslintrc.json +0 -13
- package/lib/modelCompare/utils/.eslintrc.json +0 -22
- package/lib/render/.eslintrc.json +0 -22
- package/lib/transform/.eslintrc.json +0 -13
- package/lib/transform/db/.eslintrc.json +0 -41
- package/lib/transform/draft/.eslintrc.json +0 -4
- package/lib/transform/effective/.eslintrc.json +0 -4
- package/lib/transform/universalCsn/.eslintrc.json +0 -37
- package/lib/utils/.eslintrc.json +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,42 @@
|
|
|
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 4.9.2 - 2024-05-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- compiler: Rewriting annotation expression paths in structures of projections has been improved.
|
|
15
|
+
- to.edm(x):
|
|
16
|
+
+ Operator `/` represents `DivBy` operator, explicit `DivBy` is replaced with `Div` as integer division.
|
|
17
|
+
- to.sql: consider all associations in tenant dependent entity for referential constraint generation
|
|
18
|
+
|
|
19
|
+
## Version 4.9.0 - 2024-04-25
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- compiler: Annotations with expressions are now rewritten when propagated.
|
|
24
|
+
- for.seal: Added API function that produces a CSN for SEAL.
|
|
25
|
+
- for.odata/to.edm(x): Support annotation path expressions including path flattening.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- parser: A space between `.` and `*`/`{` (nested projections) is now a warning.
|
|
30
|
+
Use `bin/cds_remove_invalid_whitespace.js` to automatically fix this warning.
|
|
31
|
+
- compiler:
|
|
32
|
+
+ Published compositions with filters are changed to associations.
|
|
33
|
+
+ Expressions as annotation values are rejected for few known annotations that don't expect them.
|
|
34
|
+
- Update OData vocabularies: 'Aggregation', 'Capabilities', 'Common', 'Hierarchy', 'PersonalData', 'Session', 'UI'.
|
|
35
|
+
- to.edm(x): Exposed anonymous parameter types are now prefixed with `ap`, `bap` and `ep` for actions, bound actions and entities.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- compiler:
|
|
40
|
+
+ Deprecated `$parameters` is no longer proposed in code completion.
|
|
41
|
+
+ Duplicate mixin definitions lead to failing name resolution.
|
|
42
|
+
- to.cdl: Types were always rendered for associations with filters, even if it would lead to a compilation failure.
|
|
43
|
+
- to.edm(x):
|
|
44
|
+
+ Fix a recursion bug in entity parameter handling.
|
|
45
|
+
+ Fix event exclusion in service preprocessing.
|
|
10
46
|
|
|
11
47
|
## Version 4.8.0 - 2024-03-21
|
|
12
48
|
|
|
@@ -39,9 +75,6 @@ The compiler behavior concerning `beta` features can change at any time without
|
|
|
39
75
|
+ Turn types and aspects into dummies to reduce CSN size.
|
|
40
76
|
+ Correctly detect a removed `.default` and forcefully set the default to `null`.
|
|
41
77
|
|
|
42
|
-
### Removed
|
|
43
|
-
|
|
44
|
-
|
|
45
78
|
## Version 4.7.6 - 2024-02-29
|
|
46
79
|
|
|
47
80
|
### Fixed
|
|
@@ -83,7 +116,8 @@ The compiler behavior concerning `beta` features can change at any time without
|
|
|
83
116
|
- compiler: published associations with filters sometimes had the filter applied twice
|
|
84
117
|
if used in inline aspect compositions
|
|
85
118
|
- to.sql|hdi|hdbcds[.migration]:
|
|
86
|
-
+ With `withHanaAssociations`: `false`, remove the association elements from the final CSN in order
|
|
119
|
+
+ With `withHanaAssociations`: `false`, remove the association elements from the final CSN in order
|
|
120
|
+
to correctly detect them during migration scenarios and
|
|
87
121
|
with generated `hdbcds`.
|
|
88
122
|
+ Skip expensive processing (for calculated elements and nested projections) if the model doesn't use it.
|
|
89
123
|
+ Don't greedily set alias on subqueries if not required.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Remove whitespace where the compiler does not expect it and will
|
|
4
|
+
// emit an error in the next major version.
|
|
5
|
+
//
|
|
6
|
+
// This script removes whitespace where necessary.
|
|
7
|
+
// It does not remove comments, even though they count as whitespace.
|
|
8
|
+
//
|
|
9
|
+
// Example CDS:
|
|
10
|
+
// entity P as projection on E { s. * };
|
|
11
|
+
// will become:
|
|
12
|
+
// entity P as projection on E { s.* };
|
|
13
|
+
//
|
|
14
|
+
// Usage:
|
|
15
|
+
// ./cds_remove_invalid_whitespace.js my_file.cds
|
|
16
|
+
//
|
|
17
|
+
// If you want to update all files in a directory, you can use
|
|
18
|
+
// this shell script:
|
|
19
|
+
// find . -type f -iname '*.cds' -exec ./cds_remove_invalid_whitespace.js {} \;
|
|
20
|
+
//
|
|
21
|
+
// Note that you need to update the path to this script in the commands above.
|
|
22
|
+
//
|
|
23
|
+
|
|
24
|
+
'use strict';
|
|
25
|
+
|
|
26
|
+
const parseLanguage = require('../lib/language/antlrParser');
|
|
27
|
+
const { createMessageFunctions } = require('../lib/base/messages');
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
|
|
32
|
+
const cliArgs = process.argv.slice(2);
|
|
33
|
+
const filepath = cliArgs[0];
|
|
34
|
+
|
|
35
|
+
if (filepath === '--help' || filepath === '-h')
|
|
36
|
+
exitError();
|
|
37
|
+
|
|
38
|
+
if (cliArgs.length !== 1)
|
|
39
|
+
exitError(`Expected exactly one argument, ${cliArgs.length} given`);
|
|
40
|
+
|
|
41
|
+
if (!filepath)
|
|
42
|
+
exitError('Expected non-empty filepath as argument!');
|
|
43
|
+
|
|
44
|
+
// Do not use allow-list approach.
|
|
45
|
+
// There may be CDS files with other extensions than `.cds`.
|
|
46
|
+
if (filepath.endsWith('.csn') || filepath.endsWith('.json'))
|
|
47
|
+
exitError('Only CDS files can be passed! Found CSN file!');
|
|
48
|
+
|
|
49
|
+
const sourceStr = fs.readFileSync(filepath, 'utf-8');
|
|
50
|
+
const newSourceStr = modernizeWhitespace(sourceStr, filepath);
|
|
51
|
+
if (newSourceStr !== sourceStr)
|
|
52
|
+
fs.writeFileSync(filepath, newSourceStr);
|
|
53
|
+
process.exit(0); // success
|
|
54
|
+
|
|
55
|
+
// --------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function modernizeWhitespace( source, filename ) {
|
|
58
|
+
const options = { messages: [], attachTokens: true };
|
|
59
|
+
const messageFunctions = createMessageFunctions( options, 'parse', null );
|
|
60
|
+
|
|
61
|
+
// parseLanguage does not throw on CompilationError, so
|
|
62
|
+
// we do not need a try...catch block.
|
|
63
|
+
const ast = parseLanguage(source, filename, options, messageFunctions);
|
|
64
|
+
|
|
65
|
+
// To avoid spam, only report errors.
|
|
66
|
+
// Users should use the compiler to get all messages.
|
|
67
|
+
const errors = options.messages.filter(msg => (msg.severity === 'Error'));
|
|
68
|
+
if (errors.length > 0) {
|
|
69
|
+
errors.forEach((msg) => {
|
|
70
|
+
console.error(msg.toString());
|
|
71
|
+
});
|
|
72
|
+
console.error(`Found ${errors.length} errors! \n`);
|
|
73
|
+
exitError('The CDS parser emitted errors. Fix them first and try again.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!ast.artifacts)
|
|
77
|
+
return source;
|
|
78
|
+
|
|
79
|
+
let currentOffset = 0;
|
|
80
|
+
|
|
81
|
+
const { tokens } = ast.tokenStream;
|
|
82
|
+
for (let i = 0; i < tokens.length; ++i) {
|
|
83
|
+
const token = tokens[i];
|
|
84
|
+
const next = tokens[i + 1];
|
|
85
|
+
if (next && token.type === ast.tokenStream.DOTbeforeBRACE &&
|
|
86
|
+
(next.type === ast.tokenStream.ASTERISK || next.type === ast.tokenStream.BRACE))
|
|
87
|
+
updateWhitespace(token, next);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return source;
|
|
91
|
+
|
|
92
|
+
// -----------------------------------------------
|
|
93
|
+
|
|
94
|
+
function updateWhitespace( dot, braceOrAsterisk ) {
|
|
95
|
+
if (dot.stop === braceOrAsterisk.start)
|
|
96
|
+
return;
|
|
97
|
+
|
|
98
|
+
const from = dot.stop + currentOffset + 1; // end points at the position *before* the character
|
|
99
|
+
const to = braceOrAsterisk.start + currentOffset;
|
|
100
|
+
|
|
101
|
+
source = replaceSliceInSource(source, from, to, '');
|
|
102
|
+
|
|
103
|
+
currentOffset -= to - from;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Replaces a given span with @p replaceWith
|
|
109
|
+
*
|
|
110
|
+
* @param {string} source
|
|
111
|
+
* @param {number} startIndex
|
|
112
|
+
* @param {number} endIndex
|
|
113
|
+
* @param {string} replaceWith
|
|
114
|
+
* @return {string}
|
|
115
|
+
*/
|
|
116
|
+
function replaceSliceInSource( source, startIndex, endIndex, replaceWith ) {
|
|
117
|
+
return source.substring(0, startIndex) +
|
|
118
|
+
replaceWith +
|
|
119
|
+
source.substring(endIndex);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @param {string} [msg]
|
|
124
|
+
*/
|
|
125
|
+
function exitError( msg ) {
|
|
126
|
+
if (msg)
|
|
127
|
+
console.error(msg);
|
|
128
|
+
usage();
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function usage() {
|
|
133
|
+
console.error('');
|
|
134
|
+
console.error(`usage: ${path.basename(process.argv[1])} <filename>`);
|
|
135
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Update CDS Annotation References to use v4 expression syntax.
|
|
4
|
+
//
|
|
5
|
+
// This script replaces bare, unchecked references in annotation assignments
|
|
6
|
+
// with the new syntax using `(`.
|
|
7
|
+
//
|
|
8
|
+
// Example CDS:
|
|
9
|
+
// @anno: ID entity E { key ID : String; };
|
|
10
|
+
// will become:
|
|
11
|
+
// @anno: (ID) entity E { key ID : String; };
|
|
12
|
+
//
|
|
13
|
+
// Usage:
|
|
14
|
+
// ./cds_update_annotations.js my_file.cds
|
|
15
|
+
//
|
|
16
|
+
// If you want to update all identifiers in a directory, you can use
|
|
17
|
+
// this Shell script:
|
|
18
|
+
// find . -type f -iname '*.cds' -exec ./cds_update_annotations.js {} \;
|
|
19
|
+
//
|
|
20
|
+
// Note that you need to update the path to this script in the commands above.
|
|
21
|
+
//
|
|
22
|
+
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
const parseLanguage = require('../lib/language/antlrParser');
|
|
26
|
+
const { createMessageFunctions } = require('../lib/base/messages');
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
const { forEachMemberRecursively } = require('../lib/base/model');
|
|
31
|
+
|
|
32
|
+
const cliArgs = process.argv.slice(2);
|
|
33
|
+
const filepath = cliArgs[0];
|
|
34
|
+
|
|
35
|
+
if (filepath === '--help' || filepath === '-h')
|
|
36
|
+
exitError();
|
|
37
|
+
|
|
38
|
+
if (cliArgs.length !== 1)
|
|
39
|
+
exitError(`Expected exactly one argument, ${cliArgs.length} given`);
|
|
40
|
+
|
|
41
|
+
if (!filepath)
|
|
42
|
+
exitError('Expected non-empty filepath as argument!');
|
|
43
|
+
|
|
44
|
+
// Do not use allow-list approach.
|
|
45
|
+
// There may be CDS files with other extensions than `.cds`.
|
|
46
|
+
if (filepath.endsWith('.csn') || filepath.endsWith('.json'))
|
|
47
|
+
exitError('Only CDS files can be passed! Found CSN file!');
|
|
48
|
+
|
|
49
|
+
const sourceStr = fs.readFileSync(filepath, 'utf-8');
|
|
50
|
+
const newSourceStr = modernizeAnnotationExpressions(sourceStr, filepath);
|
|
51
|
+
if (newSourceStr !== sourceStr)
|
|
52
|
+
fs.writeFileSync(filepath, newSourceStr);
|
|
53
|
+
process.exit(0); // success
|
|
54
|
+
|
|
55
|
+
// --------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function modernizeAnnotationExpressions( source, filename ) {
|
|
58
|
+
const options = { messages: [], attachTokens: true };
|
|
59
|
+
const messageFunctions = createMessageFunctions( options, 'parse', null );
|
|
60
|
+
|
|
61
|
+
// parseLanguage does not throw on CompilationError, so
|
|
62
|
+
// we do not need a try...catch block.
|
|
63
|
+
const ast = parseLanguage(source, filename, options, messageFunctions);
|
|
64
|
+
|
|
65
|
+
// To avoid spam, only report errors.
|
|
66
|
+
// Users should use the compiler to get all messages.
|
|
67
|
+
const errors = options.messages.filter(msg => (msg.severity === 'Error'));
|
|
68
|
+
if (errors.length > 0) {
|
|
69
|
+
errors.forEach((msg) => {
|
|
70
|
+
console.error(msg.toString());
|
|
71
|
+
});
|
|
72
|
+
console.error(`Found ${errors.length} errors! \n`);
|
|
73
|
+
exitError('The parser emitted errors. Please fix them first and try again.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!ast.artifacts)
|
|
77
|
+
return source;
|
|
78
|
+
|
|
79
|
+
let currentOffset = 0;
|
|
80
|
+
|
|
81
|
+
for (const artName in ast.artifacts) {
|
|
82
|
+
const art = ast.artifacts[artName];
|
|
83
|
+
updateAnnosOfArtifact(art);
|
|
84
|
+
forEachMemberRecursively(art, updateAnnosOfArtifact);
|
|
85
|
+
}
|
|
86
|
+
for (const vocName in ast.vocabularies) {
|
|
87
|
+
const voc = ast.vocabularies[vocName];
|
|
88
|
+
updateAnnosOfArtifact(voc);
|
|
89
|
+
forEachMemberRecursively(voc, updateAnnosOfArtifact);
|
|
90
|
+
}
|
|
91
|
+
for (const ext of ast.extensions)
|
|
92
|
+
updateAnnosOfArtifact(ext);
|
|
93
|
+
|
|
94
|
+
return source;
|
|
95
|
+
|
|
96
|
+
// -----------------------------------------------
|
|
97
|
+
|
|
98
|
+
function updateAnnosOfArtifact( art ) {
|
|
99
|
+
for (const prop in art) {
|
|
100
|
+
if (prop.charAt(0) === '@')
|
|
101
|
+
updateAnno(art[prop]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function updateAnno( anno ) {
|
|
106
|
+
if (anno.literal === 'array') {
|
|
107
|
+
anno.val.forEach(val => updateAnno( val ));
|
|
108
|
+
}
|
|
109
|
+
else if (anno.literal === 'struct') {
|
|
110
|
+
const struct = Object.values(anno.struct);
|
|
111
|
+
struct.forEach(val => updateAnno( val ));
|
|
112
|
+
}
|
|
113
|
+
else if (!anno.$tokenTexts && anno.path) {
|
|
114
|
+
const first = anno.path[0];
|
|
115
|
+
const last = anno.path[anno.path.length - 1];
|
|
116
|
+
insertParentheses(first, last);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function findTokenFor( node ) {
|
|
121
|
+
const loc = node.location;
|
|
122
|
+
// We use slow linear search; we could do binary search, but not performance critical.
|
|
123
|
+
const { tokens } = ast.tokenStream;
|
|
124
|
+
for (const token of tokens) {
|
|
125
|
+
if (token.column + 1 === loc.col && token.line === loc.line)
|
|
126
|
+
return token;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function insertParentheses( first, last ) {
|
|
132
|
+
const firstToken = findTokenFor(first);
|
|
133
|
+
const lastToken = findTokenFor(last);
|
|
134
|
+
|
|
135
|
+
if (!firstToken?.stop || !lastToken?.stop)
|
|
136
|
+
throw new Error(`INTERNAL ERROR: Identifier at ${firstToken?.start} or ${lastToken?.start} has no end! (${filepath})`);
|
|
137
|
+
|
|
138
|
+
const start = firstToken.start + currentOffset;
|
|
139
|
+
const end = lastToken.stop + currentOffset + 1; // end points at the position *before* the character
|
|
140
|
+
|
|
141
|
+
const original = source.substring(start, end);
|
|
142
|
+
if (original.includes('@'))
|
|
143
|
+
return; // we ignore annotation references for now
|
|
144
|
+
|
|
145
|
+
const newSource = `( ${original} )`;
|
|
146
|
+
source = replaceSliceInSource(source, start, end, newSource);
|
|
147
|
+
|
|
148
|
+
currentOffset += (newSource.length - original.length);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Replaces a given span with @p replaceWith
|
|
154
|
+
*
|
|
155
|
+
* @param {string} source
|
|
156
|
+
* @param {number} startIndex
|
|
157
|
+
* @param {number} endIndex
|
|
158
|
+
* @param {string} replaceWith
|
|
159
|
+
* @return {string}
|
|
160
|
+
*/
|
|
161
|
+
function replaceSliceInSource( source, startIndex, endIndex, replaceWith ) {
|
|
162
|
+
return source.substring(0, startIndex) +
|
|
163
|
+
replaceWith +
|
|
164
|
+
source.substring(endIndex);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {string} [msg]
|
|
169
|
+
*/
|
|
170
|
+
function exitError( msg ) {
|
|
171
|
+
if (msg)
|
|
172
|
+
console.error(msg);
|
|
173
|
+
usage();
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function usage() {
|
|
178
|
+
console.error('');
|
|
179
|
+
console.error(`usage: ${path.basename(process.argv[1])} <filename>`);
|
|
180
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
4
3
|
// Update CDS Delimited Identifiers
|
|
5
4
|
//
|
|
6
5
|
// This script replaces the old delimited identifier style with the new one
|
|
@@ -12,11 +11,11 @@
|
|
|
12
11
|
// entity ![My Entity] { ... }
|
|
13
12
|
//
|
|
14
13
|
// Usage:
|
|
15
|
-
// cds_update_identifiers.js my_file.cds
|
|
14
|
+
// ./cds_update_identifiers.js my_file.cds
|
|
16
15
|
//
|
|
17
16
|
// If you want to update all identifiers in a directory, you can use
|
|
18
17
|
// this Shell script:
|
|
19
|
-
// find . -type f -iname '*.cds' -exec cds_update_identifiers.js {} \;
|
|
18
|
+
// find . -type f -iname '*.cds' -exec ./cds_update_identifiers.js {} \;
|
|
20
19
|
//
|
|
21
20
|
// Note that you need to update the path to this script in the commands above.
|
|
22
21
|
//
|
|
@@ -70,7 +69,7 @@ function modernizeIdentifierStyle( source, filename ) {
|
|
|
70
69
|
console.error(msg.toString());
|
|
71
70
|
});
|
|
72
71
|
console.error(`Found ${errors.length} errors! \n`);
|
|
73
|
-
exitError('The parser emitted errors.
|
|
72
|
+
exitError('The CDS parser emitted errors. Fix them first and try again.');
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
let currentOffset = 0;
|
package/bin/cdsc.js
CHANGED
|
@@ -278,6 +278,7 @@ function executeCommandLine( command, options, args ) {
|
|
|
278
278
|
toSql,
|
|
279
279
|
inspect,
|
|
280
280
|
toEffectiveCsn,
|
|
281
|
+
forSeal,
|
|
281
282
|
};
|
|
282
283
|
const commandsWithoutCompilation = {
|
|
283
284
|
explain,
|
|
@@ -318,7 +319,7 @@ function executeCommandLine( command, options, args ) {
|
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
function toEffectiveCsn( model ) {
|
|
321
|
-
const features = [ 'resolveSimpleTypes', 'resolveProjections' ];
|
|
322
|
+
const features = [ 'resolveSimpleTypes', 'resolveProjections', 'remapOdataAnnotations', 'keepLocalized' ];
|
|
322
323
|
for (const feature of features) {
|
|
323
324
|
if (options[feature]) // map to boolean equivalent
|
|
324
325
|
options[feature] = options[feature] === 'true';
|
|
@@ -329,6 +330,18 @@ function executeCommandLine( command, options, args ) {
|
|
|
329
330
|
return model;
|
|
330
331
|
}
|
|
331
332
|
|
|
333
|
+
function forSeal( model ) {
|
|
334
|
+
const features = [ 'remapOdataAnnotations' ];
|
|
335
|
+
for (const feature of features) {
|
|
336
|
+
if (options[feature]) // map to boolean equivalent
|
|
337
|
+
options[feature] = options[feature] === 'true';
|
|
338
|
+
}
|
|
339
|
+
const csn = options.directBackend ? model : compactModel(model, options);
|
|
340
|
+
displayNamedCsn(main.for.seal(csn, options), 'seal');
|
|
341
|
+
|
|
342
|
+
return model;
|
|
343
|
+
}
|
|
344
|
+
|
|
332
345
|
// Execute the command line option 'toCsn' and display the results.
|
|
333
346
|
// Return the original model (for chaining)
|
|
334
347
|
function toCsn( model ) {
|
|
@@ -565,22 +578,12 @@ function executeCommandLine( command, options, args ) {
|
|
|
565
578
|
// Depending on 'options.rawOutput', the model is either compacted to 'name.json' or
|
|
566
579
|
// written in raw form to '<name>_raw.txt'.
|
|
567
580
|
function displayNamedXsn( xsn, name ) {
|
|
568
|
-
if (options.rawOutput)
|
|
581
|
+
if (options.rawOutput)
|
|
569
582
|
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn, options.rawOutput), false, null), true);
|
|
570
|
-
|
|
571
|
-
else if (options.internalMsg) {
|
|
583
|
+
else if (options.internalMsg)
|
|
572
584
|
writeToFileOrDisplay(options.out, `${name}_raw.txt`, util.inspect(reveal(xsn).messages, { depth: null, maxArrayLength: null }), true);
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const csn = compactModel(xsn, options);
|
|
576
|
-
if (command === 'toCsn' && options.tenantDiscriminator)
|
|
577
|
-
addTenantFields(csn, options);
|
|
578
|
-
if (command === 'toCsn' && options.withLocalized)
|
|
579
|
-
addLocalizationViews(csn, options);
|
|
580
|
-
if (options.enrichCsn)
|
|
581
|
-
enrichCsn( csn, options );
|
|
582
|
-
writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
|
|
583
|
-
}
|
|
585
|
+
else if (!options.parseOnly) // no output if parseOnly but not rawOutput
|
|
586
|
+
displayNamedCsn(compactModel(xsn, options), name);
|
|
584
587
|
}
|
|
585
588
|
|
|
586
589
|
/**
|
|
@@ -590,12 +593,22 @@ function executeCommandLine( command, options, args ) {
|
|
|
590
593
|
function displayNamedCsn( csn, name ) {
|
|
591
594
|
if (!csn) // only print CSN if it is set.
|
|
592
595
|
return;
|
|
596
|
+
|
|
597
|
+
if (command === 'toCsn' ) {
|
|
598
|
+
// If requested, run some CSN postprocessing.
|
|
599
|
+
if (options.tenantDiscriminator)
|
|
600
|
+
addTenantFields(csn, options); // always _before_ localized convenience views are added
|
|
601
|
+
if (options.withLocalized)
|
|
602
|
+
addLocalizationViews(csn, options);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (options.enrichCsn)
|
|
606
|
+
enrichCsn( csn, options );
|
|
607
|
+
|
|
593
608
|
if (options.internalMsg) {
|
|
594
609
|
writeToFileOrDisplay(options.out, `${name}_raw.txt`, options.messages, true);
|
|
595
610
|
}
|
|
596
611
|
else if (!options.internalMsg) {
|
|
597
|
-
if (command === 'toCsn' && options.withLocalized)
|
|
598
|
-
addLocalizationViews(csn, options);
|
|
599
612
|
writeToFileOrDisplay(options.out, `${name}.json`, csn, true);
|
|
600
613
|
}
|
|
601
614
|
}
|
package/doc/CHANGELOG_BETA.md
CHANGED
|
@@ -8,6 +8,25 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
|
|
|
8
8
|
The compiler behavior concerning `beta` features can change at any time without notice.
|
|
9
9
|
**Don't use `beta` fixes, changes and features in productive mode.**
|
|
10
10
|
|
|
11
|
+
## Version 4.9.0 - 2024-04-25
|
|
12
|
+
|
|
13
|
+
## Removed `odataAnnotationExpressions`
|
|
14
|
+
|
|
15
|
+
It is now enabled by default.
|
|
16
|
+
|
|
17
|
+
## Removed `odataPathsInAnnotationExpressions`
|
|
18
|
+
|
|
19
|
+
It is now enabled by default.
|
|
20
|
+
|
|
21
|
+
## Removed `annotationExpressions`
|
|
22
|
+
|
|
23
|
+
It is now enabled by default.
|
|
24
|
+
|
|
25
|
+
## Added `temporalRawProjection`
|
|
26
|
+
|
|
27
|
+
Enables revocation of temporal where clause in projections of temporal entities if the
|
|
28
|
+
`@cds.valid { from, to }` annotations on the projection elements have falsy values.
|
|
29
|
+
|
|
11
30
|
## Version 4.8.0 - 2024-03-21
|
|
12
31
|
|
|
13
32
|
### Removed `vectorType`
|