@ui5/task-adaptation 1.5.3 → 1.6.0-rc.1

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.
Files changed (53) hide show
  1. package/.hyperspace/pull_request_bot.json +19 -0
  2. package/CHANGELOG.md +18 -9
  3. package/dist/adapters/abapAdapter.d.ts +3 -0
  4. package/dist/adapters/abapAdapter.js +4 -0
  5. package/dist/adapters/adapter.d.ts +10 -0
  6. package/dist/adapters/adapter.js +11 -0
  7. package/dist/adapters/cfAdapter.d.ts +8 -0
  8. package/dist/adapters/cfAdapter.js +20 -0
  9. package/dist/appVariantManager.js +1 -1
  10. package/dist/baseAppManager.js +3 -3
  11. package/dist/buildStrategy.d.ts +0 -3
  12. package/dist/buildStrategy.js +0 -7
  13. package/dist/bundle.d.ts +4 -3
  14. package/dist/bundle.js +3663 -3606
  15. package/dist/cache/cacheHolder.d.ts +1 -1
  16. package/dist/cache/cacheHolder.js +8 -6
  17. package/dist/index.js +8 -2
  18. package/dist/model/authenticationError.d.ts +3 -0
  19. package/dist/model/authenticationError.js +8 -0
  20. package/dist/model/types.d.ts +12 -0
  21. package/dist/previewManager.d.ts +13 -0
  22. package/dist/previewManager.js +131 -0
  23. package/dist/processors/abapProcessor.d.ts +3 -0
  24. package/dist/processors/abapProcessor.js +7 -0
  25. package/dist/processors/cfProcessor.d.ts +4 -1
  26. package/dist/processors/cfProcessor.js +15 -1
  27. package/dist/processors/processor.d.ts +4 -1
  28. package/dist/repositories/html5RepoManager.d.ts +3 -2
  29. package/dist/repositories/html5RepoManager.js +18 -5
  30. package/dist/util/cf/xsAppJsonUtil.d.ts +23 -0
  31. package/dist/util/cf/xsAppJsonUtil.js +36 -0
  32. package/dist/util/cfUtil.d.ts +8 -1
  33. package/dist/util/cfUtil.js +16 -8
  34. package/dist/util/movingHandler/changeFileMoveHandler.d.ts +8 -0
  35. package/dist/util/movingHandler/changeFileMoveHandler.js +77 -0
  36. package/dist/util/resourceUtil.d.ts +11 -3
  37. package/dist/util/resourceUtil.js +83 -18
  38. package/eslint.config.js +4 -3
  39. package/package.json +15 -16
  40. package/rollup/amdToEsm.ts +22 -0
  41. package/rollup/bundle.d.ts +25 -0
  42. package/rollup/bundleDefinition.js +19 -0
  43. package/rollup/bundler.ts +35 -0
  44. package/rollup/overrides/sap/base/config.js +59 -0
  45. package/rollup/overrides/sap/ui/fl/apply/_internal/flexObjects/AppDescriptorChange.js +68 -0
  46. package/rollup/overrides/sap/ui/performance/Measurement.js +4 -0
  47. package/rollup/project/package.json +4 -0
  48. package/rollup/project/ui5.yaml +13 -0
  49. package/rollup/project/webapp/manifest.json +5 -0
  50. package/rollup/rollup.ts +133 -0
  51. package/rollup/ui5Resolve.ts +145 -0
  52. package/scripts/publish.ts +256 -0
  53. package/scripts/test-integration-prep.sh +4 -0
@@ -1,7 +1,7 @@
1
1
  export default class CacheHolder {
2
2
  private static TEMP_TASK_DIR;
3
3
  private static getTempDir;
4
- static read(repoName: string, token: string): Map<string, string> | undefined;
4
+ static read(repoName: string, token: string): Promise<Map<string, string>>;
5
5
  static write(repoName: string, token: string, files: Map<string, string>): Promise<void>;
6
6
  private static isValid;
7
7
  /**
@@ -1,21 +1,22 @@
1
1
  import * as fs from "fs";
2
2
  import * as fsPromises from "fs/promises";
3
3
  import * as path from "path";
4
+ import * as os from "node:os";
4
5
  import ResourceUtil from "../util/resourceUtil.js";
5
6
  import encodeFilename from "filenamify";
6
7
  import { getLogger } from "@ui5/logger";
7
- import tempDir from "temp-dir";
8
8
  const log = getLogger("@ui5/task-adaptation::CacheHolder");
9
9
  export default class CacheHolder {
10
10
  static TEMP_TASK_DIR = "ui5-task-adaptation";
11
11
  static getTempDir(...paths) {
12
- return path.join(tempDir, this.TEMP_TASK_DIR, ...paths.map(part => encodeFilename(part, { replacement: "_" })));
12
+ return path.join(os.tmpdir(), this.TEMP_TASK_DIR, ...paths.map(part => encodeFilename(part, { replacement: "_" })));
13
13
  }
14
14
  static read(repoName, token) {
15
15
  const directory = this.getTempDir(repoName, token);
16
16
  if (this.isValid(repoName, "repoName") && this.isValid(token, "token") && fs.existsSync(directory)) {
17
- return ResourceUtil.read(directory);
17
+ return ResourceUtil.byGlob(directory, "**/*");
18
18
  }
19
+ return Promise.resolve(new Map());
19
20
  }
20
21
  static async write(repoName, token, files) {
21
22
  this.delete(repoName);
@@ -40,7 +41,7 @@ export default class CacheHolder {
40
41
  * Clears all cached files
41
42
  */
42
43
  static clear() {
43
- this.deleteDir(path.join(tempDir, this.TEMP_TASK_DIR));
44
+ this.deleteDir(path.join(os.tmpdir(), this.TEMP_TASK_DIR));
44
45
  }
45
46
  static deleteDir(directory) {
46
47
  if (fs.existsSync(directory)) {
@@ -67,9 +68,10 @@ export function cached() {
67
68
  return function (_target, _propertyKey, descriptor) {
68
69
  const originalValue = descriptor.value;
69
70
  descriptor.value = async function (...args) {
70
- let files = CacheHolder.read(args[0], args[1]);
71
+ let files = await CacheHolder.read(args[0], args[1]);
71
72
  CacheHolder.clearOutdatedExcept(args[0]);
72
- if (files == null) {
73
+ if (files.size === 0) {
74
+ log.verbose(`Cache repo '${args[0]}' with token '${args[1]}' does not contain files. Fetching...`);
73
75
  files = await originalValue.apply(this, args);
74
76
  await CacheHolder.write(args[0], args[1], files);
75
77
  }
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import I18nMerger from "./util/i18nMerger.js";
6
6
  import ResourceUtil from "./util/resourceUtil.js";
7
7
  import { determineProcessor } from "./processors/processor.js";
8
8
  import FilesUtil from "./util/filesUtil.js";
9
+ import PreviewManager from "./previewManager.js";
9
10
  /**
10
11
  * Creates an appVariant bundle from the provided resources.
11
12
  */
@@ -14,7 +15,9 @@ export default ({ workspace, options, taskUtil }) => {
14
15
  async function process(workspace, taskUtil) {
15
16
  logBuilderVersion();
16
17
  const processor = determineProcessor(options.configuration);
18
+ const adapter = processor.getAdapter();
17
19
  const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
20
+ const previewManagerPromise = PreviewManager.createFromRoot(adaptationProject.reference, processor);
18
21
  const appVariantIdHierarchy = await processor.getAppVariantIdHierarchy(adaptationProject.reference);
19
22
  if (appVariantIdHierarchy.length === 0) {
20
23
  throw new Error(`No app variant found for reference ${adaptationProject.reference}`);
@@ -35,7 +38,8 @@ export default ({ workspace, options, taskUtil }) => {
35
38
  appVariant = adaptationProject;
36
39
  }
37
40
  appVariants.push(appVariant);
38
- const adaptedFiles = await baseApp.adapt(appVariant, processor);
41
+ let adaptedFiles = await baseApp.adapt(appVariant, processor);
42
+ adaptedFiles = await adapter.adapt(adaptedFiles, appVariantFiles);
39
43
  return I18nMerger.merge(adaptedFiles, baseApp.i18nPath, appVariant);
40
44
  };
41
45
  let files = await fetchFilesPromises.reduce(async (previousFiles, currentFiles) => adapt(await previousFiles, await currentFiles), fetchFilesPromises.shift());
@@ -43,7 +47,9 @@ export default ({ workspace, options, taskUtil }) => {
43
47
  files = FilesUtil.filter(files);
44
48
  files = FilesUtil.rename(files, references);
45
49
  adaptationProject.omitDeletedResources(files, options.projectNamespace, taskUtil);
46
- const writePromises = new Array();
50
+ // Read libs for preview
51
+ const previewManager = await previewManagerPromise;
52
+ const writePromises = new Array(previewManager.processPreviewResources(files));
47
53
  files.forEach((content, filename) => {
48
54
  const resource = ResourceUtil.createResource(filename, options.projectNamespace, content);
49
55
  writePromises.push(workspace.write(resource));
@@ -0,0 +1,3 @@
1
+ export default class AuthenticationError extends Error {
2
+ constructor(details?: string);
3
+ }
@@ -0,0 +1,8 @@
1
+ export default class AuthenticationError extends Error {
2
+ constructor(details) {
3
+ super(details);
4
+ this.name = "AuthenticationError";
5
+ this.message = "Authentication error. Use 'cf login' to authenticate in Cloud Foundry" + (details ? `: ${details}` : ".");
6
+ }
7
+ }
8
+ //# sourceMappingURL=authenticationError.js.map
@@ -85,6 +85,18 @@ export interface IHTML5RepoInfo {
85
85
  token: string;
86
86
  baseUri: string;
87
87
  }
88
+ export interface IReuseLibInfo {
89
+ name: string;
90
+ lazy: boolean;
91
+ html5AppHostId: string;
92
+ html5AppName: string;
93
+ html5AppVersion: string;
94
+ html5CacheBusterToken: string;
95
+ url: {
96
+ uri: string;
97
+ final: boolean;
98
+ };
99
+ }
88
100
  export interface IAuth {
89
101
  username: string;
90
102
  password: string;
@@ -0,0 +1,13 @@
1
+ import IProcessor from "./processors/processor.js";
2
+ export default class PreviewManager {
3
+ private readonly fetchLibsPromises;
4
+ static createFromRoot(appId: string, processor: IProcessor): Promise<PreviewManager>;
5
+ static isPreviewRequested(): boolean;
6
+ private constructor();
7
+ processPreviewResources(baseAppFiles: ReadonlyMap<string, string>): Promise<void>;
8
+ private preReadLibs;
9
+ private searchBaseAppXsAppJsonFile;
10
+ private mergeXsAppJsonFiles;
11
+ private static moveLibraryFiles;
12
+ private static modifyRoutes;
13
+ }
@@ -0,0 +1,131 @@
1
+ import { getLogger } from "@ui5/logger";
2
+ import ResourceUtil from "./util/resourceUtil.js";
3
+ import path from "path";
4
+ import { merge } from "./util/cf/xsAppJsonUtil.js";
5
+ const log = getLogger("@ui5/task-adaptation::PreviewManager");
6
+ const REUSE_DIR = ".adp/reuse";
7
+ const APP_INFO_FILE = "ui5AppInfo.json";
8
+ const XS_APP_JSON_FILE = "xs-app.json";
9
+ export default class PreviewManager {
10
+ fetchLibsPromises = new Map();
11
+ static async createFromRoot(appId, processor) {
12
+ let ui5AppInfo = "";
13
+ if (PreviewManager.isPreviewRequested()) {
14
+ try {
15
+ ui5AppInfo = await ResourceUtil.readInProject(APP_INFO_FILE);
16
+ }
17
+ catch (_err) {
18
+ log.verbose("Preview mode not requested (env variable ADP_BUILDER_MODE=preview is not set), skipping preview resources processing.");
19
+ throw new Error(`ui5AppInfo.json is missing in project root, cannot process preview resources.`);
20
+ }
21
+ }
22
+ return new PreviewManager(appId, ui5AppInfo, processor);
23
+ }
24
+ static isPreviewRequested() {
25
+ return process.env.ADP_BUILDER_MODE === "preview";
26
+ }
27
+ constructor(appId, ui5AppInfo, processor) {
28
+ // If no ui5AppInfo is provided, no preview processing is needed
29
+ if (!ui5AppInfo) {
30
+ return;
31
+ }
32
+ const appInfo = JSON.parse(ui5AppInfo)[appId];
33
+ if (!appInfo) {
34
+ throw new Error(`No app info found for original app id '${appId}' in ui5AppInfo.json`);
35
+ }
36
+ const reuseLibs = appInfo.asyncHints.libs.filter(lib => lib.html5AppHostId && lib.html5AppName && lib.html5AppVersion);
37
+ if (reuseLibs.length > 0) {
38
+ this.fetchLibsPromises = this.preReadLibs(reuseLibs, processor);
39
+ }
40
+ const logMap = {
41
+ Error: log.error,
42
+ Warning: log.warning,
43
+ Info: log.info,
44
+ debug: log.verbose
45
+ };
46
+ appInfo.messages.forEach((message) => {
47
+ const logger = logMap[message.severity] || log.info;
48
+ logger(`ui5AppInfo.json: ${message.severity} Message: ${message.message} (Error Code: ${message.errorCode})`);
49
+ });
50
+ }
51
+ async processPreviewResources(baseAppFiles) {
52
+ log.verbose(`Downloading reuse libraries to reuse folder`);
53
+ const xsAppFiles = new Map();
54
+ if (this.fetchLibsPromises.size === 0) {
55
+ log.verbose("No reuse libraries defined in ui5AppInfo.json for preview");
56
+ return;
57
+ }
58
+ const mergedFiles = new Map();
59
+ for (const [libName, libFilesPromise] of this.fetchLibsPromises) {
60
+ const libFiles = await libFilesPromise;
61
+ if (!libFiles || libFiles.size === 0) {
62
+ log.warn(`No files found in reuse library ${libName} for preview`);
63
+ continue;
64
+ }
65
+ for (const [filename, content] of libFiles) {
66
+ mergedFiles.set(filename, content);
67
+ if (filename.includes(XS_APP_JSON_FILE)) {
68
+ xsAppFiles.set(filename, content);
69
+ }
70
+ }
71
+ }
72
+ this.searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles);
73
+ this.mergeXsAppJsonFiles(xsAppFiles, mergedFiles);
74
+ await ResourceUtil.writeInProject(REUSE_DIR, mergedFiles);
75
+ }
76
+ preReadLibs(reuseLibs, processor) {
77
+ const promises = new Map();
78
+ reuseLibs.forEach(lib => {
79
+ log.info(`Downloading reuse library '${lib.html5AppName}' version '${lib.html5AppVersion}'`);
80
+ const promise = processor
81
+ .fetchReuseLib(lib.html5AppName, lib.html5CacheBusterToken, lib)
82
+ .then(libFiles => PreviewManager.moveLibraryFiles(libFiles, lib.html5AppName, lib.name));
83
+ promises.set(lib.html5AppName, promise);
84
+ });
85
+ return promises;
86
+ }
87
+ searchBaseAppXsAppJsonFile(xsAppFiles, baseAppFiles) {
88
+ const xsAppJsonContent = baseAppFiles.get(XS_APP_JSON_FILE);
89
+ if (xsAppJsonContent) {
90
+ xsAppFiles.set(XS_APP_JSON_FILE, xsAppJsonContent);
91
+ }
92
+ else {
93
+ log.warn("xs-app.json is missing in the downloaded base app files for preview");
94
+ }
95
+ }
96
+ mergeXsAppJsonFiles(xsAppFiles, files) {
97
+ const mergedXsAppJson = merge([...xsAppFiles.values()]);
98
+ if (mergedXsAppJson) {
99
+ files.set(XS_APP_JSON_FILE, mergedXsAppJson);
100
+ }
101
+ }
102
+ static moveLibraryFiles(inputFiles, libraryName, libId) {
103
+ const files = new Map();
104
+ inputFiles.forEach((content, filename) => {
105
+ const newFilename = path.join(libraryName, filename);
106
+ // Source path in xs-app.json needs to be adjusted to new location
107
+ if (filename.includes(XS_APP_JSON_FILE)) {
108
+ content = PreviewManager.modifyRoutes(content, libraryName, libId);
109
+ }
110
+ files.set(newFilename, content);
111
+ });
112
+ return files;
113
+ }
114
+ ;
115
+ static modifyRoutes(xsAppJson, libName, libId) {
116
+ const xsApp = JSON.parse(xsAppJson);
117
+ xsApp.routes = xsApp.routes.map((route) => {
118
+ route.source = route.source.replace(new RegExp("^\\^\\/?(resources/)?"), `^/resources/${libId.replaceAll(".", "/")}/`);
119
+ if (route.service === "html5-apps-repo-rt") {
120
+ route = {
121
+ source: route.source,
122
+ target: route.target,
123
+ localDir: path.join(REUSE_DIR, libName)
124
+ };
125
+ }
126
+ return route;
127
+ });
128
+ return JSON.stringify(xsApp);
129
+ }
130
+ }
131
+ //# sourceMappingURL=previewManager.js.map
@@ -3,13 +3,16 @@ import AnnotationManager from "../annotationManager.js";
3
3
  import IAppVariantIdHierarchyItem from "../model/appVariantIdHierarchyItem.js";
4
4
  import { IConfiguration } from "../model/types.js";
5
5
  import IProcessor from "./processor.js";
6
+ import { Adapter } from "../adapters/adapter.js";
6
7
  export default class AbapProcessor implements IProcessor {
7
8
  private abapRepoManager;
8
9
  private configuration;
9
10
  private annotationManager;
10
11
  constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager, annotationManager: AnnotationManager);
11
12
  getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
13
+ getAdapter(): Adapter;
12
14
  fetch(repoName: string, _cachebusterToken: string): Promise<Map<string, string>>;
15
+ fetchReuseLib(): Promise<Map<string, string>>;
13
16
  validateConfiguration(): void;
14
17
  updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>, appVariantId: string, prefix: string): Promise<void>;
15
18
  getConfigurationType(): string;
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import Language from "../model/language.js";
8
8
  import { cached } from "../cache/cacheHolder.js";
9
9
  import { validateObject } from "../util/commonUtil.js";
10
+ import AbapAdapter from "../adapters/abapAdapter.js";
10
11
  export default class AbapProcessor {
11
12
  abapRepoManager;
12
13
  configuration;
@@ -19,9 +20,15 @@ export default class AbapProcessor {
19
20
  getAppVariantIdHierarchy(appId) {
20
21
  return this.abapRepoManager.getAppVariantIdHierarchy(appId);
21
22
  }
23
+ getAdapter() {
24
+ return new AbapAdapter();
25
+ }
22
26
  fetch(repoName, _cachebusterToken) {
23
27
  return this.abapRepoManager.fetch(repoName);
24
28
  }
29
+ fetchReuseLib() {
30
+ throw new Error("Preview is not available on SAP S/4HANA On-Premise or Cloud Systems. Please create a ticket on CA-UI5-FL-ADP-BAS component.");
31
+ }
25
32
  validateConfiguration() {
26
33
  // validate general app config
27
34
  const properties = ["appName"];
@@ -1,11 +1,14 @@
1
1
  import IAppInfo from "../model/appVariantIdHierarchyItem.js";
2
- import { IConfiguration } from "../model/types.js";
2
+ import { IConfiguration, IReuseLibInfo } from "../model/types.js";
3
3
  import IProcessor from "./processor.js";
4
+ import { Adapter } from "../adapters/adapter.js";
4
5
  export default class CFProcessor implements IProcessor {
5
6
  private configuration;
6
7
  constructor(configuration: IConfiguration);
8
+ getAdapter(): Adapter;
7
9
  getAppVariantIdHierarchy(appId: string): Promise<IAppInfo[]>;
8
10
  fetch(_repoName: string, _cachebusterToken: string): Promise<Map<string, string>>;
11
+ fetchReuseLib(_libName: string, _cachebusterToken: string, lib: IReuseLibInfo): Promise<Map<string, string>>;
9
12
  validateConfiguration(): void;
10
13
  updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>): Promise<void>;
11
14
  private updateXsAppJson;
@@ -9,12 +9,17 @@ import { cached } from "../cache/cacheHolder.js";
9
9
  import { validateObject } from "../util/commonUtil.js";
10
10
  import CFUtil from "../util/cfUtil.js";
11
11
  import { getLogger } from "@ui5/logger";
12
+ import PreviewManager from "../previewManager.js";
13
+ import CFAdapter from "../adapters/cfAdapter.js";
12
14
  const log = getLogger("@ui5/task-adaptation::CFProcessor");
13
15
  export default class CFProcessor {
14
16
  configuration;
15
17
  constructor(configuration) {
16
18
  this.configuration = configuration;
17
19
  }
20
+ getAdapter() {
21
+ return new CFAdapter();
22
+ }
18
23
  async getAppVariantIdHierarchy(appId) {
19
24
  const metadata = await HTML5RepoManager.getMetadata(this.configuration);
20
25
  return [{
@@ -26,12 +31,18 @@ export default class CFProcessor {
26
31
  fetch(_repoName, _cachebusterToken) {
27
32
  return HTML5RepoManager.getBaseAppFiles(this.configuration);
28
33
  }
34
+ fetchReuseLib(_libName, _cachebusterToken, lib) {
35
+ return HTML5RepoManager.getReuseLibFiles(this.configuration, lib);
36
+ }
29
37
  validateConfiguration() {
30
38
  validateObject(this.configuration, ["appHostId", "appName", "appVersion"], "should be specified in ui5.yaml configuration");
31
39
  }
32
40
  async updateLandscapeSpecificContent(baseAppManifest, baseAppFiles) {
33
41
  this.updateCloudPlatform(baseAppManifest);
34
- await this.updateXsAppJson(baseAppFiles);
42
+ // Preview uses destinations and does not require xs-app.json updates
43
+ if (!PreviewManager.isPreviewRequested()) {
44
+ await this.updateXsAppJson(baseAppFiles);
45
+ }
35
46
  }
36
47
  async updateXsAppJson(baseAppFiles) {
37
48
  const xsAppJsonContent = baseAppFiles.get("xs-app.json");
@@ -119,4 +130,7 @@ export default class CFProcessor {
119
130
  __decorate([
120
131
  cached()
121
132
  ], CFProcessor.prototype, "fetch", null);
133
+ __decorate([
134
+ cached()
135
+ ], CFProcessor.prototype, "fetchReuseLib", null);
122
136
  //# sourceMappingURL=cfProcessor.js.map
@@ -1,8 +1,11 @@
1
1
  import IAppVariantIdHierarchyItem from "../model/appVariantIdHierarchyItem.js";
2
- import { IConfiguration } from "../model/types.js";
2
+ import { IConfiguration, IReuseLibInfo } from "../model/types.js";
3
+ import { Adapter } from "../adapters/adapter.js";
3
4
  export default interface IProcessor {
4
5
  getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
5
6
  fetch(repoName: string, cachebusterToken: string): Promise<Map<string, string>>;
7
+ fetchReuseLib(repoName: string, cachebusterToken: string, lib: IReuseLibInfo): Promise<Map<string, string>>;
8
+ getAdapter(): Adapter;
6
9
  createAppVariantHierarchyItem(appVariantId: string, version: string): void;
7
10
  updateLandscapeSpecificContent(baseAppManifest: any, baseAppFiles: Map<string, string>, appVariantId: string, prefix: string): Promise<void>;
8
11
  }
@@ -1,11 +1,12 @@
1
- import { IConfiguration } from "./../model/types.js";
1
+ import { IConfiguration, IReuseLibInfo } from "./../model/types.js";
2
2
  export default class HTML5RepoManager {
3
3
  static getBaseAppFiles(configuration: IConfiguration): Promise<Map<string, string>>;
4
4
  static getMetadata(configuration: IConfiguration): Promise<any>;
5
+ static getReuseLibFiles(configuration: IConfiguration, lib: IReuseLibInfo): Promise<Map<string, string>>;
5
6
  private static getHtml5RepoInfo;
6
7
  private static getHTML5Credentials;
7
8
  private static getToken;
8
9
  private static requestMetadata;
9
- private static getBaseAppZipEntries;
10
+ private static getAppZipEntries;
10
11
  private static download;
11
12
  }
@@ -6,12 +6,26 @@ const log = getLogger("@ui5/task-adaptation::HTML5RepoManager");
6
6
  export default class HTML5RepoManager {
7
7
  static async getBaseAppFiles(configuration) {
8
8
  const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
9
- return this.getBaseAppZipEntries(configuration, baseUri, token);
9
+ const app = {
10
+ appName: configuration.appName,
11
+ appVersion: configuration.appVersion,
12
+ appHostId: configuration.appHostId
13
+ };
14
+ return this.getAppZipEntries(app, baseUri, token);
10
15
  }
11
16
  static async getMetadata(configuration) {
12
17
  const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
13
18
  return this.requestMetadata(configuration, baseUri, token);
14
19
  }
20
+ static async getReuseLibFiles(configuration, lib) {
21
+ const { token, baseUri } = await this.getHtml5RepoInfo(configuration);
22
+ const libAppData = {
23
+ appName: lib.html5AppName,
24
+ appVersion: lib.html5AppVersion,
25
+ appHostId: lib.html5AppHostId
26
+ };
27
+ return this.getAppZipEntries(libAppData, baseUri, token);
28
+ }
15
29
  static async getHtml5RepoInfo(configuration) {
16
30
  const spaceGuid = await CFUtil.getSpaceGuid(configuration?.space);
17
31
  const credentials = await this.getHTML5Credentials(spaceGuid);
@@ -65,10 +79,9 @@ export default class HTML5RepoManager {
65
79
  const metadata = await RequestUtil.get(uri, requestOptions);
66
80
  return metadata.find((item) => item.appHostId === appHostId && item.applicationName === appName && item.applicationVersion === appVersion);
67
81
  }
68
- static async getBaseAppZipEntries(options, html5RepoBaseUri, token) {
69
- const { appHostId, appName, appVersion } = options;
70
- const uri = `${html5RepoBaseUri}/applications/content/${appName}-${appVersion}/`;
71
- const zip = await this.download(token, appHostId, uri);
82
+ static async getAppZipEntries(app, html5RepoBaseUri, token) {
83
+ const uri = `${html5RepoBaseUri}/applications/content/${app.appName}-${app.appVersion}/`;
84
+ const zip = await this.download(token, app.appHostId, uri);
72
85
  return unzipZipEntries(zip);
73
86
  }
74
87
  static async download(token, appHostId, uri) {
@@ -0,0 +1,23 @@
1
+ export type XsApp = {
2
+ welcomeFile?: string;
3
+ authenticationMethod: "none" | "route";
4
+ routes: Route[];
5
+ };
6
+ export type Route = {
7
+ source: string;
8
+ target: string;
9
+ service?: string;
10
+ destination?: string;
11
+ authenticationType?: string;
12
+ localDir?: string;
13
+ };
14
+ export declare const XSAPP_JSON_FILENAME = "xs-app.json";
15
+ /**
16
+ * Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
17
+ * xs-app.json files come first, base app xs-app.json last. Routes from all
18
+ * files are concatenated.
19
+ * @param xsAppFiles Array of xs-app.json file contents as strings
20
+ * @returns Merged xs-app.json content as a string, or undefined if no files
21
+ * were provided
22
+ */
23
+ export declare function merge(xsAppFiles: string[]): string | undefined;
@@ -0,0 +1,36 @@
1
+ export const XSAPP_JSON_FILENAME = "xs-app.json";
2
+ /**
3
+ * Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
4
+ * xs-app.json files come first, base app xs-app.json last. Routes from all
5
+ * files are concatenated.
6
+ * @param xsAppFiles Array of xs-app.json file contents as strings
7
+ * @returns Merged xs-app.json content as a string, or undefined if no files
8
+ * were provided
9
+ */
10
+ export function merge(xsAppFiles) {
11
+ if (xsAppFiles.length === 0) {
12
+ return;
13
+ }
14
+ if (xsAppFiles.length === 1) {
15
+ return xsAppFiles[0];
16
+ }
17
+ // Start with empty xs-app.json
18
+ const merged = {
19
+ authenticationMethod: "none",
20
+ routes: []
21
+ };
22
+ for (const xsAppInfoContent of xsAppFiles) {
23
+ const { authenticationMethod, routes, welcomeFile } = JSON.parse(xsAppInfoContent);
24
+ if (merged.welcomeFile === undefined && welcomeFile) {
25
+ merged.welcomeFile = welcomeFile;
26
+ }
27
+ if (merged.authenticationMethod === "none" && authenticationMethod) {
28
+ merged.authenticationMethod = authenticationMethod;
29
+ }
30
+ if (Array.isArray(routes)) {
31
+ merged.routes = merged.routes.concat(routes);
32
+ }
33
+ }
34
+ return JSON.stringify(merged, null, 4);
35
+ }
36
+ //# sourceMappingURL=xsAppJsonUtil.js.map
@@ -15,7 +15,7 @@ export default class CFUtil {
15
15
  private static createServiceKey;
16
16
  private static deleteServiceKeyUnsafe;
17
17
  private static getServiceInstance;
18
- static processErrors(json: any): void;
18
+ static processCfErrors(errors?: ICfError[]): void;
19
19
  static requestCfApi(url: string): Promise<IResource[]>;
20
20
  static getOAuthToken(): Promise<string>;
21
21
  private static cfExecute;
@@ -76,3 +76,10 @@ export default class CFUtil {
76
76
  */
77
77
  static getSpaceGuid(spaceGuid?: string): Promise<string>;
78
78
  }
79
+ interface ICfError {
80
+ code: number;
81
+ title: string;
82
+ detail: string;
83
+ [key: string]: any;
84
+ }
85
+ export {};
@@ -3,6 +3,7 @@ import { getSpaceGuidThrowIfUndefined } from "@sap/cf-tools/out/src/utils.js";
3
3
  import { Cli } from "@sap/cf-tools/out/src/cli.js";
4
4
  import { eFilters } from "@sap/cf-tools/out/src/types.js";
5
5
  import { getLogger } from "@ui5/logger";
6
+ import AuthenticationError from "../model/authenticationError.js";
6
7
  const log = getLogger("@ui5/task-adaptation::CFUtil");
7
8
  export default class CFUtil {
8
9
  /**
@@ -103,19 +104,20 @@ export default class CFUtil {
103
104
  guid: service.guid
104
105
  }));
105
106
  }
106
- static processErrors(json) {
107
- if (json?.errors?.length > 0) {
108
- const message = JSON.stringify(json.errors);
109
- if (json?.errors?.some((e) => e.title === "CF-NotAuthenticated" || e.code === 10002)) {
110
- throw new Error(`Authentication error. Use 'cf login' to authenticate in Cloud Foundry: ${message}`);
111
- }
112
- throw new Error(`Failed sending request to Cloud Foundry: ${message}`);
107
+ static processCfErrors(errors) {
108
+ if (!errors || errors.length === 0) {
109
+ return;
110
+ }
111
+ const authError = errors.find(e => e.title === "CF-NotAuthenticated" || e.code === 10002);
112
+ if (authError) {
113
+ throw new AuthenticationError(authError.detail);
113
114
  }
115
+ throw new Error(`Failed sending request to Cloud Foundry: ${JSON.stringify(errors)}`);
114
116
  }
115
117
  static async requestCfApi(url) {
116
118
  const response = await this.cfExecute(["curl", url]);
117
119
  const json = this.parseJson(response);
118
- this.processErrors(json);
120
+ this.processCfErrors(json?.errors);
119
121
  const resources = json?.resources;
120
122
  const totalPages = json?.pagination?.total_pages;
121
123
  if (totalPages > 1) {
@@ -142,11 +144,17 @@ export default class CFUtil {
142
144
  if (errorValues?.length > 0) {
143
145
  log.verbose(this.errorsToString(errorValues));
144
146
  }
147
+ if (response.stdout === "\n") {
148
+ throw new AuthenticationError();
149
+ }
145
150
  return response.stdout;
146
151
  }
147
152
  errors.add(response.error || response.stderr);
148
153
  }
149
154
  catch (error) {
155
+ if (error instanceof AuthenticationError) {
156
+ throw error;
157
+ }
150
158
  errors.add(error.message);
151
159
  }
152
160
  }
@@ -0,0 +1,8 @@
1
+ export declare const moveFiles: (inputFiles: ReadonlyMap<string, string>, prefix: string, id: string) => {
2
+ files: Map<string, string>;
3
+ renamingPaths: Map<string, string>;
4
+ };
5
+ export declare const moveFile: (filename: string, content: string, prefix: string, id: string) => {
6
+ newFilename: string;
7
+ renamingPath: Map<string, string>;
8
+ };