@sap-ux/fiori-app-sub-generator 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.
- package/LICENSE +201 -0
- package/generators/app/index.d.ts +3 -0
- package/generators/app/index.js +5 -0
- package/generators/app-headless/index.d.ts +34 -0
- package/generators/app-headless/index.js +75 -0
- package/generators/app-headless/transforms.d.ts +9 -0
- package/generators/app-headless/transforms.js +208 -0
- package/generators/fiori-app-generator/end.d.ts +49 -0
- package/generators/fiori-app-generator/end.js +105 -0
- package/generators/fiori-app-generator/fioriAppGenerator.d.ts +45 -0
- package/generators/fiori-app-generator/fioriAppGenerator.js +319 -0
- package/generators/fiori-app-generator/fioriAppGeneratorOptions.d.ts +94 -0
- package/generators/fiori-app-generator/fioriAppGeneratorOptions.js +3 -0
- package/generators/fiori-app-generator/index.d.ts +3 -0
- package/generators/fiori-app-generator/index.js +19 -0
- package/generators/fiori-app-generator/install.d.ts +34 -0
- package/generators/fiori-app-generator/install.js +80 -0
- package/generators/fiori-app-generator/prompting.d.ts +84 -0
- package/generators/fiori-app-generator/prompting.js +303 -0
- package/generators/fiori-app-generator/subgenHelpers.d.ts +43 -0
- package/generators/fiori-app-generator/subgenHelpers.js +71 -0
- package/generators/fiori-app-generator/transforms.d.ts +38 -0
- package/generators/fiori-app-generator/transforms.js +278 -0
- package/generators/fiori-app-generator/writing.d.ts +27 -0
- package/generators/fiori-app-generator/writing.js +94 -0
- package/generators/index.d.ts +6 -0
- package/generators/index.js +22 -0
- package/generators/translations/fioriAppSubGenerator.i18n.json +119 -0
- package/generators/types/common.d.ts +46 -0
- package/generators/types/common.js +3 -0
- package/generators/types/constants.d.ts +60 -0
- package/generators/types/constants.js +98 -0
- package/generators/types/external.d.ts +261 -0
- package/generators/types/external.js +88 -0
- package/generators/types/index.d.ts +7 -0
- package/generators/types/index.js +23 -0
- package/generators/types/state.d.ts +149 -0
- package/generators/types/state.js +35 -0
- package/generators/types/telemetryEvents.d.ts +61 -0
- package/generators/types/telemetryEvents.js +3 -0
- package/generators/types/yeomanUiStepConfig.d.ts +13 -0
- package/generators/types/yeomanUiStepConfig.js +3 -0
- package/generators/utils/appWizardCache.d.ts +40 -0
- package/generators/utils/appWizardCache.js +72 -0
- package/generators/utils/command-runner.d.ts +30 -0
- package/generators/utils/command-runner.js +88 -0
- package/generators/utils/common.d.ts +147 -0
- package/generators/utils/common.js +286 -0
- package/generators/utils/eventHooks.d.ts +29 -0
- package/generators/utils/eventHooks.js +48 -0
- package/generators/utils/i18n.d.ts +16 -0
- package/generators/utils/i18n.js +54 -0
- package/generators/utils/index.d.ts +9 -0
- package/generators/utils/index.js +25 -0
- package/generators/utils/sapuxLayer.d.ts +15 -0
- package/generators/utils/sapuxLayer.js +24 -0
- package/generators/utils/stepsHelper.d.ts +47 -0
- package/generators/utils/stepsHelper.js +161 -0
- package/generators/utils/telemetry.d.ts +16 -0
- package/generators/utils/telemetry.js +41 -0
- package/package.json +84 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runPostGenerationTasks = runPostGenerationTasks;
|
|
4
|
+
const yeoman_ui_types_1 = require("@sap-devx/yeoman-ui-types");
|
|
5
|
+
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
6
|
+
const fiori_generator_shared_1 = require("@sap-ux/fiori-generator-shared");
|
|
7
|
+
const store_1 = require("@sap-ux/store");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const utils_1 = require("../utils");
|
|
10
|
+
/**
|
|
11
|
+
* Save API Hub key to the store.
|
|
12
|
+
*
|
|
13
|
+
* @param apiKey - API key to save
|
|
14
|
+
* @param logger - optional logger
|
|
15
|
+
* @returns - true if the API key was saved successfully, false otherwise
|
|
16
|
+
*/
|
|
17
|
+
async function saveApiHubApiKey(apiKey, logger) {
|
|
18
|
+
let result;
|
|
19
|
+
if (!(0, btp_utils_1.isAppStudio)()) {
|
|
20
|
+
const apiHubStore = (await (0, store_1.getService)({
|
|
21
|
+
logger,
|
|
22
|
+
entityName: 'api-hub'
|
|
23
|
+
}));
|
|
24
|
+
const apiHubSettings = new store_1.ApiHubSettings({ apiKey });
|
|
25
|
+
result = await apiHubStore.write(apiHubSettings);
|
|
26
|
+
}
|
|
27
|
+
return Boolean(result);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run post generation hooks: delegates to `runHooks` with `'app-generated'` as the event name.
|
|
31
|
+
*
|
|
32
|
+
* @param projectPath
|
|
33
|
+
* @param logger
|
|
34
|
+
* @param vscode
|
|
35
|
+
* @param followUpCommand
|
|
36
|
+
*/
|
|
37
|
+
async function runPostGenHooks(projectPath, logger, vscode, followUpCommand) {
|
|
38
|
+
await (0, utils_1.runHooks)('app-generated', {
|
|
39
|
+
hookParameters: { fsPath: projectPath },
|
|
40
|
+
vscodeInstance: vscode,
|
|
41
|
+
options: { followUpCommand }
|
|
42
|
+
}, logger);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* FioriBaseGeneratror end phase related functionality.
|
|
46
|
+
*
|
|
47
|
+
* @param state
|
|
48
|
+
* @param state.service
|
|
49
|
+
* @param state.service.backendSystem
|
|
50
|
+
* @param state.service.capService
|
|
51
|
+
* @param state.service.sapClient
|
|
52
|
+
* @param state.service.odataVersion
|
|
53
|
+
* @param state.service.datasourceType
|
|
54
|
+
* @param state.service.apiHubConfig
|
|
55
|
+
* @param state.project
|
|
56
|
+
* @param state.project.targetFolder
|
|
57
|
+
* @param state.project.name
|
|
58
|
+
* @param state.project.flpAppId
|
|
59
|
+
* @param fs - the file system editor
|
|
60
|
+
* @param logger - the logger
|
|
61
|
+
* @param vscode - the vscode instance
|
|
62
|
+
* @param appWizard - the app wizard instance
|
|
63
|
+
* @param followUpCommand - the follow up command
|
|
64
|
+
* @returns {Promise<void>}
|
|
65
|
+
*/
|
|
66
|
+
async function runPostGenerationTasks({ service, project }, fs, logger, vscode, appWizard, followUpCommand) {
|
|
67
|
+
// Add launch config for non-cap projects
|
|
68
|
+
if (!service.capService) {
|
|
69
|
+
await (0, utils_1.generateLaunchConfig)({
|
|
70
|
+
targetFolder: project.targetFolder,
|
|
71
|
+
projectName: project.name,
|
|
72
|
+
flpAppId: project.flpAppId,
|
|
73
|
+
sapClientParam: service.sapClient ? (0, utils_1.buildSapClientParam)(service.sapClient) : undefined,
|
|
74
|
+
odataVersion: service.odataVersion,
|
|
75
|
+
datasourceType: service.datasourceType
|
|
76
|
+
}, fs, vscode, logger);
|
|
77
|
+
}
|
|
78
|
+
// Persist backend system connection information
|
|
79
|
+
const hostEnv = (0, fiori_generator_shared_1.getHostEnvironment)();
|
|
80
|
+
if (service.backendSystem && hostEnv !== fiori_generator_shared_1.hostEnvironment.bas && service.backendSystem.newOrUpdated) {
|
|
81
|
+
const storeService = await (0, store_1.getService)({
|
|
82
|
+
logger: logger,
|
|
83
|
+
entityName: 'system'
|
|
84
|
+
});
|
|
85
|
+
// No need to await, we cannot recover anyway
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
87
|
+
storeService.write(service.backendSystem);
|
|
88
|
+
}
|
|
89
|
+
// Display info message if using a cap service as it is not otherwise shown when a top level dir is not created
|
|
90
|
+
if (service.capService && appWizard) {
|
|
91
|
+
// this info message needs to be shown for cap projects as it is not shown when a top level dir is not created
|
|
92
|
+
appWizard.showInformation((0, utils_1.t)('wizardMessages.filesGenerated'), yeoman_ui_types_1.MessageType.notification);
|
|
93
|
+
}
|
|
94
|
+
if (hostEnv !== fiori_generator_shared_1.hostEnvironment.bas && service.apiHubConfig?.apiHubType === "API_HUB" /* ApiHubType.apiHub */) {
|
|
95
|
+
await saveApiHubApiKey(service.apiHubConfig.apiHubKey, logger);
|
|
96
|
+
}
|
|
97
|
+
// If we got here, the generation was successful and so targetFolder and name must be defined
|
|
98
|
+
const projectPath = (0, path_1.join)(project.targetFolder, project.name);
|
|
99
|
+
logger.info((0, utils_1.t)('logMessages.applicationGenerationSuccess', {
|
|
100
|
+
targetFolder: projectPath
|
|
101
|
+
}));
|
|
102
|
+
await (0, fiori_generator_shared_1.sendTelemetry)('GENERATION_SUCCESS', fiori_generator_shared_1.TelemetryHelper.telemetryData, projectPath);
|
|
103
|
+
await runPostGenHooks(projectPath, logger, vscode, followUpCommand);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=end.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ILogWrapper } from '@sap-ux/fiori-generator-shared';
|
|
2
|
+
import type { Logger } from '@sap-ux/logger';
|
|
3
|
+
import Generator from 'yeoman-generator';
|
|
4
|
+
import type { FioriStep, State } from '../types';
|
|
5
|
+
import type { FioriAppGeneratorOptions } from './fioriAppGeneratorOptions';
|
|
6
|
+
export declare const APP_GENERATOR_MODULE = "@sap/generator-fiori";
|
|
7
|
+
/**
|
|
8
|
+
* The root generator for Fiori Elements and Fiori Freestyle generators.
|
|
9
|
+
* All common functionality is implemented here.
|
|
10
|
+
*/
|
|
11
|
+
export declare class FioriAppGenerator extends Generator {
|
|
12
|
+
private readonly vscode;
|
|
13
|
+
private generationTime0;
|
|
14
|
+
private appWizard;
|
|
15
|
+
protected state: State;
|
|
16
|
+
private static _logger;
|
|
17
|
+
protected generatorVersion: string;
|
|
18
|
+
private yeomanUiStepConfig;
|
|
19
|
+
private readonly setPromptsCallback;
|
|
20
|
+
private prompts;
|
|
21
|
+
protected fioriSteps: FioriStep[];
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param args
|
|
25
|
+
* @param opts
|
|
26
|
+
*/
|
|
27
|
+
constructor(args: string | string[], opts: FioriAppGeneratorOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Static getter for the logger.
|
|
30
|
+
*
|
|
31
|
+
* @returns {ILogWrapper & Logger}
|
|
32
|
+
*/
|
|
33
|
+
static get logger(): ILogWrapper & Logger;
|
|
34
|
+
initializing(): Promise<void>;
|
|
35
|
+
prompting(): Promise<void>;
|
|
36
|
+
writing(): Promise<void>;
|
|
37
|
+
install(): Promise<void>;
|
|
38
|
+
end(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param error
|
|
42
|
+
*/
|
|
43
|
+
private _exitOnError;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=fioriAppGenerator.d.ts.map
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FioriAppGenerator = exports.APP_GENERATOR_MODULE = void 0;
|
|
7
|
+
const yeoman_ui_types_1 = require("@sap-devx/yeoman-ui-types");
|
|
8
|
+
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
9
|
+
const feature_toggle_1 = require("@sap-ux/feature-toggle");
|
|
10
|
+
const fiori_elements_writer_1 = require("@sap-ux/fiori-elements-writer");
|
|
11
|
+
const fiori_freestyle_writer_1 = require("@sap-ux/fiori-freestyle-writer");
|
|
12
|
+
const fiori_generator_shared_1 = require("@sap-ux/fiori-generator-shared");
|
|
13
|
+
const odata_service_inquirer_1 = require("@sap-ux/odata-service-inquirer");
|
|
14
|
+
const telemetry_1 = require("@sap-ux/telemetry");
|
|
15
|
+
const ui5_info_1 = require("@sap-ux/ui5-info");
|
|
16
|
+
const path_1 = require("path");
|
|
17
|
+
const yeoman_generator_1 = __importDefault(require("yeoman-generator"));
|
|
18
|
+
const types_1 = require("../types");
|
|
19
|
+
const utils_1 = require("../utils");
|
|
20
|
+
const end_1 = require("./end");
|
|
21
|
+
const install_1 = require("./install");
|
|
22
|
+
const prompting_1 = require("./prompting");
|
|
23
|
+
const subgenHelpers_1 = require("./subgenHelpers");
|
|
24
|
+
const transforms_1 = require("./transforms");
|
|
25
|
+
const writing_1 = require("./writing");
|
|
26
|
+
exports.APP_GENERATOR_MODULE = '@sap/generator-fiori';
|
|
27
|
+
/**
|
|
28
|
+
* The root generator for Fiori Elements and Fiori Freestyle generators.
|
|
29
|
+
* All common functionality is implemented here.
|
|
30
|
+
*/
|
|
31
|
+
class FioriAppGenerator extends yeoman_generator_1.default {
|
|
32
|
+
vscode;
|
|
33
|
+
// Performance measurement
|
|
34
|
+
generationTime0; // start of writing phase millisecond timestamp
|
|
35
|
+
appWizard;
|
|
36
|
+
state;
|
|
37
|
+
// The logger is static to allow convenient access from everywhere, cross-cutting concern
|
|
38
|
+
static _logger = fiori_generator_shared_1.DefaultLogger;
|
|
39
|
+
// Generator name for use in telemetry, readmes etc.
|
|
40
|
+
generatorVersion = this.rootGeneratorVersion();
|
|
41
|
+
// The configuration of steps in YUI and their interdependence
|
|
42
|
+
yeomanUiStepConfig;
|
|
43
|
+
setPromptsCallback;
|
|
44
|
+
prompts;
|
|
45
|
+
fioriSteps;
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param args
|
|
49
|
+
* @param opts
|
|
50
|
+
*/
|
|
51
|
+
constructor(args, opts) {
|
|
52
|
+
super(args, opts, {
|
|
53
|
+
unique: 'namespace'
|
|
54
|
+
});
|
|
55
|
+
this.vscode = opts['vscode'];
|
|
56
|
+
FioriAppGenerator._logger = this.options.logWrapper ?? fiori_generator_shared_1.DefaultLogger;
|
|
57
|
+
// Init the generator state
|
|
58
|
+
this.state = opts.state ?? { project: {}, service: {} };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Static getter for the logger.
|
|
62
|
+
*
|
|
63
|
+
* @returns {ILogWrapper & Logger}
|
|
64
|
+
*/
|
|
65
|
+
static get logger() {
|
|
66
|
+
return FioriAppGenerator._logger;
|
|
67
|
+
}
|
|
68
|
+
async initializing() {
|
|
69
|
+
// Ensure i18n bundles are loaded, default loading is unreliable
|
|
70
|
+
await (0, utils_1.initI18nFioriAppSubGenerator)();
|
|
71
|
+
// When running in YUI context back navigation is supported and state may be cached.
|
|
72
|
+
if (this.options.appWizard) {
|
|
73
|
+
this.appWizard = this.options.appWizard;
|
|
74
|
+
(0, utils_1.initAppWizardCache)(FioriAppGenerator._logger, this.options.appWizard);
|
|
75
|
+
}
|
|
76
|
+
await (0, telemetry_1.initTelemetrySettings)({
|
|
77
|
+
consumerModule: { name: exports.APP_GENERATOR_MODULE, version: this.rootGeneratorVersion() },
|
|
78
|
+
internalFeature: (0, feature_toggle_1.isInternalFeaturesSettingEnabled)(),
|
|
79
|
+
watchTelemetrySettingStore: false
|
|
80
|
+
});
|
|
81
|
+
fiori_generator_shared_1.TelemetryHelper.createTelemetryData({
|
|
82
|
+
...this.options.telemetryData
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* Preloading UI5 versions to be retreived from cache later in generation flow
|
|
86
|
+
* Not required when version is already in project state e.g S4
|
|
87
|
+
*/
|
|
88
|
+
if (!this.state.project?.ui5Version) {
|
|
89
|
+
const filterOptions = {
|
|
90
|
+
useCache: true
|
|
91
|
+
};
|
|
92
|
+
// do not await as this is pre-loading the cache
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
94
|
+
(0, ui5_info_1.getUI5Versions)(filterOptions);
|
|
95
|
+
}
|
|
96
|
+
// Floorplans, externally configured either via adapters or headless config
|
|
97
|
+
if (this.options.floorplan) {
|
|
98
|
+
this.state.floorplan = this.options.floorplan;
|
|
99
|
+
}
|
|
100
|
+
// Configuration of steps in YUI and their interdependance
|
|
101
|
+
this.fioriSteps = this.options.fioriSteps ?? types_1.FIORI_STEPS;
|
|
102
|
+
this.yeomanUiStepConfig = this.options.yeomanUiStepConfig;
|
|
103
|
+
this.prompts = this.yeomanUiStepConfig?.activeSteps;
|
|
104
|
+
}
|
|
105
|
+
async prompting() {
|
|
106
|
+
try {
|
|
107
|
+
const generatorOptions = this.options;
|
|
108
|
+
const isFioriFreestyleTemplate = this.state.floorplan === types_1.FloorplanFF.FF_SIMPLE;
|
|
109
|
+
if ((0, utils_1.hasStep)(this.fioriSteps, types_1.STEP_DATASOURCE_AND_SERVICE)) {
|
|
110
|
+
const cachedService = (0, utils_1.getFromCache)(this.appWizard, 'service', FioriAppGenerator.logger);
|
|
111
|
+
const options = {
|
|
112
|
+
capService: cachedService?.capService ?? this.state.service?.capService,
|
|
113
|
+
requiredOdataVersion: (0, utils_1.getRequiredOdataVersion)(this.state.floorplan),
|
|
114
|
+
allowNoDatasource: isFioriFreestyleTemplate,
|
|
115
|
+
promptOptions: generatorOptions.promptSettings,
|
|
116
|
+
showCollabDraftWarning: generatorOptions.showCollabDraftWarning,
|
|
117
|
+
workspaceFolders: generatorOptions.workspaceFolders
|
|
118
|
+
};
|
|
119
|
+
let serviceAnswers = await (0, prompting_1.promptOdataServiceAnswers)(options, FioriAppGenerator.logger, this.env.adapter);
|
|
120
|
+
/** Back button issue temp fix */
|
|
121
|
+
// Persist derived state to facilitate backwards navigation
|
|
122
|
+
if ((0, fiori_generator_shared_1.getHostEnvironment)() !== fiori_generator_shared_1.hostEnvironment.cli) {
|
|
123
|
+
if (serviceAnswers.source === odata_service_inquirer_1.DatasourceType.none || serviceAnswers.edmx) {
|
|
124
|
+
(0, utils_1.addToCache)(this.appWizard, { service: serviceAnswers }, FioriAppGenerator.logger);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
serviceAnswers =
|
|
128
|
+
(0, utils_1.getFromCache)(this.appWizard, 'service', FioriAppGenerator.logger) ?? serviceAnswers;
|
|
129
|
+
}
|
|
130
|
+
if (!(serviceAnswers.source === odata_service_inquirer_1.DatasourceType.none || serviceAnswers.edmx)) {
|
|
131
|
+
FioriAppGenerator.logger?.error((0, utils_1.t)('error.fatalError'));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** END: Back button temp fix */
|
|
135
|
+
this.state.service = { ...this.state?.service, ...serviceAnswers };
|
|
136
|
+
}
|
|
137
|
+
// Freestyle templates require a view name
|
|
138
|
+
if (isFioriFreestyleTemplate) {
|
|
139
|
+
const viewNameAnswer = await this.prompt([(0, prompting_1.getViewQuestion)()]);
|
|
140
|
+
this.state.viewName = viewNameAnswer.viewName;
|
|
141
|
+
}
|
|
142
|
+
else if (this.state.service.edmx) {
|
|
143
|
+
// Fiori Elements templates require entity and related settings
|
|
144
|
+
const entityQuestions = (0, odata_service_inquirer_1.getEntityRelatedPrompts)(this.state.service.edmx, (0, transforms_1.getTemplateType)(this.state.floorplan), !!this.state.service.capService, {
|
|
145
|
+
defaultMainEntityName: generatorOptions.preselectedEntityName,
|
|
146
|
+
useAutoComplete: (0, fiori_generator_shared_1.getHostEnvironment)() === fiori_generator_shared_1.hostEnvironment.cli,
|
|
147
|
+
hideTableLayoutPrompts: generatorOptions.showLayoutPrompts === false // Defaults to show layout prompts
|
|
148
|
+
}, this.state.service.annotations?.[0], FioriAppGenerator.logger, (0, fiori_generator_shared_1.getHostEnvironment)() !== fiori_generator_shared_1.hostEnvironment.cli);
|
|
149
|
+
const entityRelatedAnswers = await this.prompt(entityQuestions);
|
|
150
|
+
// Some state may have been assigned by adaptors, and then certain prompts hidden, so we must merge the answers
|
|
151
|
+
this.state.entityRelatedConfig = Object.assign(this.state.entityRelatedConfig ?? {}, entityRelatedAnswers);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Not Freestyle and no entity related config is an error and we cannot proceed
|
|
155
|
+
FioriAppGenerator.logger.error((0, utils_1.t)('error.edmxNotFound'));
|
|
156
|
+
this._exitOnError((0, utils_1.t)('error.edmxNotFound'));
|
|
157
|
+
}
|
|
158
|
+
// Pre-load the CAP project and get all relevant info in one call,
|
|
159
|
+
// this prevents re-reading from disc and parsing multiple times later
|
|
160
|
+
if (this.state.service.capService && !this.state.service.capService.cdsUi5PluginInfo) {
|
|
161
|
+
this.state.service.capService.cdsUi5PluginInfo = await (0, utils_1.getCdsUi5PluginInfo)(this.state.service.capService.projectPath, this.fs, this.state.service.capService.cdsVersionInfo);
|
|
162
|
+
}
|
|
163
|
+
// get project information
|
|
164
|
+
if ((0, utils_1.hasStep)(this.fioriSteps, types_1.STEP_PROJECT_ATTRIBUTES)) {
|
|
165
|
+
const { ui5AppAnswers, localUI5Version } = await (0, prompting_1.promptUI5ApplicationAnswers)({
|
|
166
|
+
projectName: this.state.project?.name,
|
|
167
|
+
targetFolder: this.state.project?.targetFolder,
|
|
168
|
+
service: this.state.service,
|
|
169
|
+
floorplan: this.state.floorplan,
|
|
170
|
+
hideUI5VersionPrompt: generatorOptions.hideUI5VersionPrompt,
|
|
171
|
+
promptSettings: generatorOptions.promptSettings,
|
|
172
|
+
promptExtension: generatorOptions.extensions
|
|
173
|
+
}, [this.yeomanUiStepConfig], this.env.adapter);
|
|
174
|
+
this.state.project = Object.assign(this.state.project ?? {}, ui5AppAnswers, {
|
|
175
|
+
ui5Version: ui5AppAnswers?.ui5Version || localUI5Version,
|
|
176
|
+
localUI5Version,
|
|
177
|
+
flpAppId: (0, utils_1.getFlpId)((0, utils_1.getAppId)(ui5AppAnswers.namespace ?? '', ui5AppAnswers?.name), this.state.floorplan === types_1.FloorplanFF.FF_SIMPLE ? types_1.defaultNavActionDisplay : types_1.defaultNavActionTile)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (this.state.project?.addDeployConfig) {
|
|
181
|
+
// Allows back nav where we have iinterdependent steps
|
|
182
|
+
// Re-add dependant steps on back nav
|
|
183
|
+
if ((0, utils_1.hasStep)(this.fioriSteps, types_1.STEP_DEPLOY_CONFIG) &&
|
|
184
|
+
!(0, utils_1.hasActiveStep)((0, utils_1.t)('steps.deployConfig.title'), this.yeomanUiStepConfig.activeSteps)) {
|
|
185
|
+
(0, utils_1.updateDependentStep)((0, utils_1.t)('steps.projectAttributesConfig.title'), [this.yeomanUiStepConfig], true, (0, utils_1.t)('steps.deployConfig.title'));
|
|
186
|
+
}
|
|
187
|
+
(0, subgenHelpers_1.addDeployGen)({
|
|
188
|
+
service: this.state.service,
|
|
189
|
+
projectName: this.state.project.name,
|
|
190
|
+
targetFolder: this.state.project.targetFolder,
|
|
191
|
+
applicationType: 'FF' // Telemetry data
|
|
192
|
+
}, this.composeWith.bind(this), FioriAppGenerator.logger, this.appWizard);
|
|
193
|
+
}
|
|
194
|
+
if (this.state.project?.addFlpConfig) {
|
|
195
|
+
// Allows back nav where we have interdependent steps
|
|
196
|
+
// Re-add dependant steps on back nav
|
|
197
|
+
if ((0, utils_1.hasStep)(this.fioriSteps, types_1.STEP_FLP_CONFIG) &&
|
|
198
|
+
!(0, utils_1.hasActiveStep)((0, utils_1.t)('steps.flpConfig.title'), this.yeomanUiStepConfig.activeSteps)) {
|
|
199
|
+
(0, utils_1.updateDependentStep)((0, utils_1.t)('steps.projectAttributesConfig.title'), [this.yeomanUiStepConfig], true, (0, utils_1.t)('steps.flpConfig.title'));
|
|
200
|
+
}
|
|
201
|
+
(0, subgenHelpers_1.addFlpGen)({
|
|
202
|
+
projectName: this.state.project.name,
|
|
203
|
+
targetFolder: this.state.project.targetFolder,
|
|
204
|
+
title: this.state.project.title,
|
|
205
|
+
skipPrompt: !(0, utils_1.hasStep)(this.fioriSteps, types_1.STEP_FLP_CONFIG)
|
|
206
|
+
}, this.composeWith.bind(this), FioriAppGenerator.logger, generatorOptions.vscode, this.appWizard);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
// Fatal prompting error
|
|
211
|
+
FioriAppGenerator.logger.error(`${(0, utils_1.t)('error.fatalError')} : ${error}`);
|
|
212
|
+
this._exitOnError(error);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async writing() {
|
|
216
|
+
try {
|
|
217
|
+
this.generationTime0 = performance.now();
|
|
218
|
+
fiori_generator_shared_1.TelemetryHelper.markAppGenStartTime();
|
|
219
|
+
const { service, project, floorplan } = this.state;
|
|
220
|
+
FioriAppGenerator.logger.info((0, utils_1.t)('logMessages.copyingTemplateFiles', { templateName: this.state.floorplan }));
|
|
221
|
+
// Set the template folder
|
|
222
|
+
// this.sourceRoot(join(__dirname, '..', '..', 'templates')); // Path must match webpacked template paths
|
|
223
|
+
const destRoot = this.destinationRoot((0, path_1.join)(project.targetFolder, project.name));
|
|
224
|
+
const t1 = performance.now();
|
|
225
|
+
let appConfig;
|
|
226
|
+
// Determine which type of app to generate based on the selected floorplan (template type)
|
|
227
|
+
if (this.state.floorplan === types_1.FloorplanFF.FF_SIMPLE) {
|
|
228
|
+
const ffApp = await (0, transforms_1.transformState)(this.state, !!service.capService || this.options.generateIndexHtml);
|
|
229
|
+
await (0, fiori_freestyle_writer_1.generate)(destRoot, ffApp, this.fs);
|
|
230
|
+
appConfig = ffApp;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
const feApp = await (0, transforms_1.transformState)(this.state, !!service.capService || this.options.generateIndexHtml);
|
|
234
|
+
await (0, fiori_elements_writer_1.generate)(destRoot, feApp, this.fs);
|
|
235
|
+
appConfig = feApp;
|
|
236
|
+
}
|
|
237
|
+
const t2 = performance.now();
|
|
238
|
+
FioriAppGenerator.logger.debug(`Writing Fiori application files from template took ${Math.round(t2 - t1)} milliseconds.`);
|
|
239
|
+
fiori_generator_shared_1.TelemetryHelper.createTelemetryData({
|
|
240
|
+
Template: (0, utils_1.t)(`floorplans.label.${floorplan}`, {
|
|
241
|
+
odataVersion: service.version
|
|
242
|
+
}),
|
|
243
|
+
DataSource: service.source,
|
|
244
|
+
UI5Version: project.ui5Version || ui5_info_1.latestVersionString,
|
|
245
|
+
Theme: project.ui5Theme,
|
|
246
|
+
AppGenVersion: this.generatorVersion,
|
|
247
|
+
AppGenSourceType: service.source,
|
|
248
|
+
AppGenSapSystemType: service.source === odata_service_inquirer_1.DatasourceType.sapSystem && service.connectedSystem
|
|
249
|
+
? (0, utils_1.getTelemetrySapSystemType)(service.connectedSystem)
|
|
250
|
+
: 'n/a',
|
|
251
|
+
AppGenBusinessHubType: (0, utils_1.getTelemetryBusinessHubType)(service.apiHubConfig?.apiHubType),
|
|
252
|
+
EnableEslint: project.enableEslint,
|
|
253
|
+
EnableTypeScript: project.enableTypeScript,
|
|
254
|
+
EnableCodeAssist: project.enableCodeAssist,
|
|
255
|
+
ToolsId: appConfig.app.sourceTemplate?.toolsId
|
|
256
|
+
});
|
|
257
|
+
if (service.apiHubConfig && (0, btp_utils_1.isAppStudio)()) {
|
|
258
|
+
(0, writing_1.writeAPIHubKeyFiles)(this.fs, destRoot, service.apiHubConfig);
|
|
259
|
+
}
|
|
260
|
+
// Write after app, using values from the transformed state so defaults have been applied
|
|
261
|
+
const readMeUpdated = { ui5Version: appConfig.ui5?.minUI5Version };
|
|
262
|
+
await (0, writing_1.writeReadMe)(this.state, types_1.generatorName, this.generatorVersion, destRoot, this.fs, readMeUpdated);
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
FioriAppGenerator.logger.fatal(`${(0, utils_1.t)('error.errorWritingApplicationFiles')} : ${error}`);
|
|
266
|
+
this._exitOnError(error);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async install() {
|
|
270
|
+
if (!this.options.skipInstall) {
|
|
271
|
+
await (0, install_1.installDependencies)({
|
|
272
|
+
appPackagePath: this.destinationPath(),
|
|
273
|
+
capService: this.state.service.capService,
|
|
274
|
+
enableCodeAssist: this.state.project?.enableCodeAssist ?? false,
|
|
275
|
+
// Assumption that npm workspaces will be enabled if cds ui5 plugin is a depenedency
|
|
276
|
+
useNpmWorkspaces: !!(this.state.service.capService?.cdsUi5PluginInfo?.isCdsUi5PluginEnabled ||
|
|
277
|
+
this.state.service.capService?.cdsUi5PluginInfo?.hasCdsUi5Plugin ||
|
|
278
|
+
this.state.service.capService?.cdsUi5PluginInfo?.isWorkspaceEnabled),
|
|
279
|
+
ui5Version: this.state.project?.ui5Version
|
|
280
|
+
}, FioriAppGenerator.logger);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
FioriAppGenerator.logger.info((0, utils_1.t)('logMessages.installSkippedOptionSpecified'));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async end() {
|
|
287
|
+
(0, utils_1.deleteCache)(this.appWizard, FioriAppGenerator.logger);
|
|
288
|
+
await (0, end_1.runPostGenerationTasks)({
|
|
289
|
+
service: {
|
|
290
|
+
backendSystem: this.state.service.connectedSystem?.backendSystem,
|
|
291
|
+
capService: this.state.service.capService,
|
|
292
|
+
sapClient: this.state.service.client,
|
|
293
|
+
odataVersion: this.state.service.version,
|
|
294
|
+
datasourceType: this.state.service.source
|
|
295
|
+
},
|
|
296
|
+
project: {
|
|
297
|
+
targetFolder: this.state.project.targetFolder,
|
|
298
|
+
name: this.state.project.name,
|
|
299
|
+
flpAppId: this.state.project.flpAppId
|
|
300
|
+
}
|
|
301
|
+
}, this.fs, FioriAppGenerator.logger, this.vscode, this.appWizard, this.options.followUpCommand);
|
|
302
|
+
const generationTime02 = performance.now();
|
|
303
|
+
FioriAppGenerator.logger.info(`Total time taken: ${Math.round((generationTime02 - this.generationTime0) / 1000)} seconds.`);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
*
|
|
307
|
+
* @param error
|
|
308
|
+
*/
|
|
309
|
+
_exitOnError(error) {
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
311
|
+
(0, fiori_generator_shared_1.sendTelemetry)('GENERATION_WRITING_FAIL', fiori_generator_shared_1.TelemetryHelper.telemetryData);
|
|
312
|
+
if ((0, fiori_generator_shared_1.getHostEnvironment)() !== fiori_generator_shared_1.hostEnvironment.cli) {
|
|
313
|
+
this.appWizard?.showError(`${(0, utils_1.t)('error.fatalError')} : ${error}`, yeoman_ui_types_1.MessageType.notification);
|
|
314
|
+
}
|
|
315
|
+
throw new Error(`${(0, utils_1.t)('error.fatalError')} : ${error}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
exports.FioriAppGenerator = FioriAppGenerator;
|
|
319
|
+
//# sourceMappingURL=fioriAppGenerator.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AppWizard, Severity } from '@sap-devx/yeoman-ui-types';
|
|
2
|
+
import type Generator from 'yeoman-generator';
|
|
3
|
+
import type { FioriGeneratorSettings, FioriStep, Floorplan, PromptExtension, FioriAppGeneratorPromptSettings, State, YeomanUiStepConfig } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Fiori generator specific options, for internal use only.
|
|
6
|
+
* todo: Split this into FioriGenerator options (e.g. disableS4, disableGeneratorExtensions, data) that are explicitly root generator options
|
|
7
|
+
* and FioriAppGenerator options which should be considered internal (passed from Fiori generator to FioriAppGenerator)
|
|
8
|
+
*/
|
|
9
|
+
export interface FioriAppGeneratorOptions extends Generator.GeneratorOptions, FioriGeneratorSettings {
|
|
10
|
+
/**
|
|
11
|
+
* Disables loading of S4 generator steps even if its found.
|
|
12
|
+
* todo: External -> FioriGeneratorOptions
|
|
13
|
+
*/
|
|
14
|
+
disableS4?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Disables loading of generator extensions even if they are found
|
|
17
|
+
* todo: External -> FioriGeneratorOptions
|
|
18
|
+
*/
|
|
19
|
+
disableGeneratorExtensions?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Additional (non-specified option) data may be passed using this property. e.g. Adaptor data
|
|
22
|
+
* todo: External -> FioriGeneratorOptions
|
|
23
|
+
*/
|
|
24
|
+
data?: Object;
|
|
25
|
+
/**
|
|
26
|
+
* Customer provided extensions used to customize existing questions
|
|
27
|
+
*/
|
|
28
|
+
extensions?: PromptExtension;
|
|
29
|
+
/**
|
|
30
|
+
* The floorplan (app type) that will be created
|
|
31
|
+
*/
|
|
32
|
+
floorplan?: Floorplan;
|
|
33
|
+
/**
|
|
34
|
+
* Prompt settings to control visibility and default values of prompts
|
|
35
|
+
*/
|
|
36
|
+
promptSettings?: FioriAppGeneratorPromptSettings;
|
|
37
|
+
/**
|
|
38
|
+
* Changes the launch config writing behaviour from detecting and creating/updating workspace files to only creating with the app target folder
|
|
39
|
+
*
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
writeLaunchConfigstoAppOnly?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Show template selection step even if only one template. In some cases callers of the generator may want users to be able to confirm the selected floorplan even if theres only one.
|
|
45
|
+
*
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
showTemplateSelectionStepIfOnlyOne?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Wizard messages may be shown on the first step adjacent to the navigation buttons using this option.
|
|
51
|
+
* This enables callers of App Gen to set end-user messages specific to the context of the caller, for example BAS Storyboard flows.
|
|
52
|
+
*/
|
|
53
|
+
wizardMessage?: {
|
|
54
|
+
/**
|
|
55
|
+
* The text of the message to show
|
|
56
|
+
*/
|
|
57
|
+
text: string;
|
|
58
|
+
/**
|
|
59
|
+
* The severity of the notification. Default is `Severity.information`.
|
|
60
|
+
*/
|
|
61
|
+
severity?: Severity;
|
|
62
|
+
/**
|
|
63
|
+
* A link may be included. Currently not supported by YUI.
|
|
64
|
+
*/
|
|
65
|
+
link?: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* State set by composing generator i.e `@sap/fiori-generator`
|
|
69
|
+
*/
|
|
70
|
+
state?: State;
|
|
71
|
+
/**
|
|
72
|
+
* App Wizard reference
|
|
73
|
+
*/
|
|
74
|
+
appWizard?: AppWizard;
|
|
75
|
+
/**
|
|
76
|
+
* The telemetry data to be sent along with any telemetry events
|
|
77
|
+
*/
|
|
78
|
+
telemetryData?: Record<string, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* Defined the steps configuration to be used in the Fiori generator. Skip steps by omitting them from the array.
|
|
81
|
+
* Note that these should be aligned with `yeomanUiStepConfig`.
|
|
82
|
+
*/
|
|
83
|
+
fioriSteps?: FioriStep[];
|
|
84
|
+
/**
|
|
85
|
+
* Defines the steps configuration to be used in the YUI generator.
|
|
86
|
+
* Not applicable to CLI usage.
|
|
87
|
+
*/
|
|
88
|
+
yeomanUiStepConfig?: YeomanUiStepConfig;
|
|
89
|
+
/**
|
|
90
|
+
* VSCode Workspace folders
|
|
91
|
+
*/
|
|
92
|
+
workspaceFolders?: string[];
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=fioriAppGeneratorOptions.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./fioriAppGenerator"), exports);
|
|
18
|
+
__exportStar(require("./fioriAppGeneratorOptions"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CapService } from '@sap-ux/cap-config-writer';
|
|
2
|
+
import { type ILogWrapper } from '@sap-ux/fiori-generator-shared';
|
|
3
|
+
/**
|
|
4
|
+
* Defines the options used to install deps to a CAP project.
|
|
5
|
+
*/
|
|
6
|
+
export type CapInstallOptions = {
|
|
7
|
+
ui5Version?: string;
|
|
8
|
+
codeAssist?: boolean;
|
|
9
|
+
rootPath?: string;
|
|
10
|
+
depsInstallPath?: string;
|
|
11
|
+
useWorkspaces?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Perform the installation of dependencies for the specified project.
|
|
15
|
+
* If a CAP service is provided AND `useNpmWorkspaces` is false, the dependencies will be installed to the CAP root project,
|
|
16
|
+
* otherwise they will be installed to the specified app `packagePath`.
|
|
17
|
+
*
|
|
18
|
+
* @param param0
|
|
19
|
+
* @param param0.appPackagePath
|
|
20
|
+
* @param param0.capService
|
|
21
|
+
* @param param0.enableCodeAssist
|
|
22
|
+
* @param param0.useNpmWorkspaces
|
|
23
|
+
* @param param0.ui5Version
|
|
24
|
+
* @param logger The logger to use for output
|
|
25
|
+
* @returns Promise<void>
|
|
26
|
+
*/
|
|
27
|
+
export declare function installDependencies({ appPackagePath, capService, enableCodeAssist, useNpmWorkspaces, ui5Version }: {
|
|
28
|
+
appPackagePath: string;
|
|
29
|
+
capService?: CapService;
|
|
30
|
+
enableCodeAssist: boolean;
|
|
31
|
+
useNpmWorkspaces: boolean;
|
|
32
|
+
ui5Version: string;
|
|
33
|
+
}, logger: ILogWrapper): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=install.d.ts.map
|