@sap/cds-compiler 2.12.0 → 2.13.6
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 +110 -15
- package/bin/cdsc.js +13 -13
- package/bin/cdsse.js +2 -2
- package/doc/CHANGELOG_BETA.md +13 -6
- package/doc/CHANGELOG_DEPRECATED.md +22 -6
- package/doc/NameResolution.md +21 -16
- package/lib/api/main.js +28 -63
- package/lib/api/options.js +3 -3
- package/lib/api/validate.js +0 -5
- package/lib/backends.js +15 -23
- package/lib/base/dictionaries.js +0 -8
- package/lib/base/error.js +26 -0
- package/lib/base/keywords.js +7 -17
- package/lib/base/location.js +9 -4
- package/lib/base/message-registry.js +25 -4
- package/lib/base/messages.js +16 -26
- package/lib/base/model.js +2 -63
- package/lib/base/optionProcessorHelper.js +158 -123
- package/lib/checks/annotationsOData.js +1 -1
- package/lib/checks/cdsPersistence.js +2 -1
- package/lib/checks/enricher.js +17 -1
- package/lib/checks/invalidTarget.js +3 -1
- package/lib/checks/managedWithoutKeys.js +3 -1
- package/lib/checks/selectItems.js +4 -4
- package/lib/checks/sql-snippets.js +27 -26
- package/lib/checks/types.js +1 -1
- package/lib/checks/validator.js +4 -7
- package/lib/compiler/assert-consistency.js +5 -3
- package/lib/compiler/builtins.js +8 -6
- package/lib/compiler/checks.js +14 -3
- package/lib/compiler/cycle-detector.js +1 -1
- package/lib/compiler/define.js +1103 -0
- package/lib/compiler/extend.js +983 -0
- package/lib/compiler/finalize-parse-cdl.js +231 -0
- package/lib/compiler/index.js +32 -13
- package/lib/compiler/kick-start.js +190 -0
- package/lib/compiler/moduleLayers.js +4 -4
- package/lib/compiler/populate.js +1226 -0
- package/lib/compiler/propagator.js +111 -46
- package/lib/compiler/resolve.js +1433 -0
- package/lib/compiler/shared.js +64 -37
- package/lib/compiler/tweak-assocs.js +529 -0
- package/lib/compiler/utils.js +197 -33
- package/lib/edm/.eslintrc.json +5 -0
- package/lib/edm/annotations/genericTranslation.js +5 -9
- package/lib/edm/annotations/preprocessAnnotations.js +2 -2
- package/lib/edm/csn2edm.js +9 -8
- package/lib/edm/edm.js +11 -12
- package/lib/edm/edmPreprocessor.js +137 -73
- package/lib/edm/edmUtils.js +116 -22
- package/lib/gen/Dictionary.json +10 -3
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +9 -1
- package/lib/gen/language.tokens +86 -83
- package/lib/gen/languageLexer.interp +10 -1
- package/lib/gen/languageLexer.js +860 -833
- package/lib/gen/languageLexer.tokens +78 -75
- package/lib/gen/languageParser.js +5282 -4265
- package/lib/json/from-csn.js +12 -1
- package/lib/json/to-csn.js +126 -66
- package/lib/language/docCommentParser.js +2 -2
- package/lib/language/genericAntlrParser.js +76 -3
- package/lib/language/language.g4 +297 -130
- package/lib/language/multiLineStringParser.js +5 -5
- package/lib/main.d.ts +468 -59
- package/lib/main.js +35 -9
- package/lib/model/api.js +3 -1
- package/lib/model/csnRefs.js +225 -156
- package/lib/model/csnUtils.js +192 -223
- package/lib/model/enrichCsn.js +70 -29
- package/lib/model/revealInternalProperties.js +27 -6
- package/lib/model/sortViews.js +2 -1
- package/lib/modelCompare/compare.js +17 -12
- package/lib/optionProcessor.js +5 -4
- package/lib/render/manageConstraints.js +35 -32
- package/lib/render/toCdl.js +73 -288
- package/lib/render/toHdbcds.js +25 -23
- package/lib/render/toSql.js +98 -41
- package/lib/render/utils/common.js +5 -10
- package/lib/render/utils/sql.js +4 -3
- package/lib/render/utils/stringEscapes.js +111 -0
- package/lib/sql-identifier.js +1 -1
- package/lib/transform/.eslintrc.json +5 -0
- package/lib/transform/db/.eslintrc.json +2 -0
- package/lib/transform/db/applyTransformations.js +35 -12
- package/lib/transform/db/assertUnique.js +1 -1
- package/lib/transform/db/associations.js +103 -305
- package/lib/transform/db/cdsPersistence.js +2 -2
- package/lib/transform/db/constraints.js +55 -52
- package/lib/transform/db/expansion.js +46 -24
- package/lib/transform/db/flattening.js +553 -102
- package/lib/transform/db/groupByOrderBy.js +3 -1
- package/lib/transform/db/transformExists.js +59 -6
- package/lib/transform/db/views.js +5 -4
- package/lib/transform/draft/.eslintrc.json +38 -0
- package/lib/transform/{db/draft.js → draft/db.js} +6 -5
- package/lib/transform/draft/odata.js +227 -0
- package/lib/transform/forHanaNew.js +67 -183
- package/lib/transform/forOdataNew.js +17 -171
- package/lib/transform/localized.js +34 -19
- package/lib/transform/odata/generateForeignKeyElements.js +1 -1
- package/lib/transform/odata/referenceFlattener.js +95 -89
- package/lib/transform/odata/structureFlattener.js +1 -1
- package/lib/transform/odata/toFinalBaseType.js +86 -12
- package/lib/transform/odata/typesExposure.js +5 -5
- package/lib/transform/odata/utils.js +2 -2
- package/lib/transform/transformUtilsNew.js +36 -22
- package/lib/transform/translateAssocsToJoins.js +2 -19
- package/lib/transform/universalCsn/.eslintrc.json +36 -0
- package/lib/transform/universalCsn/coreComputed.js +170 -0
- package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
- package/lib/transform/universalCsn/utils.js +63 -0
- package/lib/utils/objectUtils.js +30 -0
- package/package.json +1 -1
- package/share/messages/README.md +26 -0
- package/lib/compiler/definer.js +0 -2361
- package/lib/compiler/resolver.js +0 -3079
- package/lib/transform/universalCsnEnricher.js +0 -237
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const controlCharacters = /[\u{0000}-\u{001F}]/u;
|
|
4
|
+
const highSurrogate = /[\u{D800}-\u{DBFF}]/u;
|
|
5
|
+
const lowSurrogate = /[\u{DC00}-\u{DFFF}]/u;
|
|
6
|
+
// Either a high surrogate that is NOT followed by a low one or
|
|
7
|
+
// a low surrogate not preceded by a high one.
|
|
8
|
+
const unpairedSurrogate = /[^\u{D800}-\u{DBFF}][\u{DC00}-\u{DFFF}]|[\u{D800}-\u{DBFF}][^\u{DC00}-\u{DFFF}]/u;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns true if the string contains an unpaired unicode surrogate.
|
|
12
|
+
* See <https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF>.
|
|
13
|
+
* As a surrogate pair MUST consist of a high one followed by a low surrogate,
|
|
14
|
+
* an unpaired surrogate MUST be escaped.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} str
|
|
17
|
+
* @return {boolean}
|
|
18
|
+
*/
|
|
19
|
+
function hasUnpairedUnicodeSurrogate(str) {
|
|
20
|
+
return unpairedSurrogate.test(str);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns true if the string contains control characters such as LF or NUL.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} str
|
|
27
|
+
* @return {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function hasControlCharacters(str) {
|
|
30
|
+
return controlCharacters.test(str);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Escape the given string according to the given specification in `escapes`.
|
|
35
|
+
*
|
|
36
|
+
* `escapes` is an object where the entries are either:
|
|
37
|
+
* - a mapping from character to string, e.g. `{ '"': '"' }`
|
|
38
|
+
* - `control: (codePoint) => str`
|
|
39
|
+
* A function that returns an escape sequence for the given control character.
|
|
40
|
+
* - `unpairedSurrogate: (codePoint) => str`
|
|
41
|
+
* A function that returns an escape sequence for the given unpaired unicode surrogate.
|
|
42
|
+
*
|
|
43
|
+
* Multi-character keys are not allowed.
|
|
44
|
+
*
|
|
45
|
+
* Character escapes take precedence over `control` and `unpairedSurrogate` escapes,
|
|
46
|
+
* i.e. if you do not want to encode LF (`\n`), add an explicit mapping for it, e.g.
|
|
47
|
+
* `{ '\n': '\n' }`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* You can use `escapeString()` like this:
|
|
51
|
+
* ```js
|
|
52
|
+
* let escaped = escapeString(str, {
|
|
53
|
+
* '"': '\\"',
|
|
54
|
+
* control: (c) => `\\u{${c.toString(16)}}`;
|
|
55
|
+
* unpairedSurrogate: (c) => `\\u{${c.toString(16)}}`;
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @param {string} str
|
|
60
|
+
* @param {object} escapes
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
function escapeString(str, escapes) {
|
|
64
|
+
const output = [];
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < str.length; ++i) {
|
|
67
|
+
const char = str[i];
|
|
68
|
+
|
|
69
|
+
if (char in escapes) {
|
|
70
|
+
output.push(escapes[char]);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Control Characters: C0
|
|
75
|
+
// See <https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Basic_ASCII_control_codes>
|
|
76
|
+
if (controlCharacters.test(char)) {
|
|
77
|
+
output.push(escapes.control ? escapes.control(char.codePointAt(0)) : char);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Unicode Surrogates
|
|
82
|
+
// These characters appear in _pairs_. A high surrogate must be followed by a low surrogate.
|
|
83
|
+
// If this is not the case, either needs to be encoded. This is also done by JSON.
|
|
84
|
+
// See also <https://docs.microsoft.com/en-us/globalization/encoding/surrogate-pairs>
|
|
85
|
+
if (highSurrogate.test(char)) {
|
|
86
|
+
if (i + 1 >= str.length || !lowSurrogate.test(str[i + 1])) {
|
|
87
|
+
output.push(escapes.unpairedSurrogate ? escapes.unpairedSurrogate(char.codePointAt(0)) : char);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
output.push(char);
|
|
91
|
+
++i;
|
|
92
|
+
output.push(str[i]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (lowSurrogate.test(char)) {
|
|
96
|
+
output.push(escapes.unpairedSurrogate ? escapes.unpairedSurrogate(char.codePointAt(0)) : char);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// unhandled / non-special character
|
|
100
|
+
output.push(char);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return output.join('');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = {
|
|
108
|
+
escapeString,
|
|
109
|
+
hasUnpairedUnicodeSurrogate,
|
|
110
|
+
hasControlCharacters,
|
|
111
|
+
};
|
package/lib/sql-identifier.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// an identifier such that the effective name (the one in the DB schema) is
|
|
10
10
|
// the same as the name used in CDS.
|
|
11
11
|
// - 'quoted' and 'hdbcds' for HANA only: similar to the non-provided previous
|
|
12
|
-
// mode, with different
|
|
12
|
+
// mode, with different adaptations to HANA CDS and XS (classic) restrictions.
|
|
13
13
|
|
|
14
14
|
// The main objective of this file is to support the 'plain' mode in a “smart”
|
|
15
15
|
// manner. If we would use the CDS name (after `.` to `_` replacements)
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
// Don't enforce stupid descriptions
|
|
14
14
|
"jsdoc/require-param-description": "off",
|
|
15
15
|
"jsdoc/require-returns-description": "off",
|
|
16
|
+
// Sometimes if-else's are more specific
|
|
17
|
+
"sonarjs/prefer-single-boolean-return": "off",
|
|
16
18
|
// Very whiny and nitpicky
|
|
17
19
|
"sonarjs/cognitive-complexity": "off",
|
|
18
20
|
// Does not recognize TS types
|
|
@@ -18,12 +18,11 @@ const { setProp } = require('../../base/model');
|
|
|
18
18
|
* @param {string} prop The property of parent to start at
|
|
19
19
|
* @param {object} customTransformers Map of prop to transform and function to apply
|
|
20
20
|
* @param {Function[]} [artifactTransformers=[]] Transformations to run on the artifacts, like forEachDefinition
|
|
21
|
-
* @param {
|
|
22
|
-
* @param {object} [options={}] "skipArtifact": (artifact, name) => Boolean to skip certain artifacts, drillRef: boolean - whether to drill into infix/args
|
|
21
|
+
* @param {applyTransformationsOptions} [options={}]
|
|
23
22
|
* @param {CSN.Path} path Path to parent
|
|
24
23
|
* @returns {object} parent with transformations applied
|
|
25
24
|
*/
|
|
26
|
-
function applyTransformationsInternal(parent, prop, customTransformers, artifactTransformers,
|
|
25
|
+
function applyTransformationsInternal(parent, prop, customTransformers, artifactTransformers, options, path = []) {
|
|
27
26
|
const transformers = {
|
|
28
27
|
elements: dictionary,
|
|
29
28
|
definitions: dictionary,
|
|
@@ -32,6 +31,7 @@ function applyTransformationsInternal(parent, prop, customTransformers, artifact
|
|
|
32
31
|
enum: dictionary,
|
|
33
32
|
mixin: dictionary,
|
|
34
33
|
ref: pathRef,
|
|
34
|
+
$origin: () => {}, // no-op
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const csnPath = [ ...path ];
|
|
@@ -50,7 +50,12 @@ function applyTransformationsInternal(parent, prop, customTransformers, artifact
|
|
|
50
50
|
* @param {object} node The value of node[_prop]
|
|
51
51
|
*/
|
|
52
52
|
function standard( _parent, _prop, node ) {
|
|
53
|
-
if (!node || typeof node !== 'object' ||
|
|
53
|
+
if (!node || typeof node !== 'object' ||
|
|
54
|
+
!{}.propertyIsEnumerable.call( _parent, _prop ) ||
|
|
55
|
+
(typeof _prop === 'string' && _prop.startsWith('@')) ||
|
|
56
|
+
(options.skipIgnore && node._ignore) ||
|
|
57
|
+
(options.skipStandard && options.skipStandard[_prop])
|
|
58
|
+
)
|
|
54
59
|
return;
|
|
55
60
|
|
|
56
61
|
csnPath.push( _prop );
|
|
@@ -80,7 +85,7 @@ function applyTransformationsInternal(parent, prop, customTransformers, artifact
|
|
|
80
85
|
*/
|
|
81
86
|
function dictionary( node, _prop, dict ) {
|
|
82
87
|
// Allow skipping dicts like actions in forHanaNew
|
|
83
|
-
if (options.skipDict && options.skipDict[_prop])
|
|
88
|
+
if (options.skipDict && options.skipDict[_prop] || dict === null || dict === undefined) // with universal CSN, dicts might be null
|
|
84
89
|
return;
|
|
85
90
|
csnPath.push( _prop );
|
|
86
91
|
for (const name of Object.getOwnPropertyNames( dict ))
|
|
@@ -101,7 +106,10 @@ function applyTransformationsInternal(parent, prop, customTransformers, artifact
|
|
|
101
106
|
function definitions( node, _prop, dict ) {
|
|
102
107
|
csnPath.push( _prop );
|
|
103
108
|
for (const name of Object.getOwnPropertyNames( dict )) {
|
|
104
|
-
const skip = options && options.
|
|
109
|
+
const skip = (options && options.allowArtifact && !options.allowArtifact(dict[name], name)) ||
|
|
110
|
+
(options && options.skipArtifact && options.skipArtifact(dict[name], name)) ||
|
|
111
|
+
(options && options.skip && options.skip.includes(dict[name].kind)) ||
|
|
112
|
+
false;
|
|
105
113
|
if (!skip) {
|
|
106
114
|
artifactTransformers.forEach(fn => fn(dict, name, dict[name]));
|
|
107
115
|
standard( dict, name, dict[name] );
|
|
@@ -152,13 +160,15 @@ function applyTransformationsInternal(parent, prop, customTransformers, artifact
|
|
|
152
160
|
* @param {object} csn CSN to enrich in-place
|
|
153
161
|
* @param {object} customTransformers Map of _prop to transform and function to apply
|
|
154
162
|
* @param {Function[]} [artifactTransformers=[]] Transformations to run on the artifacts, like forEachDefinition
|
|
155
|
-
* @param {
|
|
156
|
-
* @param {object} [options={}] "skipArtifact": (artifact, name) => Boolean to skip certain artifacts, drillRef: boolean - whether to drill into infix/args
|
|
163
|
+
* @param {applyTransformationsOptions} [options={}]
|
|
157
164
|
* @returns {object} CSN with transformations applied
|
|
158
165
|
*/
|
|
159
|
-
function applyTransformations( csn, customTransformers = {}, artifactTransformers = [],
|
|
166
|
+
function applyTransformations( csn, customTransformers = {}, artifactTransformers = [], options = { } ) {
|
|
167
|
+
if (options.skipIgnore === undefined)
|
|
168
|
+
options.skipIgnore = true;
|
|
169
|
+
|
|
160
170
|
if (csn && csn.definitions)
|
|
161
|
-
return applyTransformationsInternal(csn, 'definitions', customTransformers, artifactTransformers,
|
|
171
|
+
return applyTransformationsInternal(csn, 'definitions', customTransformers, artifactTransformers, options);
|
|
162
172
|
return csn;
|
|
163
173
|
}
|
|
164
174
|
|
|
@@ -176,14 +186,27 @@ function applyTransformations( csn, customTransformers = {}, artifactTransformer
|
|
|
176
186
|
* @param {object} parent The "parent" of which we transform a property of
|
|
177
187
|
* @param {string} prop The property of parent to start at
|
|
178
188
|
* @param {object} customTransformers Map of prop to transform and function to apply
|
|
189
|
+
* @param {applyTransformationsOptions} [options={}]
|
|
179
190
|
* @param {CSN.Path} path Path pointing to parent
|
|
180
191
|
* @returns {object} parent[prop] with transformations applied
|
|
181
192
|
*/
|
|
182
|
-
function applyTransformationsOnNonDictionary(parent, prop, customTransformers = {}, path = []) {
|
|
183
|
-
return applyTransformationsInternal(parent, prop, customTransformers, [],
|
|
193
|
+
function applyTransformationsOnNonDictionary(parent, prop, customTransformers = {}, options = {}, path = []) {
|
|
194
|
+
return applyTransformationsInternal(parent, prop, customTransformers, [], options, path)[prop];
|
|
184
195
|
}
|
|
185
196
|
|
|
186
197
|
module.exports = {
|
|
187
198
|
applyTransformations,
|
|
188
199
|
applyTransformationsOnNonDictionary,
|
|
189
200
|
};
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @typedef {object} applyTransformationsOptions
|
|
205
|
+
* @property {(artifact, name) => boolean} [allowArtifact] to only allow certain artifacts
|
|
206
|
+
* @property {(artifact, name) => boolean} [skipArtifact] to skip certain artifacts
|
|
207
|
+
* @property {boolean} [drillRef] whether to drill into infix/args
|
|
208
|
+
* @property {string[]} [skip] skip definitions from certain kind
|
|
209
|
+
* @property {object} [skipStandard] stop drill-down on certain "standard" props
|
|
210
|
+
* @property {object} [skipDict] stop drill-down on certain "dictionary" props
|
|
211
|
+
* @property {boolean} [skipIgnore=true] Whether to skip _ignore elements or not
|
|
212
|
+
*/
|
|
@@ -158,7 +158,7 @@ function processAssertUnique(csn, options, error, info) {
|
|
|
158
158
|
function toRef(val) {
|
|
159
159
|
let ref = val.split('.');
|
|
160
160
|
const [ head, ...tail ] = ref;
|
|
161
|
-
if (
|
|
161
|
+
if (head === '$self' || head === '$projection')
|
|
162
162
|
ref = tail;
|
|
163
163
|
return {
|
|
164
164
|
ref: ref.map((ps) => {
|