@ui5/task-adaptation 1.6.5-rc.4 → 1.6.6
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/.env.test +1 -0
- package/CHANGELOG.md +13 -60
- package/dist/adapters/commands/fetchPreviewResourcesCommand.js +1 -2
- package/dist/adapters/commands/processPreviewResourcesCommand.js +5 -9
- package/dist/annotations/abapAnnotationManager.js +1 -1
- package/dist/annotations/dataSource/dataSourceManager.d.ts +1 -2
- package/dist/annotations/dataSource/dataSourceManager.js +7 -16
- package/dist/appVariant.js +2 -2
- package/dist/cache/cacheHolder.d.ts +2 -2
- package/dist/index.js +4 -14
- package/dist/landscapeConfiguration.d.ts +2 -2
- package/dist/landscapeConfiguration.js +31 -33
- package/dist/model/types.d.ts +1 -1
- package/dist/repositories/abapProvider.js +2 -2
- package/dist/repositories/abapRepository.d.ts +1 -1
- package/dist/repositories/html5Repository.d.ts +1 -1
- package/dist/repositories/localRepository.d.ts +1 -1
- package/dist/repositories/localRepository.js +7 -6
- package/dist/repositories/repository.d.ts +1 -1
- package/dist/util/fsUtil.d.ts +1 -1
- package/dist/util/fsUtil.js +2 -2
- package/dist/util/renamingUtil.js +81 -49
- package/dist/util/resourceUtil.d.ts +5 -21
- package/dist/util/resourceUtil.js +10 -51
- package/dist/util/validator/abapValidator.d.ts +4 -2
- package/dist/util/validator/abapValidator.js +16 -4
- package/dist/util/zipUtil.d.ts +1 -1
- package/dist/util/zipUtil.js +1 -1
- package/package.json +1 -1
- package/dist/util/validator/abapConnectionValidator.d.ts +0 -5
- package/dist/util/validator/abapConnectionValidator.js +0 -22
- package/dist/util/workspaceManager.d.ts +0 -9
- package/dist/util/workspaceManager.js +0 -46
package/.env.test
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
UI5_LOG_LVL=error
|
package/CHANGELOG.md
CHANGED
|
@@ -2,31 +2,19 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
-
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.6.
|
|
5
|
+
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.6.6...HEAD).
|
|
6
6
|
|
|
7
|
-
<a name="v1.6.
|
|
8
|
-
## [v1.6.
|
|
7
|
+
<a name="v1.6.6"></a>
|
|
8
|
+
## [v1.6.6] - 2026-06-30
|
|
9
9
|
|
|
10
|
-
<a name="v1.6.5
|
|
11
|
-
## [v1.6.5
|
|
10
|
+
<a name="v1.6.5"></a>
|
|
11
|
+
## [v1.6.5] - 2026-06-24
|
|
12
12
|
### Reverts
|
|
13
|
-
- Release 1.6.
|
|
13
|
+
- Release 1.6.4
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
<a name="v1.6.
|
|
17
|
-
## [v1.6.
|
|
18
|
-
|
|
19
|
-
<a name="v1.6.5-rc.1"></a>
|
|
20
|
-
## [v1.6.5-rc.1] - 2026-04-13
|
|
21
|
-
|
|
22
|
-
<a name="v1.6.4-rc.3"></a>
|
|
23
|
-
## [v1.6.4-rc.3] - 2026-04-07
|
|
24
|
-
|
|
25
|
-
<a name="v1.6.4-rc.2"></a>
|
|
26
|
-
## [v1.6.4-rc.2] - 2026-04-06
|
|
27
|
-
|
|
28
|
-
<a name="v1.6.4-rc.1"></a>
|
|
29
|
-
## [v1.6.4-rc.1] - 2026-04-06
|
|
16
|
+
<a name="v1.6.4"></a>
|
|
17
|
+
## [v1.6.4] - 2026-04-10
|
|
30
18
|
|
|
31
19
|
<a name="v1.6.3"></a>
|
|
32
20
|
## [v1.6.3] - 2026-03-18
|
|
@@ -48,24 +36,6 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
|
|
|
48
36
|
|
|
49
37
|
<a name="v1.5.4"></a>
|
|
50
38
|
## [v1.5.4] - 2026-02-16
|
|
51
|
-
### Bug Fixes
|
|
52
|
-
- Removed moved changes [`babdc1b`](https://github.com/SAP/ui5-task-adaptation/commit/babdc1bce8e407b2638e014cfaa4e6547bba10ac)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<a name="v1.6.0-rc.4"></a>
|
|
56
|
-
## [v1.6.0-rc.4] - 2026-02-12
|
|
57
|
-
|
|
58
|
-
<a name="v1.6.0-rc.3"></a>
|
|
59
|
-
## [v1.6.0-rc.3] - 2026-02-05
|
|
60
|
-
|
|
61
|
-
<a name="v1.6.0-rc.2"></a>
|
|
62
|
-
## [v1.6.0-rc.2] - 2026-02-05
|
|
63
|
-
|
|
64
|
-
<a name="v1.6.0-rc.1"></a>
|
|
65
|
-
## [v1.6.0-rc.1] - 2026-02-05
|
|
66
|
-
|
|
67
|
-
<a name="v1.6.0-rc.0"></a>
|
|
68
|
-
## [v1.6.0-rc.0] - 2026-02-02
|
|
69
39
|
|
|
70
40
|
<a name="v1.5.3"></a>
|
|
71
41
|
## [v1.5.3] - 2025-09-29
|
|
@@ -76,12 +46,6 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
|
|
|
76
46
|
- Removed moved changes [`babdc1b`](https://github.com/SAP/ui5-task-adaptation/commit/babdc1bce8e407b2638e014cfaa4e6547bba10ac)
|
|
77
47
|
|
|
78
48
|
|
|
79
|
-
<a name="v1.5.2-rc.1"></a>
|
|
80
|
-
## [v1.5.2-rc.1] - 2025-08-22
|
|
81
|
-
|
|
82
|
-
<a name="v1.5.2-rc.0"></a>
|
|
83
|
-
## [v1.5.2-rc.0] - 2025-08-19
|
|
84
|
-
|
|
85
49
|
<a name="v1.5.1"></a>
|
|
86
50
|
## [v1.5.1] - 2025-08-06
|
|
87
51
|
|
|
@@ -197,29 +161,18 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
|
|
|
197
161
|
<a name="v1.0.0"></a>
|
|
198
162
|
## v1.0.0 - 2020-12-09
|
|
199
163
|
|
|
200
|
-
[v1.6.
|
|
201
|
-
[v1.6.5
|
|
202
|
-
[v1.6.
|
|
203
|
-
[v1.6.5-rc.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.4-rc.3...v1.6.5-rc.1
|
|
204
|
-
[v1.6.4-rc.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.4-rc.2...v1.6.4-rc.3
|
|
205
|
-
[v1.6.4-rc.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.4-rc.1...v1.6.4-rc.2
|
|
206
|
-
[v1.6.4-rc.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.3...v1.6.4-rc.1
|
|
164
|
+
[v1.6.6]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.5...v1.6.6
|
|
165
|
+
[v1.6.5]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.4...v1.6.5
|
|
166
|
+
[v1.6.4]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.3...v1.6.4
|
|
207
167
|
[v1.6.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.2...v1.6.3
|
|
208
168
|
[v1.6.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.1...v1.6.2
|
|
209
169
|
[v1.6.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.0...v1.6.1
|
|
210
170
|
[v1.6.0]: https://github.com/SAP/ui5-task-adaptation/compare/v0.2.0...v1.6.0
|
|
211
171
|
[v0.2.0]: https://github.com/SAP/ui5-task-adaptation/compare/v0.1.0...v0.2.0
|
|
212
172
|
[v0.1.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.4...v0.1.0
|
|
213
|
-
[v1.5.4]: https://github.com/SAP/ui5-task-adaptation/compare/v1.
|
|
214
|
-
[v1.6.0-rc.4]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.0-rc.3...v1.6.0-rc.4
|
|
215
|
-
[v1.6.0-rc.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.0-rc.2...v1.6.0-rc.3
|
|
216
|
-
[v1.6.0-rc.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.0-rc.1...v1.6.0-rc.2
|
|
217
|
-
[v1.6.0-rc.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.6.0-rc.0...v1.6.0-rc.1
|
|
218
|
-
[v1.6.0-rc.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.3...v1.6.0-rc.0
|
|
173
|
+
[v1.5.4]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.3...v1.5.4
|
|
219
174
|
[v1.5.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.2...v1.5.3
|
|
220
|
-
[v1.5.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.
|
|
221
|
-
[v1.5.2-rc.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.2-rc.0...v1.5.2-rc.1
|
|
222
|
-
[v1.5.2-rc.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.1...v1.5.2-rc.0
|
|
175
|
+
[v1.5.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.1...v1.5.2
|
|
223
176
|
[v1.5.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.3...v1.5.1
|
|
224
177
|
[v1.4.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.2...v1.4.3
|
|
225
178
|
[v1.4.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.0...v1.4.2
|
|
@@ -76,8 +76,7 @@ export default class FetchPreviewResourcesCommand extends SetupCommand {
|
|
|
76
76
|
const newFilename = path.join(libraryName, filename);
|
|
77
77
|
// Source path in xs-app.json needs to be adjusted to new location
|
|
78
78
|
if (filename.includes("xs-app.json")) {
|
|
79
|
-
|
|
80
|
-
content = Buffer.from(modified, "utf8");
|
|
79
|
+
content = this.modifyRoutes(content, libraryName, libId);
|
|
81
80
|
}
|
|
82
81
|
files.set(newFilename, content);
|
|
83
82
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { PostCommand } from "./command.js";
|
|
2
2
|
import { getLogger } from "@ui5/logger";
|
|
3
|
-
import {
|
|
3
|
+
import { merge, XSAPP_JSON_FILENAME } from "../../util/cf/xsAppJsonUtil.js";
|
|
4
4
|
import ResourceUtil from "../../util/resourceUtil.js";
|
|
5
5
|
import { REUSE_DIR } from "../../model/configuration.js";
|
|
6
|
+
import XsAppJsonEnhanceRoutesCommand from "./xsAppJsonEnhanceRoutesCommand.js";
|
|
6
7
|
const log = getLogger("@ui5/task-adaptation::ProcessPreviewResourcesCommand");
|
|
7
8
|
export default class ProcessPreviewResourcesCommand extends PostCommand {
|
|
8
9
|
serviceCredentialsPromise;
|
|
@@ -16,11 +17,7 @@ export default class ProcessPreviewResourcesCommand extends PostCommand {
|
|
|
16
17
|
log.verbose(`Downloading reuse libraries to reuse folder`);
|
|
17
18
|
const baseAppXsAppJson = files.get(XSAPP_JSON_FILENAME);
|
|
18
19
|
const mergedFiles = await this.collectReuseLibFiles(await this.previewPromise, baseAppXsAppJson);
|
|
19
|
-
|
|
20
|
-
if (xsAppJson) {
|
|
21
|
-
const enhanced = await fetchCredentialsAndEnhanceRoutes(xsAppJson.toString("utf8"), this.serviceCredentialsPromise);
|
|
22
|
-
mergedFiles.set(XSAPP_JSON_FILENAME, Buffer.from(enhanced, "utf8"));
|
|
23
|
-
}
|
|
20
|
+
await new XsAppJsonEnhanceRoutesCommand(this.serviceCredentialsPromise).execute(mergedFiles);
|
|
24
21
|
if (mergedFiles.size === 0) {
|
|
25
22
|
return;
|
|
26
23
|
}
|
|
@@ -40,14 +37,13 @@ export default class ProcessPreviewResourcesCommand extends PostCommand {
|
|
|
40
37
|
}
|
|
41
38
|
for (const [filename, content] of libFiles) {
|
|
42
39
|
if (filename.endsWith(XSAPP_JSON_FILENAME)) {
|
|
43
|
-
|
|
44
|
-
mergedXsAppJson = mergedXsAppJson ? merge([xsAppText, mergedXsAppJson]) : xsAppText;
|
|
40
|
+
mergedXsAppJson = mergedXsAppJson ? merge([content, mergedXsAppJson]) : content;
|
|
45
41
|
}
|
|
46
42
|
mergedFiles.set(filename, content);
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
45
|
if (mergedXsAppJson) {
|
|
50
|
-
mergedFiles.set(XSAPP_JSON_FILENAME,
|
|
46
|
+
mergedFiles.set(XSAPP_JSON_FILENAME, mergedXsAppJson);
|
|
51
47
|
}
|
|
52
48
|
return mergedFiles;
|
|
53
49
|
}
|
|
@@ -22,7 +22,7 @@ export default class AbapAnnotationManager {
|
|
|
22
22
|
const i18nManager = new I18nManager(modelName, appVariantId, languages);
|
|
23
23
|
const serviceRequestor = new ServiceRequestor(this.configuration, this.repository);
|
|
24
24
|
const dataSourceManager = new DataSourceManager();
|
|
25
|
-
|
|
25
|
+
dataSourceManager.addDataSources(baseAppManifest["sap.app"]?.dataSources);
|
|
26
26
|
const annotationFiles = await dataSourceManager.createAnnotationFiles(languages, i18nManager, serviceRequestor);
|
|
27
27
|
const i18nFiles = i18nManager.createFiles(i18nPathName);
|
|
28
28
|
if (i18nManager.hasTranslations()) {
|
|
@@ -3,11 +3,10 @@ import Language from "../../model/language.js";
|
|
|
3
3
|
import ServiceRequestor from "../serviceRequestor.js";
|
|
4
4
|
export default class DataSourceManager {
|
|
5
5
|
private dataSources;
|
|
6
|
-
private shouldDownload;
|
|
7
6
|
/**
|
|
8
7
|
* Parses dataSources from manifest.json.
|
|
9
8
|
* @param dataSourcesJson manifest.json/sap.app/dataSources node
|
|
10
9
|
*/
|
|
11
|
-
addDataSources(dataSourcesJson: any):
|
|
10
|
+
addDataSources(dataSourcesJson: any): void;
|
|
12
11
|
createAnnotationFiles(languages: Language[], i18nManager: I18nManager, serviceRequestor: ServiceRequestor): Promise<Map<string, string>>;
|
|
13
12
|
}
|
|
@@ -1,28 +1,20 @@
|
|
|
1
|
+
import DataSourceOData from "./dataSourceOData.js";
|
|
1
2
|
import DataSourceODataAnnotation from "./dataSourceODataAnnotation.js";
|
|
2
3
|
import path from "path/posix";
|
|
3
4
|
export default class DataSourceManager {
|
|
4
5
|
dataSources = new Array();
|
|
5
|
-
shouldDownload(dataSource, type) {
|
|
6
|
-
// is remote service, not local file
|
|
7
|
-
return dataSource.uri?.startsWith("/") &&
|
|
8
|
-
// no local metadata file and wasn't downloaded yet
|
|
9
|
-
!dataSource.settings?.ignoreAnnotationsFromMetadata &&
|
|
10
|
-
dataSource.type === type;
|
|
11
|
-
}
|
|
12
6
|
/**
|
|
13
7
|
* Parses dataSources from manifest.json.
|
|
14
8
|
* @param dataSourcesJson manifest.json/sap.app/dataSources node
|
|
15
9
|
*/
|
|
16
|
-
|
|
10
|
+
addDataSources(dataSourcesJson) {
|
|
17
11
|
if (!dataSourcesJson) {
|
|
18
12
|
return;
|
|
19
13
|
}
|
|
20
14
|
const odataAnnotationMap = new Map();
|
|
21
|
-
const dataSourceODataEntries = Object.entries(dataSourcesJson).filter(([, dataSource]) => dataSource.uri?.startsWith("/") && dataSource.type === "OData");
|
|
22
|
-
const { default: DataSourceOData } = await import("./dataSourceOData.js");
|
|
23
15
|
// Loop over OData first to collect linked annotation names
|
|
24
|
-
for (const [name, dataSource] of
|
|
25
|
-
if (
|
|
16
|
+
for (const [name, dataSource] of Object.entries(dataSourcesJson)) {
|
|
17
|
+
if (dataSource.uri?.startsWith("/") && dataSource.type === "OData") {
|
|
26
18
|
const uri = path.normalize(dataSource.uri + "/$metadata");
|
|
27
19
|
const odata = new DataSourceOData(name, uri, dataSource);
|
|
28
20
|
odata.getAnnotations().forEach(annotation => odataAnnotationMap.set(annotation, uri));
|
|
@@ -31,11 +23,10 @@ export default class DataSourceManager {
|
|
|
31
23
|
}
|
|
32
24
|
// If ODataAnnotation is in OData annotations, pass metadata url to it
|
|
33
25
|
for (const [name, dataSource] of Object.entries(dataSourcesJson)) {
|
|
26
|
+
const uri = dataSource.uri;
|
|
34
27
|
const metadataUrl = odataAnnotationMap.get(name);
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
const odata = new DataSourceODataAnnotation(name, uri, dataSource, metadataUrl);
|
|
38
|
-
this.dataSources.push(odata);
|
|
28
|
+
if (uri?.startsWith("/") && dataSource.type === "ODataAnnotation") {
|
|
29
|
+
this.dataSources.push(new DataSourceODataAnnotation(name, uri, dataSource, metadataUrl));
|
|
39
30
|
}
|
|
40
31
|
}
|
|
41
32
|
for (const dataSource of this.dataSources) {
|
package/dist/appVariant.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dotToUnderscore, isManifestChange } from "./util/commonUtil.js";
|
|
2
|
-
import ResourceUtil
|
|
2
|
+
import ResourceUtil from "./util/resourceUtil.js";
|
|
3
3
|
import { posix as path } from "path";
|
|
4
4
|
import { moveFile, moveFiles } from "./util/movingHandler/changeFileMoveHandler.js";
|
|
5
5
|
import RenameFilesCommand from "./adapters/commands/renameFilesCommand.js";
|
|
@@ -16,7 +16,7 @@ export default class AppVariant {
|
|
|
16
16
|
movedFiles = new Map();
|
|
17
17
|
renaming = new Map();
|
|
18
18
|
static async fromWorkspace(workspace, projectNamespace) {
|
|
19
|
-
const EXTENSIONS_TO_PROCESS =
|
|
19
|
+
const EXTENSIONS_TO_PROCESS = "js,json,xml,html,properties,change,appdescr_variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change,variant,fioriversion,codeChange,xmlViewChange,context";
|
|
20
20
|
const resources = await workspace.byGlob(`/**/*.{${EXTENSIONS_TO_PROCESS}}`);
|
|
21
21
|
const files = await ResourceUtil.toFileMap(resources, projectNamespace);
|
|
22
22
|
return new AppVariant(files, resources);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export default class CacheHolder {
|
|
2
2
|
private static TEMP_TASK_DIR;
|
|
3
3
|
static getTempDir(...paths: string[]): string;
|
|
4
|
-
static read(repoName: string, token: string): Promise<Map<string,
|
|
5
|
-
static write(repoName: string, token: string, files: Map<string,
|
|
4
|
+
static read(repoName: string, token: string): Promise<Map<string, string>>;
|
|
5
|
+
static write(repoName: string, token: string, files: Map<string, string>): Promise<void>;
|
|
6
6
|
private static isValid;
|
|
7
7
|
/**
|
|
8
8
|
* Clears cached files by repo name and token
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ import { getReferences, logBuilderVersion } from "./util/commonUtil.js";
|
|
|
3
3
|
import AppVariant from "./appVariant.js";
|
|
4
4
|
import BaseApp from "./baseApp.js";
|
|
5
5
|
import { initialize } from "./landscapeConfiguration.js";
|
|
6
|
-
import WorkspaceManager from "./util/workspaceManager.js";
|
|
7
6
|
/**
|
|
8
7
|
* Creates an appVariant bundle from the provided resources.
|
|
9
8
|
*/
|
|
@@ -15,13 +14,7 @@ export default async ({ workspace, options, taskUtil }) => {
|
|
|
15
14
|
};
|
|
16
15
|
dotenv.config();
|
|
17
16
|
logBuilderVersion();
|
|
18
|
-
|
|
19
|
-
// fetched, in this case these files will overwrite the adaptation project
|
|
20
|
-
// files, so we create a snapshot to later on overwrite the workspace files
|
|
21
|
-
// with adapatation project files again to make sure they are on top
|
|
22
|
-
const workspaceManager = new WorkspaceManager(workspace, options.projectNamespace);
|
|
23
|
-
await workspaceManager.createSnapshot();
|
|
24
|
-
const { repository, adapter } = await initialize(options.configuration);
|
|
17
|
+
const { repository, adapter } = initialize(options.configuration);
|
|
25
18
|
const adaptationProject = await AppVariant.fromWorkspace(workspace, options.projectNamespace);
|
|
26
19
|
const setupCommandChain = adapter.createSetupCommandChain(adaptationProject.reference, repository);
|
|
27
20
|
await setupCommandChain.execute();
|
|
@@ -40,13 +33,10 @@ export default async ({ workspace, options, taskUtil }) => {
|
|
|
40
33
|
const baseApp = BaseApp.fromFiles(baseFiles);
|
|
41
34
|
return adapter.createAdaptCommandChain(baseApp, appVariant).execute();
|
|
42
35
|
};
|
|
43
|
-
let files = await
|
|
44
|
-
for (const
|
|
45
|
-
|
|
46
|
-
files = await adapt(files, AppVariant.fromFiles(appVariantFiles));
|
|
36
|
+
let files = await fetchFilesPromises.shift(); // original app files
|
|
37
|
+
for (const appVariantFiles of fetchFilesPromises) {
|
|
38
|
+
files = await adapt(files, AppVariant.fromFiles(await appVariantFiles));
|
|
47
39
|
}
|
|
48
|
-
// We need to overwrite base files with the adaptation project files
|
|
49
|
-
await workspaceManager.restoreSnapshot();
|
|
50
40
|
files = await adapt(files, adaptationProject);
|
|
51
41
|
const references = getReferences(appVariants, adaptationProject.id);
|
|
52
42
|
return adapter.createPostCommandChain(references, adaptationProject, ui5BuilderTools).execute(files);
|
|
@@ -2,8 +2,8 @@ import { IConfiguration } from "./model/types.js";
|
|
|
2
2
|
import { IAdapter } from "./adapters/adapter.js";
|
|
3
3
|
import IRepository from "./repositories/repository.js";
|
|
4
4
|
import IAnnotationManager from "./annotations/annotationManager.js";
|
|
5
|
-
export declare function initialize(configuration: IConfiguration):
|
|
5
|
+
export declare function initialize(configuration: IConfiguration): {
|
|
6
6
|
adapter: IAdapter;
|
|
7
7
|
repository: IRepository;
|
|
8
8
|
annotationManager: IAnnotationManager;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
@@ -1,31 +1,39 @@
|
|
|
1
|
+
import AbapAdapter from "./adapters/abapAdapter.js";
|
|
2
|
+
import CFAdapter from "./adapters/cfAdapter.js";
|
|
3
|
+
import PreviewAdapter from "./adapters/previewAdapter.js";
|
|
4
|
+
import AbapRepository from "./repositories/abapRepository.js";
|
|
5
|
+
import HTML5Repository from "./repositories/html5Repository.js";
|
|
6
|
+
import LocalRepository from "./repositories/localRepository.js";
|
|
7
|
+
import AbapAnnotationManager from "./annotations/abapAnnotationManager.js";
|
|
8
|
+
import CFAnnotationManager from "./annotations/cfAnnotationManager.js";
|
|
1
9
|
import CFValidator from "./util/validator/cfValidator.js";
|
|
10
|
+
import AbapValidator from "./util/validator/abapValidator.js";
|
|
2
11
|
import { isOneOf } from "./util/validator/validator.js";
|
|
3
12
|
import { LANDSCAPE_TYPES } from "./model/configuration.js";
|
|
4
13
|
import { getLogger } from "@ui5/logger";
|
|
5
|
-
import AbapValidator from "./util/validator/abapValidator.js";
|
|
6
14
|
import LocalAnnotationManager from "./annotations/localAnnotationManager.js";
|
|
7
15
|
const log = getLogger("@ui5/task-adaptation::LandscapeConfiguration");
|
|
8
|
-
export
|
|
9
|
-
const type =
|
|
16
|
+
export function initialize(configuration) {
|
|
17
|
+
const type = getTypeByConfiguration(configuration);
|
|
10
18
|
const enhancedConfig = { ...configuration, type };
|
|
11
|
-
const repository =
|
|
12
|
-
const annotationManager =
|
|
19
|
+
const repository = getRepository(enhancedConfig);
|
|
20
|
+
const annotationManager = getAnnotationManager(enhancedConfig, repository);
|
|
13
21
|
return {
|
|
14
|
-
adapter:
|
|
22
|
+
adapter: getAdapter(enhancedConfig, annotationManager),
|
|
15
23
|
repository,
|
|
16
24
|
annotationManager
|
|
17
25
|
};
|
|
18
26
|
}
|
|
19
|
-
|
|
27
|
+
function getTypeByConfiguration(configuration) {
|
|
28
|
+
const validators = [
|
|
29
|
+
new CFValidator(),
|
|
30
|
+
new AbapValidator(),
|
|
31
|
+
];
|
|
20
32
|
if (isOneOf(LANDSCAPE_TYPES, configuration.type)) {
|
|
21
33
|
return configuration.type;
|
|
22
34
|
}
|
|
23
35
|
else {
|
|
24
36
|
log.warn("Deprecated behavior: type is not specified or invalid. Should be either 'cf' or 'abap'. Trying to detect the type based on provided configuration");
|
|
25
|
-
const validators = [
|
|
26
|
-
new CFValidator(),
|
|
27
|
-
new AbapValidator(),
|
|
28
|
-
];
|
|
29
37
|
for (const validator of validators) {
|
|
30
38
|
try {
|
|
31
39
|
validator.validateConfiguration(configuration);
|
|
@@ -38,51 +46,41 @@ async function getTypeByConfiguration(configuration) {
|
|
|
38
46
|
throw new Error("'type' should be specified in ui5.yaml configuration: 'cf' or 'abap'");
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
|
-
|
|
49
|
+
function getAdapter(configuration, annotationManager) {
|
|
42
50
|
if (isPreview()) {
|
|
43
|
-
const { default: PreviewAdapter } = await import("./adapters/previewAdapter.js");
|
|
44
51
|
return new PreviewAdapter(configuration);
|
|
45
52
|
}
|
|
46
53
|
switch (configuration.type) {
|
|
47
|
-
case "abap":
|
|
48
|
-
const { default: AbapAdapter } = await import("./adapters/abapAdapter.js");
|
|
54
|
+
case "abap":
|
|
49
55
|
return new AbapAdapter(annotationManager);
|
|
50
|
-
|
|
51
|
-
case "cf": {
|
|
52
|
-
const { default: CFAdapter } = await import("./adapters/cfAdapter.js");
|
|
56
|
+
case "cf":
|
|
53
57
|
return new CFAdapter(configuration);
|
|
54
|
-
}
|
|
55
58
|
default:
|
|
56
59
|
throw new Error(`No adapter found for the given configuration type '${configuration.type}'`);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
|
-
|
|
62
|
+
function getRepository(configuration) {
|
|
63
|
+
if (isLocal()) {
|
|
64
|
+
return new LocalRepository();
|
|
65
|
+
}
|
|
60
66
|
switch (configuration.type) {
|
|
61
|
-
case "abap":
|
|
62
|
-
const { default: AbapRepository } = await import("./repositories/abapRepository.js");
|
|
67
|
+
case "abap":
|
|
63
68
|
return new AbapRepository(configuration);
|
|
64
|
-
|
|
65
|
-
case "cf": {
|
|
66
|
-
const { default: HTML5Repository } = await import("./repositories/html5Repository.js");
|
|
69
|
+
case "cf":
|
|
67
70
|
return new HTML5Repository(configuration);
|
|
68
|
-
}
|
|
69
71
|
default:
|
|
70
72
|
throw new Error(`No repository found for the given configuration type '${configuration.type}'`);
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
function getAnnotationManager(configuration, repository) {
|
|
74
76
|
if (isLocal()) {
|
|
75
77
|
return new LocalAnnotationManager();
|
|
76
78
|
}
|
|
77
79
|
switch (configuration.type) {
|
|
78
|
-
case "abap":
|
|
79
|
-
const { default: AbapAnnotationManager } = await import("./annotations/abapAnnotationManager.js");
|
|
80
|
+
case "abap":
|
|
80
81
|
return new AbapAnnotationManager(configuration, repository);
|
|
81
|
-
|
|
82
|
-
case "cf": {
|
|
83
|
-
const { default: CFAnnotationManager } = await import("./annotations/cfAnnotationManager.js");
|
|
82
|
+
case "cf":
|
|
84
83
|
return new CFAnnotationManager();
|
|
85
|
-
}
|
|
86
84
|
default:
|
|
87
85
|
throw new Error(`No annotation manager found for the given configuration type '${configuration.type}'`);
|
|
88
86
|
}
|
package/dist/model/types.d.ts
CHANGED
|
@@ -129,5 +129,5 @@ export type ServiceCredentials = {
|
|
|
129
129
|
} | string>;
|
|
130
130
|
"sap.cloud.service"?: string;
|
|
131
131
|
};
|
|
132
|
-
export type FetchFilesPromise = Map<string, Promise<ReadonlyMap<string,
|
|
132
|
+
export type FetchFilesPromise = Map<string, Promise<ReadonlyMap<string, string>>>;
|
|
133
133
|
export { IConfiguration };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createAbapServiceProvider } from "@sap-ux/system-access";
|
|
2
2
|
import { getLogger } from "@ui5/logger";
|
|
3
|
-
import
|
|
3
|
+
import AbapValidator from "../util/validator/abapValidator.js";
|
|
4
4
|
const log = getLogger("@ui5/task-adaptation::AbapProvider");
|
|
5
5
|
log.debug = (message) => log.verbose(message);
|
|
6
6
|
export default class AbapProvider {
|
|
7
7
|
provider = null;
|
|
8
|
-
abapValidator = new
|
|
8
|
+
abapValidator = new AbapValidator();
|
|
9
9
|
async get({ target, destination }) {
|
|
10
10
|
if (!this.provider) {
|
|
11
11
|
const abapTarget = this.abapValidator.validateAndGetAbapTarget(target, destination);
|
|
@@ -11,6 +11,6 @@ export default class AbapRepository implements IRepository {
|
|
|
11
11
|
getAnnotationMetadata(uri: string): Promise<IMetadata>;
|
|
12
12
|
downloadAnnotationFile(uri: string): Promise<Map<string, any>>;
|
|
13
13
|
getMetadata(id: string): Promise<IMetadata>;
|
|
14
|
-
fetch(resource: IAbapResource): Promise<Map<string,
|
|
14
|
+
fetch(resource: IAbapResource): Promise<Map<string, string>>;
|
|
15
15
|
}
|
|
16
16
|
export {};
|
|
@@ -10,7 +10,7 @@ export default class HTML5Repository implements IRepository {
|
|
|
10
10
|
private validator;
|
|
11
11
|
constructor(configuration: IConfiguration);
|
|
12
12
|
getAppVariantIdHierarchy(_appId: string): Promise<IHtml5Resource[]>;
|
|
13
|
-
fetch(resource: IHtml5Resource): Promise<Map<string,
|
|
13
|
+
fetch(resource: IHtml5Resource): Promise<Map<string, string>>;
|
|
14
14
|
getMetadata(): Promise<any>;
|
|
15
15
|
private getHtml5RepoInfo;
|
|
16
16
|
private getHTML5Credentials;
|
|
@@ -6,7 +6,7 @@ export interface ILocalResource extends ICachedResource {
|
|
|
6
6
|
export default class LocalRepository implements IRepository {
|
|
7
7
|
downloadAnnotationFile(_uri: string): Promise<Map<string, string>>;
|
|
8
8
|
getAppVariantIdHierarchy(appId: string): Promise<ILocalResource[]>;
|
|
9
|
-
fetch(resource: ILocalResource): Promise<Map<string,
|
|
9
|
+
fetch(resource: ILocalResource): Promise<Map<string, string>>;
|
|
10
10
|
private buildManifestIndex;
|
|
11
11
|
private getLocalFilesDir;
|
|
12
12
|
}
|
|
@@ -65,13 +65,14 @@ export default class LocalRepository {
|
|
|
65
65
|
}
|
|
66
66
|
getLocalFilesDir() {
|
|
67
67
|
const adpDirConfigured = process.env.ADP_BUILDER_DIR;
|
|
68
|
-
if (adpDirConfigured
|
|
69
|
-
|
|
68
|
+
if (adpDirConfigured) {
|
|
69
|
+
const unix = adpDirConfigured.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
70
|
+
if (/^[A-Za-z]:/.test(adpDirConfigured) || path.isAbsolute(unix)) {
|
|
71
|
+
return unix;
|
|
72
|
+
}
|
|
73
|
+
return path.join(process.cwd(), unix);
|
|
70
74
|
}
|
|
71
|
-
|
|
72
|
-
? path.normalize(adpDirConfigured).replace(/\\/g, "/").replace(/\/+$/, "").split("/")
|
|
73
|
-
: [".."];
|
|
74
|
-
return path.join(process.cwd(), ...adpDir);
|
|
75
|
+
throw new Error("Environment variable 'ADP_BUILDER_DIR' is not set. Please set it to the directory containing the local app files.");
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
//# sourceMappingURL=localRepository.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ICachedResource from "../cache/cachedResource.js";
|
|
2
2
|
export default interface IRepository {
|
|
3
3
|
getAppVariantIdHierarchy(appId: string): Promise<ICachedResource[]>;
|
|
4
|
-
fetch(resource: ICachedResource): Promise<Map<string,
|
|
4
|
+
fetch(resource: ICachedResource): Promise<Map<string, string>>;
|
|
5
5
|
downloadAnnotationFile(uri: string): Promise<Map<string, string>>;
|
|
6
6
|
}
|
package/dist/util/fsUtil.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export default class FsUtil {
|
|
|
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,
|
|
9
|
+
static readFilesRecursively(rootDirectory: string): Promise<Map<string, string>>;
|
|
10
10
|
}
|
package/dist/util/fsUtil.js
CHANGED
|
@@ -41,10 +41,10 @@ export default class FsUtil {
|
|
|
41
41
|
const fileReadTasks = entries
|
|
42
42
|
.filter(entry => entry.isFile())
|
|
43
43
|
.map(async (entry) => {
|
|
44
|
-
const parentPath = entry.parentPath ?? entry.path;
|
|
44
|
+
const parentPath = entry.parentPath ?? entry.path; // node v20.11.0 fallback
|
|
45
45
|
const entryPath = path.join(parentPath, entry.name);
|
|
46
46
|
const relativeFilePath = path.relative(rootDirectory, entryPath).replaceAll("\\", "/");
|
|
47
|
-
const content = await fs.readFile(entryPath);
|
|
47
|
+
const content = await fs.readFile(entryPath, "utf-8");
|
|
48
48
|
return [relativeFilePath, content];
|
|
49
49
|
});
|
|
50
50
|
return new Map(await Promise.all(fileReadTasks));
|
|
@@ -18,62 +18,94 @@ export function renameMap(content, references, ignoreInStrings) {
|
|
|
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
|
-
|
|
21
|
+
const dotToSlash = (str) => str.replaceAll(".", "\/");
|
|
22
|
+
// We don't want to replace in adaptation project ids
|
|
23
|
+
ignoreInStrings.push(...ignoreInStrings, ...ignoreInStrings.map(dotToSlash));
|
|
24
|
+
let start = 0;
|
|
25
|
+
while (true) {
|
|
26
|
+
// If we don't replace some strings in the content - we find all of them
|
|
27
|
+
// and then don't replace inside their start and end indices.
|
|
28
|
+
const ignoredStrings = ignoreInStrings.map(string => {
|
|
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
|
+
});
|
|
29
45
|
}
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (slashTerm !== term) {
|
|
34
|
-
replacementMap.set(slashTerm, dotToSlash(repl));
|
|
46
|
+
const found = indices.filter(({ i }) => i > -1);
|
|
47
|
+
if (found.length === 0) {
|
|
48
|
+
return content;
|
|
35
49
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
const inBetween = (intervals, i) => {
|
|
51
|
+
for (const interval of intervals) {
|
|
52
|
+
for (const { start, end } of interval) {
|
|
53
|
+
if (i >= start && i <= end) {
|
|
54
|
+
return { start, end };
|
|
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;
|
|
43
86
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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;
|
|
87
|
+
else {
|
|
88
|
+
content = content.substring(0, currentReplace.i)
|
|
89
|
+
+ currentReplace.replacement
|
|
90
|
+
+ content.substring(currentReplace.i + currentReplace.searchTerm.length);
|
|
91
|
+
start = currentReplace.i + currentReplace.replacement.length;
|
|
71
92
|
}
|
|
72
93
|
}
|
|
73
|
-
parts.push(content.substring(lastEnd));
|
|
74
|
-
return parts.join("");
|
|
75
94
|
}
|
|
76
95
|
export function renameResources(files, search, replacement) {
|
|
77
96
|
return new Map([...files].map(([filepath, content]) => [filepath, rename(content, search, replacement)]));
|
|
78
97
|
}
|
|
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
|
+
;
|
|
79
111
|
//# sourceMappingURL=renamingUtil.js.map
|
|
@@ -1,30 +1,14 @@
|
|
|
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>;
|
|
9
1
|
export default class ResourceUtil {
|
|
10
2
|
static getRootFolder(projectNamespace?: string): string;
|
|
11
3
|
static relativeToRoot(resourcePath: string, projectNamespace?: string): string;
|
|
12
4
|
static getResourcePath(projectNamespace?: string, ...paths: string[]): string;
|
|
13
|
-
static write(dir: string, files: Map<string,
|
|
14
|
-
static writeInProject(dir: string, files: Map<string,
|
|
15
|
-
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string,
|
|
16
|
-
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string,
|
|
5
|
+
static write(dir: string, files: Map<string, string>): Promise<void[]>;
|
|
6
|
+
static writeInProject(dir: string, files: Map<string, string>): Promise<void[]>;
|
|
7
|
+
static byGlob(dir: string, pattern: string, excludes?: string[]): Promise<Map<string, string>>;
|
|
8
|
+
static byGlobInProject(pattern: string, excludes?: string[]): Promise<Map<string, string>>;
|
|
17
9
|
static getString(resource: any): Promise<string>;
|
|
18
10
|
static getJson(resource: any): Promise<any>;
|
|
19
11
|
static setString(resource: any, str: string): void;
|
|
20
|
-
static createResource(filename: string, projectNamespace: string, content: string
|
|
21
|
-
private static createResourceFromContent;
|
|
12
|
+
static createResource(filename: string, projectNamespace: string, content: string): any;
|
|
22
13
|
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>;
|
|
30
14
|
}
|
|
@@ -1,30 +1,6 @@
|
|
|
1
1
|
import * as resourceFactory from "@ui5/fs/resourceFactory";
|
|
2
2
|
import { posix as path } from "path";
|
|
3
3
|
const UTF8 = "utf8";
|
|
4
|
-
/**
|
|
5
|
-
* Extensions of files whose contents are processed by the adaptation
|
|
6
|
-
* pipeline as text. Anything outside this whitelist is treated as binary
|
|
7
|
-
* (e.g. images, fonts) and is saved to the workspace verbatim by WorkspaceManager.
|
|
8
|
-
*
|
|
9
|
-
* Kept in sync with EXTENSIONS_TO_PROCESS in appVariant.ts.
|
|
10
|
-
*/
|
|
11
|
-
export const TEXT_EXTENSIONS = new Set([
|
|
12
|
-
"js",
|
|
13
|
-
"json",
|
|
14
|
-
"xml",
|
|
15
|
-
"html",
|
|
16
|
-
"properties",
|
|
17
|
-
"change",
|
|
18
|
-
"appdescr_variant",
|
|
19
|
-
"ctrl_variant",
|
|
20
|
-
"ctrl_variant_change",
|
|
21
|
-
"ctrl_variant_management_change",
|
|
22
|
-
"variant",
|
|
23
|
-
"fioriversion",
|
|
24
|
-
"codeChange",
|
|
25
|
-
"xmlViewChange",
|
|
26
|
-
"context",
|
|
27
|
-
]);
|
|
28
4
|
export default class ResourceUtil {
|
|
29
5
|
static getRootFolder(projectNamespace) {
|
|
30
6
|
const newPath = ["/resources"];
|
|
@@ -45,7 +21,7 @@ export default class ResourceUtil {
|
|
|
45
21
|
* NOTE: to write in project folder (folder where 'webapp',
|
|
46
22
|
* 'package.json', 'ui5.yaml' located), use writeInProject method.
|
|
47
23
|
* @param dir The directory to write files to.
|
|
48
|
-
* @param files A Map of file paths and their contents
|
|
24
|
+
* @param files A Map of file paths and their contents.
|
|
49
25
|
* @returns A promise that resolves when all files have been written.
|
|
50
26
|
*/
|
|
51
27
|
static write(dir, files) {
|
|
@@ -54,8 +30,8 @@ export default class ResourceUtil {
|
|
|
54
30
|
virBasePath: "/"
|
|
55
31
|
});
|
|
56
32
|
const promises = [];
|
|
57
|
-
files.forEach((
|
|
58
|
-
const resource =
|
|
33
|
+
files.forEach((string, filename) => {
|
|
34
|
+
const resource = resourceFactory.createResource({ path: "/" + filename, string });
|
|
59
35
|
promises.push(fsTarget.write(resource));
|
|
60
36
|
});
|
|
61
37
|
return Promise.all(promises);
|
|
@@ -64,7 +40,7 @@ export default class ResourceUtil {
|
|
|
64
40
|
* Write files to the project folder (folder where 'webapp',
|
|
65
41
|
* 'package.json', 'ui5.yaml' located), use writeInProject method.
|
|
66
42
|
* @param dir The directory to write files to.
|
|
67
|
-
* @param files A Map of file paths and their contents
|
|
43
|
+
* @param files A Map of file paths and their contents.
|
|
68
44
|
* @returns A promise that resolves when all files have been written.
|
|
69
45
|
*/
|
|
70
46
|
static writeInProject(dir, files) {
|
|
@@ -77,7 +53,7 @@ export default class ResourceUtil {
|
|
|
77
53
|
* @param dir The directory to search in.
|
|
78
54
|
* @param pattern The glob pattern to match files, e.g., "/ui5AppInfo.json".
|
|
79
55
|
* @param excludes An array of glob patterns to exclude from the search.
|
|
80
|
-
* @returns A promise that resolves to a Map of file paths and their contents
|
|
56
|
+
* @returns A promise that resolves to a Map of file paths and their contents.
|
|
81
57
|
*/
|
|
82
58
|
static byGlob(dir, pattern, excludes = []) {
|
|
83
59
|
const adapter = resourceFactory.createAdapter({
|
|
@@ -92,7 +68,7 @@ export default class ResourceUtil {
|
|
|
92
68
|
* 'package.json', 'ui5.yaml' located), excluding specified glob patterns.
|
|
93
69
|
* @param pattern The glob pattern to match files, e.g., "/ui5AppInfo.json".
|
|
94
70
|
* @param excludes An array of glob patterns to exclude from the search.
|
|
95
|
-
* @returns A promise that resolves to a Map of file paths and their contents
|
|
71
|
+
* @returns A promise that resolves to a Map of file paths and their contents.
|
|
96
72
|
*/
|
|
97
73
|
static byGlobInProject(pattern, excludes = []) {
|
|
98
74
|
return ResourceUtil.byGlob("./", pattern, [
|
|
@@ -111,12 +87,10 @@ export default class ResourceUtil {
|
|
|
111
87
|
resource.setBuffer(Buffer.from(str, UTF8));
|
|
112
88
|
}
|
|
113
89
|
static createResource(filename, projectNamespace, content) {
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
? { path: resourcePath, buffer: content }
|
|
119
|
-
: { path: resourcePath, string: content });
|
|
90
|
+
return resourceFactory.createResource({
|
|
91
|
+
path: this.getResourcePath(projectNamespace, filename),
|
|
92
|
+
string: content
|
|
93
|
+
});
|
|
120
94
|
}
|
|
121
95
|
static async toFileMap(resources, projectNamespace) {
|
|
122
96
|
const files = new Map();
|
|
@@ -126,20 +100,5 @@ export default class ResourceUtil {
|
|
|
126
100
|
}
|
|
127
101
|
return files;
|
|
128
102
|
}
|
|
129
|
-
/**
|
|
130
|
-
* Decodes the text-extension files of a buffer map to UTF-8 strings.
|
|
131
|
-
* Binary files (e.g. images, fonts) are dropped — they are expected to
|
|
132
|
-
* have been written to the workspace separately and are not relevant
|
|
133
|
-
* to the in-memory text pipeline.
|
|
134
|
-
*/
|
|
135
|
-
static toTextMap(buffers) {
|
|
136
|
-
const text = new Map();
|
|
137
|
-
buffers.forEach((buffer, filename) => {
|
|
138
|
-
if (TEXT_EXTENSIONS.has(path.extname(filename).slice(1))) {
|
|
139
|
-
text.set(filename, buffer.toString(UTF8));
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
return text;
|
|
143
|
-
}
|
|
144
103
|
}
|
|
145
104
|
//# sourceMappingURL=resourceUtil.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AbapTarget } from "@sap-ux/system-access";
|
|
2
|
+
import { IAbapTargetMeta, IConfiguration, LandscapeType } from "../../model/configuration.js";
|
|
2
3
|
import IValidator from "./validator.js";
|
|
3
4
|
export default class AbapValidator implements IValidator {
|
|
4
5
|
type: LandscapeType;
|
|
5
|
-
|
|
6
|
+
validateAndGetAbapTarget(target: AbapTarget & IAbapTargetMeta | undefined, destination: string | undefined): AbapTarget & IAbapTargetMeta;
|
|
7
|
+
validateConfiguration({ target, destination }: IConfiguration): void;
|
|
6
8
|
}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { validateObject } from "../commonUtil.js";
|
|
2
|
+
import { isAppStudio } from "@sap-ux/btp-utils";
|
|
1
3
|
import { getLogger } from "@ui5/logger";
|
|
2
4
|
const log = getLogger("@ui5/task-adaptation::AbapValidator");
|
|
3
5
|
export default class AbapValidator {
|
|
4
6
|
type = "abap";
|
|
5
|
-
|
|
6
|
-
if (
|
|
7
|
-
|
|
7
|
+
validateAndGetAbapTarget(target, destination) {
|
|
8
|
+
if (target) {
|
|
9
|
+
// if target configuration appears, we validate that it should be
|
|
10
|
+
// either target/destination for BAS or target/url for IDE we're
|
|
11
|
+
// trying to detect is it destination for BAS or url for IDE
|
|
12
|
+
const abapTargetProperties = isAppStudio() ? ["destination"] : ["url"];
|
|
13
|
+
validateObject(target, abapTargetProperties, "should be specified in ui5.yaml configuration/target");
|
|
14
|
+
return target;
|
|
8
15
|
}
|
|
9
|
-
else if (destination
|
|
16
|
+
else if (destination) {
|
|
10
17
|
log.warn("Destination is deprecated, use target/destination configuration instead");
|
|
18
|
+
return { destination };
|
|
11
19
|
}
|
|
20
|
+
throw new Error("Target should be specified in ui5.yaml configuration to connect the ABAP system");
|
|
21
|
+
}
|
|
22
|
+
validateConfiguration({ target, destination }) {
|
|
23
|
+
this.validateAndGetAbapTarget(target, destination);
|
|
12
24
|
}
|
|
13
25
|
}
|
|
14
26
|
//# sourceMappingURL=abapValidator.js.map
|
package/dist/util/zipUtil.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function unzipZipEntries(zip: Buffer): Promise<Map<string,
|
|
1
|
+
export declare function unzipZipEntries(zip: Buffer): Promise<Map<string, string>>;
|
package/dist/util/zipUtil.js
CHANGED
|
@@ -11,6 +11,6 @@ export async function unzipZipEntries(zip) {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
function mapEntries(entries) {
|
|
14
|
-
return new Map(entries.filter(entry => !entry.isDirectory).map(entry => [entry.entryName, entry.getData()]));
|
|
14
|
+
return new Map(entries.filter(entry => !entry.isDirectory).map(entry => [entry.entryName, entry.getData().toString("utf8")]));
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=zipUtil.js.map
|
package/package.json
CHANGED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { AbapTarget } from "@sap-ux/system-access";
|
|
2
|
-
import { IAbapTargetMeta } from "../../model/configuration.js";
|
|
3
|
-
export default class AbapConnectionValidator {
|
|
4
|
-
validateAndGetAbapTarget(target: AbapTarget & IAbapTargetMeta | undefined, destination: string | undefined): AbapTarget & IAbapTargetMeta;
|
|
5
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { validateObject } from "../commonUtil.js";
|
|
2
|
-
import { isAppStudio } from "@sap-ux/btp-utils";
|
|
3
|
-
import { getLogger } from "@ui5/logger";
|
|
4
|
-
const log = getLogger("@ui5/task-adaptation::AbapConnectionValidator");
|
|
5
|
-
export default class AbapConnectionValidator {
|
|
6
|
-
validateAndGetAbapTarget(target, destination) {
|
|
7
|
-
if (target) {
|
|
8
|
-
// if target configuration appears, we validate that it should be
|
|
9
|
-
// either target/destination for BAS or target/url for IDE we're
|
|
10
|
-
// trying to detect is it destination for BAS or url for IDE
|
|
11
|
-
const abapTargetProperties = isAppStudio() ? ["destination"] : ["url"];
|
|
12
|
-
validateObject(target, abapTargetProperties, "should be specified in ui5.yaml configuration/target");
|
|
13
|
-
return target;
|
|
14
|
-
}
|
|
15
|
-
else if (destination) {
|
|
16
|
-
log.warn("Destination is deprecated, use target/destination configuration instead");
|
|
17
|
-
return { destination };
|
|
18
|
-
}
|
|
19
|
-
throw new Error("Target should be specified in ui5.yaml configuration to connect the ABAP system");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=abapConnectionValidator.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export default class WorkspaceManager {
|
|
2
|
-
private readonly workspace;
|
|
3
|
-
private readonly projectNamespace;
|
|
4
|
-
private snapshot;
|
|
5
|
-
constructor(workspace: IWorkspace, projectNamespace: string);
|
|
6
|
-
createSnapshot(): Promise<void>;
|
|
7
|
-
restoreSnapshot(): Promise<void>;
|
|
8
|
-
saveAndConvert(buffersPromise: Promise<ReadonlyMap<string, Buffer>>): Promise<ReadonlyMap<string, string>>;
|
|
9
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import ResourceUtil, { TEXT_EXTENSIONS } from "./resourceUtil.js";
|
|
2
|
-
import { posix as path } from "path";
|
|
3
|
-
const UTF8 = "utf8";
|
|
4
|
-
export default class WorkspaceManager {
|
|
5
|
-
workspace;
|
|
6
|
-
projectNamespace;
|
|
7
|
-
snapshot;
|
|
8
|
-
constructor(workspace, projectNamespace) {
|
|
9
|
-
this.workspace = workspace;
|
|
10
|
-
this.projectNamespace = projectNamespace;
|
|
11
|
-
}
|
|
12
|
-
async createSnapshot() {
|
|
13
|
-
const resources = await this.workspace.byGlob("/**/*");
|
|
14
|
-
const rootFolderLength = ResourceUtil.getRootFolder(this.projectNamespace).length;
|
|
15
|
-
const entries = await Promise.all(resources.map(async (resource) => {
|
|
16
|
-
const filename = resource.getPath().substring(rootFolderLength + 1);
|
|
17
|
-
return [filename, await resource.getBuffer()];
|
|
18
|
-
}));
|
|
19
|
-
this.snapshot = new Map(entries);
|
|
20
|
-
}
|
|
21
|
-
async restoreSnapshot() {
|
|
22
|
-
if (!this.snapshot) {
|
|
23
|
-
throw new Error("No snapshot to restore — call createSnapshot() first");
|
|
24
|
-
}
|
|
25
|
-
const writes = [];
|
|
26
|
-
this.snapshot.forEach((buffer, filename) => {
|
|
27
|
-
const resource = ResourceUtil.createResource(filename, this.projectNamespace, buffer);
|
|
28
|
-
writes.push(this.workspace.write(resource));
|
|
29
|
-
});
|
|
30
|
-
await Promise.all(writes);
|
|
31
|
-
}
|
|
32
|
-
async saveAndConvert(buffersPromise) {
|
|
33
|
-
const buffers = await buffersPromise;
|
|
34
|
-
const writes = [];
|
|
35
|
-
const text = new Map();
|
|
36
|
-
buffers.forEach((buffer, filename) => {
|
|
37
|
-
if (TEXT_EXTENSIONS.has(path.extname(filename).slice(1))) {
|
|
38
|
-
text.set(filename, buffer.toString(UTF8));
|
|
39
|
-
}
|
|
40
|
-
writes.push(this.workspace.write(ResourceUtil.createResource(filename, this.projectNamespace, buffer)));
|
|
41
|
-
});
|
|
42
|
-
await Promise.all(writes);
|
|
43
|
-
return text;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=workspaceManager.js.map
|