@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
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// cds-compiler Inspect Module
|
|
2
|
+
// Used by `cdsc inspect` to gather details about the model such as statistics, etc.
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const { inspectModelStatistics } = require('./inspectModelStatistics');
|
|
7
|
+
const { inspectPropagation } = require('./inspectPropagation');
|
|
8
|
+
const { stringRefToPath } = require('./inspectUtils');
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
inspectModelStatistics,
|
|
12
|
+
inspectPropagation,
|
|
13
|
+
stringRefToPath,
|
|
14
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { forEach } = require('../utils/objectUtils');
|
|
4
|
+
const { term } = require('../utils/term');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Return a string representation of the inspected results.
|
|
8
|
+
*
|
|
9
|
+
* @param {XSN.Model} xsn
|
|
10
|
+
* @param {CSN.Options} options
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
function inspectModelStatistics(xsn, options) {
|
|
14
|
+
let result = '';
|
|
15
|
+
|
|
16
|
+
// Default color mode is 'auto'
|
|
17
|
+
const color = term(options.color || 'auto');
|
|
18
|
+
|
|
19
|
+
const defCount = countDefinitionKinds(xsn);
|
|
20
|
+
const sources = {
|
|
21
|
+
cdl: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'cdl').length,
|
|
22
|
+
csn: Object.keys(xsn.sources).filter(name => xsn.sources[name].$frontend === 'csn').length,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
result += `cds-compiler model statistics:
|
|
26
|
+
|
|
27
|
+
${ color.underline('files') }: ${ Object.keys(xsn.sources).length }
|
|
28
|
+
cdl sources: ${ sources.cdl }
|
|
29
|
+
csn sources: ${ sources.csn }
|
|
30
|
+
|
|
31
|
+
${ color.underline('definitions') }: ${ defCount.definitions }
|
|
32
|
+
entities: ${ defCount.entity }
|
|
33
|
+
queries: ${ defCount.view }
|
|
34
|
+
aspects: ${ defCount.aspect }
|
|
35
|
+
events: ${ defCount.event }
|
|
36
|
+
types: ${ defCount.type }
|
|
37
|
+
services: ${ defCount.service }
|
|
38
|
+
context: ${ defCount.context }
|
|
39
|
+
actions: ${ defCount.action }
|
|
40
|
+
functions: ${ defCount.function }
|
|
41
|
+
namespaces: ${ defCount.namespace } (explicitly in CDL)
|
|
42
|
+
|
|
43
|
+
${ color.underline('vocabularies') }: ${ Object.keys(xsn.vocabularies || {}).length }
|
|
44
|
+
`;
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function countDefinitionKinds(xsn) {
|
|
49
|
+
const result = {
|
|
50
|
+
definitions: 0,
|
|
51
|
+
entity: 0,
|
|
52
|
+
action: 0,
|
|
53
|
+
function: 0,
|
|
54
|
+
aspect: 0,
|
|
55
|
+
event: 0,
|
|
56
|
+
type: 0,
|
|
57
|
+
service: 0,
|
|
58
|
+
context: 0,
|
|
59
|
+
namespace: 0,
|
|
60
|
+
// non-kind
|
|
61
|
+
view: 0,
|
|
62
|
+
};
|
|
63
|
+
forEach(xsn.definitions || {}, (name, def) => {
|
|
64
|
+
if (def.builtin)
|
|
65
|
+
return;
|
|
66
|
+
++result.definitions;
|
|
67
|
+
|
|
68
|
+
if (def.query || def.projection)
|
|
69
|
+
++result.view;
|
|
70
|
+
else if (result[def.kind] !== undefined)
|
|
71
|
+
++result[def.kind];
|
|
72
|
+
else
|
|
73
|
+
throw new Error(`Unhandled kind: ${ def.kind } for ${ name }`);
|
|
74
|
+
});
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
inspectModelStatistics,
|
|
81
|
+
};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { createMessageFunctions } = require('../base/messages');
|
|
4
|
+
const { locationString } = require('../base/location');
|
|
5
|
+
const { findArtifact, stringRefToPath } = require('./inspectUtils');
|
|
6
|
+
const { term } = require('../utils/term');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {XSN.Model} xsn
|
|
10
|
+
* @param {CSN.Options} options
|
|
11
|
+
* @param {string} artifactName
|
|
12
|
+
* @returns {string|null}
|
|
13
|
+
*/
|
|
14
|
+
function inspectPropagation(xsn, options, artifactName) {
|
|
15
|
+
const { error } = createMessageFunctions(options, 'inspect', xsn);
|
|
16
|
+
const result = [];
|
|
17
|
+
|
|
18
|
+
// Default color mode is 'auto'
|
|
19
|
+
const color = term(options.color || 'auto');
|
|
20
|
+
|
|
21
|
+
const path = stringRefToPath(artifactName);
|
|
22
|
+
if (!path) {
|
|
23
|
+
error(null, null, { name: artifactName },
|
|
24
|
+
'Artifact $(NAME) is not a valid path; expected format `<def>[:element]`');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const artifactXsn = findArtifact(xsn, path);
|
|
29
|
+
|
|
30
|
+
if (!artifactXsn) {
|
|
31
|
+
error(null, null, { name: artifactName },
|
|
32
|
+
// eslint-disable-next-line max-len
|
|
33
|
+
'Artifact $(NAME) not found, only top-level artifacts and their elements are supported for now');
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
result.push(color.underline('analyzing propagation for artifact:'));
|
|
37
|
+
result.push(` name: ${ artifactXsn.name.id }`);
|
|
38
|
+
result.push(` kind: ${ artifactXsn.kind }`);
|
|
39
|
+
|
|
40
|
+
if (artifactXsn.$inferred)
|
|
41
|
+
result.push(` inferred: ${ artifactXsn.$inferred }`);
|
|
42
|
+
|
|
43
|
+
result.push('');
|
|
44
|
+
result.push(` ${ color.underline('annotation propagation:') }`);
|
|
45
|
+
result.push(..._indent(_inspectAnnotations(artifactXsn)));
|
|
46
|
+
|
|
47
|
+
result.push('');
|
|
48
|
+
result.push(` ${ color.underline('element propagation:') }`);
|
|
49
|
+
result.push(..._indent(_inspectElements(artifactXsn)));
|
|
50
|
+
|
|
51
|
+
return result.join('\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
@param {string[]} lines
|
|
56
|
+
@param {string} indent
|
|
57
|
+
* @returns {string[]}
|
|
58
|
+
*/
|
|
59
|
+
function _indent(lines, indent = ' ') {
|
|
60
|
+
return lines.map(str => `${ indent }${ str }`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {XSN.Artifact} artifactXsn
|
|
65
|
+
* @returns {string[]}
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
68
|
+
function _inspectAnnotations(artifactXsn) {
|
|
69
|
+
const result = [];
|
|
70
|
+
const annos = Object.keys(artifactXsn).filter(str => str.startsWith('@')).sort();
|
|
71
|
+
|
|
72
|
+
if (annos.length === 0)
|
|
73
|
+
return [ 'no annotations' ];
|
|
74
|
+
|
|
75
|
+
let maxAnnoLength = 30; // chosen arbitrarily, hopefully average
|
|
76
|
+
for (const anno of annos) {
|
|
77
|
+
const annoXsn = artifactXsn[anno];
|
|
78
|
+
const loc = locationString(annoXsn.name.location);
|
|
79
|
+
let origin;
|
|
80
|
+
switch (annoXsn.$priority) {
|
|
81
|
+
case false:
|
|
82
|
+
if (annoXsn.$inferred)
|
|
83
|
+
origin = 'propagation';
|
|
84
|
+
else
|
|
85
|
+
origin = 'direct';
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'extend':
|
|
89
|
+
case 'annotate':
|
|
90
|
+
origin = annoXsn.$priority;
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
case undefined:
|
|
94
|
+
if (annoXsn.$inferred === '$generated') {
|
|
95
|
+
origin = 'generated';
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
// fallthrough
|
|
99
|
+
default:
|
|
100
|
+
throw new Error(`inspect anno: Unhandled Case: ${ annoXsn.$priority }`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
maxAnnoLength = Math.max(maxAnnoLength, anno.length);
|
|
104
|
+
|
|
105
|
+
// origin: assume max length 11 of 'propagation'
|
|
106
|
+
// anno: use max length of all annotations till now
|
|
107
|
+
result.push([ origin.padStart(11), anno.padEnd(maxAnnoLength), loc ].join(' | '));
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @param {XSN.Artifact} artifactXsn
|
|
114
|
+
* @returns {string[]}
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
function _inspectElements(artifactXsn) {
|
|
118
|
+
if (!artifactXsn.elements)
|
|
119
|
+
return [ 'does not have elements' ];
|
|
120
|
+
|
|
121
|
+
const result = [];
|
|
122
|
+
const elements = Object.keys(artifactXsn.elements);
|
|
123
|
+
|
|
124
|
+
let maxElemLength = 12;
|
|
125
|
+
|
|
126
|
+
const inferredNiceOutput = {
|
|
127
|
+
'*': 'wildcard',
|
|
128
|
+
'expand-element': 'expanded',
|
|
129
|
+
'expand-param': 'expanded',
|
|
130
|
+
'aspect-composition': 'composition',
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
for (const element of elements) {
|
|
134
|
+
const elementXsn = artifactXsn.elements[element];
|
|
135
|
+
const loc = locationString(_origin(elementXsn).name.location);
|
|
136
|
+
let origin;
|
|
137
|
+
|
|
138
|
+
if (elementXsn.$inferred) {
|
|
139
|
+
// Use nice(r) output for known $inferred
|
|
140
|
+
if (inferredNiceOutput[elementXsn.$inferred])
|
|
141
|
+
origin = inferredNiceOutput[elementXsn.$inferred];
|
|
142
|
+
else
|
|
143
|
+
origin = elementXsn.$inferred;
|
|
144
|
+
}
|
|
145
|
+
else if (!isContainedInParentLocation(elementXsn, artifactXsn)) {
|
|
146
|
+
// just a heuristic
|
|
147
|
+
origin = 'extend';
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
origin = 'direct';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
maxElemLength = Math.max(maxElemLength, element.length);
|
|
154
|
+
|
|
155
|
+
// origin: assume max length 11 of 'composition'
|
|
156
|
+
// element: assume average length of 30, chosen randomly
|
|
157
|
+
result.push([ origin.padStart(11), element.padEnd(maxElemLength), loc ].join(' | '));
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function _origin(elementXsn) {
|
|
163
|
+
while (elementXsn._origin)
|
|
164
|
+
elementXsn = elementXsn._origin;
|
|
165
|
+
return elementXsn;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Returns true if `art` is contained in `parent` according to its location.
|
|
170
|
+
*
|
|
171
|
+
* @param art
|
|
172
|
+
* @param parent
|
|
173
|
+
* @returns {boolean}
|
|
174
|
+
*/
|
|
175
|
+
function isContainedInParentLocation(art, parent) {
|
|
176
|
+
const artLoc = art.location;
|
|
177
|
+
const parentLoc = parent.location;
|
|
178
|
+
if (artLoc.file !== parentLoc.file)
|
|
179
|
+
return false;
|
|
180
|
+
if (artLoc.line < parentLoc.line || artLoc.line > parentLoc.endLine)
|
|
181
|
+
return false;
|
|
182
|
+
// Good enough for now
|
|
183
|
+
// TODO: Check columns
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
module.exports = {
|
|
188
|
+
inspectPropagation,
|
|
189
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reference (string) to path (array) that can be used to identify an artifact
|
|
5
|
+
* @param str
|
|
6
|
+
* @returns {*[]|*}
|
|
7
|
+
*/
|
|
8
|
+
function stringRefToPath(str) {
|
|
9
|
+
// e.g. `ns.service.E:sub.elem.structured`
|
|
10
|
+
const path = str.split(':');
|
|
11
|
+
if (path.length === 1)
|
|
12
|
+
return path;
|
|
13
|
+
if (path.length > 2)
|
|
14
|
+
return null;
|
|
15
|
+
return [ path[0], ...path[1].split('.') ];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {XSN.Model} xsn
|
|
20
|
+
* @param {string} path
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
function findArtifact(xsn, path) {
|
|
24
|
+
const segments = [ ...path ];
|
|
25
|
+
const topLevelName = segments[0];
|
|
26
|
+
let art = (xsn.definitions && xsn.definitions[topLevelName]) ||
|
|
27
|
+
(xsn.vocabularies && xsn.vocabularies[topLevelName]);
|
|
28
|
+
if (!art)
|
|
29
|
+
return null;
|
|
30
|
+
segments.shift();
|
|
31
|
+
if (segments.length === 0)
|
|
32
|
+
return art;
|
|
33
|
+
while (segments.length && art) {
|
|
34
|
+
const segment = segments.shift();
|
|
35
|
+
art = (art.items?.elements || art.elements)?.[segment];
|
|
36
|
+
}
|
|
37
|
+
return art || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
stringRefToPath,
|
|
43
|
+
findArtifact,
|
|
44
|
+
};
|