@ui5/task-adaptation 1.5.0 → 1.5.2-rc.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.
package/CHANGELOG.md CHANGED
@@ -2,10 +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.5.0...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.5.2-rc.0...HEAD).
6
6
 
7
- <a name="v1.5.0"></a>
8
- ## [v1.5.0] - 2025-07-17
7
+ <a name="v1.5.2-rc.0"></a>
8
+ ## [v1.5.2-rc.0] - 2025-08-19
9
+
10
+ <a name="v1.5.1"></a>
11
+ ## [v1.5.1] - 2025-08-06
9
12
 
10
13
  <a name="v1.4.3"></a>
11
14
  ## [v1.4.3] - 2025-04-17
@@ -119,7 +122,8 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
119
122
  <a name="v1.0.0"></a>
120
123
  ## v1.0.0 - 2020-12-09
121
124
 
122
- [v1.5.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.3...v1.5.0
125
+ [v1.5.2-rc.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.1...v1.5.2-rc.0
126
+ [v1.5.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.3...v1.5.1
123
127
  [v1.4.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.2...v1.4.3
124
128
  [v1.4.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.0...v1.4.2
125
129
  [v1.4.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.3.3...v1.4.0
@@ -10,8 +10,7 @@ export default class AnnotationManager {
10
10
  private configuration;
11
11
  constructor(configuration: IConfiguration, abapRepoManager: AbapRepoManager);
12
12
  ANNOTATIONS_FOLDER: string;
13
- process(baseAppManifest: any, languages: Language[], id: string): Promise<Map<string, string>>;
14
- private normalizeAppVariantId;
13
+ process(baseAppManifest: any, languages: Language[], appVariantId: string, prefix: string): Promise<Map<string, string>>;
15
14
  private updateManifestModel;
16
15
  private createManifestModel;
17
16
  private enhanceManifestModel;
@@ -13,12 +13,11 @@ export default class AnnotationManager {
13
13
  this.abapRepoManager = abapRepoManager;
14
14
  }
15
15
  ANNOTATIONS_FOLDER = "annotations";
16
- async process(baseAppManifest, languages, id) {
17
- const normalisedId = this.normalizeAppVariantId(id);
16
+ async process(baseAppManifest, languages, appVariantId, prefix) {
18
17
  //TODO: switch to this after resolving @i18n custom model
19
18
  const modelName = I18N_DEFAULT_MODEL_NAME; //`i18n_a9n_${normalisedId}`;
20
- const i18nPathName = path.join(I18N_DEFAULT_PATH, normalisedId);
21
- const i18nManager = new I18nManager(modelName, id, languages);
19
+ const i18nPathName = path.join(prefix, I18N_DEFAULT_PATH);
20
+ const i18nManager = new I18nManager(modelName, appVariantId, languages);
22
21
  const serviceRequestor = new ServiceRequestor(this.configuration, this.abapRepoManager);
23
22
  const dataSourceManager = new DataSourceManager();
24
23
  dataSourceManager.addDataSources(baseAppManifest["sap.app"]?.dataSources);
@@ -29,14 +28,11 @@ export default class AnnotationManager {
29
28
  }
30
29
  return new Map([...annotationFiles, ...i18nFiles]);
31
30
  }
32
- normalizeAppVariantId(id, replaceWith = "") {
33
- return id.replace(/[.\W]+/gi, replaceWith);
34
- }
35
31
  updateManifestModel(baseAppManifest, modelName, i18nPathName) {
36
32
  const uri = `${i18nPathName}/i18n.properties`;
37
33
  this.enhanceManifestModel(baseAppManifest, modelName, uri);
38
34
  //TODO: switch to this after resolving @i18n custom model
39
- //this.createManifestModel(renamedBaseAppManifest, modelName, uri);
35
+ //this.createManifestModel(baseAppManifest, modelName, uri);
40
36
  }
41
37
  createManifestModel(manifest, modelName, uri) {
42
38
  let sapui5 = manifest[SAPUI5] == null ? manifest[SAPUI5] = {} : manifest[SAPUI5];
@@ -7,11 +7,26 @@ export default class AppVariant {
7
7
  readonly reference: string;
8
8
  readonly layer: any;
9
9
  readonly content: any;
10
+ prefix: string;
11
+ private movedFiles;
12
+ private renaming;
10
13
  static fromWorkspace(workspace: IWorkspace, projectNamespace: string): Promise<AppVariant>;
11
14
  static fromFiles(files: ReadonlyMap<string, string>): AppVariant;
12
15
  private constructor();
16
+ getProcessedFiles(): ReadonlyMap<string, string>;
17
+ /**
18
+ * Since we moved files, we need to update paths where they were referenced.
19
+ * To do this we use renameMap function along with renaming ids.
20
+ */
21
+ getRenamingForMovedFiles(): Map<string, string>;
13
22
  getProcessedManifestChanges(): IChange[];
14
23
  private validateManifest;
15
24
  private updateRelativePaths;
25
+ /**
26
+ * 3p. We not only omit files, which were moved or deleted from the resulted
27
+ * file set, but also update existing adaptation project resources with
28
+ * renamed content, otherwise flexibility-bundle will contain not renamed
29
+ * content of files.
30
+ */
16
31
  omitDeletedResources(files: ReadonlyMap<string, string>, projectNamespace: string, taskUtil: TaskUtil): void;
17
32
  }
@@ -1,6 +1,9 @@
1
+ import { dotToUnderscore, isManifestChange } from "./util/commonUtil.js";
2
+ import FilesUtil from "./util/filesUtil.js";
1
3
  import ResourceUtil from "./util/resourceUtil.js";
2
4
  import { posix as path } from "path";
3
- const MANIFEST_CHANGES_DIR = "changes/manifest/";
5
+ import { moveFile, moveFiles } from "./util/movingHandler/fileMoveHandler.js";
6
+ const CHANGES_EXT = ".change";
4
7
  export default class AppVariant {
5
8
  files;
6
9
  resources;
@@ -8,6 +11,9 @@ export default class AppVariant {
8
11
  reference;
9
12
  layer;
10
13
  content;
14
+ prefix = "";
15
+ movedFiles = new Map();
16
+ renaming = new Map();
11
17
  static async fromWorkspace(workspace, projectNamespace) {
12
18
  const EXTENSIONS_TO_PROCESS = "js,json,xml,html,properties,change,appdescr_variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change,variant,fioriversion,codeChange,xmlViewChange,context";
13
19
  const resources = await workspace.byGlob(`/**/*.{${EXTENSIONS_TO_PROCESS}}`);
@@ -27,16 +33,42 @@ export default class AppVariant {
27
33
  this.id = id;
28
34
  this.layer = layer;
29
35
  this.content = content;
36
+ // Prefix is a subfolder for the app variant to store js, fragments,
37
+ // annotations and i18n files. It can be anything, but for convenience
38
+ // it is an app variant id.
39
+ this.prefix = dotToUnderscore(this.id);
30
40
  }
41
+ getProcessedFiles() {
42
+ const { files, renamingPaths } = moveFiles(this.files, this.prefix, this.id);
43
+ // Directly rename files that with new paths, this ensures no conflict in further renaming
44
+ // In later remaming it's not possible to find correct prefix of moved files
45
+ return FilesUtil.rename(files, renamingPaths);
46
+ }
47
+ ;
48
+ /**
49
+ * Since we moved files, we need to update paths where they were referenced.
50
+ * To do this we use renameMap function along with renaming ids.
51
+ */
52
+ getRenamingForMovedFiles() {
53
+ const renaming = new Map();
54
+ const slashToDot = (str) => str.replaceAll("\/", ".");
55
+ this.renaming.forEach((newPath, oldPath) => {
56
+ renaming.set(slashToDot(oldPath), slashToDot(newPath));
57
+ });
58
+ return renaming;
59
+ }
60
+ ;
31
61
  getProcessedManifestChanges() {
32
- // Order is important: apply manifest.json changes first, then *.change
33
- // files. UI5 does the same.
62
+ // Order: manifest changes first, then *.change files
34
63
  const manifestChanges = structuredClone(this.content) ?? [];
35
64
  this.files.forEach((content, filename) => {
36
- if (filename.startsWith(MANIFEST_CHANGES_DIR)) {
65
+ if (filename.endsWith(CHANGES_EXT)) {
37
66
  const change = JSON.parse(content);
38
- this.updateRelativePaths(change, filename);
39
- manifestChanges.push(change);
67
+ if (isManifestChange(filename, content)) {
68
+ const { newFilename } = moveFile(filename, content, this.prefix, this.id);
69
+ this.updateRelativePaths(change, newFilename);
70
+ manifestChanges.push(change);
71
+ }
40
72
  }
41
73
  });
42
74
  if (this.layer) {
@@ -60,6 +92,12 @@ export default class AppVariant {
60
92
  }
61
93
  }
62
94
  }
95
+ /**
96
+ * 3p. We not only omit files, which were moved or deleted from the resulted
97
+ * file set, but also update existing adaptation project resources with
98
+ * renamed content, otherwise flexibility-bundle will contain not renamed
99
+ * content of files.
100
+ */
63
101
  omitDeletedResources(files, projectNamespace, taskUtil) {
64
102
  if (!this.resources) {
65
103
  return;
@@ -68,6 +106,11 @@ export default class AppVariant {
68
106
  const relativePath = ResourceUtil.relativeToRoot(resource.getPath(), projectNamespace);
69
107
  if (!files.has(relativePath)) {
70
108
  taskUtil.setTag(resource, taskUtil.STANDARD_TAGS.OmitFromBuildResult, true);
109
+ if (this.movedFiles.has(relativePath)) {
110
+ const newPath = this.movedFiles.get(relativePath);
111
+ const renamedContent = files.get(newPath);
112
+ resource.setString(renamedContent);
113
+ }
71
114
  }
72
115
  }
73
116
  }
@@ -11,6 +11,13 @@ export interface IManifestIdVersion {
11
11
  export interface IManifestInfo extends IManifestIdVersion {
12
12
  i18nPath: string;
13
13
  }
14
+ /**
15
+ * Processes files to replace .js file content with corresponding -dbg.js
16
+ * content and remove -dbg.js
17
+ * @param files - Map of all files
18
+ * @returns Map with .js files replaced by -dbg.js content where applicable
19
+ */
20
+ export declare function preProcessFiles(files: ReadonlyMap<string, string>): Map<string, string>;
14
21
  export default class BaseApp {
15
22
  readonly id: string;
16
23
  readonly version: string;
@@ -19,11 +26,12 @@ export default class BaseApp {
19
26
  static fromFiles(files: ReadonlyMap<string, string>): BaseApp;
20
27
  private constructor();
21
28
  adapt(appVariant: AppVariant, processor: IProcessor): Promise<ReadonlyMap<string, string>>;
29
+ private updateComponentName;
22
30
  private updateAdaptationProperties;
23
31
  private extractI18nPathFromManifest;
24
- private fillAppVariantIdHierarchy;
25
32
  private VALIDATION_RULES;
26
33
  private validateProperty;
27
34
  private applyDescriptorChanges;
35
+ private fillAppVariantIdHierarchy;
28
36
  private adjustAddNewModelEnhanceWith;
29
37
  }
@@ -1,5 +1,5 @@
1
1
  import { AppDescriptorChange, Applier, RegistrationBuild } from "../dist/bundle.js";
2
- import { dotToUnderscore, trimExtension } from "./util/commonUtil.js";
2
+ import { trimExtension } from "./util/commonUtil.js";
3
3
  import BuildStrategy from "./buildStrategy.js";
4
4
  import { getLogger } from "@ui5/logger";
5
5
  const log = getLogger("@ui5/task-adaptation::BaseAppManager");
@@ -8,6 +8,36 @@ const IGNORE_FILES = [
8
8
  "Component-preload.js",
9
9
  "sap-ui-cachebuster-info.json"
10
10
  ];
11
+ /**
12
+ * Processes files to replace .js file content with corresponding -dbg.js
13
+ * content and remove -dbg.js
14
+ * @param files - Map of all files
15
+ * @returns Map with .js files replaced by -dbg.js content where applicable
16
+ */
17
+ export function preProcessFiles(files) {
18
+ const processedFiles = new Map(files);
19
+ // Find all -dbg.js files that have corresponding .js files
20
+ for (const [filename, content] of files) {
21
+ if (filename.endsWith("-dbg.js")) {
22
+ const correspondingJsFile = filename.replace("-dbg.js", ".js");
23
+ if (files.has(correspondingJsFile)) {
24
+ // Replace the .js file content with the -dbg.js content
25
+ processedFiles.set(correspondingJsFile, content);
26
+ processedFiles.delete(filename);
27
+ }
28
+ }
29
+ else if (filename.endsWith("-dbg.js.map")) {
30
+ const correspondingJsFile = filename.replace("-dbg.js.map", ".js");
31
+ if (files.has(correspondingJsFile)) {
32
+ processedFiles.delete(filename);
33
+ }
34
+ }
35
+ if (IGNORE_FILES.some(ignoredFile => ignoredFile === filename)) {
36
+ processedFiles.delete(filename);
37
+ }
38
+ }
39
+ return processedFiles;
40
+ }
11
41
  export default class BaseApp {
12
42
  id;
13
43
  version;
@@ -17,7 +47,7 @@ export default class BaseApp {
17
47
  return new BaseApp(files);
18
48
  }
19
49
  constructor(files) {
20
- this.files = new Map([...files].filter(([filename]) => !IGNORE_FILES.includes(filename)));
50
+ this.files = preProcessFiles(files);
21
51
  const manifestString = files.get("manifest.json");
22
52
  if (!manifestString) {
23
53
  throw new Error("Original application should have manifest.json in root folder");
@@ -32,13 +62,23 @@ export default class BaseApp {
32
62
  async adapt(appVariant, processor) {
33
63
  const files = new Map(this.files);
34
64
  const manifest = JSON.parse(files.get("manifest.json"));
35
- await processor.updateLandscapeSpecificContent(manifest, files, appVariant.id);
36
- this.fillAppVariantIdHierarchy(processor, this.id, this.version, manifest);
65
+ manifest["sap.app"].id = appVariant.id;
66
+ await processor.updateLandscapeSpecificContent(manifest, files, appVariant.id, appVariant.prefix);
67
+ this.updateComponentName(manifest, this.id);
68
+ this.fillAppVariantIdHierarchy(processor, appVariant.reference, this.version, manifest);
37
69
  this.updateAdaptationProperties(manifest);
38
70
  await this.applyDescriptorChanges(manifest, appVariant);
39
71
  files.set("manifest.json", JSON.stringify(manifest));
40
72
  return files;
41
73
  }
74
+ updateComponentName(manifest, id) {
75
+ if (manifest["sap.ui5"] == null) {
76
+ manifest["sap.ui5"] = {};
77
+ }
78
+ if (manifest["sap.ui5"].componentName == null) {
79
+ manifest["sap.ui5"].componentName = id;
80
+ }
81
+ }
42
82
  updateAdaptationProperties(content) {
43
83
  if (content["sap.fiori"]?.cloudDevAdaptationStatus) {
44
84
  delete content["sap.fiori"].cloudDevAdaptationStatus;
@@ -62,17 +102,6 @@ export default class BaseApp {
62
102
  }
63
103
  return "i18n/i18n";
64
104
  }
65
- fillAppVariantIdHierarchy(processor, id, version, baseAppManifest) {
66
- log.verbose("Filling up app variant hierarchy in manifest.json");
67
- if (baseAppManifest["sap.ui5"] == null) {
68
- baseAppManifest["sap.ui5"] = {};
69
- }
70
- if (baseAppManifest["sap.ui5"].appVariantIdHierarchy == null) {
71
- baseAppManifest["sap.ui5"].appVariantIdHierarchy = [];
72
- }
73
- const appVariantIdHierarchyItem = processor.createAppVariantHierarchyItem(id, version);
74
- baseAppManifest["sap.ui5"].appVariantIdHierarchy.unshift(appVariantIdHierarchyItem);
75
- }
76
105
  VALIDATION_RULES = new Map([["sap.app/id", (value) => {
77
106
  if (!value.includes(".")) {
78
107
  throw new Error(`The original application id '${value}' should consist of multiple segments split by dot, e.g.: original.id`);
@@ -90,7 +119,7 @@ export default class BaseApp {
90
119
  async applyDescriptorChanges(baseAppManifest, appVariant) {
91
120
  log.verbose("Applying appVariant changes");
92
121
  const changesContent = new Array();
93
- const i18nBundleName = dotToUnderscore(appVariant.id);
122
+ const i18nBundleName = appVariant.prefix;
94
123
  for (const change of appVariant.getProcessedManifestChanges()) {
95
124
  changesContent.push(new AppDescriptorChange(change));
96
125
  this.adjustAddNewModelEnhanceWith(change, i18nBundleName);
@@ -100,6 +129,17 @@ export default class BaseApp {
100
129
  await Applier.applyChanges(baseAppManifest, changesContent, strategy);
101
130
  }
102
131
  }
132
+ fillAppVariantIdHierarchy(processor, id, version, baseAppManifest) {
133
+ log.verbose("Filling up app variant hierarchy in manifest.json");
134
+ if (baseAppManifest["sap.ui5"] == null) {
135
+ baseAppManifest["sap.ui5"] = {};
136
+ }
137
+ if (baseAppManifest["sap.ui5"].appVariantIdHierarchy == null) {
138
+ baseAppManifest["sap.ui5"].appVariantIdHierarchy = [];
139
+ }
140
+ const appVariantIdHierarchyItem = processor.createAppVariantHierarchyItem(id, version);
141
+ baseAppManifest["sap.ui5"].appVariantIdHierarchy.unshift(appVariantIdHierarchyItem);
142
+ }
103
143
  adjustAddNewModelEnhanceWith(change, i18nBundleName) {
104
144
  if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
105
145
  if (change.texts == null) {