@sap/cds-compiler 4.1.2 → 4.2.4
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 +107 -1
- package/bin/cdsc.js +6 -3
- package/doc/CHANGELOG_BETA.md +5 -0
- package/doc/CHANGELOG_DEPRECATED.md +15 -0
- package/lib/api/main.js +2 -2
- package/lib/api/options.js +2 -2
- package/lib/api/validate.js +24 -24
- package/lib/base/message-registry.js +41 -6
- package/lib/base/messages.js +7 -0
- package/lib/base/model.js +38 -8
- package/lib/checks/elements.js +11 -10
- package/lib/checks/manyNavigations.js +33 -0
- package/lib/checks/onConditions.js +5 -2
- package/lib/checks/queryNoDbArtifacts.js +2 -3
- package/lib/checks/selectItems.js +4 -55
- package/lib/checks/utils.js +3 -2
- package/lib/checks/validator.js +3 -1
- package/lib/compiler/.eslintrc.json +2 -1
- package/lib/compiler/assert-consistency.js +27 -24
- package/lib/compiler/base.js +6 -2
- package/lib/compiler/builtins.js +34 -34
- package/lib/compiler/checks.js +179 -208
- package/lib/compiler/classes.js +2 -2
- package/lib/compiler/cycle-detector.js +6 -6
- package/lib/compiler/define.js +66 -45
- package/lib/compiler/extend.js +81 -72
- package/lib/compiler/finalize-parse-cdl.js +26 -26
- package/lib/compiler/generate.js +61 -45
- package/lib/compiler/index.js +47 -49
- package/lib/compiler/kick-start.js +8 -7
- package/lib/compiler/moduleLayers.js +1 -1
- package/lib/compiler/populate.js +42 -35
- package/lib/compiler/propagator.js +6 -6
- package/lib/compiler/resolve.js +170 -126
- package/lib/compiler/shared.js +122 -45
- package/lib/compiler/tweak-assocs.js +93 -40
- package/lib/compiler/utils.js +15 -12
- package/lib/edm/.eslintrc.json +40 -1
- package/lib/edm/annotations/genericTranslation.js +721 -707
- package/lib/edm/annotations/preprocessAnnotations.js +88 -77
- package/lib/edm/csn2edm.js +389 -378
- package/lib/edm/edm.js +678 -772
- package/lib/edm/edmAnnoPreprocessor.js +132 -146
- package/lib/edm/edmInboundChecks.js +29 -27
- package/lib/edm/edmPreprocessor.js +686 -646
- package/lib/edm/edmUtils.js +277 -296
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1253 -1276
- package/lib/json/from-csn.js +34 -4
- package/lib/json/to-csn.js +4 -4
- package/lib/language/language.g4 +2 -5
- package/lib/main.d.ts +61 -1
- package/lib/model/csnUtils.js +31 -2
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/modelCompare/compare.js +37 -2
- package/lib/modelCompare/utils/filter.js +1 -1
- package/lib/optionProcessor.js +15 -3
- package/lib/render/toCdl.js +30 -4
- package/lib/render/toSql.js +5 -9
- package/lib/render/utils/common.js +8 -6
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/constraints.js +47 -17
- package/lib/transform/db/expansion.js +133 -50
- package/lib/transform/db/flattening.js +75 -7
- package/lib/transform/forOdata.js +4 -1
- package/lib/transform/forRelationalDB.js +80 -62
- package/lib/transform/localized.js +91 -54
- package/lib/transform/transformUtils.js +9 -10
- package/lib/utils/file.js +7 -7
- package/lib/utils/moduleResolve.js +210 -121
- package/lib/utils/objectUtils.js +1 -1
- package/package.json +5 -5
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
// Custom resolve functionality for the CDS compiler
|
|
2
2
|
//
|
|
3
3
|
// See `internalDoc/ModuleResolution.md` for details on the algorithm.
|
|
4
|
+
// See also <https://cap.cloud.sap/docs/cds/cdl#model-resolution>.
|
|
4
5
|
// The algorithm is based on NodeJS's `require()`.
|
|
6
|
+
//
|
|
7
|
+
// For debugging purpose, if the option variable `options.traceFs` is set,
|
|
8
|
+
// we log file lookups. This makes it easier to debug why a file was not
|
|
9
|
+
// found when setting custom search directories.
|
|
10
|
+
//
|
|
11
|
+
// You can set this option via your `.cdsrc.json` or `package.json`:
|
|
12
|
+
// `{ "cds": { "cdsc": { "traceFs": true } } }`.
|
|
5
13
|
|
|
6
14
|
'use strict';
|
|
7
15
|
|
|
@@ -14,18 +22,24 @@ const DEFAULT_ENCODING = 'utf-8';
|
|
|
14
22
|
/**
|
|
15
23
|
* Default lookup-extensions. If a module "./index" is requested, then
|
|
16
24
|
* "./index.cds" is checked first, then "index.csn" and so on.
|
|
25
|
+
*
|
|
26
|
+
* Keep in sync with documentation!
|
|
17
27
|
*/
|
|
18
28
|
const extensions = [ '.cds', '.csn', '.json' ];
|
|
29
|
+
/**
|
|
30
|
+
* Default module-lookup directories. Used when resolving modules.
|
|
31
|
+
* Since version v4.2, this option can be configured. Before that,
|
|
32
|
+
* only node_modules/ was a valid module-lookup directory.
|
|
33
|
+
*
|
|
34
|
+
* @type {string[]}
|
|
35
|
+
*/
|
|
36
|
+
const defaultLookupDirectories = [ 'node_modules/' ];
|
|
19
37
|
|
|
20
38
|
/**
|
|
21
|
-
* A global cds.home configuration can be set that
|
|
22
|
-
* use a certain directory for all @sap/cds/ includes.
|
|
39
|
+
* A global `cds.home` or local `options.cdsHome` configuration can be set that
|
|
40
|
+
* forces the cds-compiler to use a certain directory for all @sap/cds/ includes.
|
|
23
41
|
* This function handles such module paths.
|
|
24
42
|
*
|
|
25
|
-
* @todo Re-think:
|
|
26
|
-
* - Why can't a JAVA installation set a (symbolic) link?
|
|
27
|
-
* - Preferred to a local installation? Not the node-way!
|
|
28
|
-
*
|
|
29
43
|
* @param {string} modulePath
|
|
30
44
|
* @param {CSN.Options} options
|
|
31
45
|
* @returns {string}
|
|
@@ -43,127 +57,193 @@ function adaptCdsModule( modulePath, options = {} ) {
|
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
60
|
+
* Create the module resolver, namely `resolveModule(dep)`.
|
|
61
|
+
*
|
|
48
62
|
* @param {CSN.Options} options
|
|
63
|
+
* @param {object} fileCache
|
|
49
64
|
* @param {object} messageFunctions
|
|
50
65
|
*/
|
|
51
|
-
function
|
|
66
|
+
function makeModuleResolver( options, fileCache, messageFunctions ) {
|
|
52
67
|
const _fs = cdsFs(fileCache, options.traceFs);
|
|
53
|
-
|
|
54
|
-
// `preserveSymlinks` option does not really work -> provide workaround anyway...
|
|
55
|
-
// Hm, the resolve package also does not follow the node recommendation:
|
|
56
|
-
// "Using fs.stat() to check for the existence of a file before calling
|
|
57
|
-
// fs.open(), fs.readFile() or fs.writeFile() is not recommended"
|
|
68
|
+
/** @type {ResolveConfig} */
|
|
58
69
|
const opts = {
|
|
59
70
|
extensions,
|
|
60
|
-
basedir: dep.basedir,
|
|
61
71
|
isFile: _fs.isFile,
|
|
62
72
|
readFile: _fs.readFile,
|
|
63
73
|
realpath: _fs.realpath,
|
|
74
|
+
lookupDirs: _getLookupDirectories( options, messageFunctions ),
|
|
64
75
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
resolveModule,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function resolveModule( dep ) {
|
|
82
|
+
return new Promise( (fulfill, reject) => {
|
|
83
|
+
const lookupPath = adaptCdsModule( dep.module, options );
|
|
84
|
+
_resolveCDS( lookupPath, dep.basedir, opts, (err, res) => {
|
|
85
|
+
// console.log('RESOLVE', dep, res, err)
|
|
86
|
+
if (err) {
|
|
87
|
+
reject(err);
|
|
77
88
|
}
|
|
78
|
-
else
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
else {
|
|
90
|
+
const body = fileCache[res];
|
|
91
|
+
if (body === undefined || body === true) { // use fs if no or just temp entry
|
|
92
|
+
dep.absname = res;
|
|
93
|
+
_fs.realpath( res, cb );
|
|
94
|
+
}
|
|
95
|
+
else if (body && typeof body === 'object' && body.realname) {
|
|
96
|
+
// dep.absname = body.realname;
|
|
97
|
+
cb( null, body.realname ); // use fs.realpath name
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// dep.absname = res;
|
|
101
|
+
cb( null, res );
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
function cb( err, res ) {
|
|
107
|
+
if (err) {
|
|
108
|
+
reject(err);
|
|
81
109
|
}
|
|
82
110
|
else {
|
|
83
|
-
|
|
84
|
-
|
|
111
|
+
if (dep.absname)
|
|
112
|
+
fileCache[dep.absname] = (dep.absname === res) || { realname: res };
|
|
113
|
+
dep.resolved = res; // store in dep that module resolve was successful
|
|
114
|
+
for (const from of dep.usingFroms)
|
|
115
|
+
from.realname = res;
|
|
116
|
+
fulfill(res);
|
|
85
117
|
}
|
|
86
118
|
}
|
|
119
|
+
}).catch( () => {
|
|
120
|
+
_errorFileNotFound(dep, options, messageFunctions);
|
|
121
|
+
return false;
|
|
87
122
|
});
|
|
88
|
-
|
|
89
|
-
function cb( err, res ) {
|
|
90
|
-
if (err) {
|
|
91
|
-
reject(err);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
if (dep.absname)
|
|
95
|
-
fileCache[dep.absname] = (dep.absname === res) || { realname: res };
|
|
96
|
-
dep.resolved = res; // store in dep that module resolve was successful
|
|
97
|
-
for (const from of dep.usingFroms)
|
|
98
|
-
from.realname = res;
|
|
99
|
-
fulfill(res);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}).catch( () => {
|
|
103
|
-
_errorFileNotFound(dep, options, messageFunctions);
|
|
104
|
-
return false;
|
|
105
|
-
});
|
|
123
|
+
}
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
|
|
109
127
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
128
|
+
* Create the synchronous module resolver, namely `resolveModuleSync(dep)`.
|
|
129
|
+
*
|
|
112
130
|
* @param {CSN.Options} options
|
|
131
|
+
* @param {object} fileCache
|
|
113
132
|
* @param {object} messageFunctions
|
|
114
133
|
*/
|
|
115
|
-
function
|
|
134
|
+
function makeModuleResolverSync( options, fileCache, messageFunctions ) {
|
|
116
135
|
const _fs = cdsFs(fileCache, options.traceFs);
|
|
136
|
+
/** @type {ResolveConfig} */
|
|
117
137
|
const opts = {
|
|
118
138
|
extensions,
|
|
119
|
-
basedir: dep.basedir,
|
|
120
139
|
isFile: _fs.isFileSync,
|
|
121
140
|
readFile: _fs.readFileSync,
|
|
122
141
|
realpath: _fs.realpathSync,
|
|
142
|
+
lookupDirs: _getLookupDirectories( options, messageFunctions ),
|
|
123
143
|
};
|
|
124
144
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
resolveCDS( lookupPath, opts, (err, res) => {
|
|
130
|
-
if (err)
|
|
131
|
-
error = err;
|
|
132
|
-
if (res)
|
|
133
|
-
result = res;
|
|
134
|
-
});
|
|
145
|
+
return {
|
|
146
|
+
resolveModuleSync,
|
|
147
|
+
};
|
|
135
148
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
function resolveModuleSync( dep ) {
|
|
150
|
+
let result = null;
|
|
151
|
+
let error = null;
|
|
152
|
+
const lookupPath = adaptCdsModule(dep.module, options);
|
|
140
153
|
|
|
141
|
-
|
|
142
|
-
if (body === undefined || body === true) { // use fs if no or just temp entry
|
|
143
|
-
dep.absname = result;
|
|
144
|
-
_fs.realpathSync( result, (err, modulePath) => {
|
|
154
|
+
_resolveCDS( lookupPath, dep.basedir, opts, (err, res) => {
|
|
145
155
|
if (err)
|
|
146
156
|
error = err;
|
|
147
|
-
|
|
148
|
-
result =
|
|
157
|
+
if (res)
|
|
158
|
+
result = res;
|
|
149
159
|
});
|
|
160
|
+
|
|
161
|
+
if (error) {
|
|
162
|
+
_errorFileNotFound(dep, options, messageFunctions);
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const body = result ? fileCache[result] : undefined;
|
|
167
|
+
if (body === undefined || body === true) { // use fs if no or just temp entry
|
|
168
|
+
dep.absname = result;
|
|
169
|
+
_fs.realpathSync( result, (err, modulePath) => {
|
|
170
|
+
if (err)
|
|
171
|
+
error = err;
|
|
172
|
+
else
|
|
173
|
+
result = modulePath;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else if (body && typeof body === 'object' && body.realname) {
|
|
177
|
+
result = body.realname;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (error) {
|
|
181
|
+
_errorFileNotFound(dep, options, messageFunctions);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (dep.absname)
|
|
186
|
+
fileCache[dep.absname] = (dep.absname === result) || { realname: result };
|
|
187
|
+
dep.resolved = result; // store in dep that module resolve was successful
|
|
188
|
+
for (const from of dep.usingFroms)
|
|
189
|
+
from.realname = result;
|
|
190
|
+
|
|
191
|
+
return result;
|
|
150
192
|
}
|
|
151
|
-
|
|
152
|
-
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Get a list of module-lookup directories and ensure that user-provided lookup
|
|
197
|
+
* directories match our expectations / validate them.
|
|
198
|
+
*
|
|
199
|
+
* In case of errors (e.g. invalid options), returns the default list.
|
|
200
|
+
*
|
|
201
|
+
* @param {CSN.Options} options
|
|
202
|
+
* @param {object} messageFunctions
|
|
203
|
+
* @return {string[]}
|
|
204
|
+
*/
|
|
205
|
+
function _getLookupDirectories( options, messageFunctions ) {
|
|
206
|
+
const dirs = options?.moduleLookupDirectories || defaultLookupDirectories;
|
|
207
|
+
|
|
208
|
+
if (!Array.isArray(dirs)) {
|
|
209
|
+
messageFunctions.error('api-invalid-option', null, {
|
|
210
|
+
'#': 'type',
|
|
211
|
+
option: 'moduleLookupDirectories',
|
|
212
|
+
value: 'string[]',
|
|
213
|
+
othervalue: typeof options.moduleLookupDirectories,
|
|
214
|
+
});
|
|
215
|
+
return defaultLookupDirectories;
|
|
153
216
|
}
|
|
154
217
|
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
218
|
+
if (!dirs.includes('node_modules/')) {
|
|
219
|
+
// Special case of call-side-errors and to ensure old behavior.
|
|
220
|
+
dirs.push('node_modules/');
|
|
158
221
|
}
|
|
159
222
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
223
|
+
for (const dir of dirs) {
|
|
224
|
+
if (!dir.endsWith('/')) {
|
|
225
|
+
messageFunctions.error('api-invalid-lookup-dir', null, {
|
|
226
|
+
'#': 'slash',
|
|
227
|
+
option: 'moduleLookupDirectories',
|
|
228
|
+
value: dir,
|
|
229
|
+
othervalue: '/',
|
|
230
|
+
} );
|
|
231
|
+
return defaultLookupDirectories;
|
|
232
|
+
}
|
|
233
|
+
if (dir.startsWith('./') || dir.startsWith('../')) {
|
|
234
|
+
// Avoid relative directories, as we don't want to give the impression that they
|
|
235
|
+
// are resolved relative to the caller.
|
|
236
|
+
messageFunctions.error('api-invalid-lookup-dir', null, {
|
|
237
|
+
'#': 'relative',
|
|
238
|
+
option: 'moduleLookupDirectories',
|
|
239
|
+
value: dir,
|
|
240
|
+
othervalue: './',
|
|
241
|
+
});
|
|
242
|
+
return defaultLookupDirectories;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
165
245
|
|
|
166
|
-
return
|
|
246
|
+
return dirs;
|
|
167
247
|
}
|
|
168
248
|
|
|
169
249
|
function _errorFileNotFound( dep, options, { error } ) {
|
|
@@ -201,16 +281,18 @@ function _errorFileNotFound( dep, options, { error } ) {
|
|
|
201
281
|
* with existing code. This may change at a later point.
|
|
202
282
|
*
|
|
203
283
|
* @param {string} moduleName Module to load, e.g. `./Include.cds` or `@sap/cds/common`.
|
|
204
|
-
* @param {
|
|
284
|
+
* @param {ResolveConfig} config
|
|
285
|
+
* @param {string} baseDir
|
|
205
286
|
* @param {(err, result) => void} callback
|
|
206
287
|
*/
|
|
207
|
-
function
|
|
288
|
+
function _resolveCDS( moduleName, baseDir, config, callback ) {
|
|
208
289
|
const isWindows = (process.platform === 'win32');
|
|
209
|
-
let resolvedBaseDir = path.resolve(
|
|
290
|
+
let resolvedBaseDir = path.resolve(baseDir);
|
|
291
|
+
const lookupDirs = [ ...config.lookupDirs ];
|
|
210
292
|
|
|
211
293
|
// NodeJS does not preserve symbolic links when resolving modules.
|
|
212
294
|
// So neither do we.
|
|
213
|
-
|
|
295
|
+
config.realpath(resolvedBaseDir, (realPathErr, realPath) => {
|
|
214
296
|
// There may be an error in resolving the symlink.
|
|
215
297
|
// We ignore the error and simply use the original path.
|
|
216
298
|
// Otherwise, cds-lsp tests would fail because they don't have real
|
|
@@ -224,7 +306,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
224
306
|
if (isLocalFile(moduleName))
|
|
225
307
|
loadFromLocalFileOrDirectory();
|
|
226
308
|
else
|
|
227
|
-
|
|
309
|
+
loadAsModule(resolvedBaseDir);
|
|
228
310
|
}
|
|
229
311
|
|
|
230
312
|
/**
|
|
@@ -269,7 +351,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
269
351
|
* @param {(err, filepath: string|null) => void} cb
|
|
270
352
|
*/
|
|
271
353
|
function loadAsFile( absoluteModulePath, cb ) {
|
|
272
|
-
const extensionsToTry = [ '' ].concat(
|
|
354
|
+
const extensionsToTry = [ '' ].concat(config.extensions);
|
|
273
355
|
loadFileWithExtensions(extensionsToTry);
|
|
274
356
|
|
|
275
357
|
/**
|
|
@@ -284,7 +366,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
284
366
|
return;
|
|
285
367
|
}
|
|
286
368
|
const file = absoluteModulePath + exts.shift();
|
|
287
|
-
|
|
369
|
+
config.isFile(file, (err, foundAndIsFile) => {
|
|
288
370
|
if (!err && foundAndIsFile)
|
|
289
371
|
cb(null, file);
|
|
290
372
|
else
|
|
@@ -332,28 +414,29 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
332
414
|
}
|
|
333
415
|
|
|
334
416
|
/**
|
|
335
|
-
* Try to load the module from a
|
|
336
|
-
*
|
|
417
|
+
* Try to load the module from a specified module-lookup directory such
|
|
418
|
+
* as `node_modules/`.
|
|
419
|
+
* Start at `absoluteDir` and go through all parent directories.
|
|
337
420
|
*
|
|
338
421
|
* @param {string} absoluteDir
|
|
339
422
|
*/
|
|
340
|
-
function
|
|
341
|
-
const
|
|
342
|
-
|
|
423
|
+
function loadAsModule( absoluteDir ) {
|
|
424
|
+
const dirGen = modulePaths(absoluteDir);
|
|
425
|
+
loadNextDir();
|
|
343
426
|
|
|
344
|
-
function
|
|
345
|
-
const dir =
|
|
346
|
-
if (
|
|
427
|
+
function loadNextDir() {
|
|
428
|
+
const dir = dirGen.next();
|
|
429
|
+
if (dir.done) {
|
|
347
430
|
// We're at root
|
|
348
431
|
callback(makeNotFoundError(), null);
|
|
349
432
|
return;
|
|
350
433
|
}
|
|
351
|
-
const file = path.join(dir, moduleName);
|
|
434
|
+
const file = path.join(dir.value, moduleName);
|
|
352
435
|
loadAsLocalFileOrDirectory(file, (err, filepath) => {
|
|
353
436
|
if (!err && filepath)
|
|
354
437
|
callback(null, filepath);
|
|
355
438
|
else
|
|
356
|
-
|
|
439
|
+
loadNextDir();
|
|
357
440
|
});
|
|
358
441
|
}
|
|
359
442
|
}
|
|
@@ -368,7 +451,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
368
451
|
function loadAndParsePackageJsonInDirectory( packageDir, cb ) {
|
|
369
452
|
const file = path.join(packageDir, 'package.json');
|
|
370
453
|
|
|
371
|
-
|
|
454
|
+
config.readFile(file, DEFAULT_ENCODING, (err, content) => {
|
|
372
455
|
if (err) {
|
|
373
456
|
cb(err, null);
|
|
374
457
|
return;
|
|
@@ -385,16 +468,14 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
385
468
|
|
|
386
469
|
/**
|
|
387
470
|
* Get a list of all `node_modules` directories that MAY exist.
|
|
388
|
-
* Starting from absoluteStart upwards until at root.
|
|
471
|
+
* Starting from `absoluteStart` upwards until at root.
|
|
389
472
|
*
|
|
390
|
-
* @param {string} absoluteStart
|
|
391
|
-
* @
|
|
473
|
+
* @param {string} absoluteStart *
|
|
474
|
+
* @return {Generator<string>} Possible module directories for the given path.
|
|
392
475
|
*/
|
|
393
|
-
function
|
|
476
|
+
function* modulePaths( absoluteStart ) {
|
|
394
477
|
// Use platform-dependent separator. All NodeJS `path` methods use the system's path separator.
|
|
395
478
|
const parts = absoluteStart.split(path.sep);
|
|
396
|
-
// Do NOT use global node_modules directories.
|
|
397
|
-
const dirs = [];
|
|
398
479
|
|
|
399
480
|
// If we're on *nix systems, the first part is just an empty string ''
|
|
400
481
|
// because the path is absolute. Re-add it here because `path.join()`
|
|
@@ -403,12 +484,18 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
403
484
|
parts[0] = '/';
|
|
404
485
|
|
|
405
486
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
487
|
+
for (let j = 0; j < lookupDirs.length; ++j) {
|
|
488
|
+
const dir = lookupDirs[j];
|
|
489
|
+
if (dir && path.isAbsolute(dir)) {
|
|
490
|
+
// Only look up absolute paths once.
|
|
491
|
+
lookupDirs[j] = null;
|
|
492
|
+
yield dir;
|
|
493
|
+
}
|
|
494
|
+
else if (dir && parts[i] && !lookupDirs.includes(`${ parts[i] }/`)) {
|
|
495
|
+
yield path.join(...parts.slice(0, i + 1), dir);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
410
498
|
}
|
|
411
|
-
return dirs;
|
|
412
499
|
}
|
|
413
500
|
|
|
414
501
|
/**
|
|
@@ -417,7 +504,7 @@ function resolveCDS( moduleName, options, callback ) {
|
|
|
417
504
|
* @returns {Error}
|
|
418
505
|
*/
|
|
419
506
|
function makeNotFoundError() {
|
|
420
|
-
const moduleError = new Error(`Can't find module '${ moduleName }' from '${
|
|
507
|
+
const moduleError = new Error(`Can't find module '${ moduleName }' from '${ config.basedir }'`);
|
|
421
508
|
// eslint-disable-next-line
|
|
422
509
|
moduleError['code'] = 'MODULE_NOT_FOUND';
|
|
423
510
|
return moduleError;
|
|
@@ -437,7 +524,7 @@ function isLocalFile( moduleName ) {
|
|
|
437
524
|
}
|
|
438
525
|
|
|
439
526
|
/**
|
|
440
|
-
* Get the cds.main entry of the package.json
|
|
527
|
+
* Get the `cds.main` entry of the package.json
|
|
441
528
|
* @param {object} pkg
|
|
442
529
|
*/
|
|
443
530
|
function packageCdsMain( pkg ) {
|
|
@@ -447,8 +534,9 @@ function packageCdsMain( pkg ) {
|
|
|
447
534
|
}
|
|
448
535
|
|
|
449
536
|
/**
|
|
450
|
-
* @typedef {object}
|
|
451
|
-
* @property {string}
|
|
537
|
+
* @typedef {object} ResolveConfig
|
|
538
|
+
* @property {string[]} lookupDirs
|
|
539
|
+
* Directories to look in for modules, e.g. node_modules/.
|
|
452
540
|
* @property {string[]} extensions
|
|
453
541
|
* @property {(path: string, callback: (err, foundAndIsFile) => void) => void} isFile
|
|
454
542
|
* @property {(path: string, encoding, callback: (err, content) => void) => void} readFile
|
|
@@ -457,10 +545,11 @@ function packageCdsMain( pkg ) {
|
|
|
457
545
|
*/
|
|
458
546
|
|
|
459
547
|
module.exports = {
|
|
460
|
-
|
|
461
|
-
|
|
548
|
+
makeModuleResolver,
|
|
549
|
+
makeModuleResolverSync,
|
|
462
550
|
// exported for unit tests
|
|
463
|
-
|
|
551
|
+
_resolveCDS,
|
|
552
|
+
_getLookupDirectories,
|
|
464
553
|
isLocalFile,
|
|
465
554
|
extensions,
|
|
466
555
|
};
|
package/lib/utils/objectUtils.js
CHANGED
|
@@ -15,7 +15,7 @@ function copyPropIfExist( sourceObj, property, targetObj ) {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Takes an object and creates a dictionary out of it.
|
|
18
|
-
* This
|
|
18
|
+
* This avoids cases where e.g. properties named "toString" are interpreted
|
|
19
19
|
* as JS internal functions.
|
|
20
20
|
*
|
|
21
21
|
* @param {object} obj Object with prototype.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-compiler",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.4",
|
|
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)",
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"testci": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter-option maxDiffSize=0 test/ test3/",
|
|
23
23
|
"testverbose": "node scripts/verifyGrammarChecksum.js && mocha --parallel test/ test3/",
|
|
24
24
|
"test3": "node scripts/verifyGrammarChecksum.js && mocha --reporter-option maxDiffSize=0 test3/",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"deployDiffs": "deployRefs=true mocha --reporter-option maxDiffSize=0 test3/deployDiffs.js",
|
|
25
|
+
"deployHanaSql": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.hana-sql.js",
|
|
26
|
+
"deployHdiHdbcds": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.hdi.hdbcds.js",
|
|
27
|
+
"deployGitDiffs": "CDS_COMPILER_DEPLOY_HANA=1 mocha --reporter-option maxDiffSize=0 test3/test.deploy.git-diffs.js",
|
|
29
28
|
"gentest3": "cross-env MAKEREFS=${MAKEREFS:-'true'} mocha --reporter-option maxDiffSize=0 test3/testRefFiles.js",
|
|
30
29
|
"coverage": "cross-env nyc mocha --reporter-option maxDiffSize=0 test/ test3/ && nyc report --reporter=lcov",
|
|
31
30
|
"lint": "eslint bin/ benchmark/ lib/ test/ test3/ scripts/ types/ && node scripts/linter/lintGrammar.js && node scripts/linter/lintTests.js test3/ && node scripts/linter/lintMessages.js && node scripts/linter/lintMessageIdCoverage.js lib/ && markdownlint README.md CHANGELOG.md doc/ internalDoc/ && cd share/messages && markdownlint .",
|
|
32
31
|
"tslint": "tsc --pretty -p .",
|
|
33
32
|
"updateVocs": "node scripts/odataAnnotations/generateDictMain.js && npm run generateAllRefs",
|
|
33
|
+
"updateTocs": "node scripts/update-toc.js",
|
|
34
34
|
"generateCompilerRefs": "cross-env MAKEREFS='true' mocha test/testCompiler.js",
|
|
35
35
|
"generateEdmRefs": "cross-env MAKEREFS='true' mocha test/testEdmPositive.js",
|
|
36
36
|
"generateForHanaRefs": "cross-env MAKEREFS='true' mocha test/testHanaTransformation.js",
|