@ui5/task-adaptation 1.0.21 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/dist/annotationManager.d.ts +3 -4
  3. package/dist/annotationManager.js +20 -56
  4. package/dist/annotations/oDataModel.d.ts +20 -0
  5. package/dist/annotations/oDataModel.js +46 -0
  6. package/dist/annotations/oDataV2Model.d.ts +4 -0
  7. package/dist/annotations/oDataV2Model.js +13 -0
  8. package/dist/annotations/serviceRequestor.d.ts +17 -0
  9. package/dist/annotations/serviceRequestor.js +36 -0
  10. package/dist/appVariantManager.d.ts +0 -7
  11. package/dist/appVariantManager.js +2 -20
  12. package/dist/baseAppManager.d.ts +1 -0
  13. package/dist/baseAppManager.js +22 -5
  14. package/dist/i18nManager.d.ts +11 -10
  15. package/dist/i18nManager.js +19 -19
  16. package/dist/index.js +2 -0
  17. package/dist/model/language.d.ts +13 -0
  18. package/dist/model/language.js +37 -0
  19. package/dist/model/types.d.ts +1 -1
  20. package/dist/processors/abapProcessor.js +2 -2
  21. package/dist/repositories/abapRepoManager.js +2 -1
  22. package/dist/util/cfUtil.js +1 -1
  23. package/dist/util/commonUtil.d.ts +1 -0
  24. package/dist/util/commonUtil.js +13 -1
  25. package/dist/util/jsonDiffUtil.d.ts +14 -3
  26. package/dist/util/jsonDiffUtil.js +29 -9
  27. package/package.json +4 -3
  28. package/scripts/metadataDownloadHelper.ts +85 -0
  29. package/scripts/rollup.ts +0 -9
  30. package/dist/bundle-resourceBundle.js +0 -692
  31. package/scripts/rollup/bundleDefinition-resourceBundle.js +0 -5
  32. package/scripts/rollup/overrides/sap/base/i18n/Localization.js +0 -1
  33. package/scripts/rollup/overrides/sap/base/string/formatMessage.js +0 -1
  34. package/scripts/rollup/overrides/sap/base/util/Properties.js +0 -1
  35. package/scripts/rollup/overrides/sap/base/util/merge.js +0 -1
package/CHANGELOG.md CHANGED
@@ -2,7 +2,16 @@
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.21...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.1.0...HEAD).
6
+
7
+ <a name="v1.1.0"></a>
8
+ ## [v1.1.0] - 2024-01-30
9
+ ### Bug Fixes
10
+ - Include app variant id in bundle name [`afab97a`](https://github.com/SAP/ui5-task-adaptation/commit/afab97a10867a58b6e96eb4310f288d29773cf66)
11
+
12
+
13
+ <a name="v1.0.23"></a>
14
+ ## [v1.0.23] - 2024-01-19
6
15
 
7
16
  <a name="v1.0.21"></a>
8
17
  ## [v1.0.21] - 2024-01-03
@@ -64,6 +73,8 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
64
73
  <a name="v1.0.0"></a>
65
74
  ## v1.0.0 - 2020-12-09
66
75
 
76
+ [v1.1.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.23...v1.1.0
77
+ [v1.0.23]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.21...v1.0.23
67
78
  [v1.0.21]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.20...v1.0.21
68
79
  [v1.0.20]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.19...v1.0.20
69
80
  [v1.0.19]: https://github.com/SAP/ui5-task-adaptation/compare/v1.0.18...v1.0.19
@@ -1,5 +1,6 @@
1
1
  import AbapRepoManager from "./repositories/abapRepoManager";
2
2
  import { IConfiguration } from "./model/types";
3
+ import Language from "./model/language";
3
4
  export interface IAnnotationFiles {
4
5
  annotationName: string;
5
6
  annotationFileName: string;
@@ -9,14 +10,12 @@ export default class AnnotationManager {
9
10
  private configuration;
10
11
  constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager);
11
12
  ANNOTATIONS_FOLDER: string;
12
- process(renamedBaseAppManifest: any, languages: string[]): Promise<Map<string, string>>;
13
+ process(renamedBaseAppManifest: any, languages: Language[]): Promise<Map<string, string>>;
13
14
  private normalizeAppVariantId;
14
15
  private createAnnotationFile;
15
- private downloadAnnotations;
16
16
  private updateManifestModel;
17
17
  private updateManifestDataSources;
18
18
  private createManifestModel;
19
19
  private enhanceManifestModel;
20
- private downloadAnnotation;
21
- private getODataAnnotations;
20
+ private createODataModels;
22
21
  }
@@ -1,15 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const annotationsCacheManager_1 = require("./cache/annotationsCacheManager");
4
3
  const baseAppManager_1 = require("./baseAppManager");
5
4
  const i18nManager_1 = require("./i18nManager");
5
+ const oDataV2Model_1 = require("./annotations/oDataV2Model");
6
+ const serviceRequestor_1 = require("./annotations/serviceRequestor");
6
7
  const xmlUtil_1 = require("./util/xmlUtil");
7
8
  const path_1 = require("path");
8
9
  const I18N_DEFAULT_PATH = "i18n/annotations";
9
10
  const I18N_DEFAULT_MODEL_NAME = "@i18n";
10
11
  const SAPUI5 = "sap.ui5";
11
12
  const SAPAPP = "sap.app";
12
- const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::AnnotationManager");
13
13
  class AnnotationManager {
14
14
  constructor(configuration, abapRepoManager) {
15
15
  this.ANNOTATIONS_FOLDER = "annotations";
@@ -21,18 +21,19 @@ class AnnotationManager {
21
21
  baseAppManager_1.default.validateProperty(id, "sap.app/id");
22
22
  const normalisedId = this.normalizeAppVariantId(id);
23
23
  //TODO: switch to this after resolving @i18n custom model
24
- const oDataAnnotations = this.getODataAnnotations(renamedBaseAppManifest);
25
- const promises = this.downloadAnnotations(oDataAnnotations, languages);
26
24
  const modelName = I18N_DEFAULT_MODEL_NAME; //`i18n_a9n_${normalisedId}`;
27
25
  const i18nPathName = path_1.posix.join(I18N_DEFAULT_PATH, normalisedId);
28
26
  const annotationFiles = new Map();
29
27
  const metaInfo = new Array();
30
28
  const i18nManager = new i18nManager_1.default(modelName, id, languages);
31
- for (const { promisesPerLanguage, annotationName } of promises) {
32
- const annotationXml = await this.createAnnotationFile(promisesPerLanguage, i18nManager);
33
- const annotationFileName = `annotations/annotation_${annotationName}.xml`;
34
- annotationFiles.set(annotationFileName, annotationXml);
35
- metaInfo.push({ annotationFileName, annotationName });
29
+ const oDataModels = this.createODataModels(renamedBaseAppManifest);
30
+ for (const oDataModel of oDataModels) {
31
+ for (const { annotationJsons, annotationName } of oDataModel.getAnnotationJsons(languages)) {
32
+ const annotationXml = await this.createAnnotationFile(await annotationJsons, i18nManager);
33
+ const annotationFileName = `annotations/annotation_${annotationName}.xml`;
34
+ annotationFiles.set(annotationFileName, annotationXml);
35
+ metaInfo.push({ annotationFileName, annotationName });
36
+ }
36
37
  }
37
38
  if (metaInfo.length > 0) {
38
39
  this.updateManifestDataSources(renamedBaseAppManifest, metaInfo);
@@ -46,21 +47,10 @@ class AnnotationManager {
46
47
  normalizeAppVariantId(id, replaceWith = "") {
47
48
  return id.replace(/[.\W]+/gi, replaceWith);
48
49
  }
49
- async createAnnotationFile(promisesPerLanguage, i18nManager) {
50
- const annotationJsons = new Map();
51
- for (const promise of promisesPerLanguage) {
52
- const { language, xml } = await promise;
53
- annotationJsons.set(language, xmlUtil_1.default.xmlToJson(xml));
54
- }
50
+ async createAnnotationFile(annotationJsons, i18nManager) {
55
51
  const annotationJson = i18nManager.populateTranslations(annotationJsons);
56
52
  return xmlUtil_1.default.jsonToXml(annotationJson.json);
57
53
  }
58
- downloadAnnotations(annotations, languages) {
59
- return [...annotations].map(([name, { uri }]) => ({
60
- promisesPerLanguage: languages.map(language => this.downloadAnnotation(uri, name, language)),
61
- annotationName: name
62
- }));
63
- }
64
54
  updateManifestModel(renamedBaseAppManifest, modelName, i18nPathName) {
65
55
  const uri = `${i18nPathName}/i18n.properties`;
66
56
  this.enhanceManifestModel(renamedBaseAppManifest, modelName, uri);
@@ -107,44 +97,18 @@ class AnnotationManager {
107
97
  this.createManifestModel(manifest, modelToEnhance, bundleUrl);
108
98
  }
109
99
  }
110
- async downloadAnnotation(uri, name, language) {
111
- let annotationUri = `https://${this.configuration.destination}.dest${uri}`;
112
- let cacheFilename = name;
113
- if (language) {
114
- annotationUri += `?sap-language=${language}`;
115
- cacheFilename += `-${language}`;
116
- }
117
- const cacheManager = new annotationsCacheManager_1.default(this.configuration, cacheFilename);
118
- log.verbose(`Getting annotation '${name}' ${language} by '${annotationUri}'`);
119
- try {
120
- let files;
121
- if (this.configuration.enableAnnotationCache) {
122
- files = await cacheManager.getFiles(() => this.abapRepoManager.getAnnotationMetadata(annotationUri), () => this.abapRepoManager.downloadAnnotationFile(annotationUri));
123
- }
124
- else {
125
- files = await this.abapRepoManager.downloadAnnotationFile(annotationUri);
126
- }
127
- if (!files || files.size === 0) {
128
- throw new Error(`No files were fetched for '${name}' by '${annotationUri}'`);
129
- }
130
- return { language, xml: [...files][0][1] };
131
- }
132
- catch (error) {
133
- throw new Error(`Failed to fetch annotation '${name}' by '${annotationUri}': ${error.message}`);
134
- }
135
- }
136
- getODataAnnotations(renamedBaseAppManifest) {
137
- const oDataAnnotations = new Map();
138
- const dataSources = renamedBaseAppManifest[SAPAPP]?.dataSources;
100
+ createODataModels(renamedBaseAppManifest) {
101
+ const serviceRequestor = new serviceRequestor_1.default(this.configuration, this.abapRepoManager);
102
+ const oDataModels = [
103
+ new oDataV2Model_1.default(serviceRequestor)
104
+ ];
105
+ const dataSources = renamedBaseAppManifest["sap.app"]?.dataSources;
139
106
  if (dataSources) {
140
- for (const key of Object.keys(dataSources)) {
141
- const annotation = dataSources[key];
142
- if (annotation?.type === "ODataAnnotation" && annotation?.uri?.startsWith("/")) {
143
- oDataAnnotations.set(key, dataSources[key]);
144
- }
107
+ for (const name of Object.keys(dataSources)) {
108
+ oDataModels.forEach(model => model.addDataSource(dataSources[name], name));
145
109
  }
146
110
  }
147
- return oDataAnnotations;
111
+ return oDataModels;
148
112
  }
149
113
  }
150
114
  exports.default = AnnotationManager;
@@ -0,0 +1,20 @@
1
+ import ServiceRequestor, { ILanguageJsonContent, ILanguageXmlContent } from "./serviceRequestor";
2
+ import Language from "../model/language";
3
+ export default class ODataModel {
4
+ protected oDataAnnotations: Map<string, any>;
5
+ private serviceRequestor;
6
+ constructor(serviceRequestor: ServiceRequestor);
7
+ getAnnotationJsons(languages: Language[]): AnnotationJsonPerName[];
8
+ private getPromisesPerLanguage;
9
+ private createAnnotationJsons;
10
+ protected afterXmlDownload({ language, xml }: ILanguageXmlContent): Promise<ILanguageJsonContent>;
11
+ protected transformJsons(annotationJsons: Map<Language, any>): Promise<Map<Language, any>>;
12
+ }
13
+ export interface PromisePerAnnotation {
14
+ promisesPerLanguage: Promise<ILanguageXmlContent>[];
15
+ annotationName: string;
16
+ }
17
+ export interface AnnotationJsonPerName {
18
+ annotationName: string;
19
+ annotationJsons: Promise<Map<Language, any>>;
20
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const xmlUtil_1 = require("../util/xmlUtil");
4
+ class ODataModel {
5
+ constructor(serviceRequestor) {
6
+ this.oDataAnnotations = new Map();
7
+ this.serviceRequestor = serviceRequestor;
8
+ }
9
+ getAnnotationJsons(languages) {
10
+ const result = [];
11
+ const promisesPerLanguagePerName = this.getPromisesPerLanguage(languages);
12
+ for (const { promisesPerLanguage, annotationName } of promisesPerLanguagePerName) {
13
+ result.push({
14
+ annotationName,
15
+ annotationJsons: this.createAnnotationJsons(promisesPerLanguage)
16
+ });
17
+ }
18
+ return result;
19
+ }
20
+ getPromisesPerLanguage(languages) {
21
+ return [...this.oDataAnnotations].map(([annotationName, uri]) => ({
22
+ promisesPerLanguage: languages.map(language => this.serviceRequestor.downloadAnnotation(uri, annotationName, language)
23
+ .then(this.afterXmlDownload)),
24
+ annotationName
25
+ }));
26
+ }
27
+ async createAnnotationJsons(promisesPerLanguage) {
28
+ const annotationJsons = new Map();
29
+ for (const promise of promisesPerLanguage) {
30
+ const { language, json } = await promise;
31
+ annotationJsons.set(language, json);
32
+ }
33
+ return this.transformJsons(annotationJsons);
34
+ }
35
+ async afterXmlDownload({ language, xml }) {
36
+ return {
37
+ json: xmlUtil_1.default.xmlToJson(xml),
38
+ language
39
+ };
40
+ }
41
+ async transformJsons(annotationJsons) {
42
+ return annotationJsons;
43
+ }
44
+ }
45
+ exports.default = ODataModel;
46
+ //# sourceMappingURL=oDataModel.js.map
@@ -0,0 +1,4 @@
1
+ import ODataModel from "./oDataModel";
2
+ export default class ODataV2Model extends ODataModel {
3
+ addDataSource({ uri, type }: any, name: string): void;
4
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const oDataModel_1 = require("./oDataModel");
4
+ class ODataV2Model extends oDataModel_1.default {
5
+ addDataSource({ uri, type }, name) {
6
+ if (uri?.startsWith("/") &&
7
+ type === "ODataAnnotation") {
8
+ this.oDataAnnotations.set(name, uri);
9
+ }
10
+ }
11
+ }
12
+ exports.default = ODataV2Model;
13
+ //# sourceMappingURL=oDataV2Model.js.map
@@ -0,0 +1,17 @@
1
+ import AbapRepoManager from "../repositories/abapRepoManager";
2
+ import { IConfiguration } from "../model/types";
3
+ import Language from "../model/language";
4
+ export interface ILanguageXmlContent {
5
+ language: Language;
6
+ xml: string;
7
+ }
8
+ export interface ILanguageJsonContent {
9
+ language: Language;
10
+ json: any;
11
+ }
12
+ export default class ServiceRequestor {
13
+ private abapRepoManager;
14
+ private configuration;
15
+ constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager);
16
+ downloadAnnotation(uri: string, name: string, language: Language): Promise<ILanguageXmlContent>;
17
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const annotationsCacheManager_1 = require("../cache/annotationsCacheManager");
4
+ const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::ServiceRequestor");
5
+ class ServiceRequestor {
6
+ constructor(configuration, abapRepoManager) {
7
+ this.abapRepoManager = abapRepoManager;
8
+ this.configuration = configuration;
9
+ }
10
+ async downloadAnnotation(uri, name, language) {
11
+ if (language.sap) {
12
+ uri += `?sap-language=${language.sap}`;
13
+ name += `-${language.sap}`;
14
+ }
15
+ const cacheManager = new annotationsCacheManager_1.default(this.configuration, name);
16
+ log.verbose(`Getting annotation '${name}' ${language.sap} by '${uri}'`);
17
+ try {
18
+ let files;
19
+ if (this.configuration.enableAnnotationCache) {
20
+ files = await cacheManager.getFiles(() => this.abapRepoManager.getAnnotationMetadata(uri), () => this.abapRepoManager.downloadAnnotationFile(uri));
21
+ }
22
+ else {
23
+ files = await this.abapRepoManager.downloadAnnotationFile(uri);
24
+ }
25
+ if (!files || files.size === 0) {
26
+ throw new Error(`No files were fetched for '${name}' by '${uri}'`);
27
+ }
28
+ return { language, xml: [...files][0][1] };
29
+ }
30
+ catch (error) {
31
+ throw new Error(`Failed to fetch annotation by '${uri}': ${error.message}`);
32
+ }
33
+ }
34
+ }
35
+ exports.default = ServiceRequestor;
36
+ //# sourceMappingURL=serviceRequestor.js.map
@@ -7,11 +7,4 @@ export default class AppVariantManager {
7
7
  private static isManifestAppVariant;
8
8
  static getAppVariantInfo(appVariantResources: any[]): Promise<IAppVariantInfo>;
9
9
  private static omitFiles;
10
- /**
11
- * We need to add texts properties to changes because not all have texts property.
12
- * Changes without texts property can causes issues in bundle.js
13
- * This is needed for now, and will be removed as soon as change merger in openUI5 is updated
14
- * @param changes
15
- */
16
- private static patchMissingTextsNode;
17
10
  }
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const commonUtil_1 = require("./util/commonUtil");
4
3
  const resourceUtil_1 = require("./util/resourceUtil");
5
4
  const path_1 = require("path");
6
- const log = require("@ui5/logger").getLogger("@ui5/task-adaptation::AppVariantManager");
5
+ const commonUtil_1 = require("./util/commonUtil");
7
6
  const EXTENSIONS = "js,json,xml,html,properties,change,appdescr_variant";
8
7
  class AppVariantManager {
9
8
  static async process(appVariantResources, projectNamespace, taskUtil) {
@@ -11,7 +10,6 @@ class AppVariantManager {
11
10
  for (const resource of appVariantResources) {
12
11
  this.omitFiles(resource, taskUtil);
13
12
  }
14
- this.patchMissingTextsNode(appVariantInfo?.manifest?.content ?? []);
15
13
  await this.renameChanges(appVariantResources, projectNamespace, appVariantInfo);
16
14
  return appVariantInfo;
17
15
  }
@@ -25,7 +23,7 @@ class AppVariantManager {
25
23
  for (const resource of appVariantResources) {
26
24
  const resourcePath = resource.getPath();
27
25
  const basename = path_1.posix.dirname(resourcePath);
28
- if (changesFolder === basename) {
26
+ if (basename.startsWith(changesFolder)) {
29
27
  changes.set(resourcePath, await resourceUtil_1.default.getString(resource));
30
28
  resourcesByPath.set(resourcePath, resource);
31
29
  }
@@ -73,22 +71,6 @@ class AppVariantManager {
73
71
  taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.OmitFromBuildResult, true);
74
72
  }
75
73
  }
76
- /**
77
- * We need to add texts properties to changes because not all have texts property.
78
- * Changes without texts property can causes issues in bundle.js
79
- * This is needed for now, and will be removed as soon as change merger in openUI5 is updated
80
- * @param changes
81
- */
82
- static patchMissingTextsNode(changes) {
83
- log.verbose("Adjusting appdescr_ui5_addNewModelEnhanceWith with module");
84
- for (const change of changes) {
85
- if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
86
- if (!change.texts && change.content?.bundleUrl) {
87
- change.texts = { i18n: change.content.bundleUrl };
88
- }
89
- }
90
- }
91
- }
92
74
  }
93
75
  exports.default = AppVariantManager;
94
76
  //# sourceMappingURL=appVariantManager.js.map
@@ -23,5 +23,6 @@ export default class BaseAppManager {
23
23
  private static fillAppVariantIdHierarchy;
24
24
  static validateProperty(value: string, property: string): void;
25
25
  static applyDescriptorChanges(baseAppManifest: any, appVariantInfo: IAppVariantInfo): Promise<void>;
26
+ private static adjustAddNewModelEnhanceWith;
26
27
  static writeToWorkspace(baseAppFiles: Map<string, string>, projectNamespace: string): any[];
27
28
  }
@@ -12,7 +12,7 @@ class BaseAppManager {
12
12
  static async process(baseAppFiles, appVariantInfo, options, processor) {
13
13
  const baseAppManifest = this.getBaseAppManifest(baseAppFiles);
14
14
  const { id, version } = this.getIdVersion(baseAppManifest.content);
15
- const renamedBaseAppFiles = (0, commonUtil_1.renameResources)(baseAppFiles, appVariantInfo.reference, appVariantInfo.id);
15
+ const renamedBaseAppFiles = (0, commonUtil_2.renameResources)(baseAppFiles, appVariantInfo.reference, appVariantInfo.id);
16
16
  const { filepath, content } = this.getBaseAppManifest(renamedBaseAppFiles);
17
17
  await processor.updateLandscapeSpecificContent(content, renamedBaseAppFiles);
18
18
  this.fillAppVariantIdHierarchy(processor, id, version, content);
@@ -56,7 +56,7 @@ class BaseAppManager {
56
56
  return i18nNode["bundleName"].replace(sapAppId, "").replaceAll(".", "/").substring(1);
57
57
  }
58
58
  static extractI18NFromBundleUrl(i18nNode) {
59
- return (0, commonUtil_2.removePropertiesExtension)(i18nNode["bundleUrl"]);
59
+ return (0, commonUtil_1.removePropertiesExtension)(i18nNode["bundleUrl"]);
60
60
  }
61
61
  static getBaseAppManifest(baseAppFiles) {
62
62
  let filepath = [...baseAppFiles.keys()].find(filepath => filepath.endsWith("manifest.json"));
@@ -94,14 +94,31 @@ class BaseAppManager {
94
94
  ...manifest.content,
95
95
  ...appVariantInfo.manifestChanges
96
96
  ];
97
- if (manifest.layer) {
98
- allChanges.forEach(item => item.layer = manifest.layer);
97
+ const changesContent = new Array();
98
+ const i18nBundleName = (0, commonUtil_1.dotToUnderscore)(appVariantInfo.id);
99
+ for (const change of structuredClone(allChanges)) {
100
+ if (manifest.layer) {
101
+ change.layer = manifest.layer;
102
+ }
103
+ this.adjustAddNewModelEnhanceWith(change, i18nBundleName);
104
+ changesContent.push(new Change(change));
99
105
  }
100
- const changesContent = allChanges.map(change => new Change(change));
101
106
  if (changesContent.length > 0) {
102
107
  await Applier.applyChanges(baseAppManifest, changesContent, strategy);
103
108
  }
104
109
  }
110
+ static adjustAddNewModelEnhanceWith(change, i18nBundleName) {
111
+ if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
112
+ if (change.texts == null) {
113
+ // We need to add texts properties to changes because not all
114
+ // have texts property. Changes without texts property can
115
+ // causes issues in bundle.js This is needed for now, and will
116
+ // be removed as soon as change merger in openUI5 is updated
117
+ change.texts = { i18n: change.content?.bundleUrl || "i18n/i18n.properties" };
118
+ }
119
+ change.texts.i18n = i18nBundleName + "/" + change.texts.i18n;
120
+ }
121
+ }
105
122
  static writeToWorkspace(baseAppFiles, projectNamespace) {
106
123
  const IGNORE_FILES = [
107
124
  "/manifest-bundle.zip",
@@ -1,20 +1,21 @@
1
1
  import { IDiffProperty, IJsonContent } from "./util/jsonDiffUtil";
2
+ import Language from "./model/language";
2
3
  export declare class PropertyValue {
3
4
  value: string;
4
5
  isReference: boolean;
5
6
  qualifier: string;
6
- language: string;
7
+ language: Language;
7
8
  private static OLD;
8
9
  private static NEW;
9
10
  private constructor();
10
11
  get isOld(): boolean;
11
12
  set(diff: any, references: Map<string, string>): void;
12
- static oldFrom(language: string, value?: string): PropertyValue;
13
- static newFrom(language: string, value?: string): PropertyValue;
13
+ static oldFrom(language: Language, value?: string): PropertyValue;
14
+ static newFrom(language: Language, value?: string): PropertyValue;
14
15
  }
15
16
  export declare class I18nFileContent {
16
17
  private properties;
17
- constructor(languages: string[]);
18
+ constructor(languages: Language[]);
18
19
  add(prop: PropertyValue, key: string): void;
19
20
  private initKeyValuesForOtherLanguages;
20
21
  hasTranslations(): boolean;
@@ -27,15 +28,15 @@ export default class I18nManager {
27
28
  private references;
28
29
  private existingKeys;
29
30
  private i18nFileContent;
30
- constructor(modelName: string, appVariantId: string, languages: string[]);
31
- processDiff(properties: Set<IDiffProperty>, previousLanguage: string, currentLanguage: string): void;
31
+ constructor(modelName: string, appVariantId: string, languages: Language[]);
32
+ processDiff(properties: Set<IDiffProperty>, previousLanguage: Language, currentLanguage: Language): void;
32
33
  createFiles(i18nPathName: string): Map<string, string>;
33
- populateTranslations(annotationJsons: Map<string, any>): IJsonContent;
34
- populate(annotationJsons: [string, any][], defaultAnnotation: IJsonContent): {
35
- language: string;
34
+ populateTranslations(annotationJsons: Map<Language, any>): IJsonContent;
35
+ populate(annotationJsons: [Language, any][], defaultAnnotation: IJsonContent): {
36
+ language: Language;
36
37
  json: any;
37
38
  };
38
- static extractDefaultLanguageAnnotation(annotationJsons: Map<string, any>): IJsonContent;
39
+ static extractDefaultLanguageAnnotation(annotationJsons: Map<Language, any>): IJsonContent;
39
40
  private replaceWithModelReference;
40
41
  private createReference;
41
42
  getUniqueKeyForValue(value: string): string;
@@ -6,7 +6,6 @@ const annotationDiffStructureError_1 = require("./model/annotationDiffStructureE
6
6
  const posix_1 = require("path/posix"); // Ensure standardized dir separators to ensure Windows compatibility
7
7
  // To generate keys, english language is more common, so compare all other
8
8
  // languages with it
9
- const DEFAULT_LANGUAGES = ["", "EN", "EN_US", "EN_GB"];
10
9
  class PropertyValue {
11
10
  constructor(qualifier, language, value) {
12
11
  this.isReference = false;
@@ -71,8 +70,8 @@ class I18nFileContent {
71
70
  if (this.hasTranslations()) {
72
71
  this.properties.forEach((i18nLines, language) => {
73
72
  let filename = "i18n";
74
- if (language) {
75
- filename += "_" + language.toLowerCase();
73
+ if (language.i18n) {
74
+ filename += "_" + language.i18n;
76
75
  }
77
76
  const filepath = (0, posix_1.join)(i18nPathName, filename + ".properties");
78
77
  files.set(filepath, [...i18nLines].map(([key, value]) => `${key}=${value}`).join("\n"));
@@ -143,7 +142,7 @@ class I18nManager {
143
142
  }
144
143
  catch (error) {
145
144
  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}`);
145
+ throw new Error(`The structure of the oData annotation xml of language '${p.language.sap}' is different from xml of language '${c.language.sap}' near element: ${error.message}`);
147
146
  }
148
147
  throw error;
149
148
  }
@@ -151,9 +150,8 @@ class I18nManager {
151
150
  }
152
151
  static extractDefaultLanguageAnnotation(annotationJsons) {
153
152
  let json = null;
154
- for (const language of DEFAULT_LANGUAGES) {
155
- json = annotationJsons.get(language);
156
- if (json != null) {
153
+ for (const [language, json] of annotationJsons) {
154
+ if (language.isDefault) {
157
155
  annotationJsons.delete(language);
158
156
  return { json, language };
159
157
  }
@@ -163,18 +161,20 @@ class I18nManager {
163
161
  annotationJsons.delete(language);
164
162
  return { json, language };
165
163
  }
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));
164
+ replaceWithModelReference({ object, property, type }, propertyValues) {
165
+ if (type === jsonDiffUtil_1.DiffTypeEnum.DELTA) {
166
+ const diff = object[property];
167
+ this.initPropertyValues(diff, propertyValues);
168
+ // If there are already generated key, like on step 3. above comment, we
169
+ // take it (from __old), so we don't need to generate new
170
+ const propReference = propertyValues.find(prop => prop.isReference);
171
+ let reference = propReference?.value ?? this.createReference(diff.__old);
172
+ object[property] = reference;
173
+ // Other values, which are not references, are extracted to .properties
174
+ const key = this.references.get(reference);
175
+ if (key) {
176
+ propertyValues.filter(prop => !prop.isReference).forEach(prop => this.i18nFileContent.add(prop, key));
177
+ }
178
178
  }
179
179
  }
180
180
  createReference(value) {
package/dist/index.js CHANGED
@@ -5,12 +5,14 @@ const appVariantManager_1 = require("./appVariantManager");
5
5
  const baseAppManager_1 = require("./baseAppManager");
6
6
  const processor_1 = require("./processors/processor");
7
7
  const i18nMerger_1 = require("./util/i18nMerger");
8
+ const commonUtil_1 = require("./util/commonUtil");
8
9
  /**
9
10
  * Creates an appVariant bundle from the provided resources.
10
11
  */
11
12
  module.exports = ({ workspace, options, taskUtil }) => {
12
13
  dotenv.config();
13
14
  async function process(workspace, taskUtil) {
15
+ await (0, commonUtil_1.logBuilderVersion)();
14
16
  const processor = (0, processor_1.determineProcessor)(options.configuration);
15
17
  const appVariantResources = await appVariantManager_1.default.getAppVariantResources(workspace);
16
18
  const appVariantInfo = await appVariantManager_1.default.process(appVariantResources, options.projectNamespace, taskUtil);
@@ -0,0 +1,13 @@
1
+ export default class Language {
2
+ sap: string;
3
+ i18n: string;
4
+ isDefault: boolean;
5
+ constructor(sap: string, i18n: string);
6
+ /**
7
+ * Create a language array from languages in configuration and default language.
8
+ * @param languages Typically an array of objects. Probably could be undefined.
9
+ * @returns An array of type Language, where the default language is placed first,
10
+ * followed by the passed config languages.
11
+ */
12
+ static create(languages: any[] | undefined): Language[];
13
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Language {
4
+ constructor(sap, i18n) {
5
+ this.sap = sap;
6
+ this.i18n = i18n;
7
+ this.isDefault = sap === "";
8
+ }
9
+ /**
10
+ * Create a language array from languages in configuration and default language.
11
+ * @param languages Typically an array of objects. Probably could be undefined.
12
+ * @returns An array of type Language, where the default language is placed first,
13
+ * followed by the passed config languages.
14
+ */
15
+ static create(languages) {
16
+ const defaultLanguage = new Language("", "");
17
+ let configLanguages = [];
18
+ if (languages !== undefined) {
19
+ configLanguages = languages.map(item => {
20
+ if (typeof item === 'string') {
21
+ // For legacy language format support which is just a string and doesn't contain i18n
22
+ return new Language(item, item.toLowerCase());
23
+ }
24
+ else if (item.sap !== undefined && item.i18n !== undefined) {
25
+ return new Language(item.sap, item.i18n);
26
+ }
27
+ else {
28
+ throw new Error("Can not parse languages from ui5.yaml configuration. Please use the 'AdaptationProject: Create wizard' to generate the project.");
29
+ }
30
+ });
31
+ }
32
+ return [defaultLanguage, ...configLanguages];
33
+ }
34
+ ;
35
+ }
36
+ exports.default = Language;
37
+ //# sourceMappingURL=language.js.map
@@ -9,7 +9,7 @@ export interface IConfiguration {
9
9
  destination?: string;
10
10
  credentials?: IAuth;
11
11
  type?: "cf" | "abap";
12
- languages?: string[];
12
+ languages?: any[] | undefined;
13
13
  enableAnnotationCache?: boolean;
14
14
  }
15
15
  export interface IProjectOptions {