@ui5/task-adaptation 1.5.1 → 1.5.2-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/annotationManager.d.ts +1 -2
  3. package/dist/annotationManager.js +8 -13
  4. package/dist/appVariantManager.d.ts +15 -2
  5. package/dist/appVariantManager.js +46 -27
  6. package/dist/baseAppManager.d.ts +9 -1
  7. package/dist/baseAppManager.js +57 -18
  8. package/dist/bundle.js +97 -59
  9. package/dist/index.js +33 -2
  10. package/dist/model/configuration.d.ts +1 -0
  11. package/dist/processors/abapProcessor.d.ts +1 -1
  12. package/dist/processors/abapProcessor.js +3 -2
  13. package/dist/processors/cfProcessor.d.ts +3 -1
  14. package/dist/processors/cfProcessor.js +70 -9
  15. package/dist/processors/processor.d.ts +1 -1
  16. package/dist/util/cfUtil.d.ts +47 -0
  17. package/dist/util/cfUtil.js +121 -0
  18. package/dist/util/commonUtil.d.ts +1 -2
  19. package/dist/util/commonUtil.js +9 -40
  20. package/dist/util/filesUtil.d.ts +16 -0
  21. package/dist/util/filesUtil.js +83 -0
  22. package/dist/util/i18nMerger.js +2 -2
  23. package/dist/util/movingHandler/fileMoveHandler.d.ts +8 -0
  24. package/dist/util/movingHandler/fileMoveHandler.js +77 -0
  25. package/dist/util/renamingHandlers/manifestRenamingHandler.d.ts +6 -0
  26. package/dist/util/renamingHandlers/manifestRenamingHandler.js +20 -0
  27. package/dist/util/renamingHandlers/renamingHandler.d.ts +4 -0
  28. package/dist/util/renamingHandlers/renamingHandler.js +2 -0
  29. package/dist/util/renamingUtil.d.ts +3 -0
  30. package/dist/util/renamingUtil.js +111 -0
  31. package/package.json +8 -4
  32. package/scripts/publish.ts +256 -0
  33. package/scripts/rollup/overrides/sap/base/config.js +52 -14
  34. package/scripts/rollup.ts +1 -2
  35. package/scripts/test-integration-prep.sh +4 -0
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.5.1...HEAD).
5
+ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task-adaptation/compare/v1.5.2-rc.1...HEAD).
6
+
7
+ <a name="v1.5.2-rc.1"></a>
8
+ ## [v1.5.2-rc.1] - 2025-08-22
9
+
10
+ <a name="v1.5.2-rc.0"></a>
11
+ ## [v1.5.2-rc.0] - 2025-08-19
6
12
 
7
13
  <a name="v1.5.1"></a>
8
14
  ## [v1.5.1] - 2025-08-06
@@ -119,6 +125,8 @@ A list of unreleased changes can be found [here](https://github.com/SAP/ui5-task
119
125
  <a name="v1.0.0"></a>
120
126
  ## v1.0.0 - 2020-12-09
121
127
 
128
+ [v1.5.2-rc.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.2-rc.0...v1.5.2-rc.1
129
+ [v1.5.2-rc.0]: https://github.com/SAP/ui5-task-adaptation/compare/v1.5.1...v1.5.2-rc.0
122
130
  [v1.5.1]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.3...v1.5.1
123
131
  [v1.4.3]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.2...v1.4.3
124
132
  [v1.4.2]: https://github.com/SAP/ui5-task-adaptation/compare/v1.4.0...v1.4.2
@@ -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(renamedBaseAppManifest: any, languages: Language[]): 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,31 +13,26 @@ export default class AnnotationManager {
13
13
  this.abapRepoManager = abapRepoManager;
14
14
  }
15
15
  ANNOTATIONS_FOLDER = "annotations";
16
- async process(renamedBaseAppManifest, languages) {
17
- const { id } = renamedBaseAppManifest["sap.app"];
18
- const normalisedId = this.normalizeAppVariantId(id);
16
+ async process(baseAppManifest, languages, appVariantId, prefix) {
19
17
  //TODO: switch to this after resolving @i18n custom model
20
18
  const modelName = I18N_DEFAULT_MODEL_NAME; //`i18n_a9n_${normalisedId}`;
21
- const i18nPathName = path.join(I18N_DEFAULT_PATH, normalisedId);
22
- const i18nManager = new I18nManager(modelName, id, languages);
19
+ const i18nPathName = path.join(prefix, I18N_DEFAULT_PATH);
20
+ const i18nManager = new I18nManager(modelName, appVariantId, languages);
23
21
  const serviceRequestor = new ServiceRequestor(this.configuration, this.abapRepoManager);
24
22
  const dataSourceManager = new DataSourceManager();
25
- dataSourceManager.addDataSources(renamedBaseAppManifest["sap.app"]?.dataSources);
23
+ dataSourceManager.addDataSources(baseAppManifest["sap.app"]?.dataSources);
26
24
  const annotationFiles = await dataSourceManager.createAnnotationFiles(languages, i18nManager, serviceRequestor);
27
25
  const i18nFiles = i18nManager.createFiles(i18nPathName);
28
26
  if (i18nManager.hasTranslations()) {
29
- this.updateManifestModel(renamedBaseAppManifest, modelName, i18nPathName);
27
+ this.updateManifestModel(baseAppManifest, modelName, i18nPathName);
30
28
  }
31
29
  return new Map([...annotationFiles, ...i18nFiles]);
32
30
  }
33
- normalizeAppVariantId(id, replaceWith = "") {
34
- return id.replace(/[.\W]+/gi, replaceWith);
35
- }
36
- updateManifestModel(renamedBaseAppManifest, modelName, i18nPathName) {
31
+ updateManifestModel(baseAppManifest, modelName, i18nPathName) {
37
32
  const uri = `${i18nPathName}/i18n.properties`;
38
- this.enhanceManifestModel(renamedBaseAppManifest, modelName, uri);
33
+ this.enhanceManifestModel(baseAppManifest, modelName, uri);
39
34
  //TODO: switch to this after resolving @i18n custom model
40
- //this.createManifestModel(renamedBaseAppManifest, modelName, uri);
35
+ //this.createManifestModel(baseAppManifest, modelName, uri);
41
36
  }
42
37
  createManifestModel(manifest, modelName, uri) {
43
38
  let sapui5 = manifest[SAPUI5] == null ? manifest[SAPUI5] = {} : manifest[SAPUI5];
@@ -7,13 +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();
13
- getProcessedFiles(): Map<string, string>;
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>;
14
22
  getProcessedManifestChanges(): IChange[];
15
23
  private validateManifest;
16
24
  private updateRelativePaths;
17
- private isManifestChange;
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
+ */
18
31
  omitDeletedResources(files: ReadonlyMap<string, string>, projectNamespace: string, taskUtil: TaskUtil): void;
19
32
  }
@@ -1,9 +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
- import { rename } from "./util/commonUtil.js";
4
- const CHANGES_DIR = "changes/";
5
+ import { moveFile, moveFiles } from "./util/movingHandler/fileMoveHandler.js";
5
6
  const CHANGES_EXT = ".change";
6
- const MANIFEST_CHANGE = "appdescr_";
7
7
  export default class AppVariant {
8
8
  files;
9
9
  resources;
@@ -11,6 +11,9 @@ export default class AppVariant {
11
11
  reference;
12
12
  layer;
13
13
  content;
14
+ prefix = "";
15
+ movedFiles = new Map();
16
+ renaming = new Map();
14
17
  static async fromWorkspace(workspace, projectNamespace) {
15
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";
16
19
  const resources = await workspace.byGlob(`/**/*.{${EXTENSIONS_TO_PROCESS}}`);
@@ -30,30 +33,42 @@ export default class AppVariant {
30
33
  this.id = id;
31
34
  this.layer = layer;
32
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);
33
40
  }
34
41
  getProcessedFiles() {
35
- const files = new Map();
36
- this.files.forEach((content, filename) => {
37
- if (filename.startsWith(CHANGES_DIR)) {
38
- if (!this.isManifestChange(filename, content)) {
39
- files.set(filename, rename(content, this.reference, this.id));
40
- }
41
- }
42
- else if (filename !== "manifest.appdescr_variant") {
43
- files.set(filename, content);
44
- }
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));
45
57
  });
46
- return files;
58
+ return renaming;
47
59
  }
60
+ ;
48
61
  getProcessedManifestChanges() {
49
- // Order is important: apply manifest.json changes first, then *.change
50
- // files. UI5 does the same.
62
+ // Order: manifest changes first, then *.change files
51
63
  const manifestChanges = structuredClone(this.content) ?? [];
52
64
  this.files.forEach((content, filename) => {
53
- if (this.isManifestChange(filename, content)) {
54
- const change = JSON.parse(rename(content, this.reference, this.id));
55
- this.updateRelativePaths(change, filename);
56
- manifestChanges.push(change);
65
+ if (filename.endsWith(CHANGES_EXT)) {
66
+ const change = JSON.parse(content);
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
+ }
57
72
  }
58
73
  });
59
74
  if (this.layer) {
@@ -77,13 +92,12 @@ export default class AppVariant {
77
92
  }
78
93
  }
79
94
  }
80
- isManifestChange(filename, content) {
81
- if (filename.endsWith(CHANGES_EXT)) {
82
- const change = JSON.parse(content);
83
- return change.changeType?.startsWith(MANIFEST_CHANGE);
84
- }
85
- return false;
86
- }
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
+ */
87
101
  omitDeletedResources(files, projectNamespace, taskUtil) {
88
102
  if (!this.resources) {
89
103
  return;
@@ -92,6 +106,11 @@ export default class AppVariant {
92
106
  const relativePath = ResourceUtil.relativeToRoot(resource.getPath(), projectNamespace);
93
107
  if (!files.has(relativePath)) {
94
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
+ }
95
114
  }
96
115
  }
97
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,14 +1,43 @@
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
- import { renameResources } from "./util/commonUtil.js";
6
5
  const log = getLogger("@ui5/task-adaptation::BaseAppManager");
7
6
  const IGNORE_FILES = [
8
7
  "manifest-bundle.zip",
9
8
  "Component-preload.js",
10
9
  "sap-ui-cachebuster-info.json"
11
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
+ }
12
41
  export default class BaseApp {
13
42
  id;
14
43
  version;
@@ -18,7 +47,7 @@ export default class BaseApp {
18
47
  return new BaseApp(files);
19
48
  }
20
49
  constructor(files) {
21
- this.files = new Map([...files].filter(([filename]) => !IGNORE_FILES.includes(filename)));
50
+ this.files = preProcessFiles(files);
22
51
  const manifestString = files.get("manifest.json");
23
52
  if (!manifestString) {
24
53
  throw new Error("Original application should have manifest.json in root folder");
@@ -31,15 +60,25 @@ export default class BaseApp {
31
60
  this.i18nPath = this.extractI18nPathFromManifest(this.id, manifest["sap.app"]?.i18n);
32
61
  }
33
62
  async adapt(appVariant, processor) {
34
- const files = renameResources(this.files, appVariant.reference, appVariant.id);
63
+ const files = new Map(this.files);
35
64
  const manifest = JSON.parse(files.get("manifest.json"));
36
- await processor.updateLandscapeSpecificContent(manifest, files);
37
- 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);
38
69
  this.updateAdaptationProperties(manifest);
39
70
  await this.applyDescriptorChanges(manifest, appVariant);
40
71
  files.set("manifest.json", JSON.stringify(manifest));
41
72
  return files;
42
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
+ }
43
82
  updateAdaptationProperties(content) {
44
83
  if (content["sap.fiori"]?.cloudDevAdaptationStatus) {
45
84
  delete content["sap.fiori"].cloudDevAdaptationStatus;
@@ -63,17 +102,6 @@ export default class BaseApp {
63
102
  }
64
103
  return "i18n/i18n";
65
104
  }
66
- fillAppVariantIdHierarchy(processor, id, version, baseAppManifest) {
67
- log.verbose("Filling up app variant hierarchy in manifest.json");
68
- if (baseAppManifest["sap.ui5"] == null) {
69
- baseAppManifest["sap.ui5"] = {};
70
- }
71
- if (baseAppManifest["sap.ui5"].appVariantIdHierarchy == null) {
72
- baseAppManifest["sap.ui5"].appVariantIdHierarchy = [];
73
- }
74
- const appVariantIdHierarchyItem = processor.createAppVariantHierarchyItem(id, version);
75
- baseAppManifest["sap.ui5"].appVariantIdHierarchy.unshift(appVariantIdHierarchyItem);
76
- }
77
105
  VALIDATION_RULES = new Map([["sap.app/id", (value) => {
78
106
  if (!value.includes(".")) {
79
107
  throw new Error(`The original application id '${value}' should consist of multiple segments split by dot, e.g.: original.id`);
@@ -91,7 +119,7 @@ export default class BaseApp {
91
119
  async applyDescriptorChanges(baseAppManifest, appVariant) {
92
120
  log.verbose("Applying appVariant changes");
93
121
  const changesContent = new Array();
94
- const i18nBundleName = dotToUnderscore(appVariant.id);
122
+ const i18nBundleName = appVariant.prefix;
95
123
  for (const change of appVariant.getProcessedManifestChanges()) {
96
124
  changesContent.push(new AppDescriptorChange(change));
97
125
  this.adjustAddNewModelEnhanceWith(change, i18nBundleName);
@@ -101,6 +129,17 @@ export default class BaseApp {
101
129
  await Applier.applyChanges(baseAppManifest, changesContent, strategy);
102
130
  }
103
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
+ }
104
143
  adjustAddNewModelEnhanceWith(change, i18nBundleName) {
105
144
  if (change.changeType === "appdescr_ui5_addNewModelEnhanceWith") {
106
145
  if (change.texts == null) {