@ui5/task-adaptation 1.5.0 → 1.5.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.
- package/CHANGELOG.md +4 -4
- package/dist/annotationManager.d.ts +1 -1
- package/dist/annotationManager.js +6 -5
- package/dist/appVariantManager.d.ts +2 -0
- package/dist/appVariantManager.js +27 -3
- package/dist/baseAppManager.js +3 -2
- package/dist/index.js +8 -16
- package/dist/processors/abapProcessor.d.ts +1 -1
- package/dist/processors/abapProcessor.js +2 -3
- package/dist/processors/cfProcessor.js +7 -7
- package/dist/processors/processor.d.ts +1 -1
- package/dist/util/commonUtil.d.ts +2 -3
- package/dist/util/commonUtil.js +35 -100
- package/dist/util/i18nMerger.js +1 -1
- package/package.json +2 -3
- package/dist/util/filesUtil.d.ts +0 -17
- package/dist/util/filesUtil.js +0 -49
- package/dist/util/renamingHandlers/manifestHandler.d.ts +0 -6
- package/dist/util/renamingHandlers/manifestHandler.js +0 -20
- package/dist/util/renamingHandlers/renamingHandler.d.ts +0 -4
- package/dist/util/renamingHandlers/renamingHandler.js +0 -2
- package/scripts/test-integration-prep.sh +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
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.5.
|
|
5
|
+
A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.5.1...HEAD).
|
|
6
6
|
|
|
7
|
-
<a name="v1.5.
|
|
8
|
-
## [v1.5.
|
|
7
|
+
<a name="v1.5.1"></a>
|
|
8
|
+
## [v1.5.1] - 2025-08-06
|
|
9
9
|
|
|
10
10
|
<a name="v1.4.3"></a>
|
|
11
11
|
## [v1.4.3] - 2025-04-17
|
|
@@ -119,7 +119,7 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
|
|
|
119
119
|
<a name="v1.0.0"></a>
|
|
120
120
|
## v1.0.0 - 2020-12-09
|
|
121
121
|
|
|
122
|
-
[v1.5.
|
|
122
|
+
[v1.5.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.3...v1.5.1
|
|
123
123
|
[v1.4.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.2...v1.4.3
|
|
124
124
|
[v1.4.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.0...v1.4.2
|
|
125
125
|
[v1.4.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.3.3...v1.4.0
|
|
@@ -10,7 +10,7 @@ export default class AnnotationManager {
|
|
|
10
10
|
private configuration;
|
|
11
11
|
constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager);
|
|
12
12
|
ANNOTATIONS_FOLDER: string;
|
|
13
|
-
process(
|
|
13
|
+
process(renamedBaseAppManifest: any, languages: Language[]): Promise<Map<string, string>>;
|
|
14
14
|
private normalizeAppVariantId;
|
|
15
15
|
private updateManifestModel;
|
|
16
16
|
private createManifestModel;
|
|
@@ -13,7 +13,8 @@ export default class AnnotationManager {
|
|
|
13
13
|
this.abapRepoManager = abapRepoManager;
|
|
14
14
|
}
|
|
15
15
|
ANNOTATIONS_FOLDER = "annotations";
|
|
16
|
-
async process(
|
|
16
|
+
async process(renamedBaseAppManifest, languages) {
|
|
17
|
+
const { id } = renamedBaseAppManifest["sap.app"];
|
|
17
18
|
const normalisedId = this.normalizeAppVariantId(id);
|
|
18
19
|
//TODO: switch to this after resolving @i18n custom model
|
|
19
20
|
const modelName = I18N_DEFAULT_MODEL_NAME; //`i18n_a9n_${normalisedId}`;
|
|
@@ -21,20 +22,20 @@ export default class AnnotationManager {
|
|
|
21
22
|
const i18nManager = new I18nManager(modelName, id, languages);
|
|
22
23
|
const serviceRequestor = new ServiceRequestor(this.configuration, this.abapRepoManager);
|
|
23
24
|
const dataSourceManager = new DataSourceManager();
|
|
24
|
-
dataSourceManager.addDataSources(
|
|
25
|
+
dataSourceManager.addDataSources(renamedBaseAppManifest["sap.app"]?.dataSources);
|
|
25
26
|
const annotationFiles = await dataSourceManager.createAnnotationFiles(languages, i18nManager, serviceRequestor);
|
|
26
27
|
const i18nFiles = i18nManager.createFiles(i18nPathName);
|
|
27
28
|
if (i18nManager.hasTranslations()) {
|
|
28
|
-
this.updateManifestModel(
|
|
29
|
+
this.updateManifestModel(renamedBaseAppManifest, modelName, i18nPathName);
|
|
29
30
|
}
|
|
30
31
|
return new Map([...annotationFiles, ...i18nFiles]);
|
|
31
32
|
}
|
|
32
33
|
normalizeAppVariantId(id, replaceWith = "") {
|
|
33
34
|
return id.replace(/[.\W]+/gi, replaceWith);
|
|
34
35
|
}
|
|
35
|
-
updateManifestModel(
|
|
36
|
+
updateManifestModel(renamedBaseAppManifest, modelName, i18nPathName) {
|
|
36
37
|
const uri = `${i18nPathName}/i18n.properties`;
|
|
37
|
-
this.enhanceManifestModel(
|
|
38
|
+
this.enhanceManifestModel(renamedBaseAppManifest, modelName, uri);
|
|
38
39
|
//TODO: switch to this after resolving @i18n custom model
|
|
39
40
|
//this.createManifestModel(renamedBaseAppManifest, modelName, uri);
|
|
40
41
|
}
|
|
@@ -10,8 +10,10 @@ export default class AppVariant {
|
|
|
10
10
|
static fromWorkspace(workspace: IWorkspace, projectNamespace: string): Promise<AppVariant>;
|
|
11
11
|
static fromFiles(files: ReadonlyMap<string, string>): AppVariant;
|
|
12
12
|
private constructor();
|
|
13
|
+
getProcessedFiles(): Map<string, string>;
|
|
13
14
|
getProcessedManifestChanges(): IChange[];
|
|
14
15
|
private validateManifest;
|
|
15
16
|
private updateRelativePaths;
|
|
17
|
+
private isManifestChange;
|
|
16
18
|
omitDeletedResources(files: ReadonlyMap<string, string>, projectNamespace: string, taskUtil: TaskUtil): void;
|
|
17
19
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import ResourceUtil from "./util/resourceUtil.js";
|
|
2
2
|
import { posix as path } from "path";
|
|
3
|
-
|
|
3
|
+
import { rename } from "./util/commonUtil.js";
|
|
4
|
+
const CHANGES_DIR = "changes/";
|
|
5
|
+
const CHANGES_EXT = ".change";
|
|
6
|
+
const MANIFEST_CHANGE = "appdescr_";
|
|
4
7
|
export default class AppVariant {
|
|
5
8
|
files;
|
|
6
9
|
resources;
|
|
@@ -28,13 +31,27 @@ export default class AppVariant {
|
|
|
28
31
|
this.layer = layer;
|
|
29
32
|
this.content = content;
|
|
30
33
|
}
|
|
34
|
+
getProcessedFiles() {
|
|
35
|
+
const files = new Map();
|
|
36
|
+
this.files.forEach((content, filename) => {
|
|
37
|
+
if (filename.startsWith(CHANGES_DIR)) {
|
|
38
|
+
if (!this.isManifestChange(filename, content)) {
|
|
39
|
+
files.set(filename, rename(content, this.reference, this.id));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (filename !== "manifest.appdescr_variant") {
|
|
43
|
+
files.set(filename, content);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return files;
|
|
47
|
+
}
|
|
31
48
|
getProcessedManifestChanges() {
|
|
32
49
|
// Order is important: apply manifest.json changes first, then *.change
|
|
33
50
|
// files. UI5 does the same.
|
|
34
51
|
const manifestChanges = structuredClone(this.content) ?? [];
|
|
35
52
|
this.files.forEach((content, filename) => {
|
|
36
|
-
if (
|
|
37
|
-
const change = JSON.parse(content);
|
|
53
|
+
if (this.isManifestChange(filename, content)) {
|
|
54
|
+
const change = JSON.parse(rename(content, this.reference, this.id));
|
|
38
55
|
this.updateRelativePaths(change, filename);
|
|
39
56
|
manifestChanges.push(change);
|
|
40
57
|
}
|
|
@@ -60,6 +77,13 @@ export default class AppVariant {
|
|
|
60
77
|
}
|
|
61
78
|
}
|
|
62
79
|
}
|
|
80
|
+
isManifestChange(filename, content) {
|
|
81
|
+
if (filename.endsWith(CHANGES_EXT)) {
|
|
82
|
+
const change = JSON.parse(content);
|
|
83
|
+
return change.changeType?.startsWith(MANIFEST_CHANGE);
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
63
87
|
omitDeletedResources(files, projectNamespace, taskUtil) {
|
|
64
88
|
if (!this.resources) {
|
|
65
89
|
return;
|
package/dist/baseAppManager.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AppDescriptorChange, Applier, RegistrationBuild } from "../dist/bundle.
|
|
|
2
2
|
import { dotToUnderscore, trimExtension } from "./util/commonUtil.js";
|
|
3
3
|
import BuildStrategy from "./buildStrategy.js";
|
|
4
4
|
import { getLogger } from "@ui5/logger";
|
|
5
|
+
import { renameResources } from "./util/commonUtil.js";
|
|
5
6
|
const log = getLogger("@ui5/task-adaptation::BaseAppManager");
|
|
6
7
|
const IGNORE_FILES = [
|
|
7
8
|
"manifest-bundle.zip",
|
|
@@ -30,9 +31,9 @@ export default class BaseApp {
|
|
|
30
31
|
this.i18nPath = this.extractI18nPathFromManifest(this.id, manifest["sap.app"]?.i18n);
|
|
31
32
|
}
|
|
32
33
|
async adapt(appVariant, processor) {
|
|
33
|
-
const files =
|
|
34
|
+
const files = renameResources(this.files, appVariant.reference, appVariant.id);
|
|
34
35
|
const manifest = JSON.parse(files.get("manifest.json"));
|
|
35
|
-
await processor.updateLandscapeSpecificContent(manifest, files
|
|
36
|
+
await processor.updateLandscapeSpecificContent(manifest, files);
|
|
36
37
|
this.fillAppVariantIdHierarchy(processor, this.id, this.version, manifest);
|
|
37
38
|
this.updateAdaptationProperties(manifest);
|
|
38
39
|
await this.applyDescriptorChanges(manifest, appVariant);
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import BaseApp from "./baseAppManager.js";
|
|
|
5
5
|
import I18nMerger from "./util/i18nMerger.js";
|
|
6
6
|
import ResourceUtil from "./util/resourceUtil.js";
|
|
7
7
|
import { determineProcessor } from "./processors/processor.js";
|
|
8
|
-
import FilesUtil from "./util/filesUtil.js";
|
|
9
8
|
/**
|
|
10
9
|
* Creates an appVariant bundle from the provided resources.
|
|
11
10
|
*/
|
|
@@ -29,21 +28,14 @@ export default ({ workspace, options, taskUtil }) => {
|
|
|
29
28
|
const adaptedFiles = await baseApp.adapt(appVariant, processor);
|
|
30
29
|
return I18nMerger.merge(adaptedFiles, baseApp.i18nPath, appVariant);
|
|
31
30
|
};
|
|
32
|
-
let files = await fetchFilesPromises.reduce(async (previousFiles, currentFiles) =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const writePromises = new Array();
|
|
41
|
-
files.forEach((content, filename) => {
|
|
42
|
-
const resource = ResourceUtil.createResource(filename, options.projectNamespace, content);
|
|
43
|
-
writePromises.push(workspace.write(resource));
|
|
44
|
-
});
|
|
45
|
-
await Promise.all(writePromises);
|
|
46
|
-
}
|
|
31
|
+
let files = await fetchFilesPromises.reduce(async (previousFiles, currentFiles) => adapt(await previousFiles, await currentFiles), fetchFilesPromises.shift());
|
|
32
|
+
adaptationProject.omitDeletedResources(files, options.projectNamespace, taskUtil);
|
|
33
|
+
const writePromises = new Array();
|
|
34
|
+
files.forEach((content, filename) => {
|
|
35
|
+
const resource = ResourceUtil.createResource(filename, options.projectNamespace, content);
|
|
36
|
+
writePromises.push(workspace.write(resource));
|
|
37
|
+
});
|
|
38
|
+
await Promise.all(writePromises);
|
|
47
39
|
}
|
|
48
40
|
return process(workspace, taskUtil);
|
|
49
41
|
};
|
|
@@ -11,7 +11,7 @@ export default class AbapProcessor implements IProcessor {
|
|
|
11
11
|
getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
|
|
12
12
|
fetch(repoName: string, _cachebusterToken: string): Promise<Map<string, string>>;
|
|
13
13
|
validateConfiguration(): void;
|
|
14
|
-
updateLandscapeSpecificContent(
|
|
14
|
+
updateLandscapeSpecificContent(renamedBaseAppManifest: any, baseAppFiles?: Map<string, string>): Promise<void>;
|
|
15
15
|
getConfigurationType(): string;
|
|
16
16
|
createAppVariantHierarchyItem(appVariantId: string, version: string): {
|
|
17
17
|
appVariantId: string;
|
|
@@ -27,9 +27,8 @@ export default class AbapProcessor {
|
|
|
27
27
|
const properties = ["appName"];
|
|
28
28
|
validateObject(this.configuration, properties, "should be specified in ui5.yaml configuration");
|
|
29
29
|
}
|
|
30
|
-
async updateLandscapeSpecificContent(
|
|
31
|
-
const
|
|
32
|
-
const files = await this.annotationManager.process(baseAppManifest, languages, appVariantId);
|
|
30
|
+
async updateLandscapeSpecificContent(renamedBaseAppManifest, baseAppFiles) {
|
|
31
|
+
const files = await this.annotationManager.process(renamedBaseAppManifest, Language.create(this.configuration.languages));
|
|
33
32
|
if (baseAppFiles) {
|
|
34
33
|
files.forEach((value, key) => baseAppFiles.set(key, value));
|
|
35
34
|
}
|
|
@@ -29,20 +29,20 @@ export default class CFProcessor {
|
|
|
29
29
|
async updateLandscapeSpecificContent(renamedBaseAppManifest) {
|
|
30
30
|
this.updateCloudPlatform(renamedBaseAppManifest);
|
|
31
31
|
}
|
|
32
|
-
updateCloudPlatform(
|
|
33
|
-
const sapCloudService =
|
|
34
|
-
const sapPlatformCf =
|
|
32
|
+
updateCloudPlatform(renamedBaseAppManifest) {
|
|
33
|
+
const sapCloudService = renamedBaseAppManifest["sap.cloud"]?.service;
|
|
34
|
+
const sapPlatformCf = renamedBaseAppManifest["sap.platform.cf"];
|
|
35
35
|
if (sapPlatformCf?.oAuthScopes && sapCloudService) {
|
|
36
36
|
sapPlatformCf.oAuthScopes = sapPlatformCf.oAuthScopes.map((scope) => scope.replace(`$XSAPPNAME.`, `$XSAPPNAME('${sapCloudService}').`));
|
|
37
37
|
}
|
|
38
38
|
if (this.configuration.sapCloudService) {
|
|
39
|
-
if (
|
|
40
|
-
|
|
39
|
+
if (renamedBaseAppManifest["sap.cloud"] == null) {
|
|
40
|
+
renamedBaseAppManifest["sap.cloud"] = {};
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
renamedBaseAppManifest["sap.cloud"].service = this.configuration.sapCloudService;
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
45
|
-
delete
|
|
45
|
+
delete renamedBaseAppManifest["sap.cloud"];
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
getConfigurationType() {
|
|
@@ -4,6 +4,6 @@ export default interface IProcessor {
|
|
|
4
4
|
getAppVariantIdHierarchy(appId: string): Promise<IAppVariantIdHierarchyItem[]>;
|
|
5
5
|
fetch(repoName: string, cachebusterToken: string): Promise<Map<string, string>>;
|
|
6
6
|
createAppVariantHierarchyItem(appVariantId: string, version: string): void;
|
|
7
|
-
updateLandscapeSpecificContent(
|
|
7
|
+
updateLandscapeSpecificContent(renamedBaseAppManifest: any, baseAppFiles?: ReadonlyMap<string, string>): Promise<void>;
|
|
8
8
|
}
|
|
9
9
|
export declare function determineProcessor(configuration: IConfiguration): IProcessor;
|
|
@@ -3,8 +3,8 @@ import Language from "../model/language.js";
|
|
|
3
3
|
export declare function dotToUnderscore(value: string): string;
|
|
4
4
|
export declare function validateObject<T extends object>(options: T, properties: Array<keyof T>, message: string): void;
|
|
5
5
|
export declare function escapeRegex(update: string): string;
|
|
6
|
-
export declare function renameResources(files: ReadonlyMap<string, string>, search: string
|
|
7
|
-
export declare function rename(content: string,
|
|
6
|
+
export declare function renameResources(files: ReadonlyMap<string, string>, search: string, replacement: string): Map<string, string>;
|
|
7
|
+
export declare function rename(content: string, search: string, replacement: string): string;
|
|
8
8
|
export declare function insertInArray<T>(array: T[], index: number, insert: T): void;
|
|
9
9
|
export declare function writeTempAnnotations({ writeTempFiles }: IConfiguration, name: string, language: Language, content: string): void;
|
|
10
10
|
export declare function trimExtension(filePath: string): string;
|
|
@@ -12,4 +12,3 @@ export declare function traverse(json: any, paths: string[], callback: (json: an
|
|
|
12
12
|
export declare function logBuilderVersion(): void;
|
|
13
13
|
export declare function logBetaUsage(): void;
|
|
14
14
|
export declare function getUniqueName(existingNames: string[], template: string): string;
|
|
15
|
-
export declare function getI18nPropertyKeys(files: ReadonlyMap<string, string>): string[];
|
package/dist/util/commonUtil.js
CHANGED
|
@@ -17,96 +17,46 @@ export function validateObject(options, properties, message) {
|
|
|
17
17
|
export function escapeRegex(update) {
|
|
18
18
|
return update.replaceAll(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
19
19
|
}
|
|
20
|
-
export function renameResources(files, search, replacement
|
|
21
|
-
|
|
20
|
+
export function renameResources(files, search, replacement) {
|
|
21
|
+
const replaces = getReplaceRegex(search, replacement);
|
|
22
|
+
const renamedFiles = new Map();
|
|
23
|
+
files.forEach((content, filepath) => {
|
|
24
|
+
renamedFiles.set(filepath, replaces.reduce((p, c) => p.replace(c.regexp, c.replacement), content));
|
|
25
|
+
});
|
|
26
|
+
return renamedFiles;
|
|
22
27
|
}
|
|
23
|
-
|
|
24
|
-
if
|
|
25
|
-
|
|
28
|
+
function getReplaceRegex(search, replacement) {
|
|
29
|
+
// The current regex works if the old Id is contained in the new Id, given
|
|
30
|
+
// that they do not have the same beginning.
|
|
31
|
+
// more complete alternative: /((?<!newIdStart)|(?!newIdEnd))oldId/g
|
|
32
|
+
let escapedSearch;
|
|
33
|
+
if (replacement.includes(search)) {
|
|
34
|
+
const [before] = replacement.split(search);
|
|
35
|
+
// Matches a position in the string that is not immediately preceded by
|
|
36
|
+
// the string "before". Since we won't replace anyway, we should also
|
|
37
|
+
// ignore one with the slashes.
|
|
38
|
+
const escapedBefore = escapeRegex(before).replaceAll("\\.", "[\\./]");
|
|
39
|
+
escapedSearch = `(?<!${escapedBefore})${escapeRegex(search)}`;
|
|
26
40
|
}
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
else {
|
|
42
|
+
escapedSearch = escapeRegex(search);
|
|
29
43
|
}
|
|
30
|
-
const dotToSlash = (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const ignoredStrings = ignoreInStrings.map(string => {
|
|
40
|
-
return findAllOccurrences(content, string, start).map(i => ({ start: i, end: i + string.length }));
|
|
41
|
-
}).filter(arr => arr.length > 0) || [];
|
|
42
|
-
// We find the next search index with dots and slashes. Then we replace
|
|
43
|
-
// the nearest one and start search again in the next loop step.
|
|
44
|
-
const indices = new Array();
|
|
45
|
-
for (const searchTerm of searchTerms) {
|
|
46
|
-
const searchTermSlash = dotToSlash(searchTerm);
|
|
47
|
-
indices.push({
|
|
48
|
-
i: content.indexOf(searchTerm, start),
|
|
49
|
-
replacement,
|
|
50
|
-
searchTerm
|
|
51
|
-
});
|
|
52
|
-
indices.push({
|
|
53
|
-
i: content.indexOf(searchTermSlash, start),
|
|
54
|
-
replacement: replacementSlash,
|
|
55
|
-
searchTerm: searchTermSlash
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
const found = indices.filter(({ i }) => i > -1);
|
|
59
|
-
if (found.length === 0) {
|
|
60
|
-
return content;
|
|
61
|
-
}
|
|
62
|
-
const inBetween = (intervals, i) => {
|
|
63
|
-
for (const interval of intervals) {
|
|
64
|
-
for (const { start, end } of interval) {
|
|
65
|
-
if (i >= start && i <= end) {
|
|
66
|
-
return { start, end };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
const getNotEmptyArray = (a, b) => a.length > 0 ? a : b;
|
|
72
|
-
const findCurrentReplace = (found) => {
|
|
73
|
-
const result = new Map();
|
|
74
|
-
for (const entry of found) {
|
|
75
|
-
const existing = result.get(entry.i);
|
|
76
|
-
if (!existing || entry.searchTerm.length >= existing.searchTerm.length) {
|
|
77
|
-
result.set(entry.i, entry);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return [...result.values()].sort((a, b) => a.i - b.i)[0];
|
|
81
|
-
};
|
|
82
|
-
// Ignore if search is in i18n key: replace "id" in "{{id.key}}" with
|
|
83
|
-
// "customer.id" and we need only the next one in string
|
|
84
|
-
found.forEach(index => index.inBetween = inBetween(ignoredStrings, index.i));
|
|
85
|
-
const foundToReplace = getNotEmptyArray(found.filter(index => !index.inBetween), found);
|
|
86
|
-
const currentReplace = findCurrentReplace(foundToReplace);
|
|
87
|
-
if (currentReplace.inBetween) {
|
|
88
|
-
start = currentReplace.inBetween.end;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
content = content.substring(0, currentReplace.i)
|
|
92
|
-
+ currentReplace.replacement
|
|
93
|
-
+ content.substring(currentReplace.i + currentReplace.searchTerm.length);
|
|
94
|
-
start = currentReplace.i + currentReplace.replacement.length;
|
|
44
|
+
const dotToSlash = (update) => update.replaceAll(".", "\/");
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
regexp: new RegExp(escapedSearch, "g"),
|
|
48
|
+
replacement
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
regexp: new RegExp(dotToSlash(escapedSearch), "g"),
|
|
52
|
+
replacement: dotToSlash(replacement)
|
|
95
53
|
}
|
|
96
|
-
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
export function rename(content, search, replacement) {
|
|
57
|
+
const replaces = getReplaceRegex(search, replacement);
|
|
58
|
+
return replaces.reduce((p, c) => p.replace(c.regexp, c.replacement), content);
|
|
97
59
|
}
|
|
98
|
-
const 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
60
|
export function insertInArray(array, index, insert) {
|
|
111
61
|
array.splice(index, 0, insert);
|
|
112
62
|
}
|
|
@@ -176,19 +126,4 @@ export function getUniqueName(existingNames, template) {
|
|
|
176
126
|
} while (existingNames.includes(template + suffixString));
|
|
177
127
|
return template + suffixString;
|
|
178
128
|
}
|
|
179
|
-
export function getI18nPropertyKeys(files) {
|
|
180
|
-
const keys = new Set();
|
|
181
|
-
files.forEach((content, filename) => {
|
|
182
|
-
if (filename.endsWith(".properties")) {
|
|
183
|
-
const lines = content.split("\n").filter(line => !line.startsWith("#"));
|
|
184
|
-
for (const line of lines) {
|
|
185
|
-
const [key] = line.split("=");
|
|
186
|
-
if (key) {
|
|
187
|
-
keys.add(key);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return [...keys];
|
|
193
|
-
}
|
|
194
129
|
//# sourceMappingURL=commonUtil.js.map
|
package/dist/util/i18nMerger.js
CHANGED
|
@@ -27,7 +27,7 @@ export default class FileMerger {
|
|
|
27
27
|
const i18nTargetFolder = dotToUnderscore(appVariant.id);
|
|
28
28
|
const { copyPaths, mergePaths } = this.analyzeAppVariantManifestChanges(appVariant.getProcessedManifestChanges());
|
|
29
29
|
const files = new Map(baseAppFiles);
|
|
30
|
-
for (const [filename, content] of Array.from(appVariant.
|
|
30
|
+
for (const [filename, content] of Array.from(appVariant.getProcessedFiles())) {
|
|
31
31
|
if (filename.endsWith(".properties")) {
|
|
32
32
|
// merge/copy logic
|
|
33
33
|
// check if file matches with regex in merge/copy
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ui5/task-adaptation",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
"release-note": "git-chglog -c .chglog/release-config.yml v$npm_package_version",
|
|
17
17
|
"rollup": "tsx scripts/rollup.ts",
|
|
18
18
|
"build": "npm run rollup && tsc -p ./",
|
|
19
|
-
"download-metadata": "tsx scripts/metadataDownloadHelper.ts"
|
|
20
|
-
"integration-setup": "scripts/test-integration-prep.sh"
|
|
19
|
+
"download-metadata": "tsx scripts/metadataDownloadHelper.ts"
|
|
21
20
|
},
|
|
22
21
|
"repository": {
|
|
23
22
|
"type": "git",
|
package/dist/util/filesUtil.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export default class FilesUtil {
|
|
2
|
-
static filter(files: ReadonlyMap<string, string>): ReadonlyMap<string, string>;
|
|
3
|
-
/**
|
|
4
|
-
* Renames files in the base application substituting original id with
|
|
5
|
-
* appVariant id. Renames all files except i18n properties files, when we
|
|
6
|
-
* rename property keys of nested application variants we got in the end
|
|
7
|
-
* multiple i18n properties with the same key, but different values. UI5
|
|
8
|
-
* takes the first one which is the oldest but we need the latest most
|
|
9
|
-
* recent updated one.
|
|
10
|
-
* @param files - The files of the base application.
|
|
11
|
-
* @param reference - The reference of the app variant (original/base app id).
|
|
12
|
-
* @param id - The id of the app variant.
|
|
13
|
-
* @returns A map of renamed files.
|
|
14
|
-
*/
|
|
15
|
-
static rename(files: ReadonlyMap<string, string>, references: string[], adaptationProjectId: string): ReadonlyMap<string, string>;
|
|
16
|
-
private static ignore;
|
|
17
|
-
}
|
package/dist/util/filesUtil.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { rename, getI18nPropertyKeys } from "./commonUtil.js";
|
|
2
|
-
import ManifestHandler from "./renamingHandlers/manifestHandler.js";
|
|
3
|
-
export default class FilesUtil {
|
|
4
|
-
static filter(files) {
|
|
5
|
-
const result = new Map();
|
|
6
|
-
files.forEach((content, filename) => {
|
|
7
|
-
if (!this.ignore(filename)) {
|
|
8
|
-
result.set(filename, content);
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
return result;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Renames files in the base application substituting original id with
|
|
15
|
-
* appVariant id. Renames all files except i18n properties files, when we
|
|
16
|
-
* rename property keys of nested application variants we got in the end
|
|
17
|
-
* multiple i18n properties with the same key, but different values. UI5
|
|
18
|
-
* takes the first one which is the oldest but we need the latest most
|
|
19
|
-
* recent updated one.
|
|
20
|
-
* @param files - The files of the base application.
|
|
21
|
-
* @param reference - The reference of the app variant (original/base app id).
|
|
22
|
-
* @param id - The id of the app variant.
|
|
23
|
-
* @returns A map of renamed files.
|
|
24
|
-
*/
|
|
25
|
-
static rename(files, references, adaptationProjectId) {
|
|
26
|
-
const handlers = [new ManifestHandler()];
|
|
27
|
-
const IGNORE_EXTENSIONS = [".properties"];
|
|
28
|
-
const ignoreInStrings = getI18nPropertyKeys(files);
|
|
29
|
-
const renamedFiles = new Map();
|
|
30
|
-
for (const handler of handlers) {
|
|
31
|
-
handler.before(files);
|
|
32
|
-
}
|
|
33
|
-
files.forEach((content, filename) => {
|
|
34
|
-
if (!IGNORE_EXTENSIONS.some(ext => filename.endsWith(ext))) {
|
|
35
|
-
content = rename(content, references, adaptationProjectId, ignoreInStrings);
|
|
36
|
-
}
|
|
37
|
-
renamedFiles.set(filename, content);
|
|
38
|
-
});
|
|
39
|
-
for (const handler of handlers) {
|
|
40
|
-
handler.after(renamedFiles);
|
|
41
|
-
}
|
|
42
|
-
return renamedFiles;
|
|
43
|
-
}
|
|
44
|
-
static ignore(filename) {
|
|
45
|
-
const IGNORE_FILES = ["manifest.appdescr_variant"];
|
|
46
|
-
return filename.startsWith("changes/manifest/") || IGNORE_FILES.includes(filename);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=filesUtil.js.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export default class ManifestHandler {
|
|
2
|
-
appVariantIdHierarchy = [];
|
|
3
|
-
before(files) {
|
|
4
|
-
const manifest = files.get("manifest.json");
|
|
5
|
-
if (manifest) {
|
|
6
|
-
const manifestJson = JSON.parse(manifest);
|
|
7
|
-
this.appVariantIdHierarchy = manifestJson["sap.ui5"].appVariantIdHierarchy;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
after(files) {
|
|
11
|
-
const manifest = files.get("manifest.json");
|
|
12
|
-
if (manifest) {
|
|
13
|
-
const manifestJson = JSON.parse(manifest);
|
|
14
|
-
manifestJson["sap.ui5"].appVariantIdHierarchy = this.appVariantIdHierarchy;
|
|
15
|
-
files.set("manifest.json", JSON.stringify(manifestJson));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=manifestHandler.js.map
|