@sap-ux/fiori-migration-writer 0.0.0-stage → 0.0.2

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 (228) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +78 -2
  3. package/dist/BulkProjectMigrator.d.ts +56 -0
  4. package/dist/BulkProjectMigrator.js +162 -0
  5. package/dist/ProjectMigrator.d.ts +97 -0
  6. package/dist/ProjectMigrator.js +359 -0
  7. package/dist/adapters/index.d.ts +8 -0
  8. package/dist/adapters/index.js +8 -0
  9. package/dist/adapters/ui5-config-adapter.d.ts +62 -0
  10. package/dist/adapters/ui5-config-adapter.js +232 -0
  11. package/dist/adapters/ui5-config-helpers.d.ts +28 -0
  12. package/dist/adapters/ui5-config-helpers.js +85 -0
  13. package/dist/components/component-mapping.d.ts +14 -0
  14. package/dist/components/component-mapping.js +51 -0
  15. package/dist/components/extension.d.ts +10 -0
  16. package/dist/components/extension.js +61 -0
  17. package/dist/components/index.d.ts +3 -0
  18. package/dist/components/index.js +4 -0
  19. package/dist/config/backend-i18n.d.ts +30 -0
  20. package/dist/config/backend-i18n.js +52 -0
  21. package/dist/config/backend.d.ts +24 -0
  22. package/dist/config/backend.js +86 -0
  23. package/dist/config/flp/index.d.ts +4 -0
  24. package/dist/config/flp/index.js +5 -0
  25. package/dist/config/flp/intent-defaults.d.ts +15 -0
  26. package/dist/config/flp/intent-defaults.js +47 -0
  27. package/dist/config/flp/intent.d.ts +50 -0
  28. package/dist/config/flp/intent.js +82 -0
  29. package/dist/config/flp/sandbox.d.ts +25 -0
  30. package/dist/config/flp/sandbox.js +106 -0
  31. package/dist/config/index.d.ts +10 -0
  32. package/dist/config/index.js +11 -0
  33. package/dist/config/launch-config.d.ts +16 -0
  34. package/dist/config/launch-config.js +60 -0
  35. package/dist/config/manifest-update-helpers.d.ts +10 -0
  36. package/dist/config/manifest-update-helpers.js +88 -0
  37. package/dist/config/manifest-update.d.ts +18 -0
  38. package/dist/config/manifest-update.js +108 -0
  39. package/dist/config/manifest.d.ts +10 -0
  40. package/dist/config/manifest.js +31 -0
  41. package/dist/config/neoapp.d.ts +37 -0
  42. package/dist/config/neoapp.js +52 -0
  43. package/dist/config/package-json.d.ts +12 -0
  44. package/dist/config/package-json.js +131 -0
  45. package/dist/config/ui5-yaml.d.ts +85 -0
  46. package/dist/config/ui5-yaml.js +110 -0
  47. package/dist/data/index.d.ts +4 -0
  48. package/dist/data/index.js +5 -0
  49. package/dist/data/sap-libraries.d.ts +18 -0
  50. package/dist/data/sap-libraries.js +52 -0
  51. package/dist/data/ui5-version.d.ts +10 -0
  52. package/dist/data/ui5-version.js +35 -0
  53. package/dist/data/yaml.d.ts +29 -0
  54. package/dist/data/yaml.js +64 -0
  55. package/dist/files/file-system.d.ts +8 -0
  56. package/dist/files/file-system.js +15 -0
  57. package/dist/files/index.d.ts +4 -0
  58. package/dist/files/index.js +5 -0
  59. package/dist/files/project-files.d.ts +31 -0
  60. package/dist/files/project-files.js +137 -0
  61. package/dist/files/webapp.d.ts +21 -0
  62. package/dist/files/webapp.js +236 -0
  63. package/dist/i18n/i18n.json +20 -0
  64. package/dist/i18n.d.ts +18 -0
  65. package/dist/i18n.js +33 -0
  66. package/dist/index.d.ts +68 -0
  67. package/dist/index.js +82 -0
  68. package/dist/migration-process/configuration.d.ts +31 -0
  69. package/dist/migration-process/configuration.js +36 -0
  70. package/dist/migration-process/index.d.ts +6 -0
  71. package/dist/migration-process/index.js +7 -0
  72. package/dist/migration-process/legacy-helpers.d.ts +43 -0
  73. package/dist/migration-process/legacy-helpers.js +226 -0
  74. package/dist/migration-process/legacy.d.ts +17 -0
  75. package/dist/migration-process/legacy.js +310 -0
  76. package/dist/migration-process/migration-phases.d.ts +94 -0
  77. package/dist/migration-process/migration-phases.js +127 -0
  78. package/dist/migration-process/setup.d.ts +26 -0
  79. package/dist/migration-process/setup.js +54 -0
  80. package/dist/migration-process/validation.d.ts +33 -0
  81. package/dist/migration-process/validation.js +56 -0
  82. package/dist/migration-types.d.ts +558 -0
  83. package/dist/migration-types.js +55 -0
  84. package/dist/project/adaptation-project.d.ts +37 -0
  85. package/dist/project/adaptation-project.js +53 -0
  86. package/dist/project/index.d.ts +8 -0
  87. package/dist/project/index.js +9 -0
  88. package/dist/project/project-data.d.ts +79 -0
  89. package/dist/project/project-data.js +155 -0
  90. package/dist/project/project-detection.d.ts +9 -0
  91. package/dist/project/project-detection.js +35 -0
  92. package/dist/project/project-extension.d.ts +38 -0
  93. package/dist/project/project-extension.js +95 -0
  94. package/dist/project/project-info.d.ts +13 -0
  95. package/dist/project/project-info.js +33 -0
  96. package/dist/project/regular-project.d.ts +13 -0
  97. package/dist/project/regular-project.js +174 -0
  98. package/dist/project/reuse-library.d.ts +20 -0
  99. package/dist/project/reuse-library.js +35 -0
  100. package/dist/project-spec-types.d.ts +89 -0
  101. package/dist/project-spec-types.js +39 -0
  102. package/dist/template/application.d.ts +25 -0
  103. package/dist/template/application.js +95 -0
  104. package/dist/template/assembly.d.ts +24 -0
  105. package/dist/template/assembly.js +141 -0
  106. package/dist/template/base.d.ts +22 -0
  107. package/dist/template/base.js +64 -0
  108. package/dist/template/data.d.ts +78 -0
  109. package/dist/template/data.js +101 -0
  110. package/dist/template/details.d.ts +25 -0
  111. package/dist/template/details.js +105 -0
  112. package/dist/template/index.d.ts +8 -0
  113. package/dist/template/index.js +9 -0
  114. package/dist/template/template-helpers.d.ts +12 -0
  115. package/dist/template/template-helpers.js +40 -0
  116. package/dist/template/theme.d.ts +11 -0
  117. package/dist/template/theme.js +37 -0
  118. package/dist/template-types.d.ts +11 -0
  119. package/dist/template-types.js +23 -0
  120. package/dist/types/mem-fs-types.d.ts +60 -0
  121. package/dist/types/mem-fs-types.js +21 -0
  122. package/dist/types/project-folder.d.ts +36 -0
  123. package/dist/types/project-folder.js +32 -0
  124. package/dist/types.d.ts +4 -0
  125. package/dist/types.js +4 -0
  126. package/dist/utils/Project.d.ts +61 -0
  127. package/dist/utils/Project.js +385 -0
  128. package/dist/utils/UI5Theme.d.ts +32 -0
  129. package/dist/utils/UI5Theme.js +100 -0
  130. package/dist/utils/checkForMigration.d.ts +5 -0
  131. package/dist/utils/checkForMigration.js +55 -0
  132. package/dist/utils/common.d.ts +17 -0
  133. package/dist/utils/common.js +27 -0
  134. package/dist/utils/constants.d.ts +15 -0
  135. package/dist/utils/constants.js +38 -0
  136. package/dist/utils/file-access.d.ts +58 -0
  137. package/dist/utils/file-access.js +141 -0
  138. package/dist/utils/file-discovery.d.ts +65 -0
  139. package/dist/utils/file-discovery.js +252 -0
  140. package/dist/utils/file-system-utils.d.ts +43 -0
  141. package/dist/utils/file-system-utils.js +55 -0
  142. package/dist/utils/fs-adapter.d.ts +80 -0
  143. package/dist/utils/fs-adapter.js +149 -0
  144. package/dist/utils/index.d.ts +12 -0
  145. package/dist/utils/index.js +25 -0
  146. package/dist/utils/manifest-and-version-utils.d.ts +38 -0
  147. package/dist/utils/manifest-and-version-utils.js +74 -0
  148. package/dist/utils/migration-utils.d.ts +83 -0
  149. package/dist/utils/migration-utils.js +165 -0
  150. package/dist/utils/path-validation.d.ts +37 -0
  151. package/dist/utils/path-validation.js +109 -0
  152. package/dist/utils/project-access-adapters.d.ts +20 -0
  153. package/dist/utils/project-access-adapters.js +59 -0
  154. package/dist/utils/project-discovery.d.ts +20 -0
  155. package/dist/utils/project-discovery.js +106 -0
  156. package/dist/utils/project-readers/adaptation-project-utils.d.ts +20 -0
  157. package/dist/utils/project-readers/adaptation-project-utils.js +119 -0
  158. package/dist/utils/project-readers/backend-utils.d.ts +38 -0
  159. package/dist/utils/project-readers/backend-utils.js +95 -0
  160. package/dist/utils/project-readers/extension-project-utils.d.ts +30 -0
  161. package/dist/utils/project-readers/extension-project-utils.js +113 -0
  162. package/dist/utils/project-readers/index.d.ts +9 -0
  163. package/dist/utils/project-readers/index.js +9 -0
  164. package/dist/utils/project-readers/manifest-reader.d.ts +16 -0
  165. package/dist/utils/project-readers/manifest-reader.js +26 -0
  166. package/dist/utils/project-readers/manifest-utils.d.ts +62 -0
  167. package/dist/utils/project-readers/manifest-utils.js +253 -0
  168. package/dist/utils/project-readers/package-reader.d.ts +13 -0
  169. package/dist/utils/project-readers/package-reader.js +23 -0
  170. package/dist/utils/project-readers/reuse-lib-utils.d.ts +55 -0
  171. package/dist/utils/project-readers/reuse-lib-utils.js +113 -0
  172. package/dist/utils/project-readers/webapp-path-resolver.d.ts +11 -0
  173. package/dist/utils/project-readers/webapp-path-resolver.js +138 -0
  174. package/dist/utils/read-package-up-compat.d.ts +18 -0
  175. package/dist/utils/read-package-up-compat.js +18 -0
  176. package/dist/utils/service-detection.d.ts +13 -0
  177. package/dist/utils/service-detection.js +33 -0
  178. package/dist/utils/service.d.ts +7 -0
  179. package/dist/utils/service.js +71 -0
  180. package/dist/utils/template/index.d.ts +6 -0
  181. package/dist/utils/template/index.js +5 -0
  182. package/dist/utils/template/template-data.d.ts +14 -0
  183. package/dist/utils/template/template-data.js +19 -0
  184. package/dist/utils/template/template-paths.d.ts +26 -0
  185. package/dist/utils/template/template-paths.js +25 -0
  186. package/dist/utils/template/template-post-processors.d.ts +21 -0
  187. package/dist/utils/template/template-post-processors.js +40 -0
  188. package/dist/utils/template/template-renderer.d.ts +17 -0
  189. package/dist/utils/template/template-renderer.js +47 -0
  190. package/dist/utils/template-generators/file-handlers.d.ts +24 -0
  191. package/dist/utils/template-generators/file-handlers.js +182 -0
  192. package/dist/utils/template-generators/index.d.ts +2 -0
  193. package/dist/utils/template-generators/index.js +2 -0
  194. package/dist/utils/template-maps.d.ts +33 -0
  195. package/dist/utils/template-maps.js +144 -0
  196. package/dist/utils/validation-severity.d.ts +21 -0
  197. package/dist/utils/validation-severity.js +43 -0
  198. package/package.json +76 -3
  199. package/templates/adaptation-app-settings/package.json.tmpl +17 -0
  200. package/templates/adaptation-app-settings/ui5.yaml +18 -0
  201. package/templates/adaptation-app-settings/xs-app.json.tmpl +45 -0
  202. package/templates/app-settings/README.md +17 -0
  203. package/templates/app-settings/package.json.tmpl +26 -0
  204. package/templates/app-settings/static/gitignore.tmpl +10 -0
  205. package/templates/app-settings/ui5-local.yaml +44 -0
  206. package/templates/app-settings/ui5-mock.yaml +44 -0
  207. package/templates/app-settings/ui5.yaml +34 -0
  208. package/templates/app-settings/webapp/Component.js +7 -0
  209. package/templates/app-settings/webapp/localService/mockserver.js +125 -0
  210. package/templates/app-settings/webapp/test/changes_loader.js +39 -0
  211. package/templates/app-settings/webapp/test/changes_preview.js +189 -0
  212. package/templates/app-settings/webapp/test/flpSandbox.html +87 -0
  213. package/templates/app-settings/webapp/test/flpSandboxMockServer.html +88 -0
  214. package/templates/app-settings/webapp/test/locate-reuse-libs.js +241 -0
  215. package/templates/app-settings/webapp/v2_index.html +30 -0
  216. package/templates/app-settings/webapp/v4_index.html +29 -0
  217. package/templates/app-settings-v4/webapp/test/flpSandbox.html +85 -0
  218. package/templates/app-to-app/fioriSandboxConfig.json +9 -0
  219. package/templates/library-settings/gitignore.tmpl +10 -0
  220. package/templates/library-settings/package.json.tmpl +16 -0
  221. package/templates/library-settings/ui5.yaml +4 -0
  222. package/templates/sap-app-settings/webapp/index.html +30 -0
  223. package/templates/sap-app-settings/webapp/localService/mockserver.js +125 -0
  224. package/templates/sap-app-settings/webapp/test/ModulePathForTests.js +52 -0
  225. package/templates/sap-app-settings/webapp/test/flpSandbox.html +84 -0
  226. package/templates/sap-app-settings/webapp/test/flpSandboxMockServer.html +85 -0
  227. package/templates/sap-app-settings/webapp/test/locate-reuse-libs.js +241 -0
  228. package/templates/sap-app-settings/webapp/test/testsuite.qunit.html +22 -0
@@ -0,0 +1,359 @@
1
+ import { FioriElementsVersion, FileName } from './project-spec-types.js';
2
+ import { determineMessage, readFile, updateFile } from './utils/index.js';
3
+ import { createMemFsEditor, getCurrentEditor, runWithEditor, exists } from './utils/fs-adapter.js';
4
+ import { commitFileSystemChanges } from './files/file-system.js';
5
+ import { ui5VersionRequestInfo } from '@sap-ux/ui5-info';
6
+ import { getAppProgrammingLanguage } from '@sap-ux/project-access';
7
+ import { enableTypescript, ui5TSSupport } from '@sap-ux/ui5-application-writer';
8
+ import { UI5Config } from '@sap-ux/ui5-config';
9
+ import { readdir } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ // Migration-specific functions
12
+ import { determineSourceTemplateType, checkForErrors, createMigrationErrorMessage, prepareConfigurationData, setupProjectStructure, generateAppSettings, applyAllTemplates, postProcessMigration } from './migration-process/index.js';
13
+ // File operations
14
+ import { copyAdaptationFiles, copyLibraryFiles } from './files/index.js';
15
+ // Template functions
16
+ import { assembleTemplateData } from './template/index.js';
17
+ // Project functions
18
+ import { loadOrFetchProjectInfo, validateProjectForMigration } from './project/index.js';
19
+ // Data functions
20
+ import { resolveUI5VersionsForMigration } from './data/index.js';
21
+ import { MigrationTypes } from './utils/constants.js';
22
+ import { hasStore } from './types/mem-fs-types.js';
23
+ import { i18nText, initI18n } from './i18n.js';
24
+ export class ProjectMigrator {
25
+ // Implementation
26
+ static async migrate(
27
+ // NOSONAR - Implementation must support both overload signatures
28
+ projectRootOrOptions, baseUri, ui5SnapshotUrl, importProjectInfo, vscode, internalToggle, fs, strict) {
29
+ // Convert old signature to options object if called with positional parameters
30
+ const options = typeof projectRootOrOptions === 'string'
31
+ ? {
32
+ projectRoot: projectRootOrOptions,
33
+ baseUri: baseUri ?? '',
34
+ ui5SnapshotUrl: ui5SnapshotUrl ?? '',
35
+ importProjectInfo,
36
+ vscode,
37
+ internalToggle,
38
+ fs,
39
+ strict
40
+ }
41
+ : projectRootOrOptions;
42
+ const { projectRoot, baseUri: baseUriOpt, ui5SnapshotUrl: ui5SnapshotUrlOpt, importProjectInfo: importProjectInfoOpt, vscode: vscodeOpt, internalToggle: internalToggleOpt = false, fs: fsOpt, strict: strictOpt = false } = options;
43
+ // Create a new isolated editor instance for this migration if not provided
44
+ // This enables concurrent migrations without shared state corruption
45
+ const ownsEditor = !fsOpt;
46
+ const editor = fsOpt ?? createMemFsEditor();
47
+ await initI18n();
48
+ // Run migration within editor context so all functions have access to it
49
+ const migrationResult = await runWithEditor(editor, async () => {
50
+ let messages = [];
51
+ let result = false;
52
+ try {
53
+ // Load or fetch project information
54
+ const { projectInfo, messages: projectInfoMessages } = await loadOrFetchProjectInfo(projectRoot, importProjectInfoOpt);
55
+ messages = messages.concat(projectInfoMessages);
56
+ projectInfo.baseUri = baseUriOpt;
57
+ // Resolve UI5 versions for migration
58
+ const ui5Versions = await resolveUI5VersionsForMigration(projectInfo, ui5SnapshotUrlOpt);
59
+ projectInfo.localUI5Version = ui5Versions?.[0]?.version;
60
+ if (/^(snapshot(-untested)?)?$/i.test(projectInfo.ui5Version?.trim() ?? '')) {
61
+ projectInfo.ui5Version = projectInfo.localUI5Version ?? '';
62
+ }
63
+ // Validate project is suitable for migration (not a Fiori app in CAP project)
64
+ await validateProjectForMigration(projectRoot);
65
+ if (projectInfo &&
66
+ (projectInfo.isSAPApp ||
67
+ projectInfo.FEVersion === FioriElementsVersion.v2 ||
68
+ projectInfo.FEVersion === FioriElementsVersion.v4 ||
69
+ projectInfo.type === MigrationTypes.projectExtension) &&
70
+ checkForErrors(messages)) {
71
+ // V2 is supported (checkForErrors returns true if no ERROR-level messages)
72
+ const { messages: copyMessages, result: isSuccess } = await this.copyCommonFiles(projectInfo, vscodeOpt, ui5SnapshotUrlOpt, internalToggleOpt, strictOpt);
73
+ messages = messages.concat(copyMessages);
74
+ result = isSuccess;
75
+ }
76
+ else if (projectInfo.type === MigrationTypes.library) {
77
+ const { fs: updatedFs, messages: copyMessages, result: isSuccess } = await this.copyLibraryFiles(projectInfo);
78
+ messages = messages.concat(copyMessages);
79
+ result = isSuccess;
80
+ // Update editor to the one returned from copyLibraryFiles
81
+ return { fs: updatedFs, result, messages };
82
+ }
83
+ else if (projectInfo.uiAdaptation) {
84
+ const { fs: updatedFs, messages: copyMessages, result: isSuccess } = await this.copyAdaptationFiles(projectInfo, ui5SnapshotUrlOpt);
85
+ messages = messages.concat(copyMessages);
86
+ result = isSuccess;
87
+ // Update editor to the one returned from copyAdaptationFiles
88
+ return { fs: updatedFs, result, messages };
89
+ }
90
+ else {
91
+ messages.push({ type: 'ERROR', description: i18nText('ERROR_FAILED_TO_GET_PROJECT_INFO') });
92
+ }
93
+ }
94
+ catch (e) {
95
+ const error = e instanceof Error ? e : new Error(String(e));
96
+ const useMessage = typeof e === 'object' && e !== null && 'useMessage' in e ? Boolean(e.useMessage) : false;
97
+ messages.push({
98
+ type: 'ERROR',
99
+ description: `Error during migration: ${determineMessage(error, undefined, useMessage)}`
100
+ });
101
+ }
102
+ // Return fs editor for caller to commit
103
+ // This matches the pattern used by other open-ux-tools writers
104
+ return { fs: editor, result, messages };
105
+ });
106
+ if (ownsEditor && migrationResult.result) {
107
+ try {
108
+ await commitFileSystemChanges(migrationResult.fs);
109
+ }
110
+ catch (error) {
111
+ migrationResult.result = false;
112
+ migrationResult.messages.push({
113
+ type: 'ERROR',
114
+ description: `Error committing migration: ${error instanceof Error ? error.message : String(error)}`
115
+ });
116
+ }
117
+ }
118
+ return migrationResult;
119
+ }
120
+ /**
121
+ * Copy files from templates into the project
122
+ * Orchestrates the migration process through distinct phases
123
+ *
124
+ * @param projectInfo - Project information
125
+ * @param vscode - VS Code context
126
+ * @param ui5SnapshotUrl - UI5 snapshot URL
127
+ * @param internalToggle - Internal feature toggle
128
+ * @param strict - Enable strict validation mode (WARNINGs become ERRORs for critical issues)
129
+ * @returns Migration result with status and messages
130
+ */
131
+ static async copyCommonFiles(projectInfo, vscode, ui5SnapshotUrl, internalToggle = false, strict = false) {
132
+ const messages = [];
133
+ const { isSAPApp = false, rootPath, destination, neoappDestinations, firstNeoAppDestination } = projectInfo;
134
+ try {
135
+ // Detect TypeScript project
136
+ const isTypeScriptApp = await ProjectMigrator.detectTypeScriptApp(rootPath, projectInfo.webappPath);
137
+ // Prepare configuration data
138
+ const configData = await prepareConfigurationData(projectInfo, projectInfo.ui5Version, isTypeScriptApp);
139
+ // Phase 1: Setup project structure
140
+ const { webappPath, keepIndex } = await setupProjectStructure(projectInfo, rootPath);
141
+ projectInfo.webappPath = webappPath;
142
+ // Phase 2: Assemble template data
143
+ const templateContext = await assembleTemplateData({
144
+ projectInfo,
145
+ rootPath,
146
+ projectData: configData.projectData,
147
+ serviceData: configData.serviceData,
148
+ config: {
149
+ semanticObject: configData.semanticObject,
150
+ fullyQualifiedProjectName: configData.fullyQualifiedProjectName,
151
+ fullyQualifiedProjectNameAMD: configData.fullyQualifiedProjectNameAMD,
152
+ sapUiLibs: configData.sapUiLibs,
153
+ ui5Theme: configData.ui5Theme,
154
+ projectUI5Version: configData.projectUI5Version,
155
+ baseUiLibsStr: configData.baseUiLibsStr,
156
+ supportedThemes: configData.supportedThemes,
157
+ sapClientParam: configData.sapClientParam
158
+ },
159
+ moduleInfo: {
160
+ moduleName: projectInfo.moduleName,
161
+ moduleDescription: projectInfo.moduleDescription,
162
+ destination
163
+ },
164
+ ui5Config: {
165
+ projectUI5Version: configData.projectUI5Version,
166
+ localUI5Version: projectInfo.localUI5Version,
167
+ ui5Version: projectInfo.ui5Version,
168
+ ui5SnapshotUrl,
169
+ ui5VersionRequestInfo,
170
+ ui5Theme: configData.ui5Theme
171
+ },
172
+ backendConfig: {
173
+ baseUri: projectInfo.baseUri ?? '',
174
+ scp: projectInfo.scp,
175
+ destination,
176
+ sapClient: projectInfo.sapClient
177
+ },
178
+ libraryConfig: {
179
+ sapLibs: projectInfo.sapLibs ?? '',
180
+ baseUiLibsStr: configData.baseUiLibsStr,
181
+ supportedThemes: configData.supportedThemes
182
+ },
183
+ flags: {
184
+ keepIndex,
185
+ internalToggle,
186
+ hasRootIntent: projectInfo.hasRootIntent,
187
+ floorPlan: projectInfo.floorPlan
188
+ }
189
+ });
190
+ // Phase 3: Generate app settings
191
+ const sourceTemplateType = determineSourceTemplateType(projectInfo, MigrationTypes);
192
+ await generateAppSettings({
193
+ rootPath,
194
+ templateData: templateContext.templateData,
195
+ destination,
196
+ webappPath,
197
+ messages,
198
+ sourceTemplateType,
199
+ hasDataSource: templateContext.hasDataSource,
200
+ neoappDestinations,
201
+ sourceTemplateTest: projectInfo.sourceTemplate,
202
+ firstNeoAppDestination,
203
+ strict
204
+ });
205
+ // Phase 4: Apply all templates
206
+ await applyAllTemplates({
207
+ projectInfo,
208
+ rootPath,
209
+ templateData: templateContext.templateData,
210
+ hasDataSource: templateContext.hasDataSource,
211
+ finalKeepIndex: templateContext.keepIndex,
212
+ internalToggle,
213
+ ui5Version: projectInfo.ui5Version,
214
+ isSAPApp,
215
+ appIntent: templateContext.appIntent ?? '',
216
+ appMockIntent: templateContext.appMockIntent
217
+ });
218
+ // Phase 5: Post-processing
219
+ await postProcessMigration({
220
+ projectInfo,
221
+ rootPath,
222
+ manifestJSON: templateContext.manifestJSON,
223
+ vscode,
224
+ appIntent: templateContext.appIntent,
225
+ appMockIntent: templateContext.appMockIntent,
226
+ flpSandboxAvailable: templateContext.flpSandboxAvailable,
227
+ messages,
228
+ strict
229
+ });
230
+ // Phase 6: TypeScript setup (if TypeScript app detected)
231
+ if (isTypeScriptApp) {
232
+ const tsMessages = await ProjectMigrator.setupTypeScript(rootPath);
233
+ messages.push(...tsMessages);
234
+ }
235
+ return { result: checkForErrors(messages), messages };
236
+ }
237
+ catch (e) {
238
+ return {
239
+ result: false,
240
+ messages: [...messages, { type: 'ERROR', description: createMigrationErrorMessage(e) }]
241
+ };
242
+ }
243
+ }
244
+ /**
245
+ * Copy files from templates into the project
246
+ *
247
+ * @param projectInfo
248
+ * @param snapshotUrl
249
+ */
250
+ static async copyAdaptationFiles(projectInfo, snapshotUrl) {
251
+ return copyAdaptationFiles(projectInfo, snapshotUrl, undefined);
252
+ }
253
+ /**
254
+ * Copy files from templates into the project
255
+ *
256
+ * @param projectInfo
257
+ */
258
+ static async copyLibraryFiles(projectInfo) {
259
+ return copyLibraryFiles(projectInfo);
260
+ }
261
+ /**
262
+ * Configures a downloaded TypeScript app for local development.
263
+ * Generates tsconfig.json and TypeScript devDependencies via {@link enableTypescript},
264
+ * then patches ui5-local.yaml and ui5-mock.yaml with the transpile middleware and task.
265
+ *
266
+ * @param rootPath - The project root path.
267
+ * @returns Messages to surface to the user after setup.
268
+ */
269
+ static async setupTypeScript(rootPath) {
270
+ const messages = [];
271
+ try {
272
+ await enableTypescript(rootPath, getCurrentEditor());
273
+ }
274
+ catch (err) {
275
+ messages.push({
276
+ type: 'ERROR',
277
+ description: `Error enabling TypeScript: ${err instanceof Error ? err.message : String(err)}`
278
+ });
279
+ return messages;
280
+ }
281
+ // Check and update ui5*.yaml files sequentially - order doesn't matter but list is small
282
+ for (const yamlName of [FileName.UI5LocalYaml, FileName.UI5MockYaml]) {
283
+ const yamlPath = join(rootPath, yamlName);
284
+ if (await exists(yamlPath)) {
285
+ // NOSONAR - Only 2 files, acceptable sequential check
286
+ // readFile and updateFile are sync mem-fs operations
287
+ const yamlContent = readFile(yamlPath);
288
+ const yamlConfig = await UI5Config.newInstance(yamlContent); // NOSONAR - Sequential YAML parsing required
289
+ yamlConfig.addCustomMiddleware([ui5TSSupport.middleware]);
290
+ yamlConfig.addCustomTasks([ui5TSSupport.task]);
291
+ updateFile(yamlPath, yamlConfig.toString());
292
+ }
293
+ }
294
+ messages.push({
295
+ type: 'WARNING',
296
+ description: i18nText('TYPESCRIPT_STRICT_MODE_WARNING')
297
+ });
298
+ return messages;
299
+ }
300
+ /**
301
+ * Detects whether the project is a TypeScript application.
302
+ * First attempts detection via {@link getAppProgrammingLanguage}, which relies on tsconfig.json being present.
303
+ * Falls back to scanning the webapp folder for .ts files directly, since after a download from ABAP
304
+ * the project will not yet have a tsconfig.json — it is added as part of the migration itself.
305
+ *
306
+ * @param rootPath - The project root path.
307
+ * @param webappPath - The relative path to the webapp folder.
308
+ * @returns True if the project contains TypeScript source files.
309
+ */
310
+ static async detectTypeScriptApp(rootPath, webappPath) {
311
+ const webappFullPath = join(rootPath, webappPath);
312
+ // Try getAppProgrammingLanguage first (needs tsconfig.json and package.json)
313
+ let isTypeScript = false;
314
+ try {
315
+ isTypeScript = (await getAppProgrammingLanguage(rootPath)) === 'TypeScript';
316
+ }
317
+ catch (error) {
318
+ // Expected: getAppProgrammingLanguage may fail for legacy projects without package.json
319
+ // Will fall back to scanning for .ts files below
320
+ }
321
+ if (isTypeScript) {
322
+ return true;
323
+ }
324
+ return ProjectMigrator.webappHasTypeScriptFile(webappFullPath);
325
+ }
326
+ /**
327
+ * Scans the webapp folder for a TypeScript source file (.ts, excluding .d.ts).
328
+ * During migration the downloaded files live in the uncommitted mem-fs editor, so when an
329
+ * editor with a store is in context the mem-fs store is scanned; otherwise the real disk is read.
330
+ *
331
+ * @param webappFullPath - Absolute path to the webapp folder.
332
+ * @returns True if a non-declaration .ts file is present under the webapp folder.
333
+ */
334
+ static async webappHasTypeScriptFile(webappFullPath) {
335
+ const isTypeScriptFile = (filePath) => filePath.endsWith('.ts') && !filePath.endsWith('.d.ts');
336
+ const editor = getCurrentEditor();
337
+ if (editor && hasStore(editor)) {
338
+ // mem-fs mode: scan staged files under the webapp folder (paths use forward slashes)
339
+ const normalizedPrefix = webappFullPath.replaceAll('\\', '/').replace(/\/?$/, '/');
340
+ let found = false;
341
+ editor.store.each((file) => {
342
+ if (file.state === 'deleted') {
343
+ return;
344
+ }
345
+ const normalizedFilePath = file.path.replaceAll('\\', '/');
346
+ if (normalizedFilePath.startsWith(normalizedPrefix) && isTypeScriptFile(normalizedFilePath)) {
347
+ found = true;
348
+ }
349
+ });
350
+ return found;
351
+ }
352
+ // No editor context: scan the real filesystem
353
+ if (!(await exists(webappFullPath))) {
354
+ return false;
355
+ }
356
+ return (await readdir(webappFullPath, { recursive: true })).some((f) => typeof f === 'string' && isTypeScriptFile(f));
357
+ }
358
+ }
359
+ //# sourceMappingURL=ProjectMigrator.js.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Adapters for open-ux-tools packages
3
+ *
4
+ * These adapters wrap standard @sap-ux packages to provide migration-specific
5
+ * functionality while following open-ux-tools patterns.
6
+ */
7
+ export * from './ui5-config-adapter.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Adapters for open-ux-tools packages
3
+ *
4
+ * These adapters wrap standard @sap-ux packages to provide migration-specific
5
+ * functionality while following open-ux-tools patterns.
6
+ */
7
+ export * from './ui5-config-adapter.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Adapter for @sap-ux/ui5-config package
3
+ *
4
+ * This adapter wraps the @sap-ux/ui5-config builder to generate ui5.yaml
5
+ * files using the standard open-ux-tools package instead of custom templates.
6
+ *
7
+ * Phase 1 of refactoring: Replace custom ui5Config.ts with this adapter.
8
+ */
9
+ import type { TemplateData, NeoappDestination, Message } from '../types.js';
10
+ /**
11
+ * Options for generating UI5 YAML content
12
+ */
13
+ export interface UI5YamlOptions {
14
+ /** Migration template data containing project configuration */
15
+ templateData: TemplateData;
16
+ /** Optional array of neo-app destinations */
17
+ neoappDestinations?: NeoappDestination[];
18
+ /** Array to collect warning messages */
19
+ messages?: Message[];
20
+ /** Selected destination name */
21
+ destination?: string;
22
+ /** First neo-app destination name */
23
+ firstNeoAppDestination?: string;
24
+ /** Optional webapp path for builder configuration */
25
+ webappPath?: string;
26
+ /** Whether to set UI5 version in proxy middleware */
27
+ setUI5Version?: boolean;
28
+ /** Enable strict validation mode (WARNING becomes ERROR) */
29
+ strict?: boolean;
30
+ }
31
+ /**
32
+ * Generate ui5.yaml content using @sap-ux/ui5-config builder
33
+ *
34
+ * @param options - UI5 YAML generation options
35
+ * @returns Promise resolving to ui5.yaml content as string
36
+ */
37
+ export declare function generateUI5YamlContent(options: UI5YamlOptions): Promise<string>;
38
+ /**
39
+ * Generate ui5-local.yaml content using @sap-ux/ui5-config builder
40
+ *
41
+ * ui5-local.yaml differs from ui5.yaml in that it:
42
+ * - Does not set UI5 version in proxy middleware (relies on local framework)
43
+ * - May include sap-fe-mockserver middleware for mock data
44
+ *
45
+ * Note: Both ui5.yaml and ui5-local.yaml include framework section with SAPUI5 libraries
46
+ * when localUI5Version and sapUiLibs are provided. The @sap-ux/ui5-config library
47
+ * auto-adds the framework section based on these settings.
48
+ *
49
+ * @param options - UI5 YAML generation options (setUI5Version is ignored for local yaml)
50
+ * @returns Promise resolving to ui5-local.yaml content as string
51
+ */
52
+ export declare function generateUI5LocalYamlContent(options: UI5YamlOptions): Promise<string>;
53
+ /**
54
+ * Generate ui5-mock.yaml content using @sap-ux/ui5-config builder
55
+ *
56
+ * @param templateData - Migration template data containing project configuration
57
+ * @param webappPath - Optional webapp path for builder configuration
58
+ * @param setUI5Version - Whether to set UI5 version in proxy middleware
59
+ * @returns Promise resolving to ui5-mock.yaml content as string
60
+ */
61
+ export declare function generateUI5MockYamlContent(templateData: TemplateData, webappPath?: string, setUI5Version?: boolean): Promise<string>;
62
+ //# sourceMappingURL=ui5-config-adapter.d.ts.map
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Adapter for @sap-ux/ui5-config package
3
+ *
4
+ * This adapter wraps the @sap-ux/ui5-config builder to generate ui5.yaml
5
+ * files using the standard open-ux-tools package instead of custom templates.
6
+ *
7
+ * Phase 1 of refactoring: Replace custom ui5Config.ts with this adapter.
8
+ */
9
+ import { UI5Config } from '@sap-ux/ui5-config';
10
+ import { parse, stringify } from 'yaml';
11
+ import { setWebappPath, setAppreloadPath } from '../data/yaml.js';
12
+ import { updateNeoYamlBackends, updateYamlBackends } from '../config/backend.js';
13
+ import { buildMainBackend, buildProxyConfig, buildPreviewMiddleware } from './ui5-config-helpers.js';
14
+ /**
15
+ * Add sap-fe-mockserver middleware to the YAML configuration
16
+ *
17
+ * @param orderedYaml - YAML object to modify
18
+ * @param templateData - Template data with mockserver configuration
19
+ */
20
+ function addMockserverMiddleware(orderedYaml, templateData) {
21
+ if (!orderedYaml.server) {
22
+ orderedYaml.server = { customMiddleware: [] };
23
+ }
24
+ if (!orderedYaml.server.customMiddleware) {
25
+ orderedYaml.server.customMiddleware = [];
26
+ }
27
+ const mockserverMiddleware = {
28
+ name: 'sap-fe-mockserver',
29
+ beforeMiddleware: 'fiori-tools-proxy',
30
+ configuration: {
31
+ service: {
32
+ urlBasePath: templateData.ui5Yaml?.servicePath,
33
+ name: templateData.ui5Yaml?.serviceName ?? '',
34
+ metadataXmlPath: templateData.ui5Yaml?.metadataXmlPath || '',
35
+ mockdataRootPath: templateData.ui5Yaml?.mockdataRootPath || '',
36
+ generateMockData: templateData.ui5Yaml?.generateMockData
37
+ }
38
+ }
39
+ };
40
+ // Find index of fiori-tools-proxy and insert before it
41
+ const proxyIndex = orderedYaml.server.customMiddleware.findIndex((mw) => mw.name === 'fiori-tools-proxy');
42
+ if (proxyIndex >= 0) {
43
+ orderedYaml.server.customMiddleware.splice(proxyIndex, 0, mockserverMiddleware);
44
+ }
45
+ else {
46
+ // If proxy not found, add at beginning
47
+ orderedYaml.server.customMiddleware.unshift(mockserverMiddleware);
48
+ }
49
+ }
50
+ /**
51
+ * Build backend configuration from template data and neo-app destinations
52
+ *
53
+ * @param templateData - Template data with backend configuration
54
+ * @param neoappDestinations - Optional array of neo-app destinations
55
+ * @param messages - Array to collect warning messages
56
+ * @param destination - Selected destination name
57
+ * @param firstNeoAppDestination - First neo-app destination name
58
+ * @param strict - Enable strict validation mode
59
+ * @returns Array of backend configurations
60
+ */
61
+ function buildBackendConfigs(templateData, neoappDestinations, messages, destination, firstNeoAppDestination, strict = false) {
62
+ let backends = [];
63
+ // Add main backend if configured
64
+ const mainBackend = buildMainBackend(templateData);
65
+ if (mainBackend) {
66
+ backends.push(mainBackend);
67
+ }
68
+ // Handle neo-app destinations if provided (uses existing helper logic)
69
+ if (neoappDestinations && neoappDestinations.length > 0) {
70
+ const tempBackendConfigs = updateNeoYamlBackends(neoappDestinations, backends, templateData, messages || [], destination || '', firstNeoAppDestination, strict);
71
+ backends = tempBackendConfigs;
72
+ }
73
+ // Apply additional backend processing (uses existing helper logic)
74
+ if (backends.length > 0) {
75
+ const proxyConfigTemp = { backend: backends };
76
+ const processed = updateYamlBackends(proxyConfigTemp, templateData);
77
+ backends = processed.backend;
78
+ }
79
+ return backends;
80
+ }
81
+ /**
82
+ * Generate ui5.yaml content using @sap-ux/ui5-config builder
83
+ *
84
+ * @param options - UI5 YAML generation options
85
+ * @returns Promise resolving to ui5.yaml content as string
86
+ */
87
+ export async function generateUI5YamlContent(options) {
88
+ const { templateData, neoappDestinations, messages, destination, firstNeoAppDestination, webappPath, setUI5Version, strict = false } = options;
89
+ const config = await UI5Config.newInstance('', { validateSchema: false });
90
+ // Set metadata and type
91
+ config.setMetadata({
92
+ name: templateData.ui5Yaml?.name?.toLowerCase() || templateData.project.name?.toLowerCase() || 'app'
93
+ });
94
+ config.setType('application');
95
+ // Build backend configuration using helpers
96
+ const backends = buildBackendConfigs(templateData, neoappDestinations, messages, destination, firstNeoAppDestination, strict);
97
+ // Add fiori-tools-proxy middleware with all backends
98
+ const proxyConfig = buildProxyConfig(backends, templateData, setUI5Version);
99
+ config.addFioriToolsProxyMiddleware(proxyConfig);
100
+ // Add fiori-tools-appreload middleware
101
+ config.addFioriToolsAppReloadMiddleware();
102
+ // Add fiori-tools-preview middleware if configured
103
+ const previewMiddleware = buildPreviewMiddleware(templateData);
104
+ if (previewMiddleware) {
105
+ config.addCustomMiddleware(previewMiddleware);
106
+ }
107
+ const yamlContent = config.toString();
108
+ // Post-process: Add specVersion 4.0 (UI5Config doesn't set this)
109
+ const yamlJson = parse(yamlContent);
110
+ // Add specVersion at the top
111
+ const orderedYaml = { specVersion: '4.0' };
112
+ Object.keys(yamlJson).forEach((key) => {
113
+ orderedYaml[key] = yamlJson[key];
114
+ });
115
+ // Apply webappPath if provided
116
+ if (webappPath) {
117
+ setWebappPath(orderedYaml, webappPath);
118
+ setAppreloadPath(orderedYaml, webappPath);
119
+ }
120
+ return stringify(orderedYaml);
121
+ }
122
+ /**
123
+ * Generate ui5-local.yaml content using @sap-ux/ui5-config builder
124
+ *
125
+ * ui5-local.yaml differs from ui5.yaml in that it:
126
+ * - Does not set UI5 version in proxy middleware (relies on local framework)
127
+ * - May include sap-fe-mockserver middleware for mock data
128
+ *
129
+ * Note: Both ui5.yaml and ui5-local.yaml include framework section with SAPUI5 libraries
130
+ * when localUI5Version and sapUiLibs are provided. The @sap-ux/ui5-config library
131
+ * auto-adds the framework section based on these settings.
132
+ *
133
+ * @param options - UI5 YAML generation options (setUI5Version is ignored for local yaml)
134
+ * @returns Promise resolving to ui5-local.yaml content as string
135
+ */
136
+ export async function generateUI5LocalYamlContent(options) {
137
+ const { templateData, neoappDestinations, messages, destination, firstNeoAppDestination, webappPath, strict = false } = options;
138
+ const config = await UI5Config.newInstance('', { validateSchema: false });
139
+ // Set metadata and type
140
+ config.setMetadata({
141
+ name: templateData.ui5Yaml?.name?.toLowerCase() || templateData.project.name?.toLowerCase() || 'app'
142
+ });
143
+ config.setType('application');
144
+ // Add framework section with SAPUI5 libraries (ui5-local.yaml specific)
145
+ if (templateData.project.localUI5Version && templateData.ui5Yaml?.sapUiLibs) {
146
+ const libraries = [...templateData.ui5Yaml.sapUiLibs];
147
+ const theme = templateData.ui5Yaml?.ui5Theme || 'sap_horizon';
148
+ // Note: addUI5Framework automatically appends the theme library based on the theme parameter,
149
+ // so we don't need to manually add it to the libraries array
150
+ config.addUI5Framework('SAPUI5', templateData.project.localUI5Version, libraries, theme);
151
+ }
152
+ // Build backend configuration using helpers
153
+ const backends = buildBackendConfigs(templateData, neoappDestinations, messages, destination, firstNeoAppDestination, strict);
154
+ // Add fiori-tools-proxy middleware with all backends (no UI5 version, no ui5 proxy section for local)
155
+ const proxyConfig = {
156
+ ignoreCertErrors: false,
157
+ backend: backends
158
+ };
159
+ config.addFioriToolsProxyMiddleware(proxyConfig);
160
+ // Add fiori-tools-appreload middleware
161
+ config.addFioriToolsAppReloadMiddleware();
162
+ // Add fiori-tools-preview middleware if configured
163
+ const previewMiddleware = buildPreviewMiddleware(templateData);
164
+ if (previewMiddleware) {
165
+ config.addCustomMiddleware(previewMiddleware);
166
+ }
167
+ const yamlContent = config.toString();
168
+ // Parse and post-process
169
+ const yamlJson = parse(yamlContent);
170
+ // Add specVersion at the top
171
+ const orderedYaml = { specVersion: '4.0' };
172
+ Object.keys(yamlJson).forEach((key) => {
173
+ orderedYaml[key] = yamlJson[key];
174
+ });
175
+ // Add sap-fe-mockserver middleware if generateMockData is defined (ui5-local.yaml specific)
176
+ if (templateData.ui5Yaml?.generateMockData !== undefined && templateData.ui5Yaml?.servicePath) {
177
+ addMockserverMiddleware(orderedYaml, templateData);
178
+ }
179
+ // Apply webappPath if provided
180
+ if (webappPath) {
181
+ setWebappPath(orderedYaml, webappPath);
182
+ setAppreloadPath(orderedYaml, webappPath);
183
+ }
184
+ return stringify(orderedYaml);
185
+ }
186
+ /**
187
+ * Generate ui5-mock.yaml content using @sap-ux/ui5-config builder
188
+ *
189
+ * @param templateData - Migration template data containing project configuration
190
+ * @param webappPath - Optional webapp path for builder configuration
191
+ * @param setUI5Version - Whether to set UI5 version in proxy middleware
192
+ * @returns Promise resolving to ui5-mock.yaml content as string
193
+ */
194
+ export async function generateUI5MockYamlContent(templateData, webappPath, setUI5Version) {
195
+ const config = await UI5Config.newInstance('', { validateSchema: false });
196
+ // Set metadata and type
197
+ config.setMetadata({
198
+ name: templateData.ui5Yaml?.name?.toLowerCase() || templateData.project.name?.toLowerCase() || 'app'
199
+ });
200
+ config.setType('application');
201
+ // Add fiori-tools-proxy middleware with UI5 version if provided
202
+ const proxyConfig = {
203
+ ignoreCertErrors: false,
204
+ backend: [],
205
+ ui5: {
206
+ path: ['/resources', '/test-resources'],
207
+ url: templateData.ui5Yaml?.ui5Url || ''
208
+ }
209
+ };
210
+ // Add UI5 version to proxy if provided and setUI5Version is true
211
+ if (setUI5Version && templateData.ui5Yaml?.ui5Version) {
212
+ proxyConfig.ui5.version = templateData.ui5Yaml.ui5Version;
213
+ }
214
+ config.addFioriToolsProxyMiddleware(proxyConfig);
215
+ // Add fiori-tools-appreload middleware
216
+ config.addFioriToolsAppReloadMiddleware();
217
+ const yamlContent = config.toString();
218
+ // Post-process: Add specVersion and webappPath
219
+ const yamlJson = parse(yamlContent);
220
+ // Add specVersion at the top
221
+ const orderedYaml = { specVersion: '4.0' };
222
+ Object.keys(yamlJson).forEach((key) => {
223
+ orderedYaml[key] = yamlJson[key];
224
+ });
225
+ // Apply webappPath if provided
226
+ if (webappPath) {
227
+ setWebappPath(orderedYaml, webappPath);
228
+ setAppreloadPath(orderedYaml, webappPath);
229
+ }
230
+ return stringify(orderedYaml);
231
+ }
232
+ //# sourceMappingURL=ui5-config-adapter.js.map