@sap/cds-compiler 5.6.0 → 5.7.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 -0
- package/bin/cdsse.js +1 -0
- package/bin/cdsv2m.js +2 -1
- package/doc/Versioning.md +4 -4
- package/lib/api/options.js +1 -0
- package/lib/base/builtins.js +2 -2
- package/lib/base/dictionaries.js +1 -2
- package/lib/base/keywords.js +3 -1
- package/lib/base/lazyload.js +1 -1
- package/lib/base/message-registry.js +169 -144
- package/lib/base/messages.js +69 -59
- package/lib/base/model.js +3 -3
- package/lib/base/node-helpers.js +17 -16
- package/lib/base/optionProcessorHelper.js +13 -14
- package/lib/base/shuffle.js +4 -1
- package/lib/checks/structuredAnnoExpressions.js +1 -1
- package/lib/compiler/assert-consistency.js +1 -1
- package/lib/compiler/builtins.js +2 -1
- package/lib/compiler/extend.js +20 -5
- package/lib/compiler/resolve.js +45 -9
- package/lib/compiler/shared.js +1 -0
- package/lib/edm/annotations/edmJson.js +3 -3
- package/lib/edm/annotations/genericTranslation.js +5 -1
- package/lib/edm/annotations/vocabularyDefinitions.js +2 -2
- package/lib/edm/edmUtils.js +2 -1
- package/lib/gen/BaseParser.js +32 -32
- package/lib/gen/CdlParser.js +1526 -1488
- package/lib/json/from-csn.js +2 -0
- package/lib/json/to-csn.js +13 -4
- package/lib/language/docCommentParser.js +11 -5
- package/lib/language/errorStrategy.js +3 -3
- package/lib/language/genericAntlrParser.js +2 -0
- package/lib/model/csnUtils.js +6 -1
- package/lib/optionProcessor.js +5 -1
- package/lib/parsers/AstBuildingParser.js +161 -73
- package/lib/parsers/CdlGrammar.g4 +129 -85
- package/lib/parsers/Lexer.js +5 -3
- package/lib/parsers/index.js +1 -1
- package/lib/render/toCdl.js +6 -5
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +5 -3
- package/lib/render/utils/common.js +19 -6
- package/lib/render/utils/delta.js +1 -3
- package/lib/render/utils/standardDatabaseFunctions.js +576 -0
- package/lib/transform/addTenantFields.js +2 -1
- package/lib/transform/db/flattening.js +18 -77
- package/lib/transform/db/groupByOrderBy.js +2 -2
- package/lib/transform/db/rewriteCalculatedElements.js +14 -19
- package/lib/transform/db/temporal.js +2 -1
- package/lib/transform/odata/adaptAnnotationRefs.js +79 -0
- package/lib/transform/odata/createForeignKeys.js +4 -71
- package/lib/transform/odata/flattening.js +11 -1
- package/lib/transform/transformUtils.js +20 -85
- package/package.json +2 -1
- package/bin/cds_update_annotations.js +0 -180
|
@@ -1,180 +0,0 @@
|
|
|
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 parsers = require('../lib/parsers');
|
|
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
|
-
// parseCdl does not throw on CompilationError, so
|
|
62
|
-
// we do not need a try...catch block.
|
|
63
|
-
const ast = parsers.parseCdl(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
|
-
}
|