@ui5/task-adaptation 1.0.16 → 1.0.18

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 CHANGED
@@ -2,7 +2,13 @@
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.0.16...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.0.18...HEAD).
6
+
7
+ <a name="v1.0.18"></a>
8
+ ## [v1.0.18] - 2023-11-10
9
+
10
+ <a name="v1.0.17"></a>
11
+ ## [v1.0.17] - 2023-08-16
6
12
 
7
13
  <a name="v1.0.16"></a>
8
14
  ## [v1.0.16] - 2023-08-15
@@ -46,6 +52,8 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
46
52
  <a name="v1.0.0"></a>
47
53
  ## v1.0.0 - 2020-12-09
48
54
 
55
+ [v1.0.18]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.17...v1.0.18
56
+ [v1.0.17]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.16...v1.0.17
49
57
  [v1.0.16]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.11...v1.0.16
50
58
  [v1.0.11]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.10...v1.0.11
51
59
  [v1.0.10]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.9...v1.0.10
@@ -10,12 +10,8 @@ export default class AnnotationManager {
10
10
  constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager);
11
11
  ANNOTATIONS_FOLDER: string;
12
12
  process(renamedBaseAppManifest: any, languages: string[]): Promise<Map<string, string>>;
13
- private createI18nFiles;
14
13
  private normalizeAppVariantId;
15
14
  private createAnnotationFile;
16
- private getNormalisedLanguage;
17
- private getAdaptedAnnotation;
18
- private getUniqueKeyForPath;
19
15
  private downloadAnnotations;
20
16
  private updateManifest;
21
17
  private updateManifestDataSources;
@@ -23,10 +19,4 @@ export default class AnnotationManager {
23
19
  private enhanceManifestModel;
24
20
  private downloadAnnotation;
25
21
  private getODataAnnotations;
26
- static traverseJson(obj: any, path: string): {
27
- subject: any;
28
- property: string;
29
- };
30
- private getDiffJsonPaths;
31
- private traverseDiff;
32
22
  }
@@ -1,17 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const convert = require("xml-js");
4
- const path = require("path");
5
3
  const annotationsCacheManager_1 = require("./cache/annotationsCacheManager");
6
4
  const baseAppManager_1 = require("./baseAppManager");
7
- const json_diff_1 = require("json-diff");
8
- const util_1 = require("util");
9
- const { ResourceBundle } = require("../dist/bundle-resourceBundle");
5
+ const i18nManager_1 = require("./i18nManager");
6
+ const xmlUtil_1 = require("./util/xmlUtil");
7
+ const path_1 = require("path");
10
8
  const I18N_DEFAULT_PATH = "i18n/annotations";
11
9
  const I18N_DEFAULT_MODEL_NAME = "@i18n";
12
10
  const SAPUI5 = "sap.ui5";
13
11
  const SAPAPP = "sap.app";
14
- const XML_OPTIONS = { compact: true, spaces: 4 };
15
12
  const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::AnnotationManager");
16
13
  class AnnotationManager {
17
14
  constructor(configuration, abapRepoManager) {
@@ -27,13 +24,12 @@ class AnnotationManager {
27
24
  const oDataAnnotations = this.getODataAnnotations(renamedBaseAppManifest);
28
25
  const promises = this.downloadAnnotations(oDataAnnotations, languages);
29
26
  const modelName = I18N_DEFAULT_MODEL_NAME; //`i18n_a9n_${normalisedId}`;
30
- const i18nPathName = path.join(I18N_DEFAULT_PATH, normalisedId);
31
- const keys = new Array();
32
- const propertiesPerLanguage = new Map();
27
+ const i18nPathName = path_1.posix.join(I18N_DEFAULT_PATH, normalisedId);
33
28
  const annotationFiles = new Map();
34
29
  const metaInfo = new Array();
30
+ const i18nManager = new i18nManager_1.default(modelName, id, languages);
35
31
  for (const { promisesPerLanguage, annotationName } of promises) {
36
- const annotationXml = await this.createAnnotationFile(promisesPerLanguage, keys, modelName, propertiesPerLanguage, id);
32
+ const annotationXml = await this.createAnnotationFile(promisesPerLanguage, i18nManager);
37
33
  const annotationFileName = `annotations/annotation_${annotationName}.xml`;
38
34
  annotationFiles.set(annotationFileName, annotationXml);
39
35
  metaInfo.push({ annotationFileName, annotationName });
@@ -41,82 +37,20 @@ class AnnotationManager {
41
37
  if (metaInfo.length > 0) {
42
38
  this.updateManifest(renamedBaseAppManifest, metaInfo, modelName, i18nPathName);
43
39
  }
44
- const i18nFiles = this.createI18nFiles(propertiesPerLanguage, i18nPathName);
40
+ const i18nFiles = i18nManager.createFiles(i18nPathName);
45
41
  return new Map([...annotationFiles, ...i18nFiles]);
46
42
  }
47
- createI18nFiles(propertiesPerLanguage, i18nPathName) {
48
- const files = new Map();
49
- propertiesPerLanguage.forEach((i18nLines, language) => {
50
- i18nLines.sort();
51
- let filename = "i18n";
52
- const normalisedLanguage = this.getNormalisedLanguage(language);
53
- if (normalisedLanguage) {
54
- filename += "_" + normalisedLanguage;
55
- }
56
- const filepath = path.join(i18nPathName, filename + ".properties");
57
- files.set(filepath, i18nLines.join("\n"));
58
- });
59
- return files;
60
- }
61
43
  normalizeAppVariantId(id, replaceWith = "") {
62
44
  return id.replace(/[.\W]+/gi, replaceWith);
63
45
  }
64
- async createAnnotationFile(promisesPerLanguage, keys, modelName, propertiesPerLanguage, appVariantId) {
46
+ async createAnnotationFile(promisesPerLanguage, i18nManager) {
65
47
  const annotationJsons = new Map();
66
48
  for (const promise of promisesPerLanguage) {
67
49
  const { language, xml } = await promise;
68
- annotationJsons.set(language, JSON.parse(convert.xml2json(xml, XML_OPTIONS)));
69
- }
70
- const paths = this.getDiffJsonPaths([...annotationJsons.values()]);
71
- const { annotationJson, languageI18nContentMap } = this.getAdaptedAnnotation(paths, keys, annotationJsons, modelName, appVariantId);
72
- languageI18nContentMap.forEach((i18nLines, language) => {
73
- const properties = propertiesPerLanguage.get(language);
74
- if (properties) {
75
- properties.push(...i18nLines);
76
- }
77
- else {
78
- propertiesPerLanguage.set(language, i18nLines);
79
- }
80
- });
81
- return convert.json2xml(annotationJson, XML_OPTIONS);
82
- }
83
- getNormalisedLanguage(language) {
84
- const normalisedLanguages = ResourceBundle._getFallbackLocales(language);
85
- if (normalisedLanguages?.length > 0 && normalisedLanguages[0] != null && normalisedLanguages[0].length > 0) {
86
- return normalisedLanguages[0].toLowerCase();
50
+ annotationJsons.set(language, xmlUtil_1.default.xmlToJson(xml));
87
51
  }
88
- }
89
- getAdaptedAnnotation(paths, keys, annotationJsons, modelName, appVariantId) {
90
- const pathKeyMap = new Map();
91
- const languageI18nContentMap = new Map();
92
- for (const [language, json] of [...annotationJsons]) {
93
- const lines = [];
94
- for (const path of paths) {
95
- const { subject, property } = AnnotationManager.traverseJson(json, path);
96
- const value = subject[property];
97
- const key = appVariantId + "_" + this.getUniqueKeyForPath(pathKeyMap, path, keys, value);
98
- lines.push(key + "=" + value);
99
- subject[property] = `{${modelName}>${key}}`;
100
- }
101
- if (lines.length > 0) {
102
- languageI18nContentMap.set(language, lines);
103
- }
104
- }
105
- return { annotationJson: [...annotationJsons][0][1], languageI18nContentMap };
106
- }
107
- getUniqueKeyForPath(pathKeyMap, path, keys, value) {
108
- if (pathKeyMap.has(path)) {
109
- return pathKeyMap.get(path);
110
- }
111
- const propertyName = value.replace(/\W/gi, "_").toUpperCase();
112
- let suffix = "";
113
- while (keys.includes(propertyName + suffix)) {
114
- suffix = suffix === "" ? "0" : (parseInt(suffix) + 1).toString();
115
- }
116
- const key = propertyName + suffix;
117
- pathKeyMap.set(path, key);
118
- keys.push(key);
119
- return key;
52
+ const annotationJson = i18nManager.populateTranslations(annotationJsons);
53
+ return xmlUtil_1.default.jsonToXml(annotationJson.json);
120
54
  }
121
55
  downloadAnnotations(annotations, languages) {
122
56
  return [...annotations].map(([name, { uri }]) => ({
@@ -181,7 +115,13 @@ class AnnotationManager {
181
115
  const cacheManager = new annotationsCacheManager_1.default(this.configuration, cacheFilename);
182
116
  log.verbose(`Getting annotation '${name}' ${language} by '${annotationUri}'`);
183
117
  try {
184
- const files = await cacheManager.getFiles(() => this.abapRepoManager.getAnnotationMetadata(annotationUri), () => this.abapRepoManager.downloadAnnotationFile(annotationUri));
118
+ let files;
119
+ if (this.configuration.enableAnnotationCache) {
120
+ files = await cacheManager.getFiles(() => this.abapRepoManager.getAnnotationMetadata(annotationUri), () => this.abapRepoManager.downloadAnnotationFile(annotationUri));
121
+ }
122
+ else {
123
+ files = await this.abapRepoManager.downloadAnnotationFile(annotationUri);
124
+ }
185
125
  if (!files || files.size === 0) {
186
126
  throw new Error(`No files were fetched for '${name}' by '${annotationUri}'`);
187
127
  }
@@ -204,73 +144,6 @@ class AnnotationManager {
204
144
  }
205
145
  return oDataAnnotations;
206
146
  }
207
- static traverseJson(obj, path) {
208
- const checkArrayIndex = (part) => {
209
- if (Array.isArray(subject)) {
210
- const item = parseInt(part);
211
- if (isNaN(item)) {
212
- throw new Error(`Array index '${part}' is not a number in path '${path}' for ${json}`);
213
- }
214
- }
215
- };
216
- const json = util_1.inspect(obj, true, 100, false);
217
- const pathParts = path.split("/");
218
- if (path.endsWith("/")) {
219
- pathParts.pop();
220
- }
221
- let property = pathParts.pop();
222
- let subject = obj;
223
- for (const part of pathParts) {
224
- let item = part;
225
- checkArrayIndex(part);
226
- subject = subject[item];
227
- if (subject == null) {
228
- throw new Error(`Property '${item}' is undefined in path '${path}' for ${json}`);
229
- }
230
- }
231
- checkArrayIndex(property);
232
- if (subject[property] == null) {
233
- throw new Error(`Target property '${property}' is undefined in path '${path}' for ${json}`);
234
- }
235
- return { subject, property };
236
- }
237
- getDiffJsonPaths(jsons) {
238
- const paths = new Set();
239
- if (jsons.length > 1) {
240
- for (let j = 1; j < jsons.length; j++) {
241
- const diffResult = json_diff_1.diff(jsons[0], jsons[j], { full: false, sort: false });
242
- // if diffResult is undefined -> jsons are the same
243
- if (diffResult) {
244
- for (const path of this.traverseDiff(diffResult)) {
245
- paths.add(path);
246
- }
247
- }
248
- }
249
- }
250
- return [...paths];
251
- }
252
- traverseDiff(obj, path = "") {
253
- const branches = [];
254
- if (Array.isArray(obj)) {
255
- for (let i = 0; i < obj.length; i++) {
256
- const item = obj[i];
257
- if (item[0] == "~") {
258
- branches.push(...this.traverseDiff(item[1], path + `${i}/`));
259
- }
260
- }
261
- }
262
- else {
263
- for (const key of Object.keys(obj)) {
264
- if (key == "__old" || key == "__new") {
265
- branches.push(path);
266
- }
267
- else {
268
- branches.push(...this.traverseDiff(obj[key], path + `${key}/`));
269
- }
270
- }
271
- }
272
- return branches;
273
- }
274
147
  }
275
148
  exports.default = AnnotationManager;
276
149
  //# sourceMappingURL=annotationManager.js.map
@@ -2,6 +2,7 @@ import { IAppVariantInfo } from "./model/types";
2
2
  export default class AppVariantManager {
3
3
  static process(appVariantResources: any[], projectNamespace: string, taskUtil: any): Promise<IAppVariantInfo>;
4
4
  static getAppVariantResources(workspace: any): Promise<any[]>;
5
+ static renameChanges(appVariantResources: any[], projectNamespace: string, appVariantInfo: IAppVariantInfo): Promise<void>;
5
6
  static getAppVariantInfo(appVariantResources: any[]): Promise<IAppVariantInfo>;
6
7
  static writeI18nToModule(resource: any, projectNamespace: string, i18nBundleName: string): void;
7
8
  private static omitFiles;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const path = require("path");
4
- const resourceUtil_1 = require("./util/resourceUtil");
5
3
  const commonUtil_1 = require("./util/commonUtil");
4
+ const resourceUtil_1 = require("./util/resourceUtil");
5
+ const path_1 = require("path");
6
6
  const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::AppVariantManager");
7
7
  const OMIT_FILES = ["manifest.appdescr_variant"];
8
8
  const OMIT_FOLDERS = [];
@@ -11,42 +11,71 @@ const MANIFEST_APP_VARIANT = "manifest.appdescr_variant";
11
11
  class AppVariantManager {
12
12
  static async process(appVariantResources, projectNamespace, taskUtil) {
13
13
  const appVariantInfo = await this.getAppVariantInfo(appVariantResources);
14
- const i18nBundleName = commonUtil_1.replaceDots(appVariantInfo.id);
14
+ const i18nBundleName = (0, commonUtil_1.replaceDots)(appVariantInfo.id);
15
15
  for (const resource of appVariantResources) {
16
16
  this.writeI18nToModule(resource, projectNamespace, i18nBundleName);
17
17
  this.omitFiles(resource, taskUtil);
18
18
  }
19
19
  this.adjustAddNewModelEnhanceWith(appVariantInfo?.manifest?.content ?? [], i18nBundleName);
20
+ await this.renameChanges(appVariantResources, projectNamespace, appVariantInfo);
20
21
  return appVariantInfo;
21
22
  }
22
23
  static getAppVariantResources(workspace) {
23
24
  return workspace.byGlob(`/**/*.{${EXTENSIONS}}`);
24
25
  }
26
+ static async renameChanges(appVariantResources, projectNamespace, appVariantInfo) {
27
+ const changesFolder = resourceUtil_1.default.getResourcePath(projectNamespace, "changes");
28
+ const changes = new Map();
29
+ const resourcesByPath = new Map();
30
+ for (const resource of appVariantResources) {
31
+ const resourcePath = resource.getPath();
32
+ const basename = path_1.posix.dirname(resourcePath);
33
+ if (changesFolder === basename) {
34
+ changes.set(resourcePath, await resourceUtil_1.default.getString(resource));
35
+ resourcesByPath.set(resourcePath, resource);
36
+ }
37
+ }
38
+ const renamedChanges = (0, commonUtil_1.renameResources)(changes, appVariantInfo.reference, appVariantInfo.id);
39
+ renamedChanges.forEach((renamedContent, resourcePath) => {
40
+ const resource = resourcesByPath.get(resourcePath);
41
+ resourceUtil_1.default.setString(resource, renamedContent);
42
+ });
43
+ }
25
44
  static async getAppVariantInfo(appVariantResources) {
45
+ const changesManifestFolder = path_1.posix.join("changes", "manifest");
46
+ let manifest;
47
+ const manifestChanges = [];
26
48
  for (const resource of appVariantResources) {
27
- const basename = path.basename(resource.getPath());
49
+ const resourcePath = resource.getPath();
50
+ const dirname = path_1.posix.dirname(resource.getPath());
51
+ const basename = path_1.posix.basename(resourcePath);
28
52
  if (basename === MANIFEST_APP_VARIANT) {
29
- const manifest = await resource.getBuffer().then((buffer) => buffer.toString("utf8")).then(JSON.parse);
30
- const { id, reference } = manifest;
31
- return { id, reference, manifest };
53
+ manifest = await resourceUtil_1.default.getString(resource).then(JSON.parse);
54
+ }
55
+ else if (dirname.endsWith(changesManifestFolder)) {
56
+ const str = await resourceUtil_1.default.getString(resource);
57
+ manifestChanges.push(JSON.parse(str));
32
58
  }
33
59
  }
34
- throw new Error("Application variant should contain manifest.appdescr_variant");
60
+ if (manifest) {
61
+ return {
62
+ id: manifest.id,
63
+ reference: manifest.reference,
64
+ manifest,
65
+ manifestChanges
66
+ };
67
+ }
68
+ throw new Error("Adaptation project should contain manifest.appdescr_variant");
35
69
  }
36
70
  static writeI18nToModule(resource, projectNamespace, i18nBundleName) {
37
- if (path.extname(resource.getPath()) === ".properties") {
71
+ if (path_1.posix.extname(resource.getPath()) === ".properties") {
38
72
  let rootFolder = resourceUtil_1.default.getRootFolder(projectNamespace);
39
- if (resource.getPath().startsWith(rootFolder)) {
40
- resource.setPath(path.join(rootFolder, i18nBundleName, resource.getPath().substring(rootFolder.length)));
41
- }
42
- else {
43
- resource.setPath(path.join("/", i18nBundleName, resource.getPath()));
44
- }
73
+ resource.setPath(path_1.posix.join(rootFolder, i18nBundleName, resource.getPath().substring(rootFolder.length)));
45
74
  }
46
75
  }
47
76
  static omitFiles(resource, taskUtil) {
48
- const dirname = path.dirname(resource.getPath());
49
- const filename = path.basename(resource.getPath());
77
+ const dirname = path_1.posix.dirname(resource.getPath());
78
+ const filename = path_1.posix.basename(resource.getPath());
50
79
  if (OMIT_FILES.includes(filename) ||
51
80
  OMIT_FOLDERS.some(folder => dirname.endsWith(folder))) {
52
81
  taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.OmitFromBuildResult, true);
@@ -1,16 +1,20 @@
1
- import { IAppVariantInfo, IAppVariantManifest, IProjectOptions } from "./model/types";
1
+ import { IAppVariantInfo, IProjectOptions } from "./model/types";
2
2
  import IProcessor from "./processors/processor";
3
+ export interface IBaseAppResources {
4
+ resources: any[];
5
+ manifestInfo: IManifestInfo;
6
+ }
7
+ export interface IManifestInfo {
8
+ id: string;
9
+ version: string;
10
+ }
3
11
  export default class BaseAppManager {
4
- static process(baseAppFiles: Map<string, string>, appVariantInfo: IAppVariantInfo, options: IProjectOptions, processor: IProcessor): Promise<any[]>;
12
+ static process(baseAppFiles: Map<string, string>, appVariantInfo: IAppVariantInfo, options: IProjectOptions, processor: IProcessor): Promise<IBaseAppResources>;
5
13
  private static updateAdaptationProperties;
6
- static getManifestInfo(manifest: any): {
7
- id: string;
8
- version: string;
9
- };
10
- static renameBaseApp(baseAppFiles: Map<string, string>, search: string, replacement: string): Map<string, string>;
14
+ static getManifestInfo(manifest: any): IManifestInfo;
11
15
  private static getBaseAppManifest;
12
16
  private static fillAppVariantIdHierarchy;
13
17
  static validateProperty(value: string, property: string): void;
14
- static applyDescriptorChanges(baseAppManifest: any, appVariantManifest: IAppVariantManifest, i18nBundleName: string): Promise<void>;
18
+ static applyDescriptorChanges(baseAppManifest: any, appVariantInfo: IAppVariantInfo, i18nBundleName: string): Promise<void>;
15
19
  static writeToWorkspace(baseAppFiles: Map<string, string>, projectNamespace: string): any[];
16
20
  }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const path = require("path");
3
+ const commonUtil_1 = require("./util/commonUtil");
4
4
  const buildStrategy_1 = require("./buildStrategy");
5
5
  const resourceUtil_1 = require("./util/resourceUtil");
6
- const commonUtil_1 = require("./util/commonUtil");
6
+ const path_1 = require("path");
7
7
  const { RegistrationBuild, ApplyUtil, Applier, Change } = require("../dist/bundle");
8
8
  const resourceFactory = require("@ui5/fs/lib/resourceFactory");
9
9
  const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::BaseAppManager");
@@ -11,15 +11,18 @@ class BaseAppManager {
11
11
  static async process(baseAppFiles, appVariantInfo, options, processor) {
12
12
  const baseAppManifest = this.getBaseAppManifest(baseAppFiles);
13
13
  const { id, version } = this.getManifestInfo(baseAppManifest.content);
14
- const renamedBaseAppFiles = this.renameBaseApp(baseAppFiles, appVariantInfo.reference, appVariantInfo.id);
14
+ const renamedBaseAppFiles = (0, commonUtil_1.renameResources)(baseAppFiles, appVariantInfo.reference, appVariantInfo.id);
15
15
  const { filepath, content } = this.getBaseAppManifest(renamedBaseAppFiles);
16
16
  await processor.updateLandscapeSpecificContent(content, renamedBaseAppFiles);
17
17
  this.fillAppVariantIdHierarchy(processor, id, version, content);
18
18
  this.updateAdaptationProperties(content);
19
- const i18nBundleName = commonUtil_1.replaceDots(appVariantInfo.id);
20
- await this.applyDescriptorChanges(content, appVariantInfo.manifest, i18nBundleName);
19
+ const i18nBundleName = (0, commonUtil_1.replaceDots)(appVariantInfo.id);
20
+ await this.applyDescriptorChanges(content, appVariantInfo, i18nBundleName);
21
21
  renamedBaseAppFiles.set(filepath, JSON.stringify(content));
22
- return this.writeToWorkspace(renamedBaseAppFiles, options.projectNamespace);
22
+ return {
23
+ resources: this.writeToWorkspace(renamedBaseAppFiles, options.projectNamespace),
24
+ manifestInfo: this.getManifestInfo(content)
25
+ };
23
26
  }
24
27
  static updateAdaptationProperties(content) {
25
28
  if (content["sap.fiori"]?.cloudDevAdaptationStatus) {
@@ -35,26 +38,6 @@ class BaseAppManager {
35
38
  const version = manifest["sap.app"]?.applicationVersion?.version;
36
39
  return { id, version };
37
40
  }
38
- static renameBaseApp(baseAppFiles, search, replacement) {
39
- log.verbose("Renaming base app resources to appVariant id");
40
- const dotToSlash = (update) => update.split(".").join("\/");
41
- const dotsEscape = (update) => update.split(".").join("\\.");
42
- const replaces = [
43
- {
44
- regexp: new RegExp(dotsEscape(search), "g"),
45
- replacement
46
- },
47
- {
48
- regexp: new RegExp(dotToSlash(search), "g"),
49
- replacement: dotToSlash(replacement)
50
- }
51
- ];
52
- const renamed = new Map();
53
- baseAppFiles.forEach((content, filepath) => {
54
- renamed.set(filepath, replaces.reduce((p, c) => p.replace(c.regexp, c.replacement), content));
55
- });
56
- return renamed;
57
- }
58
41
  static getBaseAppManifest(baseAppFiles) {
59
42
  let filepath = [...baseAppFiles.keys()].find(filepath => filepath.endsWith("manifest.json"));
60
43
  if (filepath) {
@@ -83,14 +66,19 @@ class BaseAppManager {
83
66
  throw new Error(`Original application manifest should have ${property}`);
84
67
  }
85
68
  }
86
- static async applyDescriptorChanges(baseAppManifest, appVariantManifest, i18nBundleName) {
69
+ static async applyDescriptorChanges(baseAppManifest, appVariantInfo, i18nBundleName) {
87
70
  log.verbose("Applying appVariant changes");
88
71
  const strategy = new buildStrategy_1.default(RegistrationBuild, ApplyUtil, i18nBundleName);
89
- if (appVariantManifest.layer) {
90
- appVariantManifest.content?.forEach(item => item.layer = appVariantManifest.layer);
72
+ const { manifest } = appVariantInfo;
73
+ const allChanges = [
74
+ ...manifest.content,
75
+ ...appVariantInfo.manifestChanges
76
+ ];
77
+ if (manifest.layer) {
78
+ allChanges.forEach(item => item.layer = manifest.layer);
91
79
  }
92
- const changesContent = appVariantManifest.content?.map((change) => new Change(change));
93
- if (changesContent) {
80
+ const changesContent = allChanges.map(change => new Change(change));
81
+ if (changesContent.length > 0) {
94
82
  await Applier.applyChanges(baseAppManifest, changesContent, strategy);
95
83
  }
96
84
  }
@@ -116,6 +104,6 @@ class BaseAppManager {
116
104
  exports.default = BaseAppManager;
117
105
  const getPath = (filename, projectNamespace) => {
118
106
  const rootFolder = resourceUtil_1.default.getRootFolder(projectNamespace);
119
- return path.resolve(path.join(rootFolder, filename));
107
+ return path_1.posix.join(rootFolder, filename);
120
108
  };
121
109
  //# sourceMappingURL=baseAppManager.js.map
package/dist/bundle.js CHANGED
@@ -6,28 +6,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
6
6
 
7
7
  var path = require('path');
8
8
 
9
- function _interopNamespace(e) {
10
- if (e && e.__esModule) return e;
11
- var n = Object.create(null);
12
- if (e) {
13
- Object.keys(e).forEach(function (k) {
14
- if (k !== 'default') {
15
- var d = Object.getOwnPropertyDescriptor(e, k);
16
- Object.defineProperty(n, k, d.get ? d : {
17
- enumerable: true,
18
- get: function () {
19
- return e[k];
20
- }
21
- });
22
- }
23
- });
24
- }
25
- n['default'] = e;
26
- return Object.freeze(n);
27
- }
28
-
29
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
30
-
31
9
  var fnIsEmptyObject = function isEmptyObject(obj) {
32
10
  for (var sName in obj) {
33
11
  return false;
@@ -85,7 +63,7 @@ class URI {
85
63
  }
86
64
 
87
65
  normalize() {
88
- this.value = path__namespace.normalize(this.value);
66
+ this.value = path.posix.normalize(this.value).replace(/\\/g, "/");
89
67
  return this;
90
68
  }
91
69
 
@@ -27,6 +27,7 @@ class CacheManager {
27
27
  }
28
28
  }
29
29
  isMetadataSame(tempMetadata, metadata) {
30
+ // TODO: Implement correct metadata comparision.
30
31
  return tempMetadata && metadata && tempMetadata.changedOn === metadata.changedOn;
31
32
  }
32
33
  readTempMetadata() {
@@ -0,0 +1,43 @@
1
+ import { IDiffProperty, IJsonContent } from "./util/jsonDiffUtil";
2
+ export declare class PropertyValue {
3
+ value: string;
4
+ isReference: boolean;
5
+ qualifier: string;
6
+ language: string;
7
+ private static OLD;
8
+ private static NEW;
9
+ private constructor();
10
+ get isOld(): boolean;
11
+ set(diff: any, references: Map<string, string>): void;
12
+ static oldFrom(language: string, value?: string): PropertyValue;
13
+ static newFrom(language: string, value?: string): PropertyValue;
14
+ }
15
+ export declare class I18nFileContent {
16
+ private properties;
17
+ constructor(languages: string[]);
18
+ add(prop: PropertyValue, key: string): void;
19
+ private initKeyValuesForOtherLanguages;
20
+ hasTranslations(): boolean;
21
+ private getOrCreateLanguageContent;
22
+ createFiles(i18nPathName: string): Map<string, string>;
23
+ }
24
+ export default class I18nManager {
25
+ private modelName;
26
+ private appVariantId;
27
+ private references;
28
+ private existingKeys;
29
+ private i18nFileContent;
30
+ constructor(modelName: string, appVariantId: string, languages: string[]);
31
+ processDiff(properties: Set<IDiffProperty>, previousLanguage: string, currentLanguage: string): void;
32
+ createFiles(i18nPathName: string): Map<string, string>;
33
+ populateTranslations(annotationJsons: Map<string, any>): IJsonContent;
34
+ populate(annotationJsons: [string, any][], defaultAnnotation: IJsonContent): {
35
+ language: string;
36
+ json: any;
37
+ };
38
+ static extractDefaultLanguageAnnotation(annotationJsons: Map<string, any>): IJsonContent;
39
+ private replaceWithModelReference;
40
+ private createReference;
41
+ getUniqueKeyForValue(value: string): string;
42
+ private initPropertyValues;
43
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.I18nFileContent = exports.PropertyValue = void 0;
4
+ const jsonDiffUtil_1 = require("./util/jsonDiffUtil");
5
+ const annotationDiffStructureError_1 = require("./model/annotationDiffStructureError");
6
+ const path_1 = require("path");
7
+ // To generate keys, english language is more common, so compare all other
8
+ // languages with it
9
+ const DEFAULT_LANGUAGES = ["", "EN", "EN_US", "EN_GB"];
10
+ class PropertyValue {
11
+ constructor(qualifier, language, value) {
12
+ this.isReference = false;
13
+ this.qualifier = qualifier;
14
+ this.language = language;
15
+ this.value = value;
16
+ }
17
+ get isOld() {
18
+ return this.qualifier === PropertyValue.OLD;
19
+ }
20
+ set(diff, references) {
21
+ this.value = diff[this.qualifier];
22
+ this.isReference = references.has(diff[this.qualifier]);
23
+ }
24
+ static oldFrom(language, value = "") {
25
+ return new PropertyValue(PropertyValue.OLD, language, value);
26
+ }
27
+ static newFrom(language, value = "") {
28
+ return new PropertyValue(PropertyValue.NEW, language, value);
29
+ }
30
+ }
31
+ exports.PropertyValue = PropertyValue;
32
+ PropertyValue.OLD = "__old";
33
+ PropertyValue.NEW = "__new";
34
+ class I18nFileContent {
35
+ constructor(languages) {
36
+ this.properties = new Map();
37
+ languages.forEach(language => this.properties.set(language, new Map()));
38
+ }
39
+ add(prop, key) {
40
+ this.getOrCreateLanguageContent(prop.language).set(key, prop.value);
41
+ this.initKeyValuesForOtherLanguages(prop, key);
42
+ }
43
+ initKeyValuesForOtherLanguages(prop, key) {
44
+ // "", EN, EN_US, DE, FR
45
+ // If we already compared 2 languages and saved translations, we assume
46
+ // that we have generated all property keys, but suddenly 3d language or
47
+ // further contain translation which was not present in previous
48
+ // languages we need to update all other languages then. These values
49
+ // will be overwritten later by actual values of the language:
50
+ // this.getOrCreateLanguageContent(prop.language).set(key, prop.value);
51
+ if (prop.isOld) {
52
+ this.properties.forEach((keyValue, language) => {
53
+ if (language !== prop.language && !keyValue.has(key)) {
54
+ keyValue.set(key, prop.value);
55
+ }
56
+ });
57
+ }
58
+ }
59
+ hasTranslations() {
60
+ // this.properties.size can be 0 or 2+, it can't be 1
61
+ return [...this.properties.values()].some(keyValue => keyValue.size > 0);
62
+ }
63
+ getOrCreateLanguageContent(language) {
64
+ if (!this.properties.has(language)) {
65
+ this.properties.set(language, new Map());
66
+ }
67
+ return this.properties.get(language);
68
+ }
69
+ createFiles(i18nPathName) {
70
+ const files = new Map();
71
+ if (this.hasTranslations()) {
72
+ this.properties.forEach((i18nLines, language) => {
73
+ let filename = "i18n";
74
+ if (language) {
75
+ filename += "_" + language.toLowerCase();
76
+ }
77
+ const filepath = (0, path_1.join)(i18nPathName, filename + ".properties");
78
+ files.set(filepath, [...i18nLines].map(([key, value]) => `${key}=${value}`).join("\n"));
79
+ });
80
+ }
81
+ return files;
82
+ }
83
+ }
84
+ exports.I18nFileContent = I18nFileContent;
85
+ class I18nManager {
86
+ constructor(modelName, appVariantId, languages) {
87
+ this.references = new Map();
88
+ this.existingKeys = new Set();
89
+ this.modelName = modelName;
90
+ this.appVariantId = appVariantId;
91
+ this.i18nFileContent = new I18nFileContent(languages);
92
+ }
93
+ processDiff(properties, previousLanguage, currentLanguage) {
94
+ // json-diff uses __old and __new value as diff,
95
+ // so we assign it with languages which were in comparison
96
+ const propertyValues = [
97
+ PropertyValue.oldFrom(previousLanguage),
98
+ PropertyValue.newFrom(currentLanguage)
99
+ ];
100
+ for (const property of properties) {
101
+ this.replaceWithModelReference(property, propertyValues);
102
+ }
103
+ }
104
+ createFiles(i18nPathName) {
105
+ return this.i18nFileContent.createFiles(i18nPathName);
106
+ }
107
+ populateTranslations(annotationJsons) {
108
+ /* We compare annotations. Diff gives us:
109
+ {
110
+ "string": {
111
+ "__old": "A"
112
+ "__new": "B"
113
+ }
114
+ }
115
+ we generate key and extract to properties file. Now it looks so:
116
+ {
117
+ "string": "{@i18n>id_KEY}"
118
+ }
119
+ and we compare this with next language and diff gives us:
120
+ {
121
+ "string": {
122
+ "__old": "{@i18n>id_KEY}"
123
+ "__new": "C"
124
+ }
125
+ }
126
+ we use already generate key id_KEY and extract translation value to
127
+ properties file again. And then compare with the next language and so on
128
+ and so on */
129
+ let defaultAnnotation = I18nManager.extractDefaultLanguageAnnotation(annotationJsons);
130
+ if (annotationJsons.size > 0 && defaultAnnotation) {
131
+ defaultAnnotation = this.populate([...annotationJsons], defaultAnnotation);
132
+ }
133
+ return defaultAnnotation;
134
+ }
135
+ populate(annotationJsons, defaultAnnotation) {
136
+ return annotationJsons
137
+ .map(([language, json]) => ({ language, json }))
138
+ .reduce((p, c) => {
139
+ try {
140
+ const pDiff = jsonDiffUtil_1.default.diff(p.json, c.json);
141
+ this.processDiff(pDiff.properties, p.language, c.language);
142
+ return { json: pDiff.json, language: p.language };
143
+ }
144
+ catch (error) {
145
+ if (error instanceof annotationDiffStructureError_1.default) {
146
+ throw new Error(`The structure of the oData annotation xml of language '${p.language}' is different from xml of language '${c.language}' near element: ${error.message}`);
147
+ }
148
+ throw error;
149
+ }
150
+ }, defaultAnnotation);
151
+ }
152
+ static extractDefaultLanguageAnnotation(annotationJsons) {
153
+ let json = null;
154
+ for (const language of DEFAULT_LANGUAGES) {
155
+ json = annotationJsons.get(language);
156
+ if (json != null) {
157
+ annotationJsons.delete(language);
158
+ return { json, language };
159
+ }
160
+ }
161
+ const language = [...annotationJsons.keys()][0];
162
+ json = annotationJsons.get(language);
163
+ annotationJsons.delete(language);
164
+ return { json, language };
165
+ }
166
+ replaceWithModelReference({ object, property }, propertyValues) {
167
+ const diff = object[property];
168
+ this.initPropertyValues(diff, propertyValues);
169
+ // If there are already generated key, like on step 3. above comment, we
170
+ // take it (from __old), so we don't need to generate new
171
+ const propReference = propertyValues.find(prop => prop.isReference);
172
+ let reference = propReference?.value ?? this.createReference(diff.__old);
173
+ object[property] = reference;
174
+ // Other values, which are not references, are extracted to .properties
175
+ const key = this.references.get(reference);
176
+ if (key) {
177
+ propertyValues.filter(prop => !prop.isReference).forEach(prop => this.i18nFileContent.add(prop, key));
178
+ }
179
+ }
180
+ createReference(value) {
181
+ const key = this.appVariantId + "_" + this.getUniqueKeyForValue(value);
182
+ const reference = `{${this.modelName}>${key}}`;
183
+ this.references.set(reference, key);
184
+ return reference;
185
+ }
186
+ getUniqueKeyForValue(value) {
187
+ const propertyName = value.replace(/\W/gi, "_").toUpperCase();
188
+ let suffix = -1;
189
+ let suffixString;
190
+ do {
191
+ suffixString = suffix === -1 ? "" : suffix;
192
+ suffix++;
193
+ } while (this.existingKeys.has(propertyName + suffixString));
194
+ const key = propertyName + suffixString;
195
+ this.existingKeys.add(key);
196
+ return key;
197
+ }
198
+ initPropertyValues(diff, propertyValues) {
199
+ propertyValues.forEach(prop => prop.set(diff, this.references));
200
+ }
201
+ }
202
+ exports.default = I18nManager;
203
+ //# sourceMappingURL=i18nManager.js.map
package/dist/index.js CHANGED
@@ -10,12 +10,12 @@ const processor_1 = require("./processors/processor");
10
10
  module.exports = ({ workspace, options, taskUtil }) => {
11
11
  dotenv.config();
12
12
  async function process(workspace, taskUtil) {
13
- const processor = processor_1.determineProcessor(options.configuration);
13
+ const processor = (0, processor_1.determineProcessor)(options.configuration);
14
14
  const appVariantResources = await appVariantManager_1.default.getAppVariantResources(workspace);
15
15
  const appVariantInfo = await appVariantManager_1.default.process(appVariantResources, options.projectNamespace, taskUtil);
16
16
  const baseAppFiles = await processor.getBaseAppFiles(appVariantInfo.reference);
17
- const baseAppResources = await baseAppManager_1.default.process(baseAppFiles, appVariantInfo, options, processor);
18
- await Promise.all(appVariantResources.concat(baseAppResources).map(resource => workspace.write(resource)));
17
+ const { resources } = await baseAppManager_1.default.process(baseAppFiles, appVariantInfo, options, processor);
18
+ await Promise.all(appVariantResources.concat(resources).map(resource => workspace.write(resource)));
19
19
  }
20
20
  return process(workspace, taskUtil);
21
21
  };
@@ -0,0 +1,3 @@
1
+ export default class AnnotationDiffStructureError extends Error {
2
+ constructor(json: any);
3
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class AnnotationDiffStructureError extends Error {
4
+ constructor(json) {
5
+ super(JSON.stringify(json));
6
+ }
7
+ }
8
+ exports.default = AnnotationDiffStructureError;
9
+ //# sourceMappingURL=annotationDiffStructureError.js.map
@@ -10,6 +10,7 @@ export interface IConfiguration {
10
10
  credentials?: IAuth;
11
11
  type?: "cf" | "abap";
12
12
  languages?: string[];
13
+ enableAnnotationCache?: boolean;
13
14
  }
14
15
  export interface IProjectOptions {
15
16
  configuration: IConfiguration;
@@ -58,6 +59,7 @@ export interface IAppVariantInfo {
58
59
  id: string;
59
60
  reference: string;
60
61
  manifest: IAppVariantManifest;
62
+ manifestChanges: Array<IChange>;
61
63
  }
62
64
  export interface IAppVariantManifest {
63
65
  id: string;
@@ -94,6 +96,6 @@ export interface IMetadata {
94
96
  changedOn: string;
95
97
  id?: string;
96
98
  }
97
- export declare type KeyedMap<T, K extends keyof T, V> = {
99
+ export type KeyedMap<T, K extends keyof T, V> = {
98
100
  [k in K]: V;
99
101
  };
@@ -12,7 +12,7 @@ class AbapProcessor {
12
12
  return this.cacheManager.getFiles(() => this.abapRepoManager.getMetadata(baseAppId), () => this.abapRepoManager.downloadBaseAppFiles());
13
13
  }
14
14
  validateConfiguration() {
15
- commonUtil_1.validateObject(this.configuration, ["destination", "appName"], "should be specified in ui5.yaml configuration");
15
+ (0, commonUtil_1.validateObject)(this.configuration, ["destination", "appName"], "should be specified in ui5.yaml configuration");
16
16
  }
17
17
  async updateLandscapeSpecificContent(renamedBaseAppManifest, baseAppFiles) {
18
18
  const { languages } = this.configuration;
@@ -11,7 +11,7 @@ class CFProcessor {
11
11
  return this.cacheManager.getFiles(() => html5RepoManager_1.default.getMetadata(this.configuration), () => html5RepoManager_1.default.getBaseAppFiles(this.configuration));
12
12
  }
13
13
  validateConfiguration() {
14
- commonUtil_1.validateObject(this.configuration, ["appHostId", "appName", "appVersion"], "should be specified in ui5.yaml configuration");
14
+ (0, commonUtil_1.validateObject)(this.configuration, ["appHostId", "appName", "appVersion"], "should be specified in ui5.yaml configuration");
15
15
  }
16
16
  async updateLandscapeSpecificContent(renamedBaseAppManifest) {
17
17
  this.updateCloudPlatform(renamedBaseAppManifest);
@@ -50,7 +50,7 @@ class AbapRepoManager {
50
50
  const data = await requestUtil_1.default.get(uri, REQUEST_OPTIONS_XML, auth);
51
51
  if (data?.d?.ZipArchive.length > 0) {
52
52
  const buffer = Buffer.from(data.d.ZipArchive, "base64");
53
- return zipUtil_1.unzipZipEntries(buffer);
53
+ return (0, zipUtil_1.unzipZipEntries)(buffer);
54
54
  }
55
55
  throw new Error(`App '${appName}' from destination '${destination}' doesn't contain files`);
56
56
  }
@@ -69,7 +69,7 @@ class HTML5RepoManager {
69
69
  const { appHostId, appName, appVersion } = options;
70
70
  const uri = `${html5RepoBaseUri}/applications/content/${appName}-${appVersion}/`;
71
71
  const zip = await this.download(token, appHostId, uri);
72
- return zipUtil_1.unzipZipEntries(zip);
72
+ return (0, zipUtil_1.unzipZipEntries)(zip);
73
73
  }
74
74
  static async download(token, appHostId, uri) {
75
75
  if (!token) {
@@ -1,2 +1,3 @@
1
1
  export declare function replaceDots(value: string): string;
2
2
  export declare function validateObject<T extends Object>(options: T, properties: Array<keyof T>, message: string): void;
3
+ export declare function renameResources(files: Map<string, string>, search: string, replacement: string): Map<string, string>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateObject = exports.replaceDots = void 0;
3
+ exports.renameResources = exports.validateObject = exports.replaceDots = void 0;
4
4
  function replaceDots(value) {
5
5
  return value.replace(/\./g, "_");
6
6
  }
@@ -13,4 +13,36 @@ function validateObject(options, properties, message) {
13
13
  }
14
14
  }
15
15
  exports.validateObject = validateObject;
16
+ function renameResources(files, search, replacement) {
17
+ const escapeRegexSpecialChars = (update) => update.replaceAll(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
18
+ // The current regex works if the old Id is contained in the new Id, given
19
+ // that they do not have the same beginning.
20
+ // more complete alternative: /((?<!newIdStart)|(?!newIdEnd))oldId/g
21
+ if (replacement.includes(search)) {
22
+ const [before, _] = replacement.split(search);
23
+ // Matches a position in the string that is not immediately preceded by
24
+ // the string "before".
25
+ search = `(?<!${escapeRegexSpecialChars(before)})${escapeRegexSpecialChars(search)}`;
26
+ }
27
+ else {
28
+ search = escapeRegexSpecialChars(search);
29
+ }
30
+ const dotToSlash = (update) => update.replaceAll(".", "\/");
31
+ const replaces = [
32
+ {
33
+ regexp: new RegExp(search, "g"),
34
+ replacement
35
+ },
36
+ {
37
+ regexp: new RegExp(dotToSlash(search), "g"),
38
+ replacement: dotToSlash(replacement)
39
+ }
40
+ ];
41
+ const renamed = new Map();
42
+ files.forEach((content, filepath) => {
43
+ renamed.set(filepath, replaces.reduce((p, c) => p.replace(c.regexp, c.replacement), content));
44
+ });
45
+ return renamed;
46
+ }
47
+ exports.renameResources = renameResources;
16
48
  //# sourceMappingURL=commonUtil.js.map
@@ -0,0 +1,17 @@
1
+ export interface IJsonContent {
2
+ language: string;
3
+ json: any;
4
+ }
5
+ export interface IDiffProperty {
6
+ object: any;
7
+ property: string;
8
+ }
9
+ export interface IDiffJson {
10
+ json: any;
11
+ properties: Set<IDiffProperty>;
12
+ }
13
+ export default class JsonDiffUtil {
14
+ static diff(jsonA: any, jsonB: any): IDiffJson;
15
+ private static findDiffsAndRestoreStructure;
16
+ private static traverseDiffRecursive;
17
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const jsonDiff = require("json-diff");
4
+ const annotationDiffStructureError_1 = require("../model/annotationDiffStructureError");
5
+ class JsonDiffUtil {
6
+ static diff(jsonA, jsonB) {
7
+ const json = jsonDiff.diff(jsonA, jsonB, { full: true, sort: false });
8
+ const properties = this.findDiffsAndRestoreStructure(json);
9
+ return {
10
+ json,
11
+ properties
12
+ };
13
+ }
14
+ static findDiffsAndRestoreStructure(object) {
15
+ const properties = new Set();
16
+ this.traverseDiffRecursive(properties, { object }, "object");
17
+ return properties;
18
+ }
19
+ static traverseDiffRecursive(properties, object, property) {
20
+ const current = object[property];
21
+ if (typeof current !== "object") {
22
+ return;
23
+ }
24
+ if (Array.isArray(current)) {
25
+ for (let i = 0; i < current.length; i++) {
26
+ const item = current[i];
27
+ if (["~", " ", "-", "+"].some(sign => item[0] === sign)) {
28
+ current[i] = item[1];
29
+ // This is a sign from json-diff plugin, that the property contains differences.
30
+ // We will remove these signs, to restore the original structure
31
+ if (item[0] === "~") {
32
+ this.traverseDiffRecursive(properties, item, 1);
33
+ }
34
+ else if (item[0] === "+" || item[0] === "-") {
35
+ throw new annotationDiffStructureError_1.default(item[1]);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ else {
41
+ for (const key of Object.keys(current)) {
42
+ if (key == "__old" || key == "__new") {
43
+ properties.add({ object, property });
44
+ break;
45
+ }
46
+ else {
47
+ this.traverseDiffRecursive(properties, current, key);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ exports.default = JsonDiffUtil;
54
+ //# sourceMappingURL=jsonDiffUtil.js.map
@@ -1,5 +1,8 @@
1
1
  export default class ResourceUtil {
2
2
  static getRootFolder(projectNamespace?: string): string;
3
+ static getResourcePath(projectNamespace?: string, ...paths: string[]): string;
3
4
  static write(dir: string, files: Map<string, string>): Promise<void[]>;
4
5
  static read(rootFolder: string, folder: string, files: Map<string, string>, exclude?: string[]): void;
6
+ static getString(resource: any): Promise<string>;
7
+ static setString(resource: any, str: string): void;
5
8
  }
@@ -1,15 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const fs = require("fs");
4
- const path = require("path");
4
+ const path_1 = require("path");
5
5
  const resourceFactory = require("@ui5/fs/lib/resourceFactory");
6
+ const UTF8 = "utf8";
6
7
  class ResourceUtil {
7
8
  static getRootFolder(projectNamespace) {
8
9
  const newPath = ["/resources"];
9
10
  if (projectNamespace) {
10
11
  newPath.push(projectNamespace);
11
12
  }
12
- return path.join(...newPath);
13
+ return path_1.posix.join(...newPath);
14
+ }
15
+ static getResourcePath(projectNamespace, ...paths) {
16
+ return path_1.posix.join(this.getRootFolder(projectNamespace), ...paths);
13
17
  }
14
18
  static write(dir, files) {
15
19
  const fsTarget = resourceFactory.createAdapter({
@@ -26,7 +30,7 @@ class ResourceUtil {
26
30
  static read(rootFolder, folder, files, exclude = []) {
27
31
  const entries = fs.readdirSync(folder);
28
32
  for (let entry of entries) {
29
- const entryPath = path.join(folder, entry);
33
+ const entryPath = path_1.posix.join(folder, entry);
30
34
  const stats = fs.lstatSync(entryPath);
31
35
  if (stats.isFile() && !exclude.some(filepath => entryPath.endsWith(filepath))) {
32
36
  const normalized = entryPath.substring(rootFolder.length);
@@ -37,6 +41,12 @@ class ResourceUtil {
37
41
  }
38
42
  }
39
43
  }
44
+ static getString(resource) {
45
+ return resource.getBuffer().then((buffer) => buffer.toString(UTF8));
46
+ }
47
+ static setString(resource, str) {
48
+ resource.setBuffer(Buffer.from(str, UTF8));
49
+ }
40
50
  }
41
51
  exports.default = ResourceUtil;
42
52
  //# sourceMappingURL=resourceUtil.js.map
@@ -0,0 +1,4 @@
1
+ export default class XmlUtil {
2
+ static jsonToXml(json: any): string;
3
+ static xmlToJson(xml: string): any;
4
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const convert = require("xml-js");
4
+ const XML_OPTIONS = { compact: true, spaces: 4 };
5
+ class XmlUtil {
6
+ static jsonToXml(json) {
7
+ return convert.json2xml(json, {
8
+ ...XML_OPTIONS, attributeValueFn: (val) => val
9
+ .replaceAll("&quot;", "\"")
10
+ .replaceAll("&", "&amp;")
11
+ .replaceAll("<", "&lt;")
12
+ .replaceAll("\"", "&quot;")
13
+ .replaceAll("'", "&apos;")
14
+ });
15
+ }
16
+ static xmlToJson(xml) {
17
+ return JSON.parse(convert.xml2json(xml, {
18
+ ...XML_OPTIONS, attributeValueFn: (val) => val
19
+ .replaceAll("&quot;", "\"")
20
+ }));
21
+ }
22
+ }
23
+ exports.default = XmlUtil;
24
+ //# sourceMappingURL=xmlUtil.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/task-adaptation",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
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": {
@@ -13,7 +13,7 @@
13
13
  "version": "git-chglog --next-tag v$npm_package_version -o CHANGELOG.md && git add CHANGELOG.md",
14
14
  "postversion": "git push --follow-tags",
15
15
  "release-note": "git-chglog -c .chglog/release-config.yml v$npm_package_version",
16
- "rollup": "ts-node scripts/rollup.ts",
16
+ "rollup": "npx ts-node scripts/rollup.ts",
17
17
  "build": "npm run rollup && tsc -p ./"
18
18
  },
19
19
  "repository": {
@@ -62,14 +62,14 @@
62
62
  "@types/mocha": "^9.1.0",
63
63
  "@types/rimraf": "^3.0.2",
64
64
  "@types/semver": "^7.3.8",
65
- "@types/sinon": "^10.0.2",
65
+ "@types/sinon": "^10.0.16",
66
66
  "chai": "^4.3.4",
67
67
  "chai-as-promised": "^7.1.1",
68
68
  "chalk": "^4.1.2",
69
69
  "mocha": "^9.2.0",
70
70
  "mock-require": "^3.0.3",
71
71
  "nyc": "^15.1.0",
72
- "sinon": "^11.1.2",
72
+ "sinon": "^15.2.0",
73
73
  "source-map-support": "^0.5.19",
74
74
  "ts-node": "^10.4.0",
75
75
  "typescript": "^4.3.5"
@@ -1,5 +1,5 @@
1
1
  import * as fs from "fs";
2
- import * as path from "path";
2
+ import { posix as path } from "path";
3
3
  import * as semver from "semver";
4
4
  import * as rollup from "rollup";
5
5
  import * as builtins from "builtin-modules";
@@ -1,4 +1,4 @@
1
- import * as path from "path";
1
+ import { posix as path } from "path";
2
2
 
3
3
  export default class URI {
4
4
  constructor(value) {
@@ -6,7 +6,7 @@ export default class URI {
6
6
  }
7
7
 
8
8
  normalize() {
9
- this.value = path.normalize(this.value);
9
+ this.value = path.normalize(this.value).replace(/\\/g, "/");
10
10
  return this;
11
11
  }
12
12