@forge/cli
12.23.0-next.7-experimental-44b7a1213.0.0-next.11
out/command-line/controller/module-add-controller.js+
out/command-line/controller/module-add-controller.jsNew file+165
Index: package/out/command-line/controller/module-add-controller.js
===================================================================
--- package/out/command-line/controller/module-add-controller.js
+++ package/out/command-line/controller/module-add-controller.js
@@ -0,0 +1,165 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.ModuleAddController = exports.MODULE_PRODUCTS = void 0;
+const tslib_1 = require("tslib");
+const path_1 = tslib_1.__importDefault(require("path"));
+const dependencies_merger_1 = require("../../module-add/dependencies-merger");
+const cli_shared_1 = require("@forge/cli-shared");
+const register_app_commands_1 = require("../register-app-commands");
+exports.MODULE_PRODUCTS = [
+ register_app_commands_1.TemplateContext.JIRA,
+ register_app_commands_1.TemplateContext.CONFLUENCE,
+ register_app_commands_1.TemplateContext.JIRA_SERVICE_MANAGEMENT
+];
+class ModuleAddController {
+ moduleView;
+ moduleService;
+ fileService;
+ constructor(moduleView, moduleService, fileService) {
+ this.moduleView = moduleView;
+ this.moduleService = moduleService;
+ this.fileService = fileService;
+ }
+ async run(options) {
+ try {
+ await this.runModuleAdd(options);
+ }
+ finally {
+ this.moduleService.cleanup();
+ }
+ }
+ async runModuleAdd(options) {
+ const selectedTemplate = options.moduleType
+ ? await this.resolveTemplateByModuleType(options.moduleType)
+ : await this.resolveSelectedTemplate(await this.resolveProduct(options));
+ const uiType = options.uiType ?? (await this.resolveUIFramework(selectedTemplate));
+ const downloadedTemplate = await this.moduleService.prepareModuleMetadata(selectedTemplate, uiType);
+ if (!downloadedTemplate) {
+ throw new Error(cli_shared_1.Text.module.add.errorFailedToDownloadTemplate(selectedTemplate.moduleKey));
+ }
+ const depChanges = this.fileService.checkDependencies(downloadedTemplate, options.force === true);
+ const hasConflicts = depChanges.conflicts.length > 0;
+ this.assertNotBlockedByConflicts(depChanges, hasConflicts, './package.json', options);
+ const variables = await this.collectVariables(downloadedTemplate, uiType);
+ const frontendPlan = (0, dependencies_merger_1.planFrontendPackageJson)(process.cwd(), downloadedTemplate, variables, options.force === true);
+ const frontendHasConflicts = frontendPlan.depChanges.conflicts.length > 0;
+ const frontendScope = frontendPlan.frontendPackageJsonPath
+ ? path_1.default.relative(process.cwd(), frontendPlan.frontendPackageJsonPath)
+ : 'frontend package.json';
+ this.assertNotBlockedByConflicts(frontendPlan.depChanges, frontendHasConflicts, frontendScope, options);
+ if (!options.dryRun) {
+ await this.moduleService.downloadModuleBundle(downloadedTemplate, uiType);
+ }
+ const result = await this.fileService.templateMerge(downloadedTemplate, variables, {
+ dryRun: options.dryRun,
+ force: options.force,
+ install: options.install
+ });
+ this.renderRunResult(result, depChanges, hasConflicts, options);
+ }
+ async resolveProduct(options) {
+ const product = options.product ?? (await this.moduleView.promptForList(cli_shared_1.Text.module.add.promptSelectProduct, exports.MODULE_PRODUCTS));
+ if (!exports.MODULE_PRODUCTS.includes(product)) {
+ throw new Error(cli_shared_1.Text.module.add.errorInvalidProduct(product));
+ }
+ return product;
+ }
+ async resolveTemplateByModuleType(moduleType) {
+ for (const product of exports.MODULE_PRODUCTS) {
+ const moduleMap = await this.moduleService.getAvailableModules(product);
+ const template = moduleMap.get(moduleType);
+ if (template) {
+ return template;
+ }
+ }
+ throw new Error(cli_shared_1.Text.module.add.errorFailedToResolveChoice(moduleType));
+ }
+ async resolveSelectedTemplate(product) {
+ const moduleMap = await this.moduleService.getAvailableModules(product);
+ const moduleChoiceMap = this.moduleService.getModuleChoice(moduleMap);
+ const selectedChoice = await this.moduleView.promptForList(cli_shared_1.Text.module.add.promptSelectModule, Array.from(moduleChoiceMap.keys()));
+ const template = moduleChoiceMap.get(selectedChoice);
+ if (!template) {
+ throw new Error(cli_shared_1.Text.module.add.errorFailedToResolveChoice(selectedChoice));
+ }
+ return template;
+ }
+ assertNotBlockedByConflicts(depChanges, hasConflicts, scope, options) {
+ const blocked = hasConflicts && options.force !== true && options.install !== false;
+ if (blocked && !options.dryRun) {
+ this.moduleView.renderDepConflictsBlocked(depChanges, scope);
+ throw new Error(cli_shared_1.Text.module.add.depConflictsSummary(depChanges.conflicts.length));
+ }
+ }
+ renderRunResult(result, depChanges, hasConflicts, options) {
+ if (options.dryRun) {
+ this.moduleView.renderApplyResult(result, depChanges);
+ }
+ if (hasConflicts) {
+ this.renderConflicts(depChanges, './package.json', options);
+ }
+ if (result.frontendDepChanges && result.frontendPackageJsonPath) {
+ const frontendScope = path_1.default.relative(process.cwd(), result.frontendPackageJsonPath);
+ this.renderConflicts(result.frontendDepChanges, frontendScope, options);
+ }
+ for (const w of result.warnings) {
+ this.moduleView.warn(w);
+ }
+ this.moduleView.emptyLine();
+ }
+ renderConflicts(changes, scope, options) {
+ if (options.dryRun && options.force !== true && options.install !== false) {
+ this.moduleView.renderDepConflictsBlocked(changes, scope);
+ }
+ else {
+ this.moduleView.renderDepConflictsResolved(changes, scope);
+ }
+ }
+ async resolveUIFramework(template) {
+ if (!template.variants) {
+ return undefined;
+ }
+ const variants = Object.keys(template.variants);
+ if (variants.length > 1) {
+ return this.moduleView.promptForList(cli_shared_1.Text.module.add.promptSelectUIFramework, variants);
+ }
+ if (variants.length === 1) {
+ return variants[0];
+ }
+ return undefined;
+ }
+ async collectVariables(template, uiFramework) {
+ const variables = {};
+ const variableDefs = this.moduleService.getVariableDefinitions(template, uiFramework);
+ if (variableDefs.length === 0) {
+ return variables;
+ }
+ const { manifestPath, existingKeys } = this.moduleService.loadManifestContext();
+ const fragmentContent = template.cacheDir ? this.moduleService.readManifestFragment(template.cacheDir) : undefined;
+ for (const varDef of variableDefs) {
+ variables[varDef.name] = await this.promptForVariable(varDef, variables, existingKeys, template.moduleKey, fragmentContent, manifestPath);
+ }
+ return variables;
+ }
+ async promptForVariable(varDef, variables, existingKeys, moduleKey, fragmentContent, manifestPath) {
+ while (true) {
+ const effectiveDefault = this.moduleService.computeEffectiveDefault(varDef, variables);
+ const raw = await this.moduleView.promptForText(varDef.prompt, effectiveDefault);
+ const trimmed = (raw ?? '').trim();
+ const value = trimmed !== '' ? trimmed : effectiveDefault || '';
+ const errors = await this.moduleService.validateCandidateValue(varDef, value, existingKeys, moduleKey, fragmentContent, variables, manifestPath);
+ if (errors.length > 0) {
+ for (const err of errors) {
+ this.moduleView.warn(err);
+ }
+ continue;
+ }
+ if (varDef.name === 'resourceKey' && existingKeys.resourceKeys.has(value)) {
+ this.moduleView.info(cli_shared_1.Text.module.add.infoReusingResource(value));
+ }
+ return value;
+ }
+ }
+}
+exports.ModuleAddController = ModuleAddController;
+//# sourceMappingURL=module-add-controller.js.map
\ No newline at end of file