@ui5/task-adaptation 1.6.5-rc.2 → 1.6.5-rc.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 +12 -1
- package/REUSE.toml +1 -1
- package/dist/adapters/abapAdapter.d.ts +7 -5
- package/dist/adapters/abapAdapter.js +9 -11
- package/dist/adapters/adapter.d.ts +9 -5
- package/dist/adapters/adapter.js +20 -0
- package/dist/adapters/cfAdapter.d.ts +8 -5
- package/dist/adapters/cfAdapter.js +16 -10
- package/dist/adapters/commands/command.d.ts +26 -23
- package/dist/adapters/commands/command.js +73 -46
- package/dist/adapters/commands/fetchEndpointsCommand.d.ts +9 -0
- package/dist/adapters/commands/fetchEndpointsCommand.js +21 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.d.ts +15 -0
- package/dist/adapters/commands/fetchPreviewResourcesCommand.js +103 -0
- package/dist/adapters/commands/filterFilesCommand.d.ts +4 -0
- package/dist/adapters/commands/filterFilesCommand.js +22 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.d.ts +10 -0
- package/dist/adapters/commands/omitDeletedResourcesCommand.js +31 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.d.ts +9 -0
- package/dist/adapters/commands/processPreviewResourcesCommand.js +55 -0
- package/dist/adapters/commands/renameFilesCommand.d.ts +20 -0
- package/dist/{util/filesUtil.js → adapters/commands/renameFilesCommand.js} +34 -43
- package/dist/adapters/commands/writeResourcesCommand.d.ts +7 -0
- package/dist/adapters/commands/writeResourcesCommand.js +20 -0
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.d.ts +3 -3
- package/dist/adapters/commands/xsAppJsonEnhanceRoutesCommand.js +4 -4
- package/dist/adapters/previewAdapter.d.ts +12 -6
- package/dist/adapters/previewAdapter.js +28 -7
- package/dist/annotations/abapAnnotationManager.js +1 -1
- package/dist/annotations/dataSource/dataSourceManager.d.ts +2 -1
- package/dist/annotations/dataSource/dataSourceManager.js +16 -7
- package/dist/{appVariantManager.d.ts → appVariant.d.ts} +2 -9
- package/dist/{appVariantManager.js → appVariant.js} +16 -28
- package/dist/{baseAppManager.js → baseApp.js} +6 -12
- package/dist/bundle.js +53 -12
- package/dist/cache/cacheHolder.d.ts +3 -3
- package/dist/cache/cacheHolder.js +8 -7
- package/dist/cache/cachedResource.d.ts +4 -0
- package/dist/cache/cachedResource.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -69
- package/dist/landscapeConfiguration.d.ts +2 -2
- package/dist/landscapeConfiguration.js +39 -37
- package/dist/model/configuration.d.ts +1 -4
- package/dist/model/configuration.js +1 -1
- package/dist/model/types.d.ts +9 -2
- package/dist/repositories/abapProvider.js +2 -2
- package/dist/repositories/abapRepository.d.ts +6 -5
- package/dist/repositories/abapRepository.js +10 -11
- package/dist/repositories/html5Repository.d.ts +8 -5
- package/dist/repositories/html5Repository.js +18 -30
- package/dist/repositories/localRepository.d.ts +8 -12
- package/dist/repositories/localRepository.js +53 -43
- package/dist/repositories/repository.d.ts +3 -5
- package/dist/util/cf/xsAppJsonUtil.d.ts +16 -3
- package/dist/util/cf/xsAppJsonUtil.js +7 -18
- package/dist/util/commonUtil.d.ts +6 -0
- package/dist/util/commonUtil.js +17 -0
- package/dist/util/fsUtil.d.ts +2 -3
- package/dist/util/fsUtil.js +12 -33
- package/dist/util/renamingUtil.js +50 -82
- package/dist/util/resourceUtil.d.ts +21 -5
- package/dist/util/resourceUtil.js +52 -11
- package/dist/util/validator/abapConnectionValidator.d.ts +5 -0
- package/dist/util/validator/abapConnectionValidator.js +22 -0
- package/dist/util/validator/abapValidator.d.ts +2 -4
- package/dist/util/validator/abapValidator.js +4 -16
- package/dist/util/validator/validator.d.ts +1 -0
- package/dist/util/validator/validator.js +11 -0
- package/dist/util/workspaceManager.d.ts +9 -0
- package/dist/util/workspaceManager.js +46 -0
- package/dist/util/zipUtil.d.ts +1 -1
- package/dist/util/zipUtil.js +1 -1
- package/package.json +13 -13
- package/.hyperspace/pull_request_bot.json +0 -19
- package/dist/previewManager.d.ts +0 -14
- package/dist/previewManager.js +0 -141
- package/dist/util/filesUtil.d.ts +0 -19
- package/scripts/metadataDownloadHelper.ts +0 -88
- package/scripts/publish.ts +0 -256
- package/scripts/test-integration-prep.sh +0 -4
- /package/dist/{baseAppManager.d.ts → baseApp.d.ts} +0 -0
|
@@ -18,31 +18,21 @@ export default class HTML5Repository {
|
|
|
18
18
|
this.configuration = configuration;
|
|
19
19
|
this.validator.validateConfiguration(configuration);
|
|
20
20
|
}
|
|
21
|
-
async getAppVariantIdHierarchy(
|
|
22
|
-
const
|
|
21
|
+
async getAppVariantIdHierarchy(_appId) {
|
|
22
|
+
const { appName, appVersion, appHostId } = this.configuration;
|
|
23
|
+
if (!appName || !appVersion || !appHostId) {
|
|
24
|
+
throw new Error("Missing required configuration properties appName, appVersion or appHostId");
|
|
25
|
+
}
|
|
23
26
|
return [{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
appName,
|
|
28
|
+
cacheBusterToken: this.getMetadata().then(metadata => metadata.changedOn),
|
|
29
|
+
appVersion,
|
|
30
|
+
appHostId,
|
|
27
31
|
}];
|
|
28
32
|
}
|
|
29
|
-
async fetch(
|
|
33
|
+
async fetch(resource) {
|
|
30
34
|
const { token, baseUri } = await this.getHtml5RepoInfo();
|
|
31
|
-
|
|
32
|
-
appName: this.configuration.appName,
|
|
33
|
-
appVersion: this.configuration.appVersion,
|
|
34
|
-
appHostId: this.configuration.appHostId
|
|
35
|
-
};
|
|
36
|
-
return this.getAppZipEntries(appData, baseUri, token);
|
|
37
|
-
}
|
|
38
|
-
async fetchReuseLib(_libName, _cachebusterToken, lib) {
|
|
39
|
-
const { token, baseUri } = await this.getHtml5RepoInfo();
|
|
40
|
-
const libAppData = {
|
|
41
|
-
appName: lib.html5AppName,
|
|
42
|
-
appVersion: lib.html5AppVersion,
|
|
43
|
-
appHostId: lib.html5AppHostId
|
|
44
|
-
};
|
|
45
|
-
return this.getAppZipEntries(libAppData, baseUri, token);
|
|
35
|
+
return this.getAppZipEntries(resource, baseUri, token);
|
|
46
36
|
}
|
|
47
37
|
async getMetadata() {
|
|
48
38
|
const { token, baseUri } = await this.getHtml5RepoInfo();
|
|
@@ -66,17 +56,17 @@ export default class HTML5Repository {
|
|
|
66
56
|
async getHTML5Credentials(spaceGuid) {
|
|
67
57
|
log.verbose("Getting HTML5 Repo Runtime credentials from space " + spaceGuid);
|
|
68
58
|
const PLAN_NAME = "app-runtime";
|
|
69
|
-
const
|
|
59
|
+
const SERVICE_INSTANCE_NAME = "html5-apps-repo-runtime";
|
|
70
60
|
const getParams = {
|
|
71
61
|
spaceGuids: [spaceGuid],
|
|
72
62
|
planNames: [PLAN_NAME],
|
|
73
|
-
names: [
|
|
63
|
+
names: [SERVICE_INSTANCE_NAME]
|
|
74
64
|
};
|
|
75
65
|
const createParams = {
|
|
76
66
|
spaceGuid,
|
|
77
67
|
planName: PLAN_NAME,
|
|
78
68
|
serviceName: "html5-apps-repo",
|
|
79
|
-
serviceInstanceName:
|
|
69
|
+
serviceInstanceName: SERVICE_INSTANCE_NAME,
|
|
80
70
|
tags: ["html5-apps-repo-rt"]
|
|
81
71
|
};
|
|
82
72
|
const serviceKeys = await CFUtil.getServiceInstanceKeys(getParams, createParams);
|
|
@@ -107,9 +97,10 @@ export default class HTML5Repository {
|
|
|
107
97
|
const metadata = await RequestUtil.get(uri, requestOptions);
|
|
108
98
|
return metadata.find((item) => item.appHostId === appHostId && item.applicationName === appName && item.applicationVersion === appVersion);
|
|
109
99
|
}
|
|
110
|
-
async getAppZipEntries(
|
|
111
|
-
const
|
|
112
|
-
const
|
|
100
|
+
async getAppZipEntries(resource, html5RepoBaseUri, token) {
|
|
101
|
+
const { appName, appVersion, appHostId } = resource;
|
|
102
|
+
const uri = `${html5RepoBaseUri}/applications/content/${appName}-${appVersion}/`;
|
|
103
|
+
const zip = await this.download(token, appHostId, uri);
|
|
113
104
|
return unzipZipEntries(zip);
|
|
114
105
|
}
|
|
115
106
|
async download(token, appHostId, uri) {
|
|
@@ -133,7 +124,4 @@ export default class HTML5Repository {
|
|
|
133
124
|
__decorate([
|
|
134
125
|
cached()
|
|
135
126
|
], HTML5Repository.prototype, "fetch", null);
|
|
136
|
-
__decorate([
|
|
137
|
-
cached()
|
|
138
|
-
], HTML5Repository.prototype, "fetchReuseLib", null);
|
|
139
127
|
//# sourceMappingURL=html5Repository.js.map
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { IAppVariantIdHierarchyItem } from "../model/appVariantIdHierarchyItem.js";
|
|
2
|
-
import { IConfiguration } from "../model/configuration.js";
|
|
3
|
-
import { IReuseLibInfo } from "../model/types.js";
|
|
4
1
|
import IRepository from "./repository.js";
|
|
2
|
+
import ICachedResource from "../cache/cachedResource.js";
|
|
3
|
+
export interface ILocalResource extends ICachedResource {
|
|
4
|
+
absolutePath: string;
|
|
5
|
+
}
|
|
5
6
|
export default class LocalRepository implements IRepository {
|
|
6
|
-
private configuration;
|
|
7
|
-
constructor(configuration: IConfiguration);
|
|
8
7
|
downloadAnnotationFile(_uri: string): Promise<Map<string, string>>;
|
|
9
|
-
getAppVariantIdHierarchy(appId: string): Promise<
|
|
10
|
-
fetch(
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
private getExistingManifestPath;
|
|
14
|
-
private readFilesInBaseAppDir;
|
|
15
|
-
private getLocalFilesDirectory;
|
|
8
|
+
getAppVariantIdHierarchy(appId: string): Promise<ILocalResource[]>;
|
|
9
|
+
fetch(resource: ILocalResource): Promise<Map<string, Buffer>>;
|
|
10
|
+
private buildManifestIndex;
|
|
11
|
+
private getLocalFilesDir;
|
|
16
12
|
}
|
|
@@ -1,67 +1,77 @@
|
|
|
1
1
|
import { getLogger } from "@ui5/logger";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
|
+
import { glob } from "glob";
|
|
4
5
|
import FsUtil from "../util/fsUtil.js";
|
|
5
6
|
const log = getLogger("@ui5/task-adaptation::LocalRepository");
|
|
6
7
|
export default class LocalRepository {
|
|
7
|
-
configuration;
|
|
8
|
-
constructor(configuration) {
|
|
9
|
-
this.configuration = configuration;
|
|
10
|
-
}
|
|
11
8
|
async downloadAnnotationFile(_uri) {
|
|
12
9
|
log.verbose("Downloading annotation files is not supported in LocalRepository.");
|
|
13
10
|
return new Map();
|
|
14
11
|
}
|
|
15
12
|
async getAppVariantIdHierarchy(appId) {
|
|
16
13
|
const items = [];
|
|
17
|
-
|
|
14
|
+
const baseDir = this.getLocalFilesDir();
|
|
15
|
+
const index = await this.buildManifestIndex(baseDir);
|
|
16
|
+
const visited = new Set();
|
|
17
|
+
let currentAppId = appId;
|
|
18
|
+
while (currentAppId) {
|
|
19
|
+
if (visited.has(currentAppId)) {
|
|
20
|
+
throw new Error(`Cycle detected in app variant hierarchy: '${currentAppId}' was already visited. Visited IDs: ${[...visited].join(" -> ")} -> ${currentAppId}`);
|
|
21
|
+
}
|
|
22
|
+
visited.add(currentAppId);
|
|
23
|
+
const entry = index.get(currentAppId);
|
|
24
|
+
if (!entry) {
|
|
25
|
+
throw new Error(`App '${currentAppId}' not found in local directory '${baseDir}'.`);
|
|
26
|
+
}
|
|
27
|
+
items.push({
|
|
28
|
+
appName: currentAppId,
|
|
29
|
+
cacheBusterToken: Promise.resolve("local"),
|
|
30
|
+
absolutePath: entry.absolutePath,
|
|
31
|
+
});
|
|
32
|
+
if (entry.isVariant) {
|
|
33
|
+
if (!entry.reference || typeof entry.reference !== "string") {
|
|
34
|
+
throw new Error(`Invalid or missing 'reference' for app variant '${currentAppId}': expected a non-empty string but got '${entry.reference}'`);
|
|
35
|
+
}
|
|
36
|
+
currentAppId = entry.reference;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
currentAppId = undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
18
42
|
return items;
|
|
19
43
|
}
|
|
20
|
-
fetch(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
fetchReuseLib(libName, cachebusterToken, _lib) {
|
|
24
|
-
return this.readFilesInBaseAppDir(libName, cachebusterToken);
|
|
44
|
+
fetch(resource) {
|
|
45
|
+
log.verbose(`Fetching base app files from local directory: ${resource.absolutePath}`);
|
|
46
|
+
return FsUtil.readFilesRecursively(resource.absolutePath);
|
|
25
47
|
}
|
|
26
|
-
async
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (existingManifestPath.endsWith("manifest.appdescr_variant")) {
|
|
42
|
-
const manifestContent = await fs.readFile(existingManifestPath, "utf-8");
|
|
43
|
-
const manifest = JSON.parse(manifestContent);
|
|
44
|
-
await this.collectAppVariantIdHierarchyItems(manifest.reference, items);
|
|
48
|
+
async buildManifestIndex(baseDir) {
|
|
49
|
+
const index = new Map();
|
|
50
|
+
const manifestPaths = await glob("**/manifest.{json,appdescr_variant}", { cwd: baseDir, absolute: true, dot: true });
|
|
51
|
+
for (const manifestPath of manifestPaths) {
|
|
52
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
53
|
+
const manifest = JSON.parse(content);
|
|
54
|
+
const isVariant = manifestPath.endsWith("manifest.appdescr_variant");
|
|
55
|
+
const id = isVariant ? manifest.id : manifest["sap.app"]?.id;
|
|
56
|
+
if (typeof id === "string" && id) {
|
|
57
|
+
index.set(id, {
|
|
58
|
+
absolutePath: path.dirname(manifestPath),
|
|
59
|
+
reference: manifest.reference,
|
|
60
|
+
isVariant,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
45
63
|
}
|
|
64
|
+
return index;
|
|
46
65
|
}
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return filePaths[existingIndex];
|
|
66
|
+
getLocalFilesDir() {
|
|
67
|
+
const adpDirConfigured = process.env.ADP_BUILDER_DIR;
|
|
68
|
+
if (adpDirConfigured && path.isAbsolute(adpDirConfigured)) {
|
|
69
|
+
return path.normalize(adpDirConfigured);
|
|
52
70
|
}
|
|
53
|
-
throw new Error(`None of the paths exist: '${filePaths.join("', '")}'.`);
|
|
54
|
-
}
|
|
55
|
-
readFilesInBaseAppDir(_appId, cachebusterToken) {
|
|
56
|
-
log.verbose(`Fetching base app files from local directory: ${cachebusterToken}`);
|
|
57
|
-
return FsUtil.readFilesRecursively(cachebusterToken);
|
|
58
|
-
}
|
|
59
|
-
getLocalFilesDirectory(appId) {
|
|
60
|
-
const adpDirConfigured = process.env.ADP_BUILDER_DIR || this.configuration.adpDir;
|
|
61
71
|
const adpDir = adpDirConfigured
|
|
62
72
|
? path.normalize(adpDirConfigured).replace(/\\/g, "/").replace(/\/+$/, "").split("/")
|
|
63
73
|
: [".."];
|
|
64
|
-
return path.join(process.cwd(), ...adpDir
|
|
74
|
+
return path.join(process.cwd(), ...adpDir);
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
77
|
//# sourceMappingURL=localRepository.js.map
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { IReuseLibInfo } from "../model/types.js";
|
|
1
|
+
import ICachedResource from "../cache/cachedResource.js";
|
|
3
2
|
export default interface IRepository {
|
|
4
|
-
getAppVariantIdHierarchy(appId: string): Promise<
|
|
5
|
-
fetch(
|
|
6
|
-
fetchReuseLib(libName: string, cachebusterToken: string, lib: IReuseLibInfo): Promise<Map<string, string>>;
|
|
3
|
+
getAppVariantIdHierarchy(appId: string): Promise<ICachedResource[]>;
|
|
4
|
+
fetch(resource: ICachedResource): Promise<Map<string, Buffer>>;
|
|
7
5
|
downloadAnnotationFile(uri: string): Promise<Map<string, string>>;
|
|
8
6
|
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ServiceCredentials } from "../../model/types.js";
|
|
2
|
+
export type XsApp = {
|
|
3
|
+
welcomeFile?: string;
|
|
4
|
+
authenticationMethod: "none" | "route";
|
|
5
|
+
routes: Route[];
|
|
6
|
+
};
|
|
7
|
+
export type Route = {
|
|
8
|
+
source: string;
|
|
9
|
+
target: string;
|
|
10
|
+
service?: string;
|
|
11
|
+
destination?: string;
|
|
12
|
+
authenticationType?: string;
|
|
13
|
+
localDir?: string;
|
|
14
|
+
};
|
|
2
15
|
export declare const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
3
16
|
/**
|
|
4
17
|
* Merges multiple xs-app.json contents into one. AppVariant and Reuse Library
|
|
@@ -10,5 +23,5 @@ export declare const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
|
10
23
|
*/
|
|
11
24
|
export declare function merge(xsAppFiles: string[]): string | undefined;
|
|
12
25
|
export declare function enhanceRoutesWithEndpointAndService(xsAppJsonContent: string, serviceCredentials: ServiceCredentials): string;
|
|
13
|
-
export declare function enhanceRoutes(serviceCredentials: ServiceCredentials, baseRoutes:
|
|
14
|
-
export declare function fetchCredentialsAndEnhanceRoutes(xsAppJson: string,
|
|
26
|
+
export declare function enhanceRoutes(serviceCredentials: ServiceCredentials, baseRoutes: Route[]): Route[];
|
|
27
|
+
export declare function fetchCredentialsAndEnhanceRoutes(xsAppJson: string, serviceCredentialsPromise: Promise<ServiceCredentials | undefined>): Promise<string>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getLogger } from "@ui5/logger";
|
|
2
|
-
import CFUtil from "../cfUtil.js";
|
|
3
2
|
const log = getLogger("@ui5/task-adaptation::XSAppJsonUtil");
|
|
4
3
|
export const XSAPP_JSON_FILENAME = "xs-app.json";
|
|
5
4
|
/**
|
|
@@ -63,7 +62,7 @@ export function enhanceRoutes(serviceCredentials, baseRoutes) {
|
|
|
63
62
|
return acc;
|
|
64
63
|
}, {});
|
|
65
64
|
return baseRoutes.map((route) => {
|
|
66
|
-
const endpointName = destinationToEndpoint[route.destination];
|
|
65
|
+
const endpointName = route.destination && destinationToEndpoint[route.destination];
|
|
67
66
|
if (endpointName) {
|
|
68
67
|
// There is a matching endpoint: remove destination and add endpoint/service
|
|
69
68
|
const { destination: _destination, ...rest } = route;
|
|
@@ -79,22 +78,12 @@ export function enhanceRoutes(serviceCredentials, baseRoutes) {
|
|
|
79
78
|
}
|
|
80
79
|
});
|
|
81
80
|
}
|
|
82
|
-
export async function fetchCredentialsAndEnhanceRoutes(xsAppJson,
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
export async function fetchCredentialsAndEnhanceRoutes(xsAppJson, serviceCredentialsPromise) {
|
|
82
|
+
const serviceCredentials = await serviceCredentialsPromise;
|
|
83
|
+
if (!serviceCredentials) {
|
|
84
|
+
log.verbose(`No service credentials available. Skipping xs-app.json update.`);
|
|
85
|
+
return xsAppJson;
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
// Get valid service keys with proper endpoints structure
|
|
89
|
-
serviceCredentials = await CFUtil.getOrCreateServiceKeyWithEndpoints(serviceInstanceName, space);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
throw new Error(`Failed to get valid service keys for app '${appName}': ${error.message}`);
|
|
93
|
-
}
|
|
94
|
-
if (serviceCredentials) {
|
|
95
|
-
return enhanceRoutesWithEndpointAndService(xsAppJson, serviceCredentials);
|
|
96
|
-
}
|
|
97
|
-
log.info(`No endpoints found for app '${appName}'. xs-app.json will not be updated.`);
|
|
98
|
-
return xsAppJson;
|
|
87
|
+
return enhanceRoutesWithEndpointAndService(xsAppJson, serviceCredentials);
|
|
99
88
|
}
|
|
100
89
|
//# sourceMappingURL=xsAppJsonUtil.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IConfiguration } from "../model/types.js";
|
|
2
2
|
import Language from "../model/language.js";
|
|
3
|
+
import AppVariant from "../appVariant.js";
|
|
3
4
|
export declare function dotToUnderscore(value: string): string;
|
|
4
5
|
export declare function validateConfiguration<T extends object>(options: T, properties: Array<keyof T>): void;
|
|
5
6
|
export declare function validateObject<T extends object>(options: T, properties: Array<keyof T>, message: string): void;
|
|
@@ -12,3 +13,8 @@ export declare function logBuilderVersion(): void;
|
|
|
12
13
|
export declare function logBetaUsage(): void;
|
|
13
14
|
export declare function getUniqueName(existingNames: string[], template: string): string;
|
|
14
15
|
export declare function isManifestChange(filename: string, content: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 4p. Reference map contains searchTerm as key and replacement as value. Base
|
|
18
|
+
* id and app variant ids are renamed to adaptation project id.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getReferences(appVariants: AppVariant[], adaptationProjectId: string): Map<string, string>;
|
package/dist/util/commonUtil.js
CHANGED
|
@@ -98,4 +98,21 @@ export function isManifestChange(filename, content) {
|
|
|
98
98
|
}
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* 4p. Reference map contains searchTerm as key and replacement as value. Base
|
|
103
|
+
* id and app variant ids are renamed to adaptation project id.
|
|
104
|
+
*/
|
|
105
|
+
export function getReferences(appVariants, adaptationProjectId) {
|
|
106
|
+
const references = new Map();
|
|
107
|
+
appVariants.forEach((variant, i) => {
|
|
108
|
+
if (i === 0) {
|
|
109
|
+
references.set(variant.reference, adaptationProjectId);
|
|
110
|
+
}
|
|
111
|
+
if (variant.id !== adaptationProjectId) {
|
|
112
|
+
references.set(variant.id, adaptationProjectId);
|
|
113
|
+
}
|
|
114
|
+
variant.getRenamingForMovedFiles().forEach((value, key) => references.set(key, value));
|
|
115
|
+
});
|
|
116
|
+
return references;
|
|
117
|
+
}
|
|
101
118
|
//# sourceMappingURL=commonUtil.js.map
|
package/dist/util/fsUtil.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export default class FsUtil {
|
|
2
|
-
static readInProject(filepath: string): Promise<string>;
|
|
2
|
+
static readInProject(filepath: string, encoding?: BufferEncoding): Promise<Buffer | string>;
|
|
3
3
|
/**
|
|
4
4
|
* Check whether a file or directory exists (non-throwing).
|
|
5
5
|
* @param filePath Absolute or relative path
|
|
6
6
|
* @returns true if the path exists, false if not
|
|
7
7
|
*/
|
|
8
8
|
private static fileExists;
|
|
9
|
-
static readFilesRecursively(rootDirectory: string): Promise<Map<string,
|
|
10
|
-
static exists(filePath: string): Promise<boolean>;
|
|
9
|
+
static readFilesRecursively(rootDirectory: string): Promise<Map<string, Buffer>>;
|
|
11
10
|
}
|
package/dist/util/fsUtil.js
CHANGED
|
@@ -7,9 +7,9 @@ export default class FsUtil {
|
|
|
7
7
|
* @param filepath The relative file path from the project root (e.g. 'ui5AppInfo.json').
|
|
8
8
|
* @returns A promise that resolves to the file content as a string.
|
|
9
9
|
*/
|
|
10
|
-
static async readInProject(filepath) {
|
|
10
|
+
static async readInProject(filepath, encoding) {
|
|
11
11
|
try {
|
|
12
|
-
return await fs.readFile(path.join(process.cwd(), filepath),
|
|
12
|
+
return await fs.readFile(path.join(process.cwd(), filepath), encoding);
|
|
13
13
|
}
|
|
14
14
|
catch (error) {
|
|
15
15
|
const isProjectRoot = await FsUtil.fileExists(path.join(process.cwd(), "ui5.yaml"));
|
|
@@ -37,38 +37,17 @@ export default class FsUtil {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
static async readFilesRecursively(rootDirectory) {
|
|
40
|
-
const
|
|
41
|
-
const fileReadTasks =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (entry.isDirectory()) {
|
|
51
|
-
directoriesToScan.push(entryPath);
|
|
52
|
-
}
|
|
53
|
-
else if (entry.isFile()) {
|
|
54
|
-
fileReadTasks.push((async () => {
|
|
55
|
-
const relativeFilePath = path.relative(rootDirectory, entryPath);
|
|
56
|
-
const content = await fs.readFile(entryPath, "utf-8");
|
|
57
|
-
return [relativeFilePath, content];
|
|
58
|
-
})());
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
40
|
+
const entries = await fs.readdir(rootDirectory, { withFileTypes: true, recursive: true });
|
|
41
|
+
const fileReadTasks = entries
|
|
42
|
+
.filter(entry => entry.isFile())
|
|
43
|
+
.map(async (entry) => {
|
|
44
|
+
const parentPath = entry.parentPath ?? entry.path;
|
|
45
|
+
const entryPath = path.join(parentPath, entry.name);
|
|
46
|
+
const relativeFilePath = path.relative(rootDirectory, entryPath).replaceAll("\\", "/");
|
|
47
|
+
const content = await fs.readFile(entryPath);
|
|
48
|
+
return [relativeFilePath, content];
|
|
49
|
+
});
|
|
62
50
|
return new Map(await Promise.all(fileReadTasks));
|
|
63
51
|
}
|
|
64
|
-
static async exists(filePath) {
|
|
65
|
-
try {
|
|
66
|
-
await fs.access(filePath);
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
52
|
}
|
|
74
53
|
//# sourceMappingURL=fsUtil.js.map
|
|
@@ -14,98 +14,66 @@ export function renameMap(content, references, ignoreInStrings) {
|
|
|
14
14
|
if (ignoredReferenceKeys.length > 0) {
|
|
15
15
|
log.info(`Ignored renaming: ${ignoredReferenceKeys.join(", ")}`);
|
|
16
16
|
}
|
|
17
|
-
const searchTerms = [...references.keys()];
|
|
17
|
+
const searchTerms = [...references.keys()].filter(key => key.length > 0);
|
|
18
18
|
if (!content || !searchTerms || searchTerms.length === 0) {
|
|
19
19
|
return content;
|
|
20
20
|
}
|
|
21
|
-
const dotToSlash = (str) => str.replaceAll(".", "
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return findAllOccurrences(content, string, start).map(i => ({ start: i, end: i + string.length }));
|
|
30
|
-
}).filter(arr => arr.length > 0) || [];
|
|
31
|
-
// We find the next search index with dots and slashes. Then we replace
|
|
32
|
-
// the nearest one and start search again in the next loop step.
|
|
33
|
-
const indices = new Array();
|
|
34
|
-
for (const searchTerm of searchTerms) {
|
|
35
|
-
const searchTermSlash = dotToSlash(searchTerm);
|
|
36
|
-
indices.push({
|
|
37
|
-
i: content.indexOf(searchTerm, start),
|
|
38
|
-
replacement: references.get(searchTerm),
|
|
39
|
-
searchTerm
|
|
40
|
-
}, {
|
|
41
|
-
i: content.indexOf(searchTermSlash, start),
|
|
42
|
-
replacement: dotToSlash(references.get(searchTerm)),
|
|
43
|
-
searchTerm: searchTermSlash
|
|
44
|
-
});
|
|
21
|
+
const dotToSlash = (str) => str.replaceAll(".", "/");
|
|
22
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23
|
+
// Build replacement lookup: pattern → replacement string (both dot and slash variants).
|
|
24
|
+
// Empty keys are skipped to avoid infinite zero-width regex matches.
|
|
25
|
+
const replacementMap = new Map();
|
|
26
|
+
for (const term of searchTerms) {
|
|
27
|
+
if (!term) {
|
|
28
|
+
continue;
|
|
45
29
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
30
|
+
const repl = references.get(term);
|
|
31
|
+
replacementMap.set(term, repl);
|
|
32
|
+
const slashTerm = dotToSlash(term);
|
|
33
|
+
if (slashTerm !== term) {
|
|
34
|
+
replacementMap.set(slashTerm, dotToSlash(repl));
|
|
49
35
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
// If we found two strings with the same index, we take the longest one
|
|
60
|
-
// to replace, e.g.: app.variant and app.variant2 has the same index,
|
|
61
|
-
// but we don't want to replace the first one with customer.app.variant,
|
|
62
|
-
// otherwise we get customer.app.variant2, which we don't need. We need
|
|
63
|
-
// to replace the whole app.variant2 with customer.app.variant.
|
|
64
|
-
const findCurrentReplace = (found) => {
|
|
65
|
-
const result = new Map();
|
|
66
|
-
for (const entry of found) {
|
|
67
|
-
const existing = result.get(entry.i);
|
|
68
|
-
if (!existing || entry.searchTerm.length >= existing.searchTerm.length) {
|
|
69
|
-
result.set(entry.i, entry);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return [...result.values()].sort((a, b) => a.i - b.i)[0];
|
|
73
|
-
};
|
|
74
|
-
// Ignore if search is in i18n key: replace "id" in "{{id.key}}" with
|
|
75
|
-
// "customer.id" and we need only the next one in string
|
|
76
|
-
found.forEach(index => index.inBetween = inBetween(ignoredStrings, index.i));
|
|
77
|
-
// There might be a situation when we found something in ignored
|
|
78
|
-
// substrings and the index could be the nearest, but after that the
|
|
79
|
-
// next index might be the actual find to replace, so we first of all
|
|
80
|
-
// ignore all the ignored substring findings and get the next actual
|
|
81
|
-
// replacement. But if there are only ignored substrings found, we take
|
|
82
|
-
// the first one just to skip it and go further.
|
|
83
|
-
const currentReplace = findCurrentReplace(found);
|
|
84
|
-
if (currentReplace.inBetween) {
|
|
85
|
-
start = currentReplace.inBetween.end;
|
|
36
|
+
}
|
|
37
|
+
// Build deduplicated ignore set with slash variants
|
|
38
|
+
const ignoreSet = new Set();
|
|
39
|
+
for (const ignoredString of ignoreInStrings) {
|
|
40
|
+
if (ignoredString) {
|
|
41
|
+
ignoreSet.add(ignoredString);
|
|
42
|
+
ignoreSet.add(dotToSlash(ignoredString));
|
|
86
43
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
44
|
+
}
|
|
45
|
+
// When a string appears in both replacementMap and ignoreSet, ignoreSet
|
|
46
|
+
// takes precedence — the match is skipped rather than replaced. Remove such
|
|
47
|
+
// keys from replacementMap so the intent is explicit instead of relying on
|
|
48
|
+
// runtime check order.
|
|
49
|
+
for (const ignored of ignoreSet) {
|
|
50
|
+
replacementMap.delete(ignored);
|
|
51
|
+
}
|
|
52
|
+
// Collect all unique patterns sorted by length descending (longest match first).
|
|
53
|
+
// V8 compiles alternation of literal strings into an Aho-Corasick automaton
|
|
54
|
+
// internally, giving us O(n + P + z) single-pass matching in native C++ code.
|
|
55
|
+
const allPatterns = new Set([...replacementMap.keys(), ...ignoreSet]);
|
|
56
|
+
const sorted = [...allPatterns].sort((a, b) => b.length - a.length);
|
|
57
|
+
const regex = new RegExp(sorted.map(escapeRegex).join("|"), "g");
|
|
58
|
+
// Single-pass: find all matches, skip ignored ones, batch-replace the rest
|
|
59
|
+
const parts = [];
|
|
60
|
+
let lastEnd = 0;
|
|
61
|
+
let m;
|
|
62
|
+
while ((m = regex.exec(content)) !== null) {
|
|
63
|
+
const matched = m[0];
|
|
64
|
+
if (ignoreSet.has(matched))
|
|
65
|
+
continue;
|
|
66
|
+
const replacement = replacementMap.get(matched);
|
|
67
|
+
if (replacement !== undefined) {
|
|
68
|
+
parts.push(content.substring(lastEnd, m.index));
|
|
69
|
+
parts.push(replacement);
|
|
70
|
+
lastEnd = m.index + matched.length;
|
|
92
71
|
}
|
|
93
72
|
}
|
|
73
|
+
parts.push(content.substring(lastEnd));
|
|
74
|
+
return parts.join("");
|
|
94
75
|
}
|
|
95
76
|
export function renameResources(files, search, replacement) {
|
|
96
77
|
return new Map([...files].map(([filepath, content]) => [filepath, rename(content, search, replacement)]));
|
|
97
78
|
}
|
|
98
|
-
function findAllOccurrences(string, substring, start) {
|
|
99
|
-
if (!substring) {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
const indices = [];
|
|
103
|
-
let index = start;
|
|
104
|
-
while ((index = string.indexOf(substring, index)) !== -1) {
|
|
105
|
-
indices.push(index);
|
|
106
|
-
index += substring.length; // shift from current finding
|
|
107
|
-
}
|
|
108
|
-
return indices;
|
|
109
|
-
}
|
|
110
|
-
;
|
|
111
79
|
//# sourceMappingURL=renamingUtil.js.map
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extensions of files whose contents are processed by the adaptation
|
|
3
|
+
* pipeline as text. Anything outside this whitelist is treated as binary
|
|
4
|
+
* (e.g. images, fonts) and is saved to the workspace verbatim by WorkspaceManager.
|
|
5
|
+
*
|
|
6
|
+
* Kept in sync with EXTENSIONS_TO_PROCESS in appVariant.ts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TEXT_EXTENSIONS: ReadonlySet<string>;
|
|
1
9
|
export default class ResourceUtil {
|
|
2
10
|
static getRootFolder(projectNamespace?: string): string;
|
|
3
11
|
static relativeToRoot(resourcePath: string, projectNamespace?: string): string;
|
|
4
12
|
static getResourcePath(projectNamespace?: string, ...paths: string[]): string;
|
|
5
|
-
static write(dir: string, files: Map<string,
|
|
6
|
-
static writeInProject(dir: string, files: Map<string,
|
|
7
|
-
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string,
|
|
8
|
-
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string,
|
|
13
|
+
static write(dir: string, files: Map<string, Buffer>): Promise<void[]>;
|
|
14
|
+
static writeInProject(dir: string, files: Map<string, Buffer>): Promise<void[]>;
|
|
15
|
+
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string, Buffer>>;
|
|
16
|
+
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string, Buffer>>;
|
|
9
17
|
static getString(resource: any): Promise<string>;
|
|
10
18
|
static getJson(resource: any): Promise<any>;
|
|
11
19
|
static setString(resource: any, str: string): void;
|
|
12
|
-
static createResource(filename: string, projectNamespace: string, content: string): any;
|
|
20
|
+
static createResource(filename: string, projectNamespace: string, content: string | Buffer): any;
|
|
21
|
+
private static createResourceFromContent;
|
|
13
22
|
static toFileMap(resources: ReadonlyArray<Resource>, projectNamespace?: string): Promise<Map<string, string>>;
|
|
23
|
+
/**
|
|
24
|
+
* Decodes the text-extension files of a buffer map to UTF-8 strings.
|
|
25
|
+
* Binary files (e.g. images, fonts) are dropped — they are expected to
|
|
26
|
+
* have been written to the workspace separately and are not relevant
|
|
27
|
+
* to the in-memory text pipeline.
|
|
28
|
+
*/
|
|
29
|
+
static toTextMap(buffers: ReadonlyMap<string, Buffer>): ReadonlyMap<string, string>;
|
|
14
30
|
}
|