@sap/cds-compiler 3.1.0 → 3.3.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 +90 -3
- package/bin/cdsc.js +1 -1
- package/doc/CHANGELOG_BETA.md +18 -0
- package/lib/api/main.js +8 -13
- package/lib/base/error.js +2 -2
- package/lib/base/keywords.js +2 -24
- package/lib/base/message-registry.js +43 -14
- package/lib/base/messages.js +20 -10
- package/lib/base/model.js +1 -1
- package/lib/checks/actionsFunctions.js +1 -1
- package/lib/checks/annotationsOData.js +2 -2
- package/lib/checks/arrayOfs.js +15 -7
- package/lib/checks/cdsPersistence.js +1 -1
- package/lib/checks/checkForTypes.js +48 -0
- package/lib/checks/defaultValues.js +2 -2
- package/lib/checks/elements.js +81 -6
- package/lib/checks/foreignKeys.js +12 -13
- package/lib/checks/invalidTarget.js +10 -11
- package/lib/checks/managedInType.js +21 -15
- package/lib/checks/nullableKeys.js +1 -1
- package/lib/checks/onConditions.js +9 -9
- package/lib/checks/parameters.js +21 -0
- package/lib/checks/selectItems.js +1 -1
- package/lib/checks/types.js +2 -2
- package/lib/checks/utils.js +17 -7
- package/lib/checks/validator.js +26 -14
- package/lib/compiler/assert-consistency.js +13 -6
- package/lib/compiler/builtins.js +8 -0
- package/lib/compiler/checks.js +40 -33
- package/lib/compiler/define.js +50 -44
- package/lib/compiler/extend.js +303 -37
- package/lib/compiler/kick-start.js +2 -35
- package/lib/compiler/populate.js +83 -62
- package/lib/compiler/propagator.js +1 -1
- package/lib/compiler/resolve.js +61 -104
- package/lib/compiler/shared.js +16 -6
- package/lib/compiler/tweak-assocs.js +25 -12
- package/lib/compiler/utils.js +2 -2
- package/lib/edm/annotations/genericTranslation.js +15 -5
- package/lib/edm/csn2edm.js +10 -10
- package/lib/edm/edm.js +17 -9
- package/lib/edm/edmPreprocessor.js +82 -42
- package/lib/edm/edmUtils.js +18 -16
- package/lib/gen/Dictionary.json +14 -0
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +3 -2
- package/lib/gen/languageParser.js +4205 -4100
- package/lib/inspect/inspectModelStatistics.js +1 -1
- package/lib/inspect/inspectPropagation.js +23 -9
- package/lib/json/csnVersion.js +1 -1
- package/lib/json/from-csn.js +26 -19
- package/lib/json/to-csn.js +47 -5
- package/lib/language/antlrParser.js +1 -1
- package/lib/language/genericAntlrParser.js +29 -13
- package/lib/language/language.g4 +28 -8
- package/lib/main.d.ts +3 -6
- package/lib/model/.eslintrc.json +13 -0
- package/lib/model/api.js +4 -2
- package/lib/model/csnRefs.js +74 -47
- package/lib/model/csnUtils.js +236 -218
- package/lib/model/enrichCsn.js +41 -31
- package/lib/model/revealInternalProperties.js +61 -57
- package/lib/model/sortViews.js +31 -31
- package/lib/modelCompare/compare.js +6 -6
- package/lib/optionProcessor.js +5 -0
- package/lib/render/manageConstraints.js +2 -2
- package/lib/render/toCdl.js +31 -44
- package/lib/render/toHdbcds.js +7 -5
- package/lib/render/toRename.js +4 -4
- package/lib/render/toSql.js +11 -5
- package/lib/render/utils/common.js +20 -9
- package/lib/render/utils/sql.js +5 -5
- package/lib/transform/db/applyTransformations.js +32 -3
- package/lib/transform/db/expansion.js +81 -37
- package/lib/transform/db/flattening.js +1 -1
- package/lib/transform/db/temporal.js +1 -1
- package/lib/transform/db/transformExists.js +1 -1
- package/lib/transform/forOdataNew.js +10 -7
- package/lib/transform/{forHanaNew.js → forRelationalDB.js} +7 -7
- package/lib/transform/localized.js +28 -19
- package/lib/transform/odata/toFinalBaseType.js +8 -11
- package/lib/transform/odata/typesExposure.js +1 -1
- package/lib/transform/transformUtilsNew.js +101 -39
- package/lib/transform/translateAssocsToJoins.js +5 -4
- package/lib/utils/moduleResolve.js +5 -5
- package/lib/utils/objectUtils.js +3 -3
- package/package.json +2 -2
- package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
- package/share/messages/check-proper-type-of.md +4 -4
- package/share/messages/check-proper-type.md +2 -2
- package/share/messages/duplicate-autoexposed.md +4 -4
- package/share/messages/extend-repeated-intralayer.md +4 -5
- package/share/messages/extend-unrelated-layer.md +4 -4
- package/share/messages/message-explanations.json +3 -1
- package/share/messages/redirected-to-ambiguous.md +7 -6
- package/share/messages/redirected-to-complex.md +63 -0
- package/share/messages/redirected-to-unrelated.md +6 -5
- package/share/messages/rewrite-not-supported.md +4 -4
- package/share/messages/syntax-expected-integer.md +3 -3
- package/share/messages/wildcard-excluding-one.md +37 -0
package/lib/model/enrichCsn.js
CHANGED
|
@@ -60,14 +60,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
60
60
|
$origin,
|
|
61
61
|
// TODO: excluding
|
|
62
62
|
'@': () => { /* ignore annotations */ },
|
|
63
|
-
}
|
|
63
|
+
};
|
|
64
64
|
// options.enrichCsn = 'DEBUG';
|
|
65
65
|
let $$cacheObjectNumber = 0; // for debugging
|
|
66
66
|
const debugLocationInfo = options.enrichCsn === 'DEBUG' && Object.create(null);
|
|
67
67
|
|
|
68
68
|
setLocations( csn, false, null );
|
|
69
|
-
const {
|
|
70
|
-
|
|
69
|
+
const {
|
|
70
|
+
inspectRef,
|
|
71
|
+
artifactRef,
|
|
72
|
+
getOrigin,
|
|
73
|
+
initDefinition,
|
|
74
|
+
// eslint-disable-next-line camelcase
|
|
75
|
+
__getCache_forEnrichCsnDebugging,
|
|
76
|
+
} = csnRefs( csn, true );
|
|
71
77
|
|
|
72
78
|
const csnPath = [];
|
|
73
79
|
if (csn.definitions)
|
|
@@ -87,20 +93,20 @@ function enrichCsn( csn, options = {} ) {
|
|
|
87
93
|
obj.forEach( (n, i) => standard( obj, i, n ) );
|
|
88
94
|
}
|
|
89
95
|
else {
|
|
90
|
-
for (
|
|
96
|
+
for (const name of Object.getOwnPropertyNames( obj )) {
|
|
91
97
|
const trans = transformers[name] || transformers[name.charAt(0)] || standard;
|
|
92
98
|
trans( obj, name, obj[name] );
|
|
93
99
|
}
|
|
94
100
|
if (obj.$parens)
|
|
95
101
|
reveal( obj, '$parens', obj.$parens );
|
|
96
|
-
|
|
102
|
+
_cacheDebug( obj );
|
|
97
103
|
}
|
|
98
104
|
csnPath.pop();
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
function definition( parent, prop, obj ) {
|
|
102
108
|
// call getOrigin() before standard() to set implicit protos inside standard():
|
|
103
|
-
const origin = handleError( err => err ? err.toString() : getOrigin( obj ) );
|
|
109
|
+
const origin = handleError( err => (err ? err.toString() : getOrigin( obj )) );
|
|
104
110
|
standard( parent, prop, obj );
|
|
105
111
|
if (obj.$origin === undefined && !obj.type && origin != null)
|
|
106
112
|
obj._origin = refLocation( origin );
|
|
@@ -110,29 +116,31 @@ function enrichCsn( csn, options = {} ) {
|
|
|
110
116
|
if (!dict) // value null for inheritance interruption
|
|
111
117
|
return;
|
|
112
118
|
csnPath.push( prop );
|
|
113
|
-
for (
|
|
119
|
+
for (const name of Object.getOwnPropertyNames( dict )) {
|
|
114
120
|
if (prop === 'definitions')
|
|
115
121
|
initDefinition( dict[name] );
|
|
116
122
|
definition( dict, name, dict[name] );
|
|
117
123
|
}
|
|
118
124
|
if (!Object.prototype.propertyIsEnumerable.call( parent, prop ))
|
|
119
|
-
parent[
|
|
125
|
+
parent[`$${ prop }`] = dict;
|
|
120
126
|
csnPath.pop();
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
function refLocation( art ) {
|
|
124
130
|
if (!art || typeof art !== 'object' || Array.isArray( art )) {
|
|
125
|
-
if (!options.testMode)
|
|
131
|
+
if (!options.testMode) {
|
|
126
132
|
return (typeof art === 'string')
|
|
127
|
-
|
|
128
|
-
|
|
133
|
+
? `<illegal ref = ${ art }>`
|
|
134
|
+
: `<illegal ref: ${ typeof art }>`;
|
|
135
|
+
}
|
|
129
136
|
throw new Error( 'Illegal reference' );
|
|
130
137
|
}
|
|
131
|
-
else if (art.$location)
|
|
138
|
+
else if (art.$location) {
|
|
132
139
|
return art.$location;
|
|
140
|
+
}
|
|
133
141
|
|
|
134
142
|
if (!options.testMode)
|
|
135
|
-
return `<${Object.keys( art ).join('+')}+!$location>`;
|
|
143
|
+
return `<${ Object.keys( art ).join('+') }+!$location>`;
|
|
136
144
|
throw new Error( 'Reference to object without $location' );
|
|
137
145
|
}
|
|
138
146
|
|
|
@@ -140,19 +148,19 @@ function enrichCsn( csn, options = {} ) {
|
|
|
140
148
|
// try {
|
|
141
149
|
const notFound = (options.testMode) ? undefined : null;
|
|
142
150
|
if (Array.isArray( ref )) {
|
|
143
|
-
parent[
|
|
151
|
+
parent[`_${ prop }`] = ref.map( r => refLocation( artifactRef( r, notFound ) ) );
|
|
144
152
|
}
|
|
145
153
|
else if (typeof ref === 'string') {
|
|
146
154
|
if (!ref.startsWith( 'cds.'))
|
|
147
|
-
parent[
|
|
155
|
+
parent[`_${ prop }`] = refLocation( artifactRef( ref, notFound ) );
|
|
148
156
|
}
|
|
149
157
|
else if (!ref.elements) {
|
|
150
|
-
parent[
|
|
158
|
+
parent[`_${ prop }`] = refLocation( artifactRef( ref, notFound ) );
|
|
151
159
|
}
|
|
152
160
|
else { // targetAspect, target
|
|
153
161
|
csnPath.push( prop );
|
|
154
162
|
dictionary( ref, 'elements', ref.elements );
|
|
155
|
-
|
|
163
|
+
_cacheDebug( ref );
|
|
156
164
|
csnPath.pop();
|
|
157
165
|
}
|
|
158
166
|
// } catch (e) {
|
|
@@ -160,7 +168,7 @@ function enrichCsn( csn, options = {} ) {
|
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
function $origin( parent, prop, ref ) {
|
|
163
|
-
handleError( err => {
|
|
171
|
+
handleError( (err) => {
|
|
164
172
|
if (err)
|
|
165
173
|
parent._origin = err.toString();
|
|
166
174
|
else if (Array.isArray( ref ) || typeof ref === 'string') // $origin: […] / "short-ref"
|
|
@@ -171,13 +179,13 @@ function enrichCsn( csn, options = {} ) {
|
|
|
171
179
|
}
|
|
172
180
|
|
|
173
181
|
function pathRef( parent, prop, path, inspectionPath = csnPath ) {
|
|
174
|
-
const inspection = handleError( (err)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
const inspection = handleError( err => ((err) ? { scope: err.toString() } : inspectRef( inspectionPath )));
|
|
183
|
+
const {
|
|
184
|
+
links, art, scope, $env,
|
|
185
|
+
} = inspection;
|
|
178
186
|
if (links)
|
|
179
187
|
parent._links = links.map( l => refLocation( l.art ) );
|
|
180
|
-
if (links && links[links.length-1].art !== art)
|
|
188
|
+
if (links && links[links.length - 1].art !== art)
|
|
181
189
|
parent._art = refLocation( art );
|
|
182
190
|
parent._scope = scope;
|
|
183
191
|
if ($env)
|
|
@@ -211,12 +219,13 @@ function enrichCsn( csn, options = {} ) {
|
|
|
211
219
|
return callback();
|
|
212
220
|
try {
|
|
213
221
|
return callback();
|
|
214
|
-
}
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
215
224
|
return callback( err );
|
|
216
225
|
}
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
function
|
|
228
|
+
function _cacheDebug( obj, subCache ) {
|
|
220
229
|
if (options.enrichCsn !== 'DEBUG')
|
|
221
230
|
return;
|
|
222
231
|
const cache = subCache || __getCache_forEnrichCsnDebugging( obj );
|
|
@@ -251,7 +260,7 @@ function enrichCsn( csn, options = {} ) {
|
|
|
251
260
|
for (const n in val) {
|
|
252
261
|
const alias = val[n];
|
|
253
262
|
const c = {};
|
|
254
|
-
|
|
263
|
+
_cacheDebug( c, alias );
|
|
255
264
|
sub[n] = c.$$cacheObject;
|
|
256
265
|
}
|
|
257
266
|
obj.$$cacheObject[name] = sub;
|
|
@@ -259,10 +268,11 @@ function enrichCsn( csn, options = {} ) {
|
|
|
259
268
|
}
|
|
260
269
|
else if (name === '$origin$step') { // string value handled above
|
|
261
270
|
const kind = Object.keys( val )[0];
|
|
262
|
-
obj.$$cacheObject[name] = `${kind}: ${ val[kind] }`;
|
|
271
|
+
obj.$$cacheObject[name] = `${ kind }: ${ val[kind] }`;
|
|
263
272
|
}
|
|
264
273
|
else if (Array.isArray( val )) {
|
|
265
|
-
|
|
274
|
+
// eslint-disable-next-line no-loop-func
|
|
275
|
+
obj.$$cacheObject[name] = val.map( (item) => {
|
|
266
276
|
if (!item.$$objectNumber)
|
|
267
277
|
item.$$objectNumber = -(++$$cacheObjectNumber);
|
|
268
278
|
return item.$$objectNumber;
|
|
@@ -281,7 +291,7 @@ function enrichCsn( csn, options = {} ) {
|
|
|
281
291
|
if (debugLocationInfo && !userProvided) {
|
|
282
292
|
loc = loc.replace( /\([0-9]+\)\^/, '^' );
|
|
283
293
|
debugLocationInfo[loc] = (debugLocationInfo[loc] || 0) + 1;
|
|
284
|
-
loc = `${loc}(${debugLocationInfo[loc]})`;
|
|
294
|
+
loc = `${ loc }(${ debugLocationInfo[loc] })`;
|
|
285
295
|
}
|
|
286
296
|
return loc;
|
|
287
297
|
}
|
|
@@ -298,11 +308,11 @@ function enrichCsn( csn, options = {} ) {
|
|
|
298
308
|
reveal( node, '$location', debugLocation( loc, !node.$generated ) );
|
|
299
309
|
}
|
|
300
310
|
else if (prop === true || prop === 'returns') { // in dictionary or returns
|
|
301
|
-
loc = debugLocation( loc
|
|
311
|
+
loc = debugLocation( `${ loc }^` );
|
|
302
312
|
node.$location = loc;
|
|
303
313
|
}
|
|
304
314
|
else if (prop === 'items') {
|
|
305
|
-
let iloc = loc
|
|
315
|
+
let iloc = `${ loc }[]`;
|
|
306
316
|
let obj = node;
|
|
307
317
|
while (obj) {
|
|
308
318
|
// should not appear in --enrich-csn, only for _origin info
|
|
@@ -25,10 +25,10 @@ function locationString( loc ) {
|
|
|
25
25
|
return '';
|
|
26
26
|
return (typeof loc === 'object' && loc.file)
|
|
27
27
|
? msg.locationString(loc)
|
|
28
|
-
:
|
|
28
|
+
: `${ typeof loc }:${ msg.locationString(loc) }`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
let uniqueId = 0;
|
|
32
32
|
|
|
33
33
|
// some (internal) kinds are normally represented as links
|
|
34
34
|
const kindsRepresentedAsLinks = {
|
|
@@ -36,13 +36,13 @@ const kindsRepresentedAsLinks = {
|
|
|
36
36
|
select: (art, parent) => art._main && parent !== art._main.$queries,
|
|
37
37
|
// represent table alias in from / join-args property as link:
|
|
38
38
|
$tableAlias: tableAliasAsLink,
|
|
39
|
-
// represent "navigation
|
|
39
|
+
// represent "navigation elements" in _combined as links:
|
|
40
40
|
$navElement: (art, parent) => art._parent && parent !== art._parent.elements && art._parent.kind !== 'aspect',
|
|
41
41
|
// represent mixin in $tableAliases as link:
|
|
42
42
|
mixin: tableAliasAsLink,
|
|
43
43
|
// represent $projection as link, as it is just another search name for $self:
|
|
44
44
|
$self: (_a, _p, name) => name !== '$self',
|
|
45
|
-
}
|
|
45
|
+
};
|
|
46
46
|
|
|
47
47
|
function tableAliasAsLink( art, parent, name ) {
|
|
48
48
|
return art._parent && art._parent.$tableAliases && // initXYZ() is run
|
|
@@ -98,8 +98,8 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
98
98
|
_status: primOrString, // is a string anyway
|
|
99
99
|
$annotations: as => as.map( $annotation ),
|
|
100
100
|
$messageFunctions: () => '‹some functions›',
|
|
101
|
-
}
|
|
102
|
-
|
|
101
|
+
};
|
|
102
|
+
uniqueId = 1;
|
|
103
103
|
return revealXsnPath(nameOrPath, model);
|
|
104
104
|
|
|
105
105
|
// Returns the desired artifact/dictionary in the XSN.
|
|
@@ -132,7 +132,7 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
132
132
|
if (path.length === 1) {
|
|
133
133
|
const def = xsn.definitions?.[path[0]] || xsn.vocabularies?.[path[0]];
|
|
134
134
|
if (!def)
|
|
135
|
-
throw new Error(`reveal xsn: Unknown definition: “${path[0]}”`)
|
|
135
|
+
throw new Error(`reveal xsn: Unknown definition: “${ path[0] }”`);
|
|
136
136
|
return reveal( def );
|
|
137
137
|
}
|
|
138
138
|
|
|
@@ -141,11 +141,11 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
141
141
|
|
|
142
142
|
for (const segment of path) {
|
|
143
143
|
if (xsn[segment])
|
|
144
|
-
xsn = xsn[segment]
|
|
144
|
+
xsn = xsn[segment];
|
|
145
145
|
else if (segment) // huh, this should be a call error
|
|
146
|
-
throw new Error(`Raw Output: Path segment "${ segment }" could not be found. Path: ${ JSON.stringify(path) }!"`)
|
|
146
|
+
throw new Error(`Raw Output: Path segment "${ segment }" could not be found. Path: ${ JSON.stringify(path) }!"`);
|
|
147
147
|
}
|
|
148
|
-
const propName = path[path.length > 1 ? path.length - 2 : 0
|
|
148
|
+
const propName = path[path.length > 1 ? path.length - 2 : 0];
|
|
149
149
|
const obj = {};
|
|
150
150
|
obj[propName] = xsn;
|
|
151
151
|
return reveal( obj );
|
|
@@ -175,9 +175,9 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
175
175
|
|
|
176
176
|
function layerExtends( dict ) {
|
|
177
177
|
const r = Object.create( Object.getPrototypeOf(dict)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for (
|
|
178
|
+
? NOT_A_DICTIONARY.prototype
|
|
179
|
+
: Object.prototype );
|
|
180
|
+
for (const name in dict)
|
|
181
181
|
r[name] = true;
|
|
182
182
|
return r;
|
|
183
183
|
}
|
|
@@ -185,17 +185,17 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
185
185
|
function $annotation( anno ) { // property for cds-lsp
|
|
186
186
|
const { name, $flatten } = anno.value || anno;
|
|
187
187
|
const value = ($flatten)
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
? { name: reveal( name ), $flatten: $flatten.map( $annotation ) }
|
|
189
|
+
: `@${ name?.absolute }`;
|
|
190
190
|
return { value, location: locationString( anno.location || anno.name.location ) };
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
function columns( nodes, query ) {
|
|
194
194
|
// If we will have specified elements, we need another test to see columns in --parse-cdl
|
|
195
195
|
return nodes && array( nodes,
|
|
196
|
-
c => (c._parent && c._parent.elements)
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
c => ((c._parent && c._parent.elements)
|
|
197
|
+
? artifactIdentifier( c, query )
|
|
198
|
+
: reveal( c, nodes )) );
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
function elements( dict, parent ) {
|
|
@@ -213,9 +213,9 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
213
213
|
if (!node || typeof node !== 'object' || !model.definitions || parent === model )
|
|
214
214
|
return dictionary( node ); // no dictionary or no definitions section
|
|
215
215
|
const dict = Object.create( Object.getPrototypeOf(node)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
for (
|
|
216
|
+
? NOT_A_DICTIONARY.prototype
|
|
217
|
+
: Object.prototype );
|
|
218
|
+
for (const name in node) {
|
|
219
219
|
const art = node[name];
|
|
220
220
|
dict[name] = (art.kind !== 'using')
|
|
221
221
|
? artifactIdentifier( art )
|
|
@@ -231,9 +231,9 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
231
231
|
return array( node, reveal );
|
|
232
232
|
// Make unexpected prototype visible with node-10+:
|
|
233
233
|
const r = Object.create( Object.getPrototypeOf(node)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
for (
|
|
234
|
+
? NOT_A_DICTIONARY.prototype
|
|
235
|
+
: Object.prototype );
|
|
236
|
+
for (const prop of Object.getOwnPropertyNames( node )) { // also non-enumerable
|
|
237
237
|
r[prop] = reveal( node[prop], node, prop );
|
|
238
238
|
}
|
|
239
239
|
if (node[$inferred] && !node['[$inferred]'])
|
|
@@ -246,8 +246,7 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
246
246
|
function origin( node, parent ) {
|
|
247
247
|
if (!node || node.$inferred === 'REDIRECTED')
|
|
248
248
|
return reveal( node, parent );
|
|
249
|
-
|
|
250
|
-
return artifactIdentifier( node, parent );
|
|
249
|
+
return artifactIdentifier( node, parent );
|
|
251
250
|
}
|
|
252
251
|
|
|
253
252
|
function revealNonEnum( node, parent ) {
|
|
@@ -263,20 +262,20 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
263
262
|
|
|
264
263
|
function reveal( node, parent, name ) {
|
|
265
264
|
if (node == null || typeof node !== 'object' )
|
|
266
|
-
return node
|
|
265
|
+
return node;
|
|
267
266
|
if (Array.isArray(node))
|
|
268
267
|
return array( node, n => reveal( n, node, name ) );
|
|
269
268
|
|
|
270
|
-
const asLinkTest = kindsRepresentedAsLinks[
|
|
269
|
+
const asLinkTest = kindsRepresentedAsLinks[node.kind];
|
|
271
270
|
if (asLinkTest && asLinkTest( node, parent, name ))
|
|
272
271
|
return artifactIdentifier( node, parent );
|
|
273
272
|
|
|
274
|
-
|
|
273
|
+
const r = Object.create( Object.getPrototypeOf( node ) );
|
|
275
274
|
// property to recognize === objects
|
|
276
275
|
if (node.kind && node.__unique_id__ == null)
|
|
277
|
-
Object.defineProperty( node, '__unique_id__', { value: ++
|
|
276
|
+
Object.defineProperty( node, '__unique_id__', { value: ++uniqueId } );
|
|
278
277
|
|
|
279
|
-
for (
|
|
278
|
+
for (const prop of Object.getOwnPropertyNames( node )) { // also non-enumerable
|
|
280
279
|
const func = transformers[prop] ||
|
|
281
280
|
({}.propertyIsEnumerable.call( node, prop ) ? reveal : revealNonEnum);
|
|
282
281
|
r[prop] = func( node[prop], node );
|
|
@@ -285,8 +284,8 @@ function revealInternalProperties( model, nameOrPath ) {
|
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
function targetAspect( node, parent ) {
|
|
288
|
-
if (node.elements &&
|
|
289
|
-
Object.defineProperty( node, '__unique_id__', { value: ++
|
|
287
|
+
if (node.elements && uniqueId && node.__unique_id__ == null)
|
|
288
|
+
Object.defineProperty( node, '__unique_id__', { value: ++uniqueId } );
|
|
290
289
|
return reveal( node, parent );
|
|
291
290
|
}
|
|
292
291
|
|
|
@@ -305,28 +304,33 @@ function array( node, fn ) {
|
|
|
305
304
|
function artifactIdentifier( node, parent ) {
|
|
306
305
|
if (Array.isArray(node))
|
|
307
306
|
return node.map( a => artifactIdentifier( a, node ) );
|
|
308
|
-
if (
|
|
309
|
-
Object.defineProperty( node, '__unique_id__', { value: ++
|
|
310
|
-
let outer =
|
|
307
|
+
if (uniqueId && node.__unique_id__ == null)
|
|
308
|
+
Object.defineProperty( node, '__unique_id__', { value: ++uniqueId } );
|
|
309
|
+
let outer = uniqueId ? `##${ node.__unique_id__ }` : '';
|
|
311
310
|
if (node._outer) {
|
|
312
|
-
if (node.$inferred === 'REDIRECTED')
|
|
313
|
-
outer =
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
311
|
+
if (node.$inferred === 'REDIRECTED') {
|
|
312
|
+
outer = `/redirected${ outer }`;
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
// eslint-disable-next-line no-nested-ternary
|
|
316
|
+
outer = (node._outer.items === node) ? `/items${ outer }`
|
|
317
|
+
// eslint-disable-next-line no-nested-ternary
|
|
318
|
+
: (node._outer.returns === node) ? `/returns${ outer }`
|
|
319
|
+
// eslint-disable-next-line no-nested-ternary
|
|
320
|
+
: (node._outer.targetAspect === node) ? `/target${ outer }`
|
|
321
|
+
: `/returns/items${ outer }`;
|
|
322
|
+
}
|
|
319
323
|
node = node._outer;
|
|
320
324
|
}
|
|
321
325
|
if (node === parent)
|
|
322
326
|
return 'this';
|
|
323
327
|
if (node.kind === 'source')
|
|
324
|
-
return
|
|
328
|
+
return `source:${ quoted( node.location.file ) }`;
|
|
325
329
|
if (node.kind === '$magicVariables')
|
|
326
330
|
return '$magicVariables';
|
|
327
331
|
if (!node.name) {
|
|
328
332
|
try {
|
|
329
|
-
return
|
|
333
|
+
return `${ locationString( node.location ) || '' }##${ node.__unique_id__ }`;
|
|
330
334
|
// return JSON.stringify(node);
|
|
331
335
|
}
|
|
332
336
|
catch (e) {
|
|
@@ -339,47 +343,47 @@ function artifactIdentifier( node, parent ) {
|
|
|
339
343
|
? artifactIdentifier( node._artifact )
|
|
340
344
|
: JSON.stringify(node.name);
|
|
341
345
|
case 'builtin':
|
|
342
|
-
return
|
|
346
|
+
return `$magicVariables/${ msg.artName(node) }`;
|
|
343
347
|
case 'source':
|
|
344
348
|
case 'using':
|
|
345
|
-
return
|
|
346
|
-
|
|
349
|
+
return `source:${ quoted( node.location && node.location.file )
|
|
350
|
+
}/using:${ quoted( node.name.id ) }`;
|
|
347
351
|
default: {
|
|
348
352
|
let main = node._main;
|
|
349
353
|
while (main && main._outer) // anonymous aspect
|
|
350
354
|
main = main._outer._main;
|
|
351
|
-
return (
|
|
355
|
+
return `${ (main || node).kind || '<kind>' }:${ msg.artName( node ) }${ outer }`;
|
|
352
356
|
}
|
|
353
357
|
}
|
|
354
358
|
}
|
|
355
359
|
|
|
356
360
|
function primOrString( node ) {
|
|
357
361
|
if (node == null || typeof node !== 'object')
|
|
358
|
-
return node
|
|
362
|
+
return node;
|
|
359
363
|
if (Array.isArray(node))
|
|
360
364
|
return array( node, primOrString );
|
|
361
365
|
if (Object.getPrototypeOf( node ))
|
|
362
|
-
return
|
|
363
|
-
|
|
364
|
-
return '<dict>';
|
|
366
|
+
return `${ node }`;
|
|
367
|
+
return '<dict>';
|
|
365
368
|
}
|
|
366
369
|
|
|
367
370
|
function quoted( name, undef = '‹undefined›' ) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
+
if (typeof name === 'number')
|
|
372
|
+
return name;
|
|
373
|
+
return (name ? `“${ name }”` : undef);
|
|
371
374
|
}
|
|
372
375
|
|
|
373
376
|
// To be used for tracing, e.g. by
|
|
374
377
|
// require('../model/revealInternalProperties').log(model, 'E_purposes')
|
|
375
378
|
function logXsnModel( model, name ) {
|
|
379
|
+
// eslint-disable-next-line no-console, global-require
|
|
376
380
|
console.log( require('util').inspect( revealInternalProperties( model, name ), false, null ) );
|
|
377
381
|
}
|
|
378
382
|
|
|
379
383
|
// To be used for tracing, e.g. by
|
|
380
384
|
// console.log(require('../model/revealInternalProperties').ref(type._artifact))
|
|
381
385
|
function xsnRef( node ) {
|
|
382
|
-
|
|
386
|
+
uniqueId = 0;
|
|
383
387
|
return artifactIdentifier( node );
|
|
384
388
|
}
|
|
385
389
|
|
package/lib/model/sortViews.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
const {
|
|
2
|
+
|
|
3
|
+
const { setDependencies } = require('./csnUtils');
|
|
4
|
+
const { ModelError } = require('../base/error');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {Object} Layers
|
|
@@ -19,22 +20,22 @@ const { ModelError } = require("../base/error");
|
|
|
19
20
|
* @param {Symbol} _dependencies Symbol used to attach the dependencies
|
|
20
21
|
* @returns {Layers}
|
|
21
22
|
*/
|
|
22
|
-
function sortTopologically(csn, _dependents, _dependencies){
|
|
23
|
+
function sortTopologically(csn, _dependents, _dependencies) {
|
|
23
24
|
const layers = [];
|
|
24
25
|
let { zero, nonZero } = _calculateDepth(Object.entries(csn.definitions), _dependents, _dependencies);
|
|
25
|
-
while (zero.length !== 0){
|
|
26
|
+
while (zero.length !== 0) {
|
|
26
27
|
const currentLayer = [];
|
|
27
|
-
zero.forEach(([artifactName, artifact]) => {
|
|
28
|
+
zero.forEach(([ artifactName, artifact ]) => {
|
|
28
29
|
currentLayer.push(artifactName);
|
|
29
|
-
if(artifact[_dependents]) {
|
|
30
|
+
if (artifact[_dependents]) {
|
|
30
31
|
Object.values(artifact[_dependents]).forEach((dependant) => {
|
|
31
|
-
dependant.$pointers
|
|
32
|
+
dependant.$pointers -= 1;
|
|
32
33
|
dependant[_dependencies].delete(artifact);
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
layers.push(currentLayer);
|
|
37
|
-
({zero, nonZero} = _findWithXPointers(nonZero, 0, _dependents, _dependencies));
|
|
38
|
+
({ zero, nonZero } = _findWithXPointers(nonZero, 0, _dependents, _dependencies));
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
return { layers, leftover: nonZero };
|
|
@@ -44,37 +45,37 @@ function _calculateDepth(definitionsArray, _dependents, _dependencies) {
|
|
|
44
45
|
const zero = [];
|
|
45
46
|
const nonZero = [];
|
|
46
47
|
|
|
47
|
-
definitionsArray.forEach(([artifactName, artifact]) => {
|
|
48
|
-
if(artifact[_dependencies]) {
|
|
48
|
+
definitionsArray.forEach(([ artifactName, artifact ]) => {
|
|
49
|
+
if (artifact[_dependencies]) {
|
|
49
50
|
artifact.$pointers = artifact[_dependencies].size;
|
|
50
|
-
nonZero.push([artifactName, artifact]);
|
|
51
|
-
}
|
|
51
|
+
nonZero.push([ artifactName, artifact ]);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
52
54
|
artifact.$pointers = 0;
|
|
53
|
-
zero.push([artifactName, artifact]);
|
|
55
|
+
zero.push([ artifactName, artifact ]);
|
|
54
56
|
}
|
|
55
57
|
});
|
|
56
58
|
return {
|
|
57
59
|
zero,
|
|
58
|
-
nonZero
|
|
59
|
-
}
|
|
60
|
+
nonZero,
|
|
61
|
+
};
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
function _findWithXPointers(definitionsArray, x, _dependents, _dependencies){
|
|
64
|
+
function _findWithXPointers(definitionsArray, x, _dependents, _dependencies) {
|
|
63
65
|
const zero = [];
|
|
64
66
|
const nonZero = [];
|
|
65
67
|
|
|
66
|
-
definitionsArray.forEach(([artifactName, artifact]) => {
|
|
67
|
-
if(artifact.$pointers !== undefined && artifact.$pointers === x)
|
|
68
|
-
zero.push([artifactName, artifact]);
|
|
69
|
-
|
|
70
|
-
nonZero.push([artifactName, artifact]);
|
|
71
|
-
}
|
|
68
|
+
definitionsArray.forEach(([ artifactName, artifact ]) => {
|
|
69
|
+
if (artifact.$pointers !== undefined && artifact.$pointers === x)
|
|
70
|
+
zero.push([ artifactName, artifact ]);
|
|
71
|
+
else
|
|
72
|
+
nonZero.push([ artifactName, artifact ]);
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
return {
|
|
75
76
|
zero,
|
|
76
|
-
nonZero
|
|
77
|
-
}
|
|
77
|
+
nonZero,
|
|
78
|
+
};
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -86,24 +87,23 @@ function _findWithXPointers(definitionsArray, x, _dependents, _dependencies){
|
|
|
86
87
|
* @param {CSN.Model} csn
|
|
87
88
|
*
|
|
88
89
|
* @returns {{name: string, sql: string}[]} Sorted array of artifact name / "CREATE STATEMENTS" pairs
|
|
89
|
-
*
|
|
90
90
|
*/
|
|
91
|
-
module.exports = function({sql, csn}){
|
|
92
|
-
const {cleanup, _dependents, _dependencies} = setDependencies(csn);
|
|
91
|
+
module.exports = function sortViews({ sql, csn }) {
|
|
92
|
+
const { cleanup, _dependents, _dependencies } = setDependencies(csn);
|
|
93
93
|
const { layers, leftover } = sortTopologically(csn, _dependents, _dependencies);
|
|
94
94
|
cleanup.forEach(fn => fn());
|
|
95
|
-
if(leftover.length > 0)
|
|
95
|
+
if (leftover.length > 0)
|
|
96
96
|
throw new ModelError('Unable to build a correct dependency graph! Are there cycles?');
|
|
97
97
|
|
|
98
98
|
const result = [];
|
|
99
99
|
// keep the "artifact name" - needed for to.hdi sorting
|
|
100
|
-
layers.forEach(layer => layer.forEach(objName => result.push({name: objName, sql: sql[objName]})));
|
|
100
|
+
layers.forEach(layer => layer.forEach(objName => result.push({ name: objName, sql: sql[objName] })));
|
|
101
101
|
// attach sql artifacts which are not considered during the view sorting algorithm
|
|
102
102
|
// --> this is the case for "ALTER TABLE ADD CONSTRAINT" statements,
|
|
103
103
|
// because their identifiers are not part of the csn.definitions
|
|
104
104
|
Object.entries(sql).forEach(([ name, sqlString ]) => {
|
|
105
105
|
if (!result.some( o => o.name === name )) // not in result but in incoming sql
|
|
106
|
-
result.push({ name, sql: sqlString })
|
|
106
|
+
result.push({ name, sql: sqlString });
|
|
107
107
|
});
|
|
108
108
|
return result;
|
|
109
|
-
}
|
|
109
|
+
};
|
|
@@ -46,17 +46,17 @@ function validateCsnVersions(beforeModel, afterModel, options) {
|
|
|
46
46
|
|
|
47
47
|
if (!beforeVersionParts || beforeVersionParts.length < 2) {
|
|
48
48
|
const { error, throwWithAnyError } = makeMessageFunction(beforeModel, options, 'modelCompare');
|
|
49
|
-
error(null, null, `Invalid CSN version: ${beforeVersion}`);
|
|
49
|
+
error(null, null, {}, `Invalid CSN version: ${beforeVersion}`);
|
|
50
50
|
throwWithAnyError();
|
|
51
51
|
}
|
|
52
52
|
if (!afterVersionParts || afterVersionParts.length < 2) {
|
|
53
53
|
const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
|
|
54
|
-
error(null, null, `Invalid CSN version: ${afterVersion}`);
|
|
54
|
+
error(null, null, {}, `Invalid CSN version: ${afterVersion}`);
|
|
55
55
|
throwWithAnyError();
|
|
56
56
|
}
|
|
57
57
|
if (beforeVersionParts[0] > afterVersionParts[0] && !(options && options.allowCsnDowngrade)) {
|
|
58
58
|
const { error, throwWithAnyError } = makeMessageFunction(afterModel, options, 'modelCompare');
|
|
59
|
-
error(null, null, `Incompatible CSN versions: ${afterVersion} is a major downgrade from ${beforeVersion}. Is @sap/cds-compiler version ${require('../../package.json').version} outdated?`);
|
|
59
|
+
error(null, null, {}, `Incompatible CSN versions: ${afterVersion} is a major downgrade from ${beforeVersion}. Is @sap/cds-compiler version ${require('../../package.json').version} outdated?`);
|
|
60
60
|
throwWithAnyError();
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -65,7 +65,7 @@ function getArtifactComparator(otherModel, options, addedEntities, deletedEntiti
|
|
|
65
65
|
return function compareArtifacts(artifact, name) {
|
|
66
66
|
function addElements() {
|
|
67
67
|
const elements = {};
|
|
68
|
-
forEachMember(artifact, getElementComparator(otherArtifact, elements));
|
|
68
|
+
forEachMember(artifact, getElementComparator(otherArtifact, elements), [ 'definitions', name ], true, { elementsOnly: true });
|
|
69
69
|
if (Object.keys(elements).length > 0) {
|
|
70
70
|
elementAdditions.push(addedElements(name, elements));
|
|
71
71
|
}
|
|
@@ -92,12 +92,12 @@ function getArtifactComparator(otherModel, options, addedEntities, deletedEntiti
|
|
|
92
92
|
migration.properties = changedProperties;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
forEachMember(otherArtifact, getElementComparator(artifact, removedElements));
|
|
95
|
+
forEachMember(otherArtifact, getElementComparator(artifact, removedElements), [ 'definitions', name ], true, { elementsOnly: true });
|
|
96
96
|
if (Object.keys(removedElements).length > 0) {
|
|
97
97
|
migration.remove = removedElements;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
forEachMember(artifact, getElementComparator(otherArtifact, null, changedElements));
|
|
100
|
+
forEachMember(artifact, getElementComparator(otherArtifact, null, changedElements), [ 'definitions', name ], true, { elementsOnly: true });
|
|
101
101
|
if (Object.keys(changedElements).length > 0) {
|
|
102
102
|
migration.change = changedElements;
|
|
103
103
|
}
|
package/lib/optionProcessor.js
CHANGED
|
@@ -142,6 +142,11 @@ optionProcessor
|
|
|
142
142
|
manageConstraints [options] <files...> (internal) Generate ALTER TABLE statements to
|
|
143
143
|
add / modify referential constraints.
|
|
144
144
|
inspect [options] <files...> (internal) Inspect the given CDS files.
|
|
145
|
+
|
|
146
|
+
Environment variables
|
|
147
|
+
NO_COLOR If set, compiler messages (/output) will not be colored.
|
|
148
|
+
Can be overwritten by '--color'
|
|
149
|
+
CDSC_TIMETRACING If set, additional timing information is printed to stderr.
|
|
145
150
|
`);
|
|
146
151
|
|
|
147
152
|
// ----------- toHana -----------
|