@sap-ux/repo-app-import-sub-generator 0.2.6 → 0.2.8

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.
@@ -94,7 +94,7 @@ class default_1 extends yeoman_generator_1.default {
94
94
  */
95
95
  async prompting() {
96
96
  const quickDeployedAppConfig = this.options?.data?.quickDeployedAppConfig;
97
- const questions = await (0, prompts_1.getPrompts)(this.appRootPath, quickDeployedAppConfig);
97
+ const questions = await (0, prompts_1.getPrompts)(this.appRootPath, quickDeployedAppConfig, this.appWizard);
98
98
  const answers = await this.prompt(questions);
99
99
  const { targetFolder } = answers;
100
100
  if (quickDeployedAppConfig?.appId) {
@@ -117,40 +117,33 @@ class default_1 extends yeoman_generator_1.default {
117
117
  * Writes the configuration files for the project, including deployment config, and README.
118
118
  */
119
119
  async writing() {
120
- // Extract downloaded app
121
- const archive = prompt_state_1.PromptState.downloadedAppPackage;
122
- await (0, download_utils_1.extractZip)(this.extractedProjectPath, archive, this.fs);
120
+ await (0, download_utils_1.extractZip)(this.extractedProjectPath, this.fs);
123
121
  // Check if the qfa.json file
124
122
  const qfaJsonFilePath = (0, path_1.join)(this.extractedProjectPath, constants_1.qfaJsonFileName);
125
- if (this.fs.exists(qfaJsonFilePath)) {
126
- const qfaJson = (0, file_helpers_1.makeValidJson)(qfaJsonFilePath, this.fs);
127
- // Generate project files
128
- (0, validators_1.validateQfaJsonFile)(qfaJson);
129
- // Generate app config
130
- const config = await (0, app_config_1.getAppConfig)(this.answers.selectedApp, this.extractedProjectPath, qfaJson, this.fs);
131
- await (0, fiori_elements_writer_1.generate)(this.projectPath, config, this.fs);
132
- // Generate deploy config
133
- const deployConfig = (0, app_config_1.getAbapDeployConfig)(this.answers.selectedApp, qfaJson);
134
- await (0, abap_deploy_config_writer_1.generate)(this.projectPath, deployConfig, undefined, this.fs);
135
- if (this.vscode) {
136
- // Generate Fiori launch config
137
- const fioriOptions = this._getLaunchConfig(config);
138
- // Create launch configuration
139
- await (0, launch_config_1.createLaunchConfig)(this.projectPath, fioriOptions, this.fs, logger_1.default.logger);
140
- (0, fiori_tools_settings_1.writeApplicationInfoSettings)(this.projectPath);
141
- }
142
- // Generate README
143
- const readMeConfig = this._getReadMeConfig(config);
144
- (0, fiori_generator_shared_1.generateReadMe)(this.projectPath, readMeConfig, this.fs);
145
- // Replace webapp files with downloaded app files
146
- await (0, updates_1.replaceWebappFiles)(this.projectPath, this.extractedProjectPath, this.fs);
147
- await (0, updates_1.validateAndUpdateManifestUI5Version)((0, path_1.join)(this.projectPath, project_access_1.DirName.Webapp, project_access_1.FileName.Manifest), this.fs);
148
- // Clean up extracted project files
149
- this.fs.delete(this.extractedProjectPath);
150
- }
151
- else {
152
- logger_1.default.logger?.error((0, i18n_1.t)('error.qfaJsonNotFound', { jsonFileName: constants_1.qfaJsonFileName }));
123
+ const qfaJson = (0, file_helpers_1.makeValidJson)(qfaJsonFilePath, this.fs);
124
+ // Generate project files
125
+ (0, validators_1.validateQfaJsonFile)(qfaJson);
126
+ // Generate app config
127
+ const config = await (0, app_config_1.getAppConfig)(this.answers.selectedApp, this.extractedProjectPath, qfaJson, this.fs);
128
+ await (0, fiori_elements_writer_1.generate)(this.projectPath, config, this.fs);
129
+ // Generate deploy config
130
+ const deployConfig = (0, app_config_1.getAbapDeployConfig)(this.answers.selectedApp, qfaJson);
131
+ await (0, abap_deploy_config_writer_1.generate)(this.projectPath, deployConfig, undefined, this.fs);
132
+ if (this.vscode) {
133
+ // Generate Fiori launch config
134
+ const fioriOptions = this._getLaunchConfig(config);
135
+ // Create launch configuration
136
+ await (0, launch_config_1.createLaunchConfig)(this.projectPath, fioriOptions, this.fs, logger_1.default.logger);
137
+ (0, fiori_tools_settings_1.writeApplicationInfoSettings)(this.projectPath);
153
138
  }
139
+ // Generate README
140
+ const readMeConfig = this._getReadMeConfig(config);
141
+ (0, fiori_generator_shared_1.generateReadMe)(this.projectPath, readMeConfig, this.fs);
142
+ // Replace webapp files with downloaded app files
143
+ await (0, updates_1.replaceWebappFiles)(this.projectPath, this.extractedProjectPath, this.fs);
144
+ await (0, updates_1.validateAndUpdateManifestUI5Version)((0, path_1.join)(this.projectPath, project_access_1.DirName.Webapp, project_access_1.FileName.Manifest), this.fs);
145
+ // Clean up extracted project files
146
+ this.fs.delete(this.extractedProjectPath);
154
147
  }
155
148
  /**
156
149
  * Returns the configuration for the README file.
@@ -281,13 +274,13 @@ class default_1 extends yeoman_generator_1.default {
281
274
  async end() {
282
275
  try {
283
276
  this.appWizard.showInformation((0, i18n_1.t)('info.repoAppDownloadCompleteMsg'), yeoman_ui_types_1.MessageType.notification);
277
+ await this._handlePostAppGeneration();
284
278
  await (0, fiori_generator_shared_1.sendTelemetry)(telemetryEvents_1.EventName.GENERATION_SUCCESS, fiori_generator_shared_1.TelemetryHelper.createTelemetryData({
285
279
  appType: 'repo-app-import-sub-generator',
286
280
  ...this.options.telemetryData
287
281
  }) ?? {}).catch((error) => {
288
282
  logger_1.default.logger?.error((0, i18n_1.t)('error.telemetry', { error: error.message }));
289
283
  });
290
- await this._handlePostAppGeneration();
291
284
  }
292
285
  catch (error) {
293
286
  logger_1.default.logger?.error((0, i18n_1.t)('error.endPhase', { error: error.message }));
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import type { SystemSelectionAnswers } from '../app/types';
3
+ import AdmZip from 'adm-zip';
3
4
  /**
4
5
  * Much of the values returned by the app downloader prompting are derived from prompt answers and are not direct answer values.
5
6
  * Since inquirer does not provide a way to return values that are not direct answers from prompts, this class will maintain the derived values
@@ -8,7 +9,7 @@ import type { SystemSelectionAnswers } from '../app/types';
8
9
  */
9
10
  export declare class PromptState {
10
11
  private static _systemSelection;
11
- private static _downloadedAppPackage?;
12
+ private static _admZipInstance?;
12
13
  /**
13
14
  * Returns the current state of the service config.
14
15
  *
@@ -24,13 +25,13 @@ export declare class PromptState {
24
25
  /**
25
26
  * Set the downloaded app package.
26
27
  */
27
- static set downloadedAppPackage(archive: Buffer);
28
+ static set admZip(archive: Buffer);
28
29
  /**
29
- * Returns the downloaded app package.
30
+ * Returns the AdmZip instance created from the downloaded archive.
30
31
  *
31
- * @returns {Buffer} downloaded app package
32
+ * @returns {admZip | undefined} admZip instance
32
33
  */
33
- static get downloadedAppPackage(): Buffer;
34
+ static get admZip(): AdmZip | undefined;
34
35
  /**
35
36
  * Get the baseURL from the connected system's service provider defaults.
36
37
  *
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.PromptState = void 0;
7
+ const adm_zip_1 = __importDefault(require("adm-zip"));
4
8
  /**
5
9
  * Much of the values returned by the app downloader prompting are derived from prompt answers and are not direct answer values.
6
10
  * Since inquirer does not provide a way to return values that are not direct answers from prompts, this class will maintain the derived values
@@ -9,7 +13,7 @@ exports.PromptState = void 0;
9
13
  */
10
14
  class PromptState {
11
15
  static _systemSelection = {};
12
- static _downloadedAppPackage;
16
+ static _admZipInstance;
13
17
  /**
14
18
  * Returns the current state of the service config.
15
19
  *
@@ -29,16 +33,16 @@ class PromptState {
29
33
  /**
30
34
  * Set the downloaded app package.
31
35
  */
32
- static set downloadedAppPackage(archive) {
33
- this._downloadedAppPackage = archive;
36
+ static set admZip(archive) {
37
+ this._admZipInstance = new adm_zip_1.default(archive);
34
38
  }
35
39
  /**
36
- * Returns the downloaded app package.
40
+ * Returns the AdmZip instance created from the downloaded archive.
37
41
  *
38
- * @returns {Buffer} downloaded app package
42
+ * @returns {admZip | undefined} admZip instance
39
43
  */
40
- static get downloadedAppPackage() {
41
- return this._downloadedAppPackage ?? Buffer.alloc(0);
44
+ static get admZip() {
45
+ return this._admZipInstance;
42
46
  }
43
47
  /**
44
48
  * Get the baseURL from the connected system's service provider defaults.
@@ -58,7 +62,7 @@ class PromptState {
58
62
  }
59
63
  static reset() {
60
64
  PromptState.systemSelection = {};
61
- PromptState._downloadedAppPackage = undefined;
65
+ PromptState._admZipInstance = undefined;
62
66
  }
63
67
  }
64
68
  exports.PromptState = PromptState;
@@ -1,10 +1,12 @@
1
1
  import type { RepoAppDownloadQuestions, QuickDeployedAppConfig } from '../app/types';
2
+ import type { AppWizard } from '@sap-devx/yeoman-ui-types';
2
3
  /**
3
4
  * Retrieves prompts for selecting a system, app list, and target folder where the app will be generated.
4
5
  *
5
6
  * @param {string} [appRootPath] - The root path of the application.
6
7
  * @param {QuickDeployedAppConfig} [quickDeployedAppConfig] - The quick deployed app configuration.
8
+ * @param {AppWizard} [appWizard] - The app wizard instance.
7
9
  * @returns {Promise<RepoAppDownloadQuestions[]>} A list of prompts for user interaction.
8
10
  */
9
- export declare function getPrompts(appRootPath?: string, quickDeployedAppConfig?: QuickDeployedAppConfig): Promise<RepoAppDownloadQuestions[]>;
11
+ export declare function getPrompts(appRootPath?: string, quickDeployedAppConfig?: QuickDeployedAppConfig, appWizard?: AppWizard): Promise<RepoAppDownloadQuestions[]>;
10
12
  //# sourceMappingURL=prompts.d.ts.map
@@ -48,9 +48,10 @@ const getTargetFolderPrompt = (appRootPath, appId) => {
48
48
  *
49
49
  * @param {string} [appRootPath] - The root path of the application.
50
50
  * @param {QuickDeployedAppConfig} [quickDeployedAppConfig] - The quick deployed app configuration.
51
+ * @param {AppWizard} [appWizard] - The app wizard instance.
51
52
  * @returns {Promise<RepoAppDownloadQuestions[]>} A list of prompts for user interaction.
52
53
  */
53
- async function getPrompts(appRootPath, quickDeployedAppConfig) {
54
+ async function getPrompts(appRootPath, quickDeployedAppConfig, appWizard) {
54
55
  try {
55
56
  prompt_state_1.PromptState.reset();
56
57
  const systemQuestions = await (0, odata_service_inquirer_1.getSystemSelectionQuestions)({
@@ -76,7 +77,7 @@ async function getPrompts(appRootPath, quickDeployedAppConfig) {
76
77
  },
77
78
  message: (0, i18n_1.t)('prompts.appSelection.message'),
78
79
  choices: () => (appList.length ? (0, prompt_helpers_1.formatAppChoices)(appList) : []),
79
- validate: async (answers) => (0, validators_1.validateAppSelection)(answers, appList, quickDeployedAppConfig)
80
+ validate: async (answers) => (0, validators_1.validateAppSelection)(answers, appList, quickDeployedAppConfig, appWizard)
80
81
  }
81
82
  ];
82
83
  const targetFolderPrompts = getTargetFolderPrompt(appRootPath, quickDeployedAppConfig?.appId);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "error": {
3
3
  "telemetry": "Failed to send telemetry data after downloading the application from the SAPUI5 ABAP Repository. {{- error}}",
4
- "qfaJsonNotFound": "{{- jsonFileName }} not found in the downloaded application. Check the file exists.",
4
+ "qfaJsonNotFound": "{{- jsonFileName }} not found in the downloaded application. Ensure the downloaded application is properly deployed to the ABAP repository.",
5
5
  "replaceWebappFilesError": "An error occurred when replacing files in the downloaded application: {{- error}}. For more information, view the logs.",
6
6
  "requiredFieldsMissing": "Required fields are missing for the {{- app }} application. Check if the application is deployed correctly.",
7
7
  "applicationListFetchError": "An error occurred when fetching the application list: {{- error}}. Check if your application is available in the system.",
@@ -1,13 +1,18 @@
1
- /// <reference types="node" />
2
1
  import type { Editor } from 'mem-fs-editor';
2
+ /**
3
+ * Checks whether the ZIP archive contains an entry named qfa.json
4
+ * and verifies that a file named qfa.json exists in the archive.
5
+ *
6
+ * @returns {boolean} true qfa.json file exists, otherwise false.
7
+ */
8
+ export declare function hasQfaJson(): boolean;
3
9
  /**
4
10
  * Extracts a ZIP archive to a temporary directory.
5
11
  *
6
12
  * @param {string} extractedProjectPath - The path where the archive should be extracted.
7
- * @param {Buffer} archive - The ZIP archive buffer.
8
13
  * @param {Editor} fs - The file system editor.
9
14
  */
10
- export declare function extractZip(extractedProjectPath: string, archive: Buffer, fs: Editor): Promise<void>;
15
+ export declare function extractZip(extractedProjectPath: string, fs: Editor): Promise<void>;
11
16
  /**
12
17
  * Downloads application files from the ABAP repository.
13
18
  *
@@ -3,23 +3,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.downloadApp = exports.extractZip = void 0;
7
- const adm_zip_1 = __importDefault(require("adm-zip"));
6
+ exports.downloadApp = exports.extractZip = exports.hasQfaJson = void 0;
8
7
  const path_1 = require("path");
9
8
  const prompt_state_1 = require("../prompts/prompt-state");
10
9
  const i18n_1 = require("./i18n");
11
10
  const logger_1 = __importDefault(require("../utils/logger"));
11
+ const constants_1 = require("./constants");
12
+ /**
13
+ * Checks whether the ZIP archive contains an entry named qfa.json
14
+ * and verifies that a file named qfa.json exists in the archive.
15
+ *
16
+ * @returns {boolean} true qfa.json file exists, otherwise false.
17
+ */
18
+ function hasQfaJson() {
19
+ const qfaEntries = prompt_state_1.PromptState.admZip?.getEntries().filter((entry) => entry.entryName === constants_1.qfaJsonFileName);
20
+ return qfaEntries?.length === 1;
21
+ }
22
+ exports.hasQfaJson = hasQfaJson;
12
23
  /**
13
24
  * Extracts a ZIP archive to a temporary directory.
14
25
  *
15
26
  * @param {string} extractedProjectPath - The path where the archive should be extracted.
16
- * @param {Buffer} archive - The ZIP archive buffer.
17
27
  * @param {Editor} fs - The file system editor.
18
28
  */
19
- async function extractZip(extractedProjectPath, archive, fs) {
29
+ async function extractZip(extractedProjectPath, fs) {
20
30
  try {
21
- const zip = new adm_zip_1.default(archive);
22
- zip.getEntries().forEach(function (zipEntry) {
31
+ prompt_state_1.PromptState.admZip?.getEntries().forEach(function (zipEntry) {
23
32
  if (!zipEntry.isDirectory) {
24
33
  // Extract the file content
25
34
  const fileContent = zipEntry.getData().toString('utf8');
@@ -42,7 +51,7 @@ async function downloadApp(repoName) {
42
51
  const serviceProvider = prompt_state_1.PromptState.systemSelection?.connectedSystem?.serviceProvider;
43
52
  const downloadedAppPackage = await serviceProvider.getUi5AbapRepository().downloadFiles(repoName);
44
53
  // store downloaded package in prompt state
45
- prompt_state_1.PromptState.downloadedAppPackage = downloadedAppPackage;
54
+ prompt_state_1.PromptState.admZip = downloadedAppPackage;
46
55
  }
47
56
  exports.downloadApp = downloadApp;
48
57
  //# sourceMappingURL=download-utils.js.map
@@ -1,6 +1,7 @@
1
1
  import type { AppIndex } from '@sap-ux/axios-extension';
2
2
  import type { ValidationLink } from '@sap-ux/inquirer-common';
3
3
  import type { AppInfo, QuickDeployedAppConfig, QfaJsonConfig } from '../app/types';
4
+ import type { AppWizard } from '@sap-devx/yeoman-ui-types';
4
5
  /**
5
6
  * Validates the entire app configuration.
6
7
  *
@@ -22,7 +23,8 @@ export declare const isValidPromptState: (targetFolder: string, appId?: string)
22
23
  * @param answers - The selected app information.
23
24
  * @param appList - The list of available apps.
24
25
  * @param quickDeployedAppConfig - The quick deployed app configuration.
26
+ * @param appWizard - The app wizard instance.
25
27
  * @returns A promise resolving to a boolean or a validation error message.
26
28
  */
27
- export declare function validateAppSelection(answers: AppInfo, appList: AppIndex, quickDeployedAppConfig?: QuickDeployedAppConfig): Promise<string | boolean | ValidationLink>;
29
+ export declare function validateAppSelection(answers: AppInfo, appList: AppIndex, quickDeployedAppConfig?: QuickDeployedAppConfig, appWizard?: AppWizard): Promise<string | boolean | ValidationLink>;
28
30
  //# sourceMappingURL=validators.d.ts.map
@@ -10,6 +10,8 @@ const prompt_state_1 = require("../prompts/prompt-state");
10
10
  const guided_answers_helper_1 = require("@sap-ux/guided-answers-helper");
11
11
  const inquirer_common_1 = require("@sap-ux/inquirer-common");
12
12
  const download_utils_1 = require("../utils/download-utils");
13
+ const yeoman_ui_types_1 = require("@sap-devx/yeoman-ui-types");
14
+ const constants_1 = require("../utils/constants");
13
15
  /**
14
16
  * Validates the metadata section of the app configuration.
15
17
  *
@@ -108,9 +110,10 @@ async function generateAppNotFoundHelpLink() {
108
110
  * @param answers - The selected app information.
109
111
  * @param appList - The list of available apps.
110
112
  * @param quickDeployedAppConfig - The quick deployed app configuration.
113
+ * @param appWizard - The app wizard instance.
111
114
  * @returns A promise resolving to a boolean or a validation error message.
112
115
  */
113
- async function validateAppSelection(answers, appList, quickDeployedAppConfig) {
116
+ async function validateAppSelection(answers, appList, quickDeployedAppConfig, appWizard) {
114
117
  // Quick deploy config exists but no apps found
115
118
  if (quickDeployedAppConfig?.appId && appList.length === 0) {
116
119
  return await generateAppNotFoundHelpLink();
@@ -123,7 +126,11 @@ async function validateAppSelection(answers, appList, quickDeployedAppConfig) {
123
126
  if (answers?.appId) {
124
127
  try {
125
128
  await (0, download_utils_1.downloadApp)(answers.repoName);
126
- return true;
129
+ const isQfaJsonPresent = (0, download_utils_1.hasQfaJson)();
130
+ if (!isQfaJsonPresent) {
131
+ appWizard?.showError((0, i18n_1.t)('error.qfaJsonNotFound', { jsonFileName: constants_1.qfaJsonFileName }), yeoman_ui_types_1.MessageType.notification);
132
+ }
133
+ return isQfaJsonPresent;
127
134
  }
128
135
  catch (error) {
129
136
  return (0, i18n_1.t)('error.appDownloadErrors.appDownloadFailure', { error: error.message });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/repo-app-import-sub-generator",
3
3
  "description": "Generator to download LROP Fiori applications deployed from an ABAP repository.",
4
- "version": "0.2.6",
4
+ "version": "0.2.8",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -28,7 +28,7 @@
28
28
  "@sap-ux/fiori-generator-shared": "0.11.2",
29
29
  "@sap-ux/inquirer-common": "0.6.39",
30
30
  "@sap-ux/project-access": "1.29.21",
31
- "@sap-ux/odata-service-inquirer": "2.3.3",
31
+ "@sap-ux/odata-service-inquirer": "2.3.4",
32
32
  "@sap-ux/fiori-elements-writer": "2.3.2",
33
33
  "@sap-ux/logger": "0.6.0",
34
34
  "@sap-ux/project-input-validator": "0.5.4",