@sap/cds-compiler 3.3.2 → 3.4.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 +33 -0
- package/bin/cdsc.js +3 -1
- package/doc/CHANGELOG_BETA.md +17 -0
- package/lib/api/main.js +147 -18
- package/lib/api/validate.js +8 -3
- package/lib/base/dictionaries.js +6 -6
- package/lib/base/keywords.js +104 -0
- package/lib/base/message-registry.js +137 -68
- package/lib/base/messages.js +59 -48
- package/lib/base/model.js +1 -0
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +13 -8
- package/lib/checks/defaultValues.js +3 -1
- package/lib/checks/elements.js +1 -1
- package/lib/checks/parameters.js +4 -2
- package/lib/checks/queryNoDbArtifacts.js +1 -1
- package/lib/checks/sql-snippets.js +12 -10
- package/lib/checks/validator.js +14 -4
- package/lib/compiler/assert-consistency.js +8 -7
- package/lib/compiler/checks.js +30 -20
- package/lib/compiler/define.js +89 -25
- package/lib/compiler/extend.js +33 -28
- package/lib/compiler/finalize-parse-cdl.js +14 -9
- package/lib/compiler/populate.js +30 -8
- package/lib/compiler/propagator.js +23 -28
- package/lib/compiler/resolve.js +11 -5
- package/lib/compiler/shared.js +66 -48
- package/lib/compiler/tweak-assocs.js +2 -3
- package/lib/compiler/utils.js +11 -0
- package/lib/edm/annotations/genericTranslation.js +7 -4
- package/lib/edm/csn2edm.js +1 -1
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +3565 -3544
- package/lib/json/csnVersion.js +13 -13
- package/lib/json/from-csn.js +140 -158
- package/lib/json/to-csn.js +23 -5
- package/lib/language/.eslintrc.json +4 -0
- package/lib/language/antlrParser.js +7 -10
- package/lib/language/docCommentParser.js +1 -2
- package/lib/language/errorStrategy.js +54 -27
- package/lib/language/genericAntlrParser.js +115 -84
- package/lib/language/language.g4 +29 -25
- package/lib/language/multiLineStringParser.js +75 -63
- package/lib/main.js +1 -0
- package/lib/model/csnRefs.js +4 -3
- package/lib/model/csnUtils.js +39 -7
- package/lib/model/sortViews.js +7 -3
- package/lib/modelCompare/compare.js +49 -15
- package/lib/modelCompare/filter.js +83 -0
- package/lib/optionProcessor.js +5 -1
- package/lib/render/manageConstraints.js +9 -5
- package/lib/render/toCdl.js +120 -62
- package/lib/render/toHdbcds.js +1 -1
- package/lib/render/toSql.js +6 -2
- package/lib/render/utils/common.js +7 -0
- package/lib/sql-identifier.js +7 -0
- package/lib/transform/db/assertUnique.js +27 -38
- package/lib/transform/db/expansion.js +11 -4
- package/lib/transform/db/temporal.js +3 -1
- package/lib/transform/db/transformExists.js +7 -1
- package/lib/transform/db/views.js +42 -13
- package/lib/transform/draft/db.js +2 -2
- package/lib/transform/forOdataNew.js +7 -3
- package/lib/transform/forRelationalDB.js +12 -6
- package/lib/transform/localized.js +1 -1
- package/lib/transform/odata/typesExposure.js +2 -1
- package/lib/transform/parseExpr.js +245 -0
- package/lib/transform/transformUtilsNew.js +23 -14
- package/lib/transform/translateAssocsToJoins.js +12 -12
- package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
- package/lib/utils/term.js +5 -5
- package/package.json +2 -2
- package/share/messages/message-explanations.json +1 -1
- package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +1 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* parseExpr accepts any JSON object and tries to convert a token stream expression
|
|
5
|
+
* array into an AST like expression with CDL operator precedence.
|
|
6
|
+
*
|
|
7
|
+
* The following operators are supported:
|
|
8
|
+
*
|
|
9
|
+
* Multiplication/Division: '*', '/'
|
|
10
|
+
* Addition/Subtraction: '+', '-'
|
|
11
|
+
* Concatenation: '||'
|
|
12
|
+
* Relational: '=', '<>', '>', '>=', '<', '<=', '!=', 'like', 'in', 'exists', 'between and'
|
|
13
|
+
* Unary: 'is [not] null', 'not'
|
|
14
|
+
* Conditional: 'case [when then]+ [else]? end', 'and', 'or'
|
|
15
|
+
*
|
|
16
|
+
* Not yet implmemented: 'new'
|
|
17
|
+
*
|
|
18
|
+
* This is not an optimized LL(1) parser but a token 'sniffer'. A stream is
|
|
19
|
+
* cracked up in sub streams and passed down to the next higher function.
|
|
20
|
+
*
|
|
21
|
+
* Complex aggregates like case/when/else/end and between are parsed first to pass down the
|
|
22
|
+
* resulting sub expressions and avoiding 'and' ambiguities.
|
|
23
|
+
*
|
|
24
|
+
* Sub expressions are grouped as arrays, the final AST is an array of nested arrays.
|
|
25
|
+
* Alternatively, an object like AST can be produced by setting argument 'array' to false.
|
|
26
|
+
*
|
|
27
|
+
* This parser intentionally does no error handling. If a clause is malformed, it is accepted as is.
|
|
28
|
+
*
|
|
29
|
+
* @param {any} xpr A JSON object.
|
|
30
|
+
* @param {Boolean} array Bias AST representation.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
function parseExpr(xpr, array=true) {
|
|
34
|
+
return parseExprInt(xpr);
|
|
35
|
+
|
|
36
|
+
function parseExprInt(xpr) {
|
|
37
|
+
return conditionOR(...CaseWhen(xpr));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function CaseWhen(xpr) {
|
|
41
|
+
if(Array.isArray(xpr))
|
|
42
|
+
inner(xpr);
|
|
43
|
+
return [xpr, 0, Array.isArray(xpr) ? xpr.length : 1];
|
|
44
|
+
|
|
45
|
+
// replace case/end from inner to outer
|
|
46
|
+
function inner(pxpr, lvl=0) {
|
|
47
|
+
const s = pxpr.findIndex(t => t === 'case');
|
|
48
|
+
if(s >= 0) {
|
|
49
|
+
let e = findLastIndex(pxpr, 'end');
|
|
50
|
+
pxpr = pxpr.slice(s+1, e);
|
|
51
|
+
const dist = inner(pxpr, lvl+1);
|
|
52
|
+
e -= dist;
|
|
53
|
+
if(dist > 0)
|
|
54
|
+
pxpr = xpr.slice(s+1, e+1);
|
|
55
|
+
const caseTree = array ? [ 'case' ] : { 'case': [] };
|
|
56
|
+
let i = pxpr.findIndex(t => t === 'else');
|
|
57
|
+
let elseCond = undefined;
|
|
58
|
+
if(i >= 0) {
|
|
59
|
+
elseCond = pxpr.slice(i+1);
|
|
60
|
+
pxpr = pxpr.slice(0, i);
|
|
61
|
+
}
|
|
62
|
+
i = pxpr.findIndex(t => t === 'when');
|
|
63
|
+
while(i >= 0) {
|
|
64
|
+
pxpr = pxpr.slice(i+1);
|
|
65
|
+
const when = { 'when': [] };
|
|
66
|
+
if(array)
|
|
67
|
+
caseTree.push('when');
|
|
68
|
+
else
|
|
69
|
+
caseTree.case.push(when);
|
|
70
|
+
i = pxpr.findIndex(t => t === 'then');
|
|
71
|
+
if(i >= 0) {
|
|
72
|
+
const arg = pxpr.slice(0, i);
|
|
73
|
+
if(array)
|
|
74
|
+
caseTree.push(arg);
|
|
75
|
+
else
|
|
76
|
+
when.when.push(arg.length === 1 ? arg[0] : arg);
|
|
77
|
+
}
|
|
78
|
+
pxpr = pxpr.slice(i+1);
|
|
79
|
+
i = pxpr.findIndex(t => t === 'when');
|
|
80
|
+
const arg = ((i >= 0) ? pxpr.slice(0, i) : pxpr);
|
|
81
|
+
if(array)
|
|
82
|
+
caseTree.push('then', arg);
|
|
83
|
+
else
|
|
84
|
+
when.when.push(arg.length === 1 ? arg[0] : arg);
|
|
85
|
+
}
|
|
86
|
+
if(elseCond) {
|
|
87
|
+
if(array)
|
|
88
|
+
caseTree.push('else', elseCond);
|
|
89
|
+
else
|
|
90
|
+
caseTree.case.push(elseCond.length === 1 ? elseCond[0] : elseCond);
|
|
91
|
+
}
|
|
92
|
+
if(array)
|
|
93
|
+
caseTree.push('end');
|
|
94
|
+
if(lvl > 0)
|
|
95
|
+
xpr.splice(s+1, e-s+1, caseTree);
|
|
96
|
+
else {
|
|
97
|
+
xpr = caseTree;
|
|
98
|
+
}
|
|
99
|
+
return e-s+1;
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function findLastIndex(expr, token, l=expr.length-1) {
|
|
106
|
+
while(l >= 0 && expr[l] !== token) l--;
|
|
107
|
+
return l;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function conditionOR(xpr, s, e) {
|
|
112
|
+
return binaryExpr(xpr, ['or'], conditionAnd, s, e);
|
|
113
|
+
}
|
|
114
|
+
function conditionAnd(xpr, s, e) {
|
|
115
|
+
return binaryExpr(xpr, (xpr, s, e) => {
|
|
116
|
+
let a = s-1;
|
|
117
|
+
let b;
|
|
118
|
+
// scan for 'and', skip 'between/and'
|
|
119
|
+
do {
|
|
120
|
+
b = false;
|
|
121
|
+
for(a++; xpr[a] !== 'and' && a < e; a++) {
|
|
122
|
+
if(xpr[a] === 'between')
|
|
123
|
+
b = true;
|
|
124
|
+
}
|
|
125
|
+
} while(b && a < e)
|
|
126
|
+
|
|
127
|
+
if(!b && a < e)
|
|
128
|
+
return [1, a]
|
|
129
|
+
else
|
|
130
|
+
return [1, -1];
|
|
131
|
+
}, conditionTerm, s, e);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function conditionTerm(xpr, s, e) {
|
|
135
|
+
if(Array.isArray(xpr)) {
|
|
136
|
+
if(xpr.length >= 3 && xpr[s+1] === 'is') {
|
|
137
|
+
if(xpr[s+2] === 'null')
|
|
138
|
+
return array ? [ conditionOR(xpr[s]), 'is', 'null' ] : { 'isNull': conditionOR(xpr[s]) };
|
|
139
|
+
else if(xpr[s+2] === 'not' && xpr[s+3] === 'null')
|
|
140
|
+
return array ? [ conditionOR(xpr[s]), 'is', 'not', 'null' ] : { 'isNotNull': conditionOR(xpr[s]) };
|
|
141
|
+
}
|
|
142
|
+
if(xpr[s] === 'not')
|
|
143
|
+
return array ? [ 'not', conditionTerm(xpr, s+1, e) ] : { 'not': conditionTerm(xpr, s+1, e) };
|
|
144
|
+
if(xpr[s] === 'exists')
|
|
145
|
+
return array ? [ 'exists', conditionOR(xpr[s+1]) ] : { 'exists': conditionOR(xpr[s+1]) };
|
|
146
|
+
}
|
|
147
|
+
return compareTerm(xpr, s, e);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function compareTerm(xpr, s, e) {
|
|
151
|
+
if(Array.isArray(xpr)) {
|
|
152
|
+
let i = s;
|
|
153
|
+
while(i < e && xpr[i] !== 'between') i++;
|
|
154
|
+
const b = i < e ? i : -1;
|
|
155
|
+
while(i < e && xpr[i] !== 'and') i++;
|
|
156
|
+
const a = i < e ? i : -1;
|
|
157
|
+
if(b >= 0) {
|
|
158
|
+
const expr = expression(xpr, s, b);
|
|
159
|
+
const between = array ? [ expr, 'between' ] : { 'between': [ expr ] };
|
|
160
|
+
if(a >= 0) {
|
|
161
|
+
const lower = expression(xpr, b+1, a);
|
|
162
|
+
const upper = expression(xpr, a+1, e);
|
|
163
|
+
if(array)
|
|
164
|
+
between.push(lower, 'and', upper);
|
|
165
|
+
else {
|
|
166
|
+
between.between.push(lower, upper);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const unspec = expression(xpr, b+1, e);
|
|
171
|
+
if(array)
|
|
172
|
+
between.push(unspec);
|
|
173
|
+
else
|
|
174
|
+
between.between.push(unspec);
|
|
175
|
+
}
|
|
176
|
+
return between;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return binaryExpr(xpr, ['=', '<>', '>', '>=', '<', '<=', '!=', 'like', 'in'], expression, s, e);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function expression(xpr, s, e) {
|
|
183
|
+
return binaryExpr(xpr, ['||'], exprAddSub, s, e);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function exprAddSub(xpr, s, e) {
|
|
187
|
+
return binaryExpr(xpr, ['+', '-'], exprMulDiv, s, e);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function exprMulDiv(xpr, s, e) {
|
|
191
|
+
return binaryExpr(xpr, ['*', '/'], terminal, s, e);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function terminal(xpr, s, e) {
|
|
195
|
+
if(Array.isArray(xpr) && xpr.length > 0) {
|
|
196
|
+
if(e-s <= 1)
|
|
197
|
+
return parseExprInt(xpr[e-1]);
|
|
198
|
+
else
|
|
199
|
+
return xpr.slice(s, e).map(parseExprInt);
|
|
200
|
+
}
|
|
201
|
+
if (typeof xpr === 'object') {
|
|
202
|
+
for(let n in xpr) {
|
|
203
|
+
xpr[n] = parseExprInt(xpr[n]);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return xpr;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function binaryExpr(xpr, token, next, s, e) {
|
|
210
|
+
if (Array.isArray(xpr)) {
|
|
211
|
+
let [tl, p] = findToken(s, e);
|
|
212
|
+
if (p >= 0) {
|
|
213
|
+
let lhs = next(xpr, s, p);
|
|
214
|
+
let op = xpr[p];
|
|
215
|
+
s = p+tl;
|
|
216
|
+
[tl, p] = findToken(s, e);
|
|
217
|
+
while(p >= 0) {
|
|
218
|
+
let rhs = next(xpr, s, p);
|
|
219
|
+
lhs = array ? [ lhs, op, rhs ] : { [op]: [lhs, rhs] };
|
|
220
|
+
op = xpr[p];
|
|
221
|
+
s = p+tl;
|
|
222
|
+
[tl, p] = findToken(s, e);
|
|
223
|
+
}
|
|
224
|
+
return array ? [ lhs, op, next(xpr, s, e) ] : { [op]: [lhs, next(xpr, s, e)] };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return next(xpr, s, e);
|
|
228
|
+
|
|
229
|
+
function findToken(s, e) {
|
|
230
|
+
if(typeof token === 'function')
|
|
231
|
+
return token(xpr, s, e);
|
|
232
|
+
else {
|
|
233
|
+
while(s < e && !token.includes(xpr[s])) s++;
|
|
234
|
+
if(s < e)
|
|
235
|
+
return [1, s];
|
|
236
|
+
}
|
|
237
|
+
return [1, -1];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = {
|
|
244
|
+
parseExpr,
|
|
245
|
+
};
|
|
@@ -12,6 +12,7 @@ const { cloneCsnNonDict, cloneCsnDictionary, getUtils } = require('../model/csnU
|
|
|
12
12
|
const { typeParameters, isBuiltinType } = require('../compiler/builtins');
|
|
13
13
|
const { ModelError } = require("../base/error");
|
|
14
14
|
const { forEach } = require('../utils/objectUtils');
|
|
15
|
+
const { pathName } = require("../compiler/utils");
|
|
15
16
|
|
|
16
17
|
const RestrictedOperators = ['<', '>', '>=', '<='];
|
|
17
18
|
const RelationalOperators = ['=', '!=', '<>', 'is' /*, 'like'*/,...RestrictedOperators];
|
|
@@ -711,7 +712,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
711
712
|
if (artifactName) {
|
|
712
713
|
path = ['definitions', artifactName, 'elements', elemName];
|
|
713
714
|
}
|
|
714
|
-
error(null, path, { name: elemName },
|
|
715
|
+
error(null, path, { name: elemName }, 'Generated element $(NAME) conflicts with existing element');
|
|
715
716
|
return;
|
|
716
717
|
}
|
|
717
718
|
|
|
@@ -865,9 +866,9 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
865
866
|
if (array.length > 1) {
|
|
866
867
|
const loc = ['definitions', artifactName];
|
|
867
868
|
if (err === true) {
|
|
868
|
-
error(null, loc, { anno: annoName },
|
|
869
|
+
error(null, loc, { anno: annoName }, 'Annotation $(ANNO) must be assigned only once');
|
|
869
870
|
} else {
|
|
870
|
-
warning(null, loc, { anno: annoName }
|
|
871
|
+
warning(null, loc, { anno: annoName },'Annotation $(ANNO) must be assigned only once');
|
|
871
872
|
}
|
|
872
873
|
}
|
|
873
874
|
}
|
|
@@ -958,7 +959,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
958
959
|
node[name] = value;
|
|
959
960
|
if(wasOverwritten)
|
|
960
961
|
info(null, path, { anno: name, prop: value, otherprop: oldValue },
|
|
961
|
-
|
|
962
|
+
'Value $(OTHERPROP) of annotation $(ANNO) is overwritten with new value $(PROP)');
|
|
962
963
|
return wasOverwritten;
|
|
963
964
|
}
|
|
964
965
|
|
|
@@ -1161,42 +1162,50 @@ function getTransformers(model, options, pathDelimiter = '_') {
|
|
|
1161
1162
|
const xrefvalues = Object.values(xref);
|
|
1162
1163
|
let cont = true;
|
|
1163
1164
|
|
|
1164
|
-
if(op === 'like' && xrefvalues.reduce((a, v) => {
|
|
1165
|
+
if(op === 'like' && xrefvalues.reduce((a, v) => {
|
|
1165
1166
|
return (v.lhs && v.rhs) ? a + 1: a;
|
|
1166
1167
|
}, 0) === 0) {
|
|
1167
1168
|
// error if intersection of paths is zero
|
|
1168
|
-
error(null, location,
|
|
1169
|
+
error(null, location, { lhs: pathName(lhs.ref), op, rhs: pathName(rhs.ref) },
|
|
1170
|
+
'Expected compatible types for $(LHS) $(OP) $(RHS)');
|
|
1169
1171
|
cont = false;
|
|
1170
1172
|
}
|
|
1171
1173
|
|
|
1172
1174
|
cont && xrefkeys.forEach(xn => {
|
|
1173
1175
|
const x = xref[xn];
|
|
1176
|
+
const prefix = `${pathName(lhs.ref)} ${op} ${pathName(rhs.ref)}`;
|
|
1174
1177
|
// do the paths match?
|
|
1175
1178
|
if(op !== 'like' && !(x.lhs && x.rhs)) {
|
|
1176
|
-
if(xn.length)
|
|
1177
|
-
error(null, location,
|
|
1178
|
-
|
|
1179
|
-
|
|
1179
|
+
if(xn.length) {
|
|
1180
|
+
error(null, location, { prefix, name: xn, alias: pathName((x.lhs ? rhs : lhs).ref) },
|
|
1181
|
+
'$(PREFIX): Sub path $(NAME) not found in $(ALIAS)');
|
|
1182
|
+
}
|
|
1183
|
+
else {
|
|
1184
|
+
error(null, location, { prefix, name: pathName((x.lhs ? lhs : rhs).ref), alias: pathName((x.lhs ? rhs : lhs).ref) },
|
|
1185
|
+
'$(PREFIX): Path $(NAME) does not match $(ALIAS)');
|
|
1186
|
+
}
|
|
1180
1187
|
cont = false;
|
|
1181
1188
|
}
|
|
1182
1189
|
// lhs && rhs are present, consistency checks that affect both ends
|
|
1183
1190
|
else {
|
|
1184
1191
|
// is lhs scalar?
|
|
1185
1192
|
if(!lhsIsVal && x.lhs && !isScalarOrNoType(x.lhs._art)) {
|
|
1186
|
-
error(null, location,
|
|
1193
|
+
error(null, location, { prefix, name: `${pathName(x.lhs.ref)}${(xn.length ? '.' + xn : '')}` },
|
|
1194
|
+
'$(PREFIX): Path $(NAME) must end on a scalar type')
|
|
1187
1195
|
cont = false;
|
|
1188
1196
|
}
|
|
1189
1197
|
// is rhs scalar?
|
|
1190
1198
|
if(!rhsIsVal && x.rhs && !isScalarOrNoType(x.rhs._art)) {
|
|
1191
|
-
error(null, location,
|
|
1199
|
+
error(null, location, { prefix, name: `${pathName(x.rhs.ref)}${(xn.length ? '.' + xn : '')}` },
|
|
1200
|
+
'$(PREFIX): Path $(NAME) must end on a scalar type');
|
|
1192
1201
|
cont = false;
|
|
1193
1202
|
}
|
|
1194
|
-
// info about type incompatibility if no other errors
|
|
1203
|
+
// info about type incompatibility if no other errors occurred
|
|
1195
1204
|
if(!(lhsIsVal || rhsIsVal) && x.lhs && x.rhs && xn && cont) {
|
|
1196
1205
|
const lhst = getType(x.lhs._art);
|
|
1197
1206
|
const rhst = getType(x.rhs._art);
|
|
1198
1207
|
if(lhst !== rhst) {
|
|
1199
|
-
info(null, location,
|
|
1208
|
+
info(null, location, { prefix, name: xn },'$(PREFIX): Types for sub path $(NAME) don\'t match');
|
|
1200
1209
|
}
|
|
1201
1210
|
}
|
|
1202
1211
|
}
|
|
@@ -902,29 +902,29 @@ function translateAssocsToJoins(model, inputOptions = {})
|
|
|
902
902
|
// source side from view point of view (target side from forward point of view)
|
|
903
903
|
path = tail; // pop assoc step
|
|
904
904
|
let elt = env.lead._combined[path[0].id];
|
|
905
|
-
let err = 'Element "' + path[0].id +
|
|
906
|
-
'" referred in association "' + assoc.name.id +'" of Artifact "' + assoc.name.absolute +'"';
|
|
907
905
|
|
|
908
906
|
if(elt) {
|
|
909
907
|
if(Array.isArray(elt)) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
908
|
+
const names = elt.map(e => e._origin.name.absolute);
|
|
909
|
+
error(null, [ assocQAT._origin.location, assocQAT._origin ], { elemref: path[0].id, id: assoc.name.id, art: assoc.name.absolute, names },
|
|
910
|
+
'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) is available from multiple query sources $(NAMES)');
|
|
913
911
|
return pathNode.path;
|
|
914
912
|
} else {
|
|
915
913
|
// check if element has same origin on both ends
|
|
916
914
|
if(elt._origin._main !== path[0]._artifact._origin._main) {
|
|
917
|
-
|
|
918
|
-
path[0].
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
915
|
+
warning(null, [ assocQAT._origin.location, assocQAT._origin ], {
|
|
916
|
+
elemref: path[0].id,
|
|
917
|
+
id: assoc.name.id, art: assoc.name.absolute,
|
|
918
|
+
name: path[0]._artifact._origin._main.name.absolute,
|
|
919
|
+
alias: elt._origin._main.name.absolute,
|
|
920
|
+
source: elt._main.name.absolute,
|
|
921
|
+
}, 'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) originates from $(NAME) and from $(ALIAS) in $(SOURCE)');
|
|
922
922
|
}
|
|
923
923
|
_navigation = elt._parent;
|
|
924
924
|
}
|
|
925
925
|
} else {
|
|
926
|
-
|
|
927
|
-
|
|
926
|
+
error(null, [ assocQAT._origin.location, assocQAT._origin ], { elemref: path[0].id, id: assoc.name.id, art: assoc.name.absolute },
|
|
927
|
+
'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) has not been found');
|
|
928
928
|
return pathNode.path;
|
|
929
929
|
}
|
|
930
930
|
} else {
|
|
@@ -28,6 +28,7 @@ module.exports = (csn, options) => {
|
|
|
28
28
|
// Properties on definition level that we treat specially.
|
|
29
29
|
const definitionPropagationRules = {
|
|
30
30
|
'@cds.autoexpose': onlyViaArtifact,
|
|
31
|
+
'@cds.external': skip,
|
|
31
32
|
'@fiori.draft.enabled': onlyViaArtifact,
|
|
32
33
|
'@': nullStopsPropagation,
|
|
33
34
|
// Example: `type E : F;` does not have `elements`, but they are required for e.g. OData.
|
package/lib/utils/term.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//
|
|
2
2
|
// This file is used for color output to stderr and stdout.
|
|
3
|
-
// Use `term.
|
|
3
|
+
// Use `term.asError`, `term.asWarn` and `term.asInfo` as they use color output
|
|
4
4
|
// per default if the process runs in a TTY, i.e. stdout as well as
|
|
5
5
|
// stderr are TTYs. stderr/stdout are no TTYs if they are
|
|
6
6
|
// (for example) piped into another process or written to file:
|
|
@@ -88,10 +88,10 @@ function term(useColor = 'auto') {
|
|
|
88
88
|
bold,
|
|
89
89
|
|
|
90
90
|
severity: asSeverity,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
asError,
|
|
92
|
+
asWarning,
|
|
93
|
+
asInfo,
|
|
94
|
+
asHelp,
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"description": "CDS (Core Data Services) compiler and backends",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"author": "SAP SE (https://www.sap.com)",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"download": "node scripts/downloadANTLR.js",
|
|
18
18
|
"gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js",
|
|
19
|
-
"xmakeBeforeInstall": "echo \"Due to binary mirror, use sqlite 5.1.
|
|
19
|
+
"xmakeBeforeInstall": "echo \"Due to binary mirror, use sqlite 5.1.2 explicitly\" && npm install --save --save-exact --no-package-lock sqlite3@5.1.2",
|
|
20
20
|
"xmakeAfterInstall": "npm run gen",
|
|
21
21
|
"xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
|
|
22
22
|
"test": "node scripts/verifyGrammarChecksum.js && mocha --reporter min --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter min --reporter-option maxDiffSize=0 test/ test3/",
|