@sap-ux/project-access 1.38.1 → 2.0.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/dist/command/index.d.ts +1 -1
- package/dist/command/index.js +1 -5
- package/dist/command/npm-command.js +3 -6
- package/dist/constants.js +10 -13
- package/dist/file/file-access.d.ts +1 -1
- package/dist/file/file-access.js +18 -32
- package/dist/file/file-search.js +25 -35
- package/dist/file/index.d.ts +2 -2
- package/dist/file/index.js +2 -19
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -102
- package/dist/library/constants.js +1 -4
- package/dist/library/helpers.d.ts +1 -1
- package/dist/library/helpers.js +36 -44
- package/dist/library/index.d.ts +1 -1
- package/dist/library/index.js +1 -6
- package/dist/odata/index.d.ts +1 -1
- package/dist/odata/index.js +1 -6
- package/dist/odata/metadata.js +2 -6
- package/dist/path/index.d.ts +1 -1
- package/dist/path/index.js +1 -5
- package/dist/path/normalize.js +3 -6
- package/dist/project/access.d.ts +1 -1
- package/dist/project/access.js +30 -34
- package/dist/project/cap.d.ts +1 -1
- package/dist/project/cap.js +75 -102
- package/dist/project/dependencies.d.ts +1 -1
- package/dist/project/dependencies.js +16 -22
- package/dist/project/flex-changes.js +7 -10
- package/dist/project/i18n/i18n.d.ts +1 -1
- package/dist/project/i18n/i18n.js +22 -22
- package/dist/project/i18n/index.d.ts +3 -3
- package/dist/project/i18n/index.js +3 -13
- package/dist/project/i18n/read.d.ts +1 -1
- package/dist/project/i18n/read.js +11 -15
- package/dist/project/i18n/write.d.ts +1 -1
- package/dist/project/i18n/write.js +22 -28
- package/dist/project/index.d.ts +15 -15
- package/dist/project/index.js +14 -79
- package/dist/project/info.d.ts +1 -1
- package/dist/project/info.js +45 -54
- package/dist/project/module-loader.js +27 -64
- package/dist/project/mta.d.ts +1 -1
- package/dist/project/mta.js +6 -9
- package/dist/project/script.js +11 -18
- package/dist/project/search.d.ts +1 -1
- package/dist/project/search.js +77 -86
- package/dist/project/service.d.ts +1 -1
- package/dist/project/service.js +10 -16
- package/dist/project/specification.js +38 -44
- package/dist/project/ui5-config.js +21 -29
- package/dist/project/ui5-xml-id-validator.js +3 -6
- package/dist/types/access/index.d.ts +4 -4
- package/dist/types/access/index.js +1 -2
- package/dist/types/cap/index.js +1 -2
- package/dist/types/find/index.d.ts +1 -1
- package/dist/types/find/index.js +1 -2
- package/dist/types/i18n/index.js +1 -2
- package/dist/types/index.d.ts +9 -9
- package/dist/types/index.js +9 -25
- package/dist/types/info/index.d.ts +2 -2
- package/dist/types/info/index.js +1 -2
- package/dist/types/library/index.js +5 -2
- package/dist/types/mta/index.js +1 -2
- package/dist/types/package/basic.js +1 -2
- package/dist/types/package/index.d.ts +1 -1
- package/dist/types/package/index.js +1 -2
- package/dist/types/package/literal-union.d.ts +1 -1
- package/dist/types/package/literal-union.js +1 -2
- package/dist/types/package/package-json.d.ts +2 -2
- package/dist/types/package/package-json.js +1 -2
- package/dist/types/package/primitive.js +1 -2
- package/dist/types/vscode/index.js +1 -2
- package/dist/types/webapp/index.d.ts +2 -3
- package/dist/types/webapp/index.js +1 -2
- package/package.json +7 -5
package/dist/project/search.js
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.findAllApps = findAllApps;
|
|
8
|
-
exports.findFioriArtifacts = findFioriArtifacts;
|
|
9
|
-
exports.findCapProjects = findCapProjects;
|
|
10
|
-
const node_path_1 = require("node:path");
|
|
11
|
-
const constants_1 = require("../constants");
|
|
12
|
-
const file_1 = require("../file");
|
|
13
|
-
const dependencies_1 = require("./dependencies");
|
|
14
|
-
const cap_1 = require("./cap");
|
|
15
|
-
const ui5_config_1 = require("./ui5-config");
|
|
1
|
+
import { basename, dirname, isAbsolute, join, parse, sep } from 'node:path';
|
|
2
|
+
import { FileName } from '../constants.js';
|
|
3
|
+
import { fileExists, findBy, findFileUp, readJSON } from '../file/index.js';
|
|
4
|
+
import { hasDependency } from './dependencies.js';
|
|
5
|
+
import { getCapProjectType } from './cap.js';
|
|
6
|
+
import { getWebappPath } from './ui5-config.js';
|
|
16
7
|
/**
|
|
17
8
|
* Map artifact to file that is specific to the artifact type. Some artifacts can
|
|
18
9
|
* be identified by the same file, like app and library have file 'manifest.json'.
|
|
@@ -20,11 +11,11 @@ const ui5_config_1 = require("./ui5-config");
|
|
|
20
11
|
* functions.
|
|
21
12
|
*/
|
|
22
13
|
const filterFileMap = {
|
|
23
|
-
applications: [
|
|
24
|
-
adaptations: [
|
|
25
|
-
components: [
|
|
26
|
-
extensions: [
|
|
27
|
-
libraries: [
|
|
14
|
+
applications: [FileName.Manifest],
|
|
15
|
+
adaptations: [FileName.ManifestAppDescrVar],
|
|
16
|
+
components: [FileName.Manifest],
|
|
17
|
+
extensions: [FileName.ExtConfigJson],
|
|
18
|
+
libraries: [FileName.Library, FileName.Manifest]
|
|
28
19
|
};
|
|
29
20
|
/**
|
|
30
21
|
* Default folders to exclude from search.
|
|
@@ -70,19 +61,19 @@ function wsFoldersToRootPaths(wsFolders) {
|
|
|
70
61
|
* @param memFs - optional mem-fs-editor instance
|
|
71
62
|
* @returns {*} {Promise<string>} - Project Root
|
|
72
63
|
*/
|
|
73
|
-
async function findProjectRoot(path, sapuxRequired = true, silent = false, memFs) {
|
|
74
|
-
const packageJson = await
|
|
64
|
+
export async function findProjectRoot(path, sapuxRequired = true, silent = false, memFs) {
|
|
65
|
+
const packageJson = await findFileUp(FileName.Package, path, memFs);
|
|
75
66
|
if (!packageJson) {
|
|
76
67
|
if (silent) {
|
|
77
68
|
return '';
|
|
78
69
|
}
|
|
79
70
|
throw new Error(`Could not find any project root for '${path}'. Search was done for ${sapuxRequired ? 'Fiori elements' : 'All'} projects.`);
|
|
80
71
|
}
|
|
81
|
-
let root =
|
|
72
|
+
let root = dirname(packageJson);
|
|
82
73
|
if (sapuxRequired) {
|
|
83
|
-
const sapux = (await
|
|
74
|
+
const sapux = (await readJSON(packageJson, memFs)).sapux;
|
|
84
75
|
if (!sapux) {
|
|
85
|
-
root = await findProjectRoot(
|
|
76
|
+
root = await findProjectRoot(dirname(root), sapuxRequired, silent, memFs);
|
|
86
77
|
}
|
|
87
78
|
}
|
|
88
79
|
return root;
|
|
@@ -105,12 +96,12 @@ function findRootsWithSapux(sapux, path, root) {
|
|
|
105
96
|
else if (Array.isArray(sapux)) {
|
|
106
97
|
// Backward compatibility for FE apps in CAP projects that have no app package.json,
|
|
107
98
|
// but are listed in CAP root sapux array
|
|
108
|
-
const pathWithSep = path.endsWith(
|
|
109
|
-
const relAppPaths = sapux.map((a) =>
|
|
110
|
-
const relApp = relAppPaths.find((app) => pathWithSep.startsWith(
|
|
99
|
+
const pathWithSep = path.endsWith(sep) ? path : path + sep;
|
|
100
|
+
const relAppPaths = sapux.map((a) => join(...a.split(/[\\/]/)));
|
|
101
|
+
const relApp = relAppPaths.find((app) => pathWithSep.startsWith(join(root, app) + sep));
|
|
111
102
|
if (relApp) {
|
|
112
103
|
return {
|
|
113
|
-
appRoot:
|
|
104
|
+
appRoot: join(root, relApp),
|
|
114
105
|
projectRoot: root
|
|
115
106
|
};
|
|
116
107
|
}
|
|
@@ -124,12 +115,12 @@ function findRootsWithSapux(sapux, path, root) {
|
|
|
124
115
|
* @param webappPath - path to webapp folder, where manifest.json is
|
|
125
116
|
* @returns - root path of the application, where usually ui5.yaml and package.json are
|
|
126
117
|
*/
|
|
127
|
-
async function getAppRootFromWebappPath(webappPath) {
|
|
128
|
-
const ui5YamlPath = await
|
|
129
|
-
let appRoot =
|
|
118
|
+
export async function getAppRootFromWebappPath(webappPath) {
|
|
119
|
+
const ui5YamlPath = await findFileUp(FileName.Ui5Yaml, webappPath);
|
|
120
|
+
let appRoot = dirname(webappPath);
|
|
130
121
|
if (ui5YamlPath) {
|
|
131
|
-
const candidate =
|
|
132
|
-
const webapp = await
|
|
122
|
+
const candidate = dirname(ui5YamlPath);
|
|
123
|
+
const webapp = await getWebappPath(candidate);
|
|
133
124
|
if (webapp === webappPath) {
|
|
134
125
|
appRoot = candidate;
|
|
135
126
|
}
|
|
@@ -182,7 +173,7 @@ function getFindOptions(options) {
|
|
|
182
173
|
* @param options - optional mem-fs-editor instance or options object with optional memFs and cache
|
|
183
174
|
* @returns - in case a supported app is found this function returns the appRoot and projectRoot path
|
|
184
175
|
*/
|
|
185
|
-
async function findRootsForPath(path, options) {
|
|
176
|
+
export async function findRootsForPath(path, options) {
|
|
186
177
|
try {
|
|
187
178
|
const { memFs, cache } = getFindOptions(options);
|
|
188
179
|
// Get the root of the app, that is where the package.json is, otherwise not supported
|
|
@@ -190,7 +181,7 @@ async function findRootsForPath(path, options) {
|
|
|
190
181
|
if (!appRoot) {
|
|
191
182
|
return null;
|
|
192
183
|
}
|
|
193
|
-
cache.files[path] ??= await
|
|
184
|
+
cache.files[path] ??= await readJSON(join(appRoot, FileName.Package), memFs);
|
|
194
185
|
const appPckJson = cache.files[path];
|
|
195
186
|
// Check for most common app, Fiori elements with sapux=true in package.json
|
|
196
187
|
if (appPckJson.sapux) {
|
|
@@ -207,8 +198,8 @@ async function findRootsForPath(path, options) {
|
|
|
207
198
|
}
|
|
208
199
|
else if (
|
|
209
200
|
// Check for freestyle non CAP
|
|
210
|
-
(await
|
|
211
|
-
|
|
201
|
+
(await fileExists(join(appRoot, FileName.Ui5LocalYaml), memFs)) &&
|
|
202
|
+
hasDependency(appPckJson, '@sap/ux-ui5-tooling')) {
|
|
212
203
|
return {
|
|
213
204
|
appRoot,
|
|
214
205
|
projectRoot: appRoot
|
|
@@ -228,28 +219,28 @@ async function findRootsForPath(path, options) {
|
|
|
228
219
|
* @param options - optional mem-fs-editor instance or options object with optional memFs and cache
|
|
229
220
|
* @returns - CAP project root path
|
|
230
221
|
*/
|
|
231
|
-
async function findCapProjectRoot(path, checkForAppRouter = true, options) {
|
|
222
|
+
export async function findCapProjectRoot(path, checkForAppRouter = true, options) {
|
|
232
223
|
try {
|
|
233
|
-
if (!
|
|
224
|
+
if (!isAbsolute(path)) {
|
|
234
225
|
return null;
|
|
235
226
|
}
|
|
236
227
|
const { memFs, cache } = getFindOptions(options);
|
|
237
|
-
const { root } =
|
|
238
|
-
let projectRoot =
|
|
228
|
+
const { root } = parse(path);
|
|
229
|
+
let projectRoot = dirname(path);
|
|
239
230
|
while (projectRoot !== root) {
|
|
240
231
|
if (!cache.capProjectType.has(projectRoot)) {
|
|
241
|
-
cache.capProjectType.set(projectRoot, await
|
|
232
|
+
cache.capProjectType.set(projectRoot, await getCapProjectType(projectRoot, memFs));
|
|
242
233
|
}
|
|
243
234
|
const capProjectType = cache.capProjectType.get(projectRoot);
|
|
244
235
|
if (capProjectType) {
|
|
245
236
|
// We have found a CAP project as root. Check if the found app is not directly in CAP's 'app/' folder.
|
|
246
237
|
// Sometime there is a <CAP_ROOT>/app/package.json file that is used for app router (not an app)
|
|
247
238
|
// or skip app router check if checkForAppRouter is false and return the project root.
|
|
248
|
-
if ((checkForAppRouter &&
|
|
239
|
+
if ((checkForAppRouter && join(projectRoot, 'app') !== path) || !checkForAppRouter) {
|
|
249
240
|
return projectRoot;
|
|
250
241
|
}
|
|
251
242
|
}
|
|
252
|
-
projectRoot =
|
|
243
|
+
projectRoot = dirname(projectRoot);
|
|
253
244
|
}
|
|
254
245
|
}
|
|
255
246
|
catch {
|
|
@@ -266,7 +257,7 @@ async function findCapProjectRoot(path, checkForAppRouter = true, options) {
|
|
|
266
257
|
* @param memFs - optional mem-fs-editor instance
|
|
267
258
|
* @returns - results as path to apps plus files already parsed, e.g. manifest.json
|
|
268
259
|
*/
|
|
269
|
-
async function findAllApps(wsFolders, memFs) {
|
|
260
|
+
export async function findAllApps(wsFolders, memFs) {
|
|
270
261
|
const findResults = await findFioriArtifacts({ wsFolders, artifacts: ['applications'], memFs });
|
|
271
262
|
return findResults.applications ?? [];
|
|
272
263
|
}
|
|
@@ -279,17 +270,17 @@ async function findAllApps(wsFolders, memFs) {
|
|
|
279
270
|
*/
|
|
280
271
|
async function filterApplications(pathMap, memFs) {
|
|
281
272
|
const result = [];
|
|
282
|
-
const manifestPaths = Object.keys(pathMap.files).filter((path) =>
|
|
273
|
+
const manifestPaths = Object.keys(pathMap.files).filter((path) => basename(path) === FileName.Manifest);
|
|
283
274
|
for (const manifestPath of manifestPaths) {
|
|
284
275
|
try {
|
|
285
276
|
// All UI5 apps have at least sap.app: { id: <ID>, type: "application" } in manifest.json
|
|
286
|
-
pathMap.files[manifestPath] ??= await
|
|
277
|
+
pathMap.files[manifestPath] ??= await readJSON(manifestPath, memFs);
|
|
287
278
|
const manifest = pathMap.files[manifestPath];
|
|
288
279
|
if (!manifest['sap.app']?.id || manifest['sap.app'].type !== 'application') {
|
|
289
280
|
continue;
|
|
290
281
|
}
|
|
291
|
-
const roots = await findRootsForPath(
|
|
292
|
-
if (roots && !(await
|
|
282
|
+
const roots = await findRootsForPath(dirname(manifestPath), { memFs, cache: pathMap });
|
|
283
|
+
if (roots && !(await fileExists(join(roots.appRoot, '.adp', FileName.AdaptationConfig), memFs))) {
|
|
293
284
|
result.push({ appRoot: roots.appRoot, projectRoot: roots.projectRoot, manifest, manifestPath });
|
|
294
285
|
}
|
|
295
286
|
}
|
|
@@ -308,12 +299,12 @@ async function filterApplications(pathMap, memFs) {
|
|
|
308
299
|
*/
|
|
309
300
|
async function filterAdaptations(pathMap, memFs) {
|
|
310
301
|
const results = [];
|
|
311
|
-
const manifestAppDescrVars = Object.keys(pathMap.files).filter((path) => path.endsWith(
|
|
302
|
+
const manifestAppDescrVars = Object.keys(pathMap.files).filter((path) => path.endsWith(FileName.ManifestAppDescrVar));
|
|
312
303
|
for (const manifestAppDescrVar of manifestAppDescrVars) {
|
|
313
|
-
const packageJsonPath = await
|
|
314
|
-
const projectRoot = packageJsonPath ?
|
|
315
|
-
const webappPath = await
|
|
316
|
-
if (projectRoot && (await
|
|
304
|
+
const packageJsonPath = await findFileUp(FileName.Package, dirname(manifestAppDescrVar), memFs);
|
|
305
|
+
const projectRoot = packageJsonPath ? dirname(packageJsonPath) : null;
|
|
306
|
+
const webappPath = await getWebappPath(projectRoot ?? '', memFs);
|
|
307
|
+
if (projectRoot && (await fileExists(join(webappPath, FileName.ManifestAppDescrVar), memFs))) {
|
|
317
308
|
results.push({ appRoot: projectRoot, manifestAppdescrVariantPath: manifestAppDescrVar });
|
|
318
309
|
}
|
|
319
310
|
}
|
|
@@ -328,29 +319,29 @@ async function filterAdaptations(pathMap, memFs) {
|
|
|
328
319
|
*/
|
|
329
320
|
async function filterExtensions(pathMap, memFs) {
|
|
330
321
|
const results = [];
|
|
331
|
-
const extensionConfigs = Object.keys(pathMap.files).filter((path) =>
|
|
322
|
+
const extensionConfigs = Object.keys(pathMap.files).filter((path) => basename(path) === FileName.ExtConfigJson);
|
|
332
323
|
for (const extensionConfig of extensionConfigs) {
|
|
333
324
|
try {
|
|
334
325
|
let manifest = null;
|
|
335
|
-
let manifestPath = Object.keys(pathMap).find((path) => path.startsWith(
|
|
326
|
+
let manifestPath = Object.keys(pathMap).find((path) => path.startsWith(dirname(extensionConfig) + sep) && basename(path) === FileName.Manifest);
|
|
336
327
|
if (manifestPath) {
|
|
337
|
-
pathMap.files[manifestPath] ??= await
|
|
328
|
+
pathMap.files[manifestPath] ??= await readJSON(manifestPath, memFs);
|
|
338
329
|
manifest = pathMap.files[manifestPath];
|
|
339
330
|
}
|
|
340
331
|
else {
|
|
341
|
-
const manifests = await
|
|
342
|
-
fileNames: [
|
|
343
|
-
root:
|
|
332
|
+
const manifests = await findBy({
|
|
333
|
+
fileNames: [FileName.Manifest],
|
|
334
|
+
root: dirname(extensionConfig),
|
|
344
335
|
excludeFolders,
|
|
345
336
|
memFs
|
|
346
337
|
});
|
|
347
338
|
if (manifests.length === 1) {
|
|
348
339
|
[manifestPath] = manifests;
|
|
349
|
-
manifest = await
|
|
340
|
+
manifest = await readJSON(manifestPath, memFs);
|
|
350
341
|
}
|
|
351
342
|
}
|
|
352
343
|
if (manifestPath && manifest) {
|
|
353
|
-
results.push({ appRoot:
|
|
344
|
+
results.push({ appRoot: dirname(extensionConfig), manifest, manifestPath });
|
|
354
345
|
}
|
|
355
346
|
}
|
|
356
347
|
catch {
|
|
@@ -370,12 +361,12 @@ async function filterExtensions(pathMap, memFs) {
|
|
|
370
361
|
async function filterDotLibraries(pathMap, manifestPaths, memFs) {
|
|
371
362
|
const dotLibraries = [];
|
|
372
363
|
const dotLibraryPaths = Object.keys(pathMap.files)
|
|
373
|
-
.filter((path) =>
|
|
374
|
-
.map((path) =>
|
|
375
|
-
.filter((path) => !manifestPaths.map((manifestPath) =>
|
|
364
|
+
.filter((path) => basename(path) === FileName.Library)
|
|
365
|
+
.map((path) => dirname(path))
|
|
366
|
+
.filter((path) => !manifestPaths.map((manifestPath) => dirname(manifestPath)).includes(path));
|
|
376
367
|
if (dotLibraryPaths) {
|
|
377
368
|
for (const libraryPath of dotLibraryPaths) {
|
|
378
|
-
const projectRoot =
|
|
369
|
+
const projectRoot = dirname((await findFileUp(FileName.Package, dirname(libraryPath), memFs)) ?? libraryPath);
|
|
379
370
|
dotLibraries.push({ projectRoot, libraryPath });
|
|
380
371
|
}
|
|
381
372
|
}
|
|
@@ -390,16 +381,16 @@ async function filterDotLibraries(pathMap, manifestPaths, memFs) {
|
|
|
390
381
|
*/
|
|
391
382
|
async function filterLibraries(pathMap, memFs) {
|
|
392
383
|
const results = [];
|
|
393
|
-
const manifestPaths = Object.keys(pathMap.files).filter((path) =>
|
|
384
|
+
const manifestPaths = Object.keys(pathMap.files).filter((path) => basename(path) === FileName.Manifest);
|
|
394
385
|
results.push(...(await filterDotLibraries(pathMap, manifestPaths, memFs)));
|
|
395
386
|
for (const manifestPath of manifestPaths) {
|
|
396
387
|
try {
|
|
397
|
-
pathMap.files[manifestPath] ??= await
|
|
388
|
+
pathMap.files[manifestPath] ??= await readJSON(manifestPath, memFs);
|
|
398
389
|
const manifest = pathMap.files[manifestPath];
|
|
399
390
|
if (manifest['sap.app']?.type === 'library') {
|
|
400
|
-
const packageJsonPath = await
|
|
401
|
-
const projectRoot = packageJsonPath ?
|
|
402
|
-
if (projectRoot && (await
|
|
391
|
+
const packageJsonPath = await findFileUp(FileName.Package, dirname(manifestPath), memFs);
|
|
392
|
+
const projectRoot = packageJsonPath ? dirname(packageJsonPath) : null;
|
|
393
|
+
if (projectRoot && (await fileExists(join(projectRoot, FileName.Ui5Yaml), memFs))) {
|
|
403
394
|
results.push({ projectRoot, manifestPath, manifest });
|
|
404
395
|
}
|
|
405
396
|
}
|
|
@@ -419,14 +410,14 @@ async function filterLibraries(pathMap, memFs) {
|
|
|
419
410
|
*/
|
|
420
411
|
async function filterComponents(pathMap, memFs) {
|
|
421
412
|
const results = [];
|
|
422
|
-
const manifestPaths = Object.keys(pathMap.files).filter((path) =>
|
|
413
|
+
const manifestPaths = Object.keys(pathMap.files).filter((path) => basename(path) === FileName.Manifest);
|
|
423
414
|
for (const manifestPath of manifestPaths) {
|
|
424
415
|
try {
|
|
425
|
-
pathMap.files[manifestPath] ??= await
|
|
416
|
+
pathMap.files[manifestPath] ??= await readJSON(manifestPath, memFs);
|
|
426
417
|
const manifest = pathMap.files[manifestPath];
|
|
427
418
|
if (manifest['sap.app']?.type === 'component') {
|
|
428
|
-
const packageJsonPath = await
|
|
429
|
-
const projectRoot = packageJsonPath ?
|
|
419
|
+
const packageJsonPath = await findFileUp(FileName.Package, dirname(manifestPath), memFs);
|
|
420
|
+
const projectRoot = packageJsonPath ? dirname(packageJsonPath) : null;
|
|
430
421
|
if (projectRoot) {
|
|
431
422
|
results.push({ projectRoot, manifestPath, manifest });
|
|
432
423
|
}
|
|
@@ -462,14 +453,14 @@ function getFilterFileNames(artifacts) {
|
|
|
462
453
|
* @param options.memFs - optional mem-fs-editor instance
|
|
463
454
|
* @returns - data structure containing the search results, for app e.g. as path to app plus files already parsed, e.g. manifest.json
|
|
464
455
|
*/
|
|
465
|
-
async function findFioriArtifacts(options) {
|
|
456
|
+
export async function findFioriArtifacts(options) {
|
|
466
457
|
const results = {};
|
|
467
458
|
const fileNames = getFilterFileNames(options.artifacts);
|
|
468
459
|
const wsRoots = wsFoldersToRootPaths(options.wsFolders);
|
|
469
460
|
const pathMap = { files: {}, capProjectType: new Map() };
|
|
470
461
|
for (const root of wsRoots) {
|
|
471
462
|
try {
|
|
472
|
-
const foundFiles = await
|
|
463
|
+
const foundFiles = await findBy({
|
|
473
464
|
fileNames,
|
|
474
465
|
root,
|
|
475
466
|
excludeFolders,
|
|
@@ -506,25 +497,25 @@ async function findFioriArtifacts(options) {
|
|
|
506
497
|
* @param options.noTraversal - optional flag to disable folder traversal for given paths
|
|
507
498
|
* @returns - root file paths that may contain a CAP project
|
|
508
499
|
*/
|
|
509
|
-
async function findCapProjects(options) {
|
|
500
|
+
export async function findCapProjects(options) {
|
|
510
501
|
const result = new Set();
|
|
511
502
|
const excludeFolders = ['node_modules', 'dist', 'webapp', 'MDKModule', 'gen'];
|
|
512
|
-
const fileNames = [
|
|
503
|
+
const fileNames = [FileName.Pom, FileName.Package, FileName.CapJavaApplicationYaml];
|
|
513
504
|
const wsRoots = wsFoldersToRootPaths(options.wsFolders);
|
|
514
505
|
const noTraversal = options.noTraversal ?? false;
|
|
515
506
|
for (const root of wsRoots) {
|
|
516
|
-
const filesToCheck = await
|
|
507
|
+
const filesToCheck = await findBy({
|
|
517
508
|
fileNames,
|
|
518
509
|
root,
|
|
519
510
|
excludeFolders,
|
|
520
511
|
noTraversal
|
|
521
512
|
});
|
|
522
513
|
const appYamlsToCheck = Array.from(new Set(filesToCheck
|
|
523
|
-
.filter((file) =>
|
|
524
|
-
.map((file) =>
|
|
514
|
+
.filter((file) => basename(file) === FileName.CapJavaApplicationYaml)
|
|
515
|
+
.map((file) => dirname(file))));
|
|
525
516
|
const foldersToCheck = Array.from(new Set(filesToCheck
|
|
526
|
-
.filter((file) =>
|
|
527
|
-
.map((file) =>
|
|
517
|
+
.filter((file) => basename(file) !== FileName.CapJavaApplicationYaml)
|
|
518
|
+
.map((file) => dirname(file))));
|
|
528
519
|
for (const appYamlToCheck of appYamlsToCheck) {
|
|
529
520
|
const capRoot = await findCapProjectRoot(appYamlToCheck);
|
|
530
521
|
if (capRoot) {
|
|
@@ -532,7 +523,7 @@ async function findCapProjects(options) {
|
|
|
532
523
|
}
|
|
533
524
|
}
|
|
534
525
|
for (const folderToCheck of foldersToCheck) {
|
|
535
|
-
if ((await
|
|
526
|
+
if ((await getCapProjectType(folderToCheck)) !== undefined) {
|
|
536
527
|
result.add(folderToCheck);
|
|
537
528
|
}
|
|
538
529
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Manifest, ManifestNamespace, ServiceSpecification } from '../types';
|
|
1
|
+
import type { Manifest, ManifestNamespace, ServiceSpecification } from '../types/index.js';
|
|
2
2
|
import type { Editor } from 'mem-fs-editor';
|
|
3
3
|
export interface UsedEntity {
|
|
4
4
|
service: string;
|
package/dist/project/service.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.getMainService = getMainService;
|
|
4
|
-
exports.getServicesAndAnnotations = getServicesAndAnnotations;
|
|
5
|
-
exports.filterDataSourcesByType = filterDataSourcesByType;
|
|
6
|
-
exports.getUsedEntitiesFromManifest = getUsedEntitiesFromManifest;
|
|
7
|
-
const node_path_1 = require("node:path");
|
|
8
|
-
const file_1 = require("../file");
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { readJSON } from '../file/index.js';
|
|
9
3
|
/**
|
|
10
4
|
* Get the main service name from the manifest.
|
|
11
5
|
* LROP: by definition the service name can be read from the UI5 model with "" as name.
|
|
@@ -14,7 +8,7 @@ const file_1 = require("../file");
|
|
|
14
8
|
* @param manifest - application manifest
|
|
15
9
|
* @returns - main service name
|
|
16
10
|
*/
|
|
17
|
-
function getMainService(manifest) {
|
|
11
|
+
export function getMainService(manifest) {
|
|
18
12
|
const model = typeof manifest?.['sap.ovp']?.globalFilterModel === 'string' ? manifest['sap.ovp'].globalFilterModel : '';
|
|
19
13
|
return typeof manifest?.['sap.ui5']?.models?.[model]?.dataSource === 'string'
|
|
20
14
|
? manifest['sap.ui5'].models[model].dataSource
|
|
@@ -28,9 +22,9 @@ function getMainService(manifest) {
|
|
|
28
22
|
* @param memFs - optional mem-fs-editor instance
|
|
29
23
|
* @returns - service and annotation specification
|
|
30
24
|
*/
|
|
31
|
-
async function getServicesAndAnnotations(manifestPath, manifest, memFs) {
|
|
32
|
-
const parsedManifest = manifest ?? (await
|
|
33
|
-
const manifestFolder =
|
|
25
|
+
export async function getServicesAndAnnotations(manifestPath, manifest, memFs) {
|
|
26
|
+
const parsedManifest = manifest ?? (await readJSON(manifestPath, memFs));
|
|
27
|
+
const manifestFolder = dirname(manifestPath);
|
|
34
28
|
const services = {};
|
|
35
29
|
const dataSources = parsedManifest?.['sap.app']?.dataSources ?? {};
|
|
36
30
|
for (const name in dataSources) {
|
|
@@ -53,7 +47,7 @@ function getServiceSpecification(webappFolder, name, dataSources) {
|
|
|
53
47
|
const dataSource = dataSources[name];
|
|
54
48
|
const uri = dataSource.uri;
|
|
55
49
|
const local = typeof dataSource.settings?.localUri === 'string'
|
|
56
|
-
?
|
|
50
|
+
? join(webappFolder, dataSource.settings.localUri)
|
|
57
51
|
: '';
|
|
58
52
|
const odataVersion = dataSource.settings?.odataVersion ?? '2.0';
|
|
59
53
|
const annotations = [];
|
|
@@ -64,7 +58,7 @@ function getServiceSpecification(webappFolder, name, dataSources) {
|
|
|
64
58
|
if (annotation) {
|
|
65
59
|
annotations.push({
|
|
66
60
|
uri: annotation.uri,
|
|
67
|
-
local: annotation.settings?.localUri ?
|
|
61
|
+
local: annotation.settings?.localUri ? join(webappFolder, annotation.settings.localUri) : undefined
|
|
68
62
|
});
|
|
69
63
|
}
|
|
70
64
|
}
|
|
@@ -83,7 +77,7 @@ function getServiceSpecification(webappFolder, name, dataSources) {
|
|
|
83
77
|
* @param {string} type - Data source type to filter by.
|
|
84
78
|
* @returns {Record<string, ManifestNamespace.DataSource>} Data source IDs.
|
|
85
79
|
*/
|
|
86
|
-
function filterDataSourcesByType(dataSources, type) {
|
|
80
|
+
export function filterDataSourcesByType(dataSources, type) {
|
|
87
81
|
return Object.fromEntries(Object.entries(dataSources).filter(([, data]) => data.type === type));
|
|
88
82
|
}
|
|
89
83
|
/**
|
|
@@ -109,7 +103,7 @@ function getViewPaths(settings) {
|
|
|
109
103
|
* @param manifest - parsed manifest.json
|
|
110
104
|
* @returns - array of used entities, each with service URI and entity name
|
|
111
105
|
*/
|
|
112
|
-
function getUsedEntitiesFromManifest(manifest) {
|
|
106
|
+
export function getUsedEntitiesFromManifest(manifest) {
|
|
113
107
|
const targets = manifest['sap.ui5']?.routing?.targets;
|
|
114
108
|
if (!targets || typeof targets !== 'object') {
|
|
115
109
|
return [];
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const ui5_config_1 = require("./ui5-config");
|
|
13
|
-
const info_1 = require("./info");
|
|
14
|
-
const constants_1 = require("../constants");
|
|
15
|
-
const file_1 = require("../file");
|
|
16
|
-
const command_1 = require("../command");
|
|
17
|
-
const specificationDistTagPath = (0, node_path_1.join)(constants_1.fioriToolsDirectory, constants_1.FileName.SpecificationDistTags);
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { valid } from 'semver';
|
|
5
|
+
import { deleteModule, getModule, getModulePath, loadModuleFromProject } from './module-loader.js';
|
|
6
|
+
import { getWebappPath } from './ui5-config.js';
|
|
7
|
+
import { getMinimumUI5Version } from './info.js';
|
|
8
|
+
import { FileName, fioriToolsDirectory, moduleCacheRoot } from '../constants.js';
|
|
9
|
+
import { readJSON, writeFile } from '../file/index.js';
|
|
10
|
+
import { execNpmCommand } from '../command/index.js';
|
|
11
|
+
const specificationDistTagPath = join(fioriToolsDirectory, FileName.SpecificationDistTags);
|
|
18
12
|
/**
|
|
19
13
|
* Gets the dist-tag for the provided project/app and returns it.
|
|
20
14
|
*
|
|
@@ -26,10 +20,10 @@ const specificationDistTagPath = (0, node_path_1.join)(constants_1.fioriToolsDir
|
|
|
26
20
|
async function getProjectDistTag(root, options) {
|
|
27
21
|
let distTag = 'latest';
|
|
28
22
|
try {
|
|
29
|
-
const webappPath = await
|
|
30
|
-
const manifest = await
|
|
31
|
-
const minUI5Version =
|
|
32
|
-
if (minUI5Version &&
|
|
23
|
+
const webappPath = await getWebappPath(root);
|
|
24
|
+
const manifest = await readJSON(join(webappPath, FileName.Manifest));
|
|
25
|
+
const minUI5Version = getMinimumUI5Version(manifest);
|
|
26
|
+
if (minUI5Version && valid(minUI5Version)) {
|
|
33
27
|
const [mayor, minor] = minUI5Version.split('.');
|
|
34
28
|
distTag = `UI5-${mayor}.${minor}`;
|
|
35
29
|
}
|
|
@@ -46,7 +40,7 @@ async function getProjectDistTag(root, options) {
|
|
|
46
40
|
* @returns If dev dependency to specification is found in package.json
|
|
47
41
|
*/
|
|
48
42
|
async function hasSpecificationDevDependency(root) {
|
|
49
|
-
const packageJson = await
|
|
43
|
+
const packageJson = await readJSON(join(root, FileName.Package));
|
|
50
44
|
return !!packageJson.devDependencies?.['@sap/ux-specification'];
|
|
51
45
|
}
|
|
52
46
|
/**
|
|
@@ -57,7 +51,7 @@ async function hasSpecificationDevDependency(root) {
|
|
|
57
51
|
* @param [options.logger] - logger instance
|
|
58
52
|
* @returns - specification instance
|
|
59
53
|
*/
|
|
60
|
-
async function getSpecificationModuleFromCache(root, options) {
|
|
54
|
+
export async function getSpecificationModuleFromCache(root, options) {
|
|
61
55
|
const logger = options?.logger;
|
|
62
56
|
let specification;
|
|
63
57
|
const version = await getSpecificationVersion(root, { logger });
|
|
@@ -81,13 +75,13 @@ async function getSpecificationModuleFromCache(root, options) {
|
|
|
81
75
|
* @param [options.logger] - logger instance
|
|
82
76
|
* @returns - specification instance
|
|
83
77
|
*/
|
|
84
|
-
async function getSpecification(root, options) {
|
|
78
|
+
export async function getSpecification(root, options) {
|
|
85
79
|
const logger = options?.logger;
|
|
86
80
|
try {
|
|
87
81
|
if (await hasSpecificationDevDependency(root)) {
|
|
88
82
|
logger?.debug(`Specification found in devDependencies of project '${root}', trying to load`);
|
|
89
83
|
// Early return with load module from project. If it throws an error it is not handled here.
|
|
90
|
-
return
|
|
84
|
+
return loadModuleFromProject(root, '@sap/ux-specification');
|
|
91
85
|
}
|
|
92
86
|
}
|
|
93
87
|
catch {
|
|
@@ -101,10 +95,10 @@ async function getSpecification(root, options) {
|
|
|
101
95
|
* @param [options] - optional options, like logger
|
|
102
96
|
* @param [options.logger] - logger instance
|
|
103
97
|
*/
|
|
104
|
-
async function refreshSpecificationDistTags(options) {
|
|
98
|
+
export async function refreshSpecificationDistTags(options) {
|
|
105
99
|
const logger = options?.logger;
|
|
106
100
|
try {
|
|
107
|
-
const distTagsString = await
|
|
101
|
+
const distTagsString = await execNpmCommand(['view', '@sap/ux-specification', 'dist-tags', '--json'], {
|
|
108
102
|
logger
|
|
109
103
|
});
|
|
110
104
|
const distTags = JSON.parse(distTagsString);
|
|
@@ -113,22 +107,22 @@ async function refreshSpecificationDistTags(options) {
|
|
|
113
107
|
throw new Error(distTagsString);
|
|
114
108
|
}
|
|
115
109
|
// Make sure fiori tools directory exists
|
|
116
|
-
if (!
|
|
117
|
-
await
|
|
110
|
+
if (!existsSync(fioriToolsDirectory)) {
|
|
111
|
+
await mkdir(fioriToolsDirectory, { recursive: true });
|
|
118
112
|
}
|
|
119
|
-
await
|
|
113
|
+
await writeFile(specificationDistTagPath, JSON.stringify(distTags, null, 4));
|
|
120
114
|
const uniqueVersions = new Set(Object.values(distTags));
|
|
121
115
|
// Check if we have cached versions that are not required anymore
|
|
122
|
-
const specificationCachePath =
|
|
123
|
-
const removeExistingVersions =
|
|
124
|
-
? (await
|
|
116
|
+
const specificationCachePath = join(moduleCacheRoot, '@sap/ux-specification');
|
|
117
|
+
const removeExistingVersions = existsSync(specificationCachePath)
|
|
118
|
+
? (await readdir(specificationCachePath, { withFileTypes: true }))
|
|
125
119
|
.filter((d) => d.isDirectory())
|
|
126
120
|
.filter((d) => !uniqueVersions.has(d.name))
|
|
127
121
|
.map((d) => d.name)
|
|
128
122
|
: [];
|
|
129
123
|
// Delete cached versions that are not required anymore
|
|
130
124
|
for (const version of removeExistingVersions) {
|
|
131
|
-
await
|
|
125
|
+
await deleteModule('@sap/ux-specification', version);
|
|
132
126
|
logger?.debug(`Deleted unused specification module '@sap/ux-specification@${version}' from cache`);
|
|
133
127
|
}
|
|
134
128
|
}
|
|
@@ -146,7 +140,7 @@ async function refreshSpecificationDistTags(options) {
|
|
|
146
140
|
*/
|
|
147
141
|
async function getSpecificationByVersion(version, options) {
|
|
148
142
|
const logger = options?.logger;
|
|
149
|
-
const specification = await
|
|
143
|
+
const specification = await getModule('@sap/ux-specification', version, { logger });
|
|
150
144
|
return specification;
|
|
151
145
|
}
|
|
152
146
|
/**
|
|
@@ -159,11 +153,11 @@ async function getSpecificationByVersion(version, options) {
|
|
|
159
153
|
*/
|
|
160
154
|
async function convertDistTagToVersion(distTag, options) {
|
|
161
155
|
const logger = options?.logger;
|
|
162
|
-
if (!
|
|
156
|
+
if (!existsSync(specificationDistTagPath)) {
|
|
163
157
|
logger?.debug(`Specification dist-tags not found at '${specificationDistTagPath}'. Trying to refresh.`);
|
|
164
158
|
await refreshSpecificationDistTags({ logger });
|
|
165
159
|
}
|
|
166
|
-
let specificationDistTags = await
|
|
160
|
+
let specificationDistTags = await readJSON(specificationDistTagPath);
|
|
167
161
|
// Validate the current dist-tags file
|
|
168
162
|
if ('error' in specificationDistTags &&
|
|
169
163
|
!(distTag in specificationDistTags) &&
|
|
@@ -171,7 +165,7 @@ async function convertDistTagToVersion(distTag, options) {
|
|
|
171
165
|
// Refresh if dist-tags are invalid
|
|
172
166
|
logger?.debug(`Specification dist-tags file has error at '${specificationDistTagPath}'. Trying to refresh.`);
|
|
173
167
|
await refreshSpecificationDistTags({ logger });
|
|
174
|
-
specificationDistTags = await
|
|
168
|
+
specificationDistTags = await readJSON(specificationDistTagPath);
|
|
175
169
|
}
|
|
176
170
|
const version = specificationDistTags[distTag] ?? specificationDistTags.latest;
|
|
177
171
|
return version;
|
|
@@ -198,19 +192,19 @@ async function getSpecificationVersion(root, options) {
|
|
|
198
192
|
* @param [options.logger] - optional logger instance
|
|
199
193
|
* @returns - path to specification
|
|
200
194
|
*/
|
|
201
|
-
async function getSpecificationPath(root, options) {
|
|
195
|
+
export async function getSpecificationPath(root, options) {
|
|
202
196
|
const logger = options?.logger;
|
|
203
197
|
const moduleName = '@sap/ux-specification';
|
|
204
198
|
if (await hasSpecificationDevDependency(root)) {
|
|
205
|
-
const modulePath = await
|
|
199
|
+
const modulePath = await getModulePath(root, moduleName);
|
|
206
200
|
logger?.debug(`Specification root found in project '${root}'`);
|
|
207
|
-
return modulePath.slice(0, modulePath.lastIndexOf(
|
|
201
|
+
return modulePath.slice(0, modulePath.lastIndexOf(join(moduleName)) + join(moduleName).length);
|
|
208
202
|
}
|
|
209
203
|
await getSpecificationModuleFromCache(root, { logger });
|
|
210
204
|
const version = await getSpecificationVersion(root, { logger });
|
|
211
205
|
logger?.debug(`Specification not found in project '${root}', using path from cache with version '${version}'`);
|
|
212
|
-
const moduleRoot =
|
|
213
|
-
const modulePath = await
|
|
214
|
-
return modulePath.slice(0, modulePath.lastIndexOf(
|
|
206
|
+
const moduleRoot = join(moduleCacheRoot, moduleName, version);
|
|
207
|
+
const modulePath = await getModulePath(moduleRoot, moduleName);
|
|
208
|
+
return modulePath.slice(0, modulePath.lastIndexOf(join(moduleName)) + join(moduleName).length);
|
|
215
209
|
}
|
|
216
210
|
//# sourceMappingURL=specification.js.map
|