diff --git a/packages/fx-core/resource/package.nls.json b/packages/fx-core/resource/package.nls.json index c89be2b7aa..e86daf5bbc 100644 --- a/packages/fx-core/resource/package.nls.json +++ b/packages/fx-core/resource/package.nls.json @@ -379,40 +379,6 @@ "core.createProjectQuestion.apiSpec.multipleValidationErrors.message": "Incompatible OpenAPI description document. Check output panel for details.", "core.createProjectQuestion.apiSpec.multipleValidationErrors.vscode.message": "Incompatible OpenAPI description document. Check [output panel](command:fx-extension.showOutputChannel) for details.", "core.createProjectQuestion.meArchitecture.title": "Architecture of Search Based Message Extension", - "core.createProjectQuestion.officeXMLAddin.bar.title": "Office Add-in", - "core.createProjectQuestion.officeXMLAddin.bar.detail": "Creating Project.", - "core.createProjectQuestion.officeXMLAddin.mainEntry.title": "Office Add-in", - "core.createProjectQuestion.officeXMLAddin.mainEntry.detail": "Create integration with Outlook, Word, Excel, or PowerPoint", - "core.createProjectQuestion.officeXMLAddin.create.title": "Select to Create an Outlook, Word, Excel, or PowerPoint Add-in", - "core.createProjectQuestion.officeXMLAddin.word.title": "Word Add-in", - "core.createProjectQuestion.officeXMLAddin.word.detail": "Create an add-in that can run in Word across multiple platforms", - "core.createProjectQuestion.officeXMLAddin.word.sso.title": "Add-in with Single Sign On", - "core.createProjectQuestion.officeXMLAddin.word.sso.detail": "Create a Word add-in with Single Sign On capabilities", - "core.createProjectQuestion.officeXMLAddin.word.react.title": "Add-in with React Framework", - "core.createProjectQuestion.officeXMLAddin.word.react.detail": "Create a Word add-in with React framework", - "core.createProjectQuestion.officeXMLAddin.word.create.title": "Create a Word Add-in", - "core.createProjectQuestion.officeXMLAddin.excel.title": "Excel Add-in", - "core.createProjectQuestion.officeXMLAddin.excel.detail": "Extend Excel functionality and access Excel data on multiple platforms", - "core.createProjectQuestion.officeXMLAddin.excel.sso.title": "Add-in with Single Sign On", - "core.createProjectQuestion.officeXMLAddin.excel.sso.detail": "Create an Excel add-in with Single Sign On capabilities", - "core.createProjectQuestion.officeXMLAddin.excel.react.title": "Add-in with React Framework", - "core.createProjectQuestion.officeXMLAddin.excel.react.detail": "Create an Excel add-in with React framework", - "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.title": "Excel Custom Functions Using Shared Runtime", - "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.detail": "Create an Excel add-in leveraging Custom Functions using a Shared Runtime", - "core.createProjectQuestion.officeXMLAddin.excel.cf.js.title": "Excel Custom Functions Using JavaScript-only Runtime", - "core.createProjectQuestion.officeXMLAddin.excel.cf.js.detail": "Create an Excel add-in leveraging Custom Functions using a JavaScript-only Runtime", - "core.createProjectQuestion.officeXMLAddin.excel.create.title": "Create Excel Add-in", - "core.createProjectQuestion.officeXMLAddin.powerpoint.title": "PowerPoint Add-in", - "core.createProjectQuestion.officeXMLAddin.powerpoint.detail": "Build engaging solutions for presentations across platform", - "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.title": "Add-in with Single Sign On", - "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.detail": "PowerPoint add-in with Single Sign On capabilities", - "core.createProjectQuestion.officeXMLAddin.powerpoint.react.title": "Add-in with React Framework", - "core.createProjectQuestion.officeXMLAddin.powerpoint.react.detail": "Create a PowerPoint add-in with React framework", - "core.createProjectQuestion.officeXMLAddin.powerpoint.create.title": "Create a PowerPoint Add-in", - "core.createProjectQuestion.officeXMLAddin.taskpane.title": "Add-in with Basic Task Pane", - "core.createProjectQuestion.officeXMLAddin.taskpane.detail": "Customize the Ribbon with a button and create a dashboard in the Task Pane", - "core.createProjectQuestion.officeXMLAddin.manifestOnly.title": "Add-in Project With only Manifest File", - "core.createProjectQuestion.officeXMLAddin.manifestOnly.detail": "Create an add-in project that includes only the manifest file", "core.aiAssistantBotOption.label": "AI Agent Bot", "core.aiAssistantBotOption.detail": "A custom AI Agent bot in Teams using Teams AI library and OpenAI Assistants API", "core.aiBotOption.label": "AI Chat Bot", diff --git a/packages/fx-core/src/component/coordinator/index.ts b/packages/fx-core/src/component/coordinator/index.ts index 548b28b009..2eb1c4983c 100644 --- a/packages/fx-core/src/component/coordinator/index.ts +++ b/packages/fx-core/src/component/coordinator/index.ts @@ -44,7 +44,6 @@ import { CapabilityOptions, CustomCopilotRagOptions, MeArchitectureOptions, - OfficeAddinHostOptions, ProjectTypeOptions, QuestionNames, ScratchOptions, @@ -61,7 +60,6 @@ import { CopilotPluginGenerator } from "../generator/copilotPlugin/generator"; import { Generator } from "../generator/generator"; import { Generators } from "../generator/generatorProvider"; import { OfficeAddinGenerator } from "../generator/officeAddin/generator"; -import { OfficeXMLAddinGenerator } from "../generator/officeXMLAddin/generator"; import { SPFxGenerator } from "../generator/spfx/spfxGenerator"; import { Feature2TemplateName } from "../generator/templates/templateNames"; import { convertToLangKey } from "../generator/utils"; @@ -191,18 +189,8 @@ class Coordinator { const res = await SPFxGenerator.generate(context, inputs, projectPath); if (res.isErr()) return err(res.error); } else if (ProjectTypeOptions.officeAddinAllIds().includes(projectType)) { - const addinHost = inputs[QuestionNames.OfficeAddinHost]; - if ( - projectType === ProjectTypeOptions.officeXMLAddin().id && - addinHost && - addinHost !== OfficeAddinHostOptions.outlook().id - ) { - const res = await OfficeXMLAddinGenerator.generate(context, inputs, projectPath); - if (res.isErr()) return err(res.error); - } else { - const res = await OfficeAddinGenerator.generate(context, inputs, projectPath); - if (res.isErr()) return err(res.error); - } + const res = await OfficeAddinGenerator.generate(context, inputs, projectPath); + if (res.isErr()) return err(res.error); } else if (capability === CapabilityOptions.copilotPluginApiSpec().id) { const res = await CopilotPluginGenerator.generatePluginFromApiSpec( context, diff --git a/packages/fx-core/src/component/generator/generatorProvider.ts b/packages/fx-core/src/component/generator/generatorProvider.ts index 49eae6aa19..023c13553e 100644 --- a/packages/fx-core/src/component/generator/generatorProvider.ts +++ b/packages/fx-core/src/component/generator/generatorProvider.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import { CopilotGenerator } from "./copilotPlugin/generator"; import { OfficeAddinGeneratorNew } from "./officeAddin/generator"; -import { OfficeXmlAddinGeneratorNew } from "./officeXMLAddin/generator"; import { SPFxGeneratorImport, SPFxGeneratorNew } from "./spfx/spfxGenerator"; import { SsrTabGenerator } from "./templates/ssrTabGenerator"; import { DefaultTemplateGenerator } from "./templates/templateGenerator"; @@ -10,7 +9,6 @@ import { DefaultTemplateGenerator } from "./templates/templateGenerator"; // When multiple generators are activated, only the top one will be executed. export const Generators = [ new OfficeAddinGeneratorNew(), - new OfficeXmlAddinGeneratorNew(), new SsrTabGenerator(), new DefaultTemplateGenerator(), new SPFxGeneratorNew(), diff --git a/packages/fx-core/src/component/generator/officeAddin/generator.ts b/packages/fx-core/src/component/generator/officeAddin/generator.ts index 5b7ea3e028..12cde9e913 100644 --- a/packages/fx-core/src/component/generator/officeAddin/generator.ts +++ b/packages/fx-core/src/component/generator/officeAddin/generator.ts @@ -27,7 +27,6 @@ import { getLocalizedString } from "../../../common/localizeUtils"; import { assembleError } from "../../../error"; import { CapabilityOptions, - OfficeAddinHostOptions, ProgrammingLanguage, ProjectTypeOptions, QuestionNames, @@ -108,11 +107,7 @@ export class OfficeAddinGenerator { const capability = inputs[QuestionNames.Capabilities]; const inputHost = inputs[QuestionNames.OfficeAddinHost]; let host: string = inputHost; - if ( - projectType === ProjectTypeOptions.outlookAddin().id || - (projectType === ProjectTypeOptions.officeXMLAddin().id && - inputHost === OfficeAddinHostOptions.outlook().id) - ) { + if (projectType === ProjectTypeOptions.outlookAddin().id) { host = "outlook"; } else if (projectType === ProjectTypeOptions.officeAddin().id) { if (capability === "json-taskpane") { @@ -133,10 +128,7 @@ export class OfficeAddinGenerator { if (!fromFolder) { // from template const framework = getOfficeAddinFramework(inputs); - const templateConfig = getOfficeAddinTemplateConfig( - projectType, - inputs[QuestionNames.OfficeAddinHost] - ); + const templateConfig = getOfficeAddinTemplateConfig(); const projectLink = templateConfig[capability].framework[framework][language]; // Copy project template files from project repository diff --git a/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts b/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts deleted file mode 100644 index d98aee7837..0000000000 --- a/packages/fx-core/src/component/generator/officeXMLAddin/generator.ts +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * @author zyun@microsoft.com - */ - -import { hooks } from "@feathersjs/hooks/lib"; -import { Context, FxError, GeneratorResult, Inputs, Result, err, ok } from "@microsoft/teamsfx-api"; -import * as childProcess from "child_process"; -import _, { merge } from "lodash"; -import { OfficeAddinManifest } from "office-addin-manifest"; -import { join } from "path"; -import { promisify } from "util"; -import { getLocalizedString } from "../../../common/localizeUtils"; -import { assembleError } from "../../../error"; -import { - OfficeAddinHostOptions, - ProgrammingLanguage, - ProjectTypeOptions, - QuestionNames, -} from "../../../question/constants"; -import { getOfficeAddinTemplateConfig } from "../../../question/create"; -import { ActionContext, ActionExecutionMW } from "../../middleware/actionExecutionMW"; -import { Generator } from "../generator"; -import { HelperMethods } from "../officeAddin/helperMethods"; -import { DefaultTemplateGenerator } from "../templates/templateGenerator"; -import { TemplateInfo } from "../templates/templateInfo"; -import { convertToLangKey } from "../utils"; - -const COMPONENT_NAME = "office-xml-addin"; -const TELEMETRY_EVENT = "generate"; -const TEMPLATE_BASE = "office-xml-addin"; -const TEMPLATE_COMMON_NAME = "office-xml-addin-common"; -const TEMPLATE_COMMON_LANG = "common"; - -const enum OfficeXMLAddinTelemetryProperties { - host = "office-xml-addin-host", - project = "office-xml-addin-project", - lang = "office-xml-addin-lang", -} - -/** - * project-type=office-xml-addin-type addin-host!==outlook - */ -export class OfficeXMLAddinGenerator { - @hooks([ - ActionExecutionMW({ - enableTelemetry: true, - telemetryComponentName: COMPONENT_NAME, - telemetryEventName: TELEMETRY_EVENT, - errorSource: COMPONENT_NAME, - }), - ]) - static async generate( - context: Context, - inputs: Inputs, - destinationPath: string, - actionContext?: ActionContext - ): Promise> { - const host = inputs[QuestionNames.OfficeAddinHost] as string; - const capability = inputs[QuestionNames.Capabilities]; - const lang = _.toLower(inputs[QuestionNames.ProgrammingLanguage]) as - | "javascript" - | "typescript"; - const langKey = convertToLangKey(lang); - const appName = inputs[QuestionNames.AppName] as string; - const projectType = inputs[QuestionNames.ProjectType]; - const templateConfig = getOfficeAddinTemplateConfig(projectType, host); - const templateName = templateConfig[capability].localTemplate; - const projectLink = templateConfig[capability].framework["default"][lang]; - const workingDir = process.cwd(); - const progressBar = context.userInteraction.createProgressBar( - getLocalizedString("core.createProjectQuestion.officeXMLAddin.bar.title"), - 1 - ); - - merge(actionContext?.telemetryProps, { - [OfficeXMLAddinTelemetryProperties.host]: host, - [OfficeXMLAddinTelemetryProperties.project]: capability, - [OfficeXMLAddinTelemetryProperties.lang]: lang, - }); - - try { - process.chdir(destinationPath); - await progressBar.start(); - await progressBar.next( - getLocalizedString("core.createProjectQuestion.officeXMLAddin.bar.detail") - ); - - if (!!projectLink) { - // [Condition]: Project have remote repo (not manifest-only proj) - - // -> Step: Download the project from GitHub - const fetchRes = await HelperMethods.fetchAndUnzip( - "office-xml-addin-generator", - projectLink, - destinationPath - ); - if (fetchRes.isErr()) { - return err(fetchRes.error); - } - // -> Step: Convert to single Host - await OfficeXMLAddinGenerator.childProcessExec( - `npm run convert-to-single-host --if-present -- ${_.toLower(host)}` - ); - } else { - // [Condition]: Manifest Only - - // -> Step: Copy proj files for manifest-only project - const getManifestOnlyProjectTemplateRes = await Generator.generateTemplate( - context, - destinationPath, - `${TEMPLATE_BASE}-manifest-only`, - langKey - ); - if (getManifestOnlyProjectTemplateRes.isErr()) - throw err(getManifestOnlyProjectTemplateRes.error); - } - - // -> Common Step: Copy the README (or with manifest for manifest-only proj) - const getReadmeTemplateRes = await Generator.generateTemplate( - context, - destinationPath, - `${TEMPLATE_BASE}-${templateName}`, - langKey - ); - if (getReadmeTemplateRes.isErr()) throw err(getReadmeTemplateRes.error); - - // -> Common Step: Modify the Manifest - await OfficeAddinManifest.modifyManifestFile( - `${join(destinationPath, "manifest.xml")}`, - "random", - `${appName}` - ); - - // -> Common Step: Generate OfficeXMLAddin specific `teamsapp.yml` - const generateOfficeYMLRes = await Generator.generateTemplate( - context, - destinationPath, - TEMPLATE_COMMON_NAME, - TEMPLATE_COMMON_LANG - ); - if (generateOfficeYMLRes.isErr()) throw err(generateOfficeYMLRes.error); - - process.chdir(workingDir); - await progressBar.end(true, true); - return ok(undefined); - } catch (e) { - process.chdir(workingDir); - await progressBar.end(false, true); - return err(assembleError(e as Error)); - } - } - - public static async childProcessExec(cmdLine: string): Promise<{ - stdout: string; - stderr: string; - }> { - return promisify(childProcess.exec)(cmdLine); - } -} - -export class OfficeXmlAddinGeneratorNew extends DefaultTemplateGenerator { - componentName = "office-xml-addin-generator"; - - public activate(context: Context, inputs: Inputs): boolean { - const projectType = inputs[QuestionNames.ProjectType]; - const addinHost = inputs[QuestionNames.OfficeAddinHost]; - return ( - projectType === ProjectTypeOptions.officeXMLAddin().id && - addinHost && - addinHost !== OfficeAddinHostOptions.outlook().id - ); - } - - public async getTemplateInfos( - context: Context, - inputs: Inputs, - destinationPath: string, - actionContext?: ActionContext - ): Promise> { - const host = inputs[QuestionNames.OfficeAddinHost] as string; - const capability = inputs[QuestionNames.Capabilities]; - const lang = _.toLower(inputs[QuestionNames.ProgrammingLanguage]) as - | "javascript" - | "typescript"; - const projectType = inputs[QuestionNames.ProjectType]; - const templateConfig = getOfficeAddinTemplateConfig(projectType, host); - const templateName = templateConfig[capability].localTemplate; - const projectLink = templateConfig[capability].framework["default"][lang]; - merge(actionContext?.telemetryProps, { - [OfficeXMLAddinTelemetryProperties.host]: host, - [OfficeXMLAddinTelemetryProperties.project]: capability, - [OfficeXMLAddinTelemetryProperties.lang]: lang, - }); - - process.chdir(destinationPath); - const templates: TemplateInfo[] = []; - if (!!projectLink) { - // [Condition]: Project have remote repo (not manifest-only proj) - - // -> Step: Download the project from GitHub - const fetchRes = await HelperMethods.fetchAndUnzip( - this.componentName, - projectLink, - destinationPath - ); - if (fetchRes.isErr()) { - return err(fetchRes.error); - } - // -> Step: Convert to single Host - await OfficeXMLAddinGenerator.childProcessExec( - `npm run convert-to-single-host --if-present -- ${_.toLower(host)}` - ); - } else { - templates.push({ - templateName: `${TEMPLATE_BASE}-manifest-only`, - language: lang as ProgrammingLanguage, - }); - } - // -> Common Step: Copy the README (or with manifest for manifest-only proj) - templates.push({ - templateName: `${TEMPLATE_BASE}-${templateName}`, - language: lang as ProgrammingLanguage, - }); - templates.push({ - templateName: TEMPLATE_COMMON_NAME, - language: ProgrammingLanguage.None, - }); - return ok(templates); - } - - public async post( - context: Context, - inputs: Inputs, - destinationPath: string, - actionContext?: ActionContext - ): Promise> { - const appName = inputs[QuestionNames.AppName] as string; - // -> Common Step: Modify the Manifest - await OfficeAddinManifest.modifyManifestFile( - `${join(destinationPath, "manifest.xml")}`, - "random", - `${appName}` - ); - return ok({}); - } -} diff --git a/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts b/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts index e0fce984aa..da4e3fe808 100644 --- a/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts +++ b/packages/fx-core/src/component/generator/officeXMLAddin/projectConfig.ts @@ -24,42 +24,6 @@ export interface IOfficeAddinProjectConfig { [property: string]: IOfficeAddinHostConfig; } -const CommonProjectConfig = { - taskpane: { - title: "core.createProjectQuestion.officeXMLAddin.taskpane.title", - detail: "core.createProjectQuestion.officeXMLAddin.taskpane.detail", - framework: { - default: { - typescript: "https://aka.ms/ccdevx-fx-taskpane-ts", - javascript: "https://aka.ms/ccdevx-fx-taskpane-js", - }, - }, - }, - sso: { - framework: { - default: { - typescript: "https://aka.ms/ccdevx-fx-sso-ts", - javascript: "https://aka.ms/ccdevx-fx-sso-js", - }, - }, - }, - react: { - framework: { - default: { - typescript: "https://aka.ms/ccdevx-fx-react-ts", - javascript: "https://aka.ms/ccdevx-fx-react-js", - }, - }, - }, - manifest: { - title: "core.createProjectQuestion.officeXMLAddin.manifestOnly.title", - detail: "core.createProjectQuestion.officeXMLAddin.manifestOnly.detail", - framework: { - default: {}, - }, - }, -}; - export const OfficeAddinProjectConfig: IOfficeAddinProjectConfig = { json: { "json-taskpane": { @@ -94,92 +58,4 @@ export const OfficeAddinProjectConfig: IOfficeAddinProjectConfig = { manifestPath: "manifest.json", }, }, - word: { - "word-taskpane": { - localTemplate: "word-taskpane", - ...CommonProjectConfig.taskpane, - }, - "word-sso": { - title: "core.createProjectQuestion.officeXMLAddin.word.sso.title", - detail: "core.createProjectQuestion.officeXMLAddin.word.sso.detail", - localTemplate: "word-sso", - ...CommonProjectConfig.sso, - }, - "word-react": { - title: "core.createProjectQuestion.officeXMLAddin.word.react.title", - detail: "core.createProjectQuestion.officeXMLAddin.word.react.detail", - localTemplate: "word-react", - ...CommonProjectConfig.react, - }, - "word-manifest": { - localTemplate: "word-manifest-only", - ...CommonProjectConfig.manifest, - }, - }, - excel: { - "excel-taskpane": { - localTemplate: "excel-taskpane", - ...CommonProjectConfig.taskpane, - }, - "excel-sso": { - title: "core.createProjectQuestion.officeXMLAddin.excel.sso.title", - detail: "core.createProjectQuestion.officeXMLAddin.excel.sso.detail", - localTemplate: "excel-sso", - ...CommonProjectConfig.sso, - }, - "excel-react": { - title: "core.createProjectQuestion.officeXMLAddin.excel.react.title", - detail: "core.createProjectQuestion.officeXMLAddin.excel.react.detail", - localTemplate: "excel-react", - ...CommonProjectConfig.react, - }, - "excel-custom-functions-shared": { - title: "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.title", - detail: "core.createProjectQuestion.officeXMLAddin.excel.cf.shared.detail", - localTemplate: "excel-cf", - framework: { - default: { - typescript: "https://aka.ms/ccdevx-fx-cf-shared-ts", - javascript: "https://aka.ms/ccdevx-fx-cf-shared-js", - }, - }, - }, - "excel-custom-functions-js": { - title: "core.createProjectQuestion.officeXMLAddin.excel.cf.js.title", - detail: "core.createProjectQuestion.officeXMLAddin.excel.cf.js.detail", - localTemplate: "excel-cf", - framework: { - default: { - typescript: "https://aka.ms/ccdevx-fx-cf-js-ts", - javascript: "https://aka.ms/ccdevx-fx-cf-js-js", - }, - }, - }, - "excel-manifest": { - localTemplate: "excel-manifest-only", - ...CommonProjectConfig.manifest, - }, - }, - powerpoint: { - "powerpoint-taskpane": { - localTemplate: "powerpoint-taskpane", - ...CommonProjectConfig.taskpane, - }, - "powerpoint-sso": { - localTemplate: "powerpoint-sso", - title: "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.title", - detail: "core.createProjectQuestion.officeXMLAddin.powerpoint.sso.detail", - ...CommonProjectConfig.sso, - }, - "powerpoint-react": { - localTemplate: "powerpoint-react", - title: "core.createProjectQuestion.officeXMLAddin.powerpoint.react.title", - detail: "core.createProjectQuestion.officeXMLAddin.powerpoint.react.detail", - ...CommonProjectConfig.react, - }, - "powerpoint-manifest": { - localTemplate: "powerpoint-manifest-only", - ...CommonProjectConfig.manifest, - }, - }, }; diff --git a/packages/fx-core/src/index.ts b/packages/fx-core/src/index.ts index 3eb5f4e21b..46fa61a453 100644 --- a/packages/fx-core/src/index.ts +++ b/packages/fx-core/src/index.ts @@ -98,3 +98,5 @@ export * from "./error/index"; export * from "./question/constants"; export * from "./question/inputs"; export * from "./question/options"; +export * from "./component/middleware/actionExecutionMW"; +export { TemplateInfo } from "./component/generator/templates/templateInfo"; diff --git a/packages/fx-core/src/question/constants.ts b/packages/fx-core/src/question/constants.ts index 1c229bf475..030de0725a 100644 --- a/packages/fx-core/src/question/constants.ts +++ b/packages/fx-core/src/question/constants.ts @@ -97,6 +97,7 @@ export enum ProgrammingLanguage { TS = "typescript", CSharp = "csharp", PY = "python", + Common = "common", None = "none", } @@ -215,17 +216,6 @@ export class ProjectTypeOptions { }; } - static officeXMLAddin(platform?: Platform): OptionItem { - return { - id: "office-xml-addin-type", - label: `${platform === Platform.VSCode ? "$(teamsfx-m365) " : ""}${getLocalizedString( - "core.createProjectQuestion.officeXMLAddin.mainEntry.title" - )}`, - detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.mainEntry.detail"), - groupName: ProjectTypeOptions.getCreateGroupName(), - }; - } - static officeAddin(platform?: Platform): OptionItem { return { id: "office-addin-type", @@ -240,7 +230,6 @@ export class ProjectTypeOptions { static officeAddinAllIds(platform?: Platform): string[] { return [ ProjectTypeOptions.officeAddin(platform).id, - ProjectTypeOptions.officeXMLAddin(platform).id, ProjectTypeOptions.outlookAddin(platform).id, ]; } @@ -567,9 +556,6 @@ export class CapabilityOptions { const items: OptionItem[] = []; const isOutlookAddin = projectType === ProjectTypeOptions.outlookAddin().id; const isOfficeAddin = projectType === ProjectTypeOptions.officeAddin().id; - const isOfficeXMLAddinForOutlook = - projectType === ProjectTypeOptions.officeXMLAddin().id && - host === OfficeAddinHostOptions.outlook().id; const pushToItems = (option: any) => { const capabilityValue = OfficeAddinProjectConfig.json[option]; @@ -580,11 +566,11 @@ export class CapabilityOptions { }); }; - if (isOutlookAddin || isOfficeAddin || isOfficeXMLAddinForOutlook) { + if (isOutlookAddin || isOfficeAddin) { pushToItems("json-taskpane"); - if (isOutlookAddin || isOfficeXMLAddinForOutlook) { + if (isOutlookAddin) { items.push(CapabilityOptions.outlookAddinImport()); - } else if (isOfficeAddin) { + } else { items.push(CapabilityOptions.officeContentAddin()); items.push(CapabilityOptions.officeAddinImport()); } @@ -819,53 +805,6 @@ export class CapabilityOptions { } } -export class OfficeAddinHostOptions { - static all(platform?: Platform): OptionItem[] { - return [ - OfficeAddinHostOptions.outlook(platform), - OfficeAddinHostOptions.word(), - OfficeAddinHostOptions.excel(), - OfficeAddinHostOptions.powerpoint(), - ]; - } - static outlook(platform?: Platform): OptionItem { - return { - id: "outlook", - label: `${platform === Platform.VSCode ? "$(mail) " : ""}${getLocalizedString( - "core.createProjectQuestion.projectType.outlookAddin.label" - )}`, - detail: getLocalizedString("core.createProjectQuestion.projectType.outlookAddin.detail"), - data: "Outlook", - }; - } - static word(): OptionItem { - return { - id: "word", - label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.word.title"), - detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.word.detail"), - data: "Word", - }; - } - - static excel(): OptionItem { - return { - id: "excel", - label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.title"), - detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.detail"), - data: "Excel", - }; - } - - static powerpoint(): OptionItem { - return { - id: "powerpoint", - label: getLocalizedString("core.createProjectQuestion.officeXMLAddin.powerpoint.title"), - detail: getLocalizedString("core.createProjectQuestion.officeXMLAddin.powerpoint.detail"), - data: "PowerPoint", - }; - } -} - export class ApiAuthOptions { static none(): OptionItem { return { diff --git a/packages/fx-core/src/question/create.ts b/packages/fx-core/src/question/create.ts index bc0343d69b..145c58e705 100644 --- a/packages/fx-core/src/question/create.ts +++ b/packages/fx-core/src/question/create.ts @@ -57,7 +57,6 @@ import { CustomCopilotRagOptions, MeArchitectureOptions, NotificationTriggerOptions, - OfficeAddinHostOptions, ProgrammingLanguage, ProjectTypeOptions, QuestionNames, @@ -72,7 +71,6 @@ export function projectTypeQuestion(): SingleSelectQuestion { ProjectTypeOptions.bot(Platform.CLI), ProjectTypeOptions.tab(Platform.CLI), ProjectTypeOptions.me(Platform.CLI), - ProjectTypeOptions.officeXMLAddin(Platform.CLI), ProjectTypeOptions.officeAddin(Platform.CLI), ProjectTypeOptions.outlookAddin(Platform.CLI), ]; @@ -109,15 +107,10 @@ export function projectTypeQuestion(): SingleSelectQuestion { return [projectType]; } } else { - if (inputs.agent === "office") { - //only for @office agent, officeXMLAddin are supported - staticOptions.push(ProjectTypeOptions.officeXMLAddin(inputs.platform)); + if (featureFlagManager.getBooleanValue(FeatureFlags.OfficeAddin)) { + staticOptions.push(ProjectTypeOptions.officeAddin(inputs.platform)); } else { - if (featureFlagManager.getBooleanValue(FeatureFlags.OfficeAddin)) { - staticOptions.push(ProjectTypeOptions.officeAddin(inputs.platform)); - } else { - staticOptions.push(ProjectTypeOptions.outlookAddin(inputs.platform)); - } + staticOptions.push(ProjectTypeOptions.outlookAddin(inputs.platform)); } } @@ -185,28 +178,9 @@ export function capabilityQuestion(): SingleSelectQuestion { "core.createProjectQuestion.projectType.messageExtension.title" ); case ProjectTypeOptions.outlookAddin().id: + return getLocalizedString("core.createProjectQuestion.projectType.outlookAddin.title"); case ProjectTypeOptions.officeAddin().id: - case ProjectTypeOptions.officeXMLAddin().id: { - switch (inputs[QuestionNames.OfficeAddinHost]) { - case OfficeAddinHostOptions.outlook().id: - return getLocalizedString( - "core.createProjectQuestion.projectType.outlookAddin.title" - ); - case OfficeAddinHostOptions.word().id: - return getLocalizedString( - "core.createProjectQuestion.officeXMLAddin.word.create.title" - ); - case OfficeAddinHostOptions.excel().id: - return getLocalizedString( - "core.createProjectQuestion.officeXMLAddin.excel.create.title" - ); - case OfficeAddinHostOptions.powerpoint().id: - return getLocalizedString( - "core.createProjectQuestion.officeXMLAddin.powerpoint.create.title" - ); - } return getLocalizedString("core.createProjectQuestion.projectType.officeAddin.title"); - } case ProjectTypeOptions.copilotPlugin().id: return getLocalizedString("core.createProjectQuestion.projectType.copilotPlugin.title"); case ProjectTypeOptions.customCopilot().id: @@ -500,15 +474,6 @@ export function SPFxImportFolderQuestion(hasDefaultFunc = false): FolderQuestion }; } -export function officeAddinHostingQuestion(): SingleSelectQuestion { - return { - name: QuestionNames.OfficeAddinHost, - title: getLocalizedString("core.createProjectQuestion.officeXMLAddin.create.title"), - type: "singleSelect", - staticOptions: OfficeAddinHostOptions.all(), - }; -} - export function officeAddinFrameworkQuestion(): SingleSelectQuestion { return { type: "singleSelect", @@ -531,12 +496,7 @@ export function officeAddinFrameworkQuestion(): SingleSelectQuestion { export function getAddinFrameworkOptions(inputs: Inputs): OptionItem[] { const projectType = inputs[QuestionNames.ProjectType]; const capabilities = inputs[QuestionNames.Capabilities]; - const host = inputs[QuestionNames.OfficeAddinHost]; - if ( - projectType === ProjectTypeOptions.outlookAddin().id || - (projectType === ProjectTypeOptions.officeXMLAddin().id && - host === OfficeAddinHostOptions.outlook().id) - ) { + if (projectType === ProjectTypeOptions.outlookAddin().id) { return [{ id: "default", label: "Default" }]; } else if ( (projectType === ProjectTypeOptions.officeAddin().id && @@ -564,29 +524,17 @@ export function getOfficeAddinFramework(inputs: Inputs): string { inputs[QuestionNames.OfficeAddinFramework] ) { return inputs[QuestionNames.OfficeAddinFramework]; - } else if ( - (projectType === ProjectTypeOptions.officeXMLAddin().id && - inputs[QuestionNames.OfficeAddinHost] === OfficeAddinHostOptions.outlook().id) || - projectType === ProjectTypeOptions.outlookAddin().id - ) { + } else if (projectType === ProjectTypeOptions.outlookAddin().id) { return "default_old"; } else { return "default"; } } -export function getOfficeAddinTemplateConfig( - projectType: string, - addinHost?: string -): IOfficeAddinHostConfig { - if ( - projectType === ProjectTypeOptions.officeXMLAddin().id && - addinHost && - addinHost !== OfficeAddinHostOptions.outlook().id - ) { - return OfficeAddinProjectConfig[addinHost]; - } + +export function getOfficeAddinTemplateConfig(): IOfficeAddinHostConfig { return OfficeAddinProjectConfig["json"]; } + export function getLanguageOptions(inputs: Inputs): OptionItem[] { const runtime = getRuntime(inputs); // dotnet runtime only supports C# @@ -594,7 +542,6 @@ export function getLanguageOptions(inputs: Inputs): OptionItem[] { return [{ id: ProgrammingLanguage.CSharp, label: "C#" }]; } const capabilities = inputs[QuestionNames.Capabilities] as string; - const host = inputs[QuestionNames.OfficeAddinHost] as string; // office addin supports language defined in officeAddinJsonData const projectType = inputs[QuestionNames.ProjectType]; @@ -602,19 +549,14 @@ export function getLanguageOptions(inputs: Inputs): OptionItem[] { if (capabilities.endsWith("-manifest")) { return [{ id: ProgrammingLanguage.JS, label: "JavaScript" }]; } - if ( - projectType === ProjectTypeOptions.outlookAddin().id || - (projectType === ProjectTypeOptions.officeXMLAddin().id && - host === OfficeAddinHostOptions.outlook().id) - ) { + if (projectType === ProjectTypeOptions.outlookAddin().id) { return [{ id: ProgrammingLanguage.TS, label: "TypeScript" }]; } - const officeXMLAddinLangConfig = getOfficeAddinTemplateConfig(projectType, host)[capabilities] - .framework["default"]; + const officeAddinLangConfig = getOfficeAddinTemplateConfig()[capabilities].framework["default"]; const officeXMLAddinLangOptions = []; - if (!!officeXMLAddinLangConfig.typescript) + if (!!officeAddinLangConfig.typescript) officeXMLAddinLangOptions.push({ id: ProgrammingLanguage.TS, label: "TypeScript" }); - if (!!officeXMLAddinLangConfig.javascript) + if (!!officeAddinLangConfig.javascript) officeXMLAddinLangOptions.push({ id: ProgrammingLanguage.JS, label: "JavaScript" }); return officeXMLAddinLangOptions; } @@ -1528,11 +1470,6 @@ export function createProjectQuestionNode(): IQTreeNode { data: projectTypeQuestion(), cliOptionDisabled: "self", }, - { - condition: (inputs: Inputs) => - inputs[QuestionNames.ProjectType] === ProjectTypeOptions.officeXMLAddin().id, - data: officeAddinHostingQuestion(), - }, capabilitySubTree(), { condition: (inputs: Inputs) => diff --git a/packages/fx-core/src/question/inputs/CreateProjectInputs.ts b/packages/fx-core/src/question/inputs/CreateProjectInputs.ts index 8f8430a72b..891de34d06 100644 --- a/packages/fx-core/src/question/inputs/CreateProjectInputs.ts +++ b/packages/fx-core/src/question/inputs/CreateProjectInputs.ts @@ -14,15 +14,7 @@ export interface CreateProjectInputs extends Inputs { /** @description Teams Toolkit: select runtime for your app */ runtime?: "node" | "dotnet"; /** @description New Project */ - "project-type"?: - | "bot-type" - | "tab-type" - | "me-type" - | "office-xml-addin-type" - | "office-addin-type" - | "outlook-addin-type"; - /** @description Select to Create an Outlook, Word, Excel, or PowerPoint Add-in */ - "addin-host"?: "outlook" | "word" | "excel" | "powerpoint"; + "project-type"?: "bot-type" | "tab-type" | "me-type" | "office-addin-type" | "outlook-addin-type"; /** @description Capabilities */ capabilities?: | "empty" @@ -49,21 +41,7 @@ export interface CreateProjectInputs extends Inputs { | "basic-declarative-copilot" | "declarative-copilot-with-plugin-from-scratch" | "json-taskpane" - | "office-content-addin" - | "word-taskpane" - | "word-sso" - | "word-react" - | "word-manifest" - | "excel-taskpane" - | "excel-sso" - | "excel-react" - | "excel-custom-functions-shared" - | "excel-custom-functions-js" - | "excel-manifest" - | "powerpoint-taskpane" - | "powerpoint-sso" - | "powerpoint-react" - | "powerpoint-manifest"; + | "office-content-addin"; /** @description Select triggers */ "bot-host-type-trigger"?: | "http-restify" diff --git a/packages/fx-core/src/question/options/CreateProjectOptions.ts b/packages/fx-core/src/question/options/CreateProjectOptions.ts index 4f55d9ab47..10c325c7b3 100644 --- a/packages/fx-core/src/question/options/CreateProjectOptions.ts +++ b/packages/fx-core/src/question/options/CreateProjectOptions.ts @@ -19,12 +19,6 @@ export const CreateProjectOptions: CLICommandOption[] = [ hidden: true, choices: ["node", "dotnet"], }, - { - name: "addin-host", - type: "string", - description: "Select to Create an Outlook, Word, Excel, or PowerPoint Add-in", - choices: ["outlook", "word", "excel", "powerpoint"], - }, { name: "capability", questionName: "capabilities", @@ -58,20 +52,6 @@ export const CreateProjectOptions: CLICommandOption[] = [ "declarative-copilot-with-plugin-from-scratch", "json-taskpane", "office-content-addin", - "word-taskpane", - "word-sso", - "word-react", - "word-manifest", - "excel-taskpane", - "excel-sso", - "excel-react", - "excel-custom-functions-shared", - "excel-custom-functions-js", - "excel-manifest", - "powerpoint-taskpane", - "powerpoint-sso", - "powerpoint-react", - "powerpoint-manifest", ], choiceListCommand: "teamsapp list templates", }, diff --git a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts index 5ea3f141c2..d5e3401fcc 100644 --- a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts +++ b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts @@ -16,7 +16,6 @@ import { OfficeAddinGenerator, OfficeAddinGeneratorNew, } from "../../../src/component/generator/officeAddin/generator"; -import { OfficeXMLAddinGenerator } from "../../../src/component/generator/officeXMLAddin/generator"; import { SPFxGenerator } from "../../../src/component/generator/spfx/spfxGenerator"; import { DefaultTemplateGenerator } from "../../../src/component/generator/templates/templateGenerator"; import { TemplateNames } from "../../../src/component/generator/templates/templateNames"; @@ -30,7 +29,6 @@ import { CustomCopilotAssistantOptions, CustomCopilotRagOptions, MeArchitectureOptions, - OfficeAddinHostOptions, ProjectTypeOptions, QuestionNames, ScratchOptions, @@ -225,44 +223,13 @@ const V3Version = MetadataV3.projectVersion; assert.isTrue(res.error instanceof InputValidationError); } }); - it("create project for new office XML Addin MissingRequiredInputError missing App name", async () => { - const inputs: Inputs = { - platform: Platform.VSCode, - ignoreLockByUT: true, - folder: ".", - [QuestionNames.Scratch]: ScratchOptions.yes().id, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - }; - const context = createContext(); - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isErr()); - if (res.isErr()) { - assert.isTrue(res.error instanceof MissingRequiredInputError); - } - }); - it("create project for new office XML Addin InputValidationError invalid App name", async () => { - const inputs: Inputs = { - platform: Platform.VSCode, - ignoreLockByUT: true, - folder: ".", - [QuestionNames.Scratch]: ScratchOptions.yes().id, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.AppName]: "__#$%___", - }; - const context = createContext(); - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isErr()); - if (res.isErr()) { - assert.isTrue(res.error instanceof InputValidationError); - } - }); it("create project for new office JSON Addin MissingRequiredInputError missing App name", async () => { const inputs: Inputs = { platform: Platform.VSCode, ignoreLockByUT: true, folder: ".", [QuestionNames.Scratch]: ScratchOptions.yes().id, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, + [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id, }; const context = createContext(); const res = await coordinator.create(context, inputs); @@ -277,7 +244,7 @@ const V3Version = MetadataV3.projectVersion; ignoreLockByUT: true, folder: ".", [QuestionNames.Scratch]: ScratchOptions.yes().id, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, + [QuestionNames.ProjectType]: ProjectTypeOptions.officeAddin().id, "app-name": "__#$%___", }; const context = createContext(); @@ -1062,87 +1029,6 @@ describe("Office Addin", async () => { }); }); -describe("Office XML Addin", async () => { - let mockedEnvRestore: RestoreFn = () => {}; - const sandbox = sinon.createSandbox(); - const tools = new MockTools(); - tools.ui = new MockedUserInteraction(); - setTools(tools); - - beforeEach(() => { - sandbox.stub(fs, "ensureDir").resolves(); - mockedEnvRestore = mockedEnv({ TEAMSFX_NEW_GENERATOR: "false" }); - }); - - afterEach(() => { - sandbox.restore(); - mockedEnvRestore(); - }); - - it("should scaffold project successfully", async () => { - const context = createContext(); - context.userInteraction = new MockedUserInteraction(); - - sandbox.stub(OfficeXMLAddinGenerator, "generate").resolves(ok(undefined)); - - const inputs: Inputs = { - platform: Platform.VSCode, - folder: ".", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.AppName]: randomAppName(), - [QuestionNames.Scratch]: ScratchOptions.yes().id, - }; - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isOk()); - }); - - it("should return error if app name is invalid", async () => { - const context = createContext(); - context.userInteraction = new MockedUserInteraction(); - const inputs: Inputs = { - platform: Platform.VSCode, - folder: ".", - [QuestionNames.AppName]: "__invalid__", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - }; - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isErr() && res.error instanceof InputValidationError); - }); - - it("should return error if app name is undefined", async () => { - const context = createContext(); - context.userInteraction = new MockedUserInteraction(); - const inputs: Inputs = { - platform: Platform.VSCode, - folder: ".", - [QuestionNames.AppName]: undefined, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - }; - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isErr() && res.error instanceof MissingRequiredInputError); - }); - - it("should return error if OfficeXMLAddinGenerator returns error", async () => { - const context = createContext(); - context.userInteraction = new MockedUserInteraction(); - - const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage"); - sandbox.stub(OfficeXMLAddinGenerator, "generate").resolves(err(mockedError)); - - const inputs: Inputs = { - platform: Platform.VSCode, - folder: ".", - [QuestionNames.Scratch]: ScratchOptions.yes().id, - [QuestionNames.AppName]: randomAppName(), - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - }; - const res = await coordinator.create(context, inputs); - assert.isTrue(res.isErr() && res.error.name === "mockedError"); - }); -}); - describe("Office Addin", async () => { let mockedEnvRestore: RestoreFn = () => {}; const sandbox = sinon.createSandbox(); diff --git a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts index 3762a612bc..123c70a016 100644 --- a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts +++ b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts @@ -40,7 +40,6 @@ import { HelperMethods } from "../../../src/component/generator/officeAddin/help import { UserCancelError } from "../../../src/error"; import { CapabilityOptions, - OfficeAddinHostOptions, ProgrammingLanguage, ProjectTypeOptions, QuestionNames, @@ -194,26 +193,6 @@ describe("OfficeAddinGenerator for Outlook Addin", function () { chai.expect(result.isOk()).to.eq(true); }); - it("should scaffold taskpane successfully on happy path if project-type is officeXMLAddin and host is outlook", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - "app-name": "outlook-addin-test", - }; - inputs[QuestionNames.ProjectType] = ProjectTypeOptions.officeXMLAddin().id; - inputs[QuestionNames.OfficeAddinHost] = OfficeAddinHostOptions.outlook().id; - inputs[QuestionNames.Capabilities] = "json-taskpane"; - inputs[QuestionNames.OfficeAddinFolder] = undefined; - inputs[QuestionNames.ProgrammingLanguage] = "typescript"; - - sinon.stub(OfficeAddinGenerator, "childProcessExec").resolves(); - sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); - sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({}); - const result = await OfficeAddinGenerator.doScaffolding(context, inputs, testFolder); - - chai.expect(result.isOk()).to.eq(true); - }); - it("should scaffold taskpane failed, throw error", async () => { const inputs: Inputs = { platform: Platform.CLI, diff --git a/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts deleted file mode 100644 index 73551d0fef..0000000000 --- a/packages/fx-core/tests/component/generator/officeXMLAddinGenerator.test.ts +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * @author zyun@microsoft.com - */ - -import { Context, Inputs, Platform, SystemError, err, ok } from "@microsoft/teamsfx-api"; -import * as chai from "chai"; -import * as childProcess from "child_process"; -import fs from "fs"; -import fse from "fs-extra"; -import "mocha"; -import mockedEnv, { RestoreFn } from "mocked-env"; -import { OfficeAddinManifest } from "office-addin-manifest"; -import * as path from "path"; -import * as sinon from "sinon"; -import * as uuid from "uuid"; -import { createContext, setTools } from "../../../src/common/globalVars"; -import { cpUtils } from "../../../src/component/deps-checker/"; -import { Generator } from "../../../src/component/generator/generator"; -import { HelperMethods } from "../../../src/component/generator/officeAddin/helperMethods"; -import { - OfficeXMLAddinGenerator, - OfficeXmlAddinGeneratorNew, -} from "../../../src/component/generator/officeXMLAddin/generator"; -import { - OfficeAddinHostOptions, - ProgrammingLanguage, - ProjectTypeOptions, - QuestionNames, - getOfficeAddinTemplateConfig, -} from "../../../src/question"; -import { MockTools } from "../../core/utils"; - -describe("OfficeXMLAddinGenerator", function () { - const testFolder = path.resolve("./tmp"); - let context: Context; - let mockedEnvRestore: RestoreFn; - const mockedError = new SystemError("mockedSource", "mockedError", "mockedMessage"); - - beforeEach(async () => { - mockedEnvRestore = mockedEnv({ clear: true }); - const gtools = new MockTools(); - setTools(gtools); - context = createContext(); - - await fse.ensureDir(testFolder); - sinon.stub(fs, "stat").resolves(); - sinon.stub(cpUtils, "executeCommand").resolves("succeed"); - const manifestId = uuid.v4(); - sinon.stub(fs, "readFile").resolves(new Buffer(`{"id": "${manifestId}"}`)); - sinon.stub(fs, "writeFile").resolves(); - sinon.stub(fs, "rename").resolves(); - sinon.stub(fs, "copyFile").resolves(); - sinon.stub(fse, "remove").resolves(); - sinon.stub(fse, "readJson").resolves({}); - sinon.stub(fse, "ensureFile").resolves(); - sinon.stub(fse, "writeJSON").resolves(); - }); - - afterEach(async () => { - sinon.restore(); - mockedEnvRestore(); - if (await fse.pathExists(testFolder)) { - await fse.rm(testFolder, { recursive: true }); - } - }); - - it("should run childProcessExec command success", async function () { - sinon.stub(childProcess, "exec").yields(`echo 'test'`, "test"); - chai.assert(await OfficeXMLAddinGenerator.childProcessExec(`echo 'test'`), "test"); - }); - - it("should throw error once command fail", async function () { - try { - await OfficeXMLAddinGenerator.childProcessExec("exit -1"); - } catch (err) { - chai.assert(err.message, "Command failed: exit -1"); - } - }); - - it("should success when generate normal project on happy path", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: "word-taskpane", - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "typescript", - }; - - sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); - sinon.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves(); - sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({}); - sinon.stub(Generator, "generateTemplate").resolves(ok(undefined)); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.expect(result.isOk()).to.eq(true); - }); - - it("should success when generate manifest-only project on happy path", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: "word-manifest", - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "javascript", - }; - - sinon.stub(Generator, "generateTemplate").resolves(ok(undefined)); - sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({}); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.expect(result.isOk()).to.eq(true); - }); - - it("should failed when generate manifest-only project on happy path when download failed", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: ["react"], - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "typescript", - }; - - sinon.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); - sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({}); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.assert.isTrue(result.isErr()); - }); - - it("should failed when get manifest-only failed", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: ["word-manifest"], - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "javascript", - }; - - sinon.stub(Generator, "generateTemplate").onCall(0).resolves(err(mockedError)); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.assert.isTrue(result.isErr()); - }); - - it("should failed when get readme failed", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: ["word-manifest"], - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "javascript", - }; - - const generatorStub = sinon.stub(Generator, "generateTemplate"); - generatorStub.onCall(0).resolves(ok(undefined)); - generatorStub.onCall(1).resolves(err(mockedError)); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.assert.isTrue(result.isErr()); - }); - - it("should failed when gen yml failed", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: testFolder, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: ["word-manifest"], - [QuestionNames.AppName]: "office-addin-test", - [QuestionNames.OfficeAddinFolder]: undefined, - [QuestionNames.ProgrammingLanguage]: "javascript", - }; - - const generatorStub = sinon.stub(Generator, "generateTemplate"); - generatorStub.onCall(0).resolves(ok(undefined)); - generatorStub.onCall(1).resolves(ok(undefined)); - generatorStub.onCall(2).resolves(err(mockedError)); - sinon.stub(OfficeAddinManifest, "modifyManifestFile").resolves({}); - const result = await OfficeXMLAddinGenerator.generate(context, inputs, testFolder); - - chai.assert.isTrue(result.isErr()); - }); -}); - -describe("getOfficeAddinTemplateConfig", () => { - it("should return empty repo info if manifest-only project", () => { - const config = getOfficeAddinTemplateConfig(ProjectTypeOptions.officeXMLAddin().id, "excel"); - chai.assert.equal(config["excel-manifest"].framework?.default?.typescript, undefined); - chai.assert.equal( - config["excel-react"].framework?.default?.typescript, - "https://aka.ms/ccdevx-fx-react-ts" - ); - }); -}); - -describe("OfficeXmlAddinGeneratorNew", () => { - const gtools = new MockTools(); - setTools(gtools); - const generator = new OfficeXmlAddinGeneratorNew(); - const context = createContext(); - describe("active()", () => { - it(`should return true`, async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: "./", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - }; - const res = generator.activate(context, inputs); - chai.assert.isTrue(res); - }); - - it(`should return false`, async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: "./", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.outlook().id, - }; - const res = generator.activate(context, inputs); - chai.assert.isFalse(res); - }); - }); - - describe("getTemplateInfos()", () => { - const sandbox = sinon.createSandbox(); - afterEach(() => { - sandbox.restore(); - }); - it("happy path for word-taskpane", async () => { - sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); - sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves(); - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: "./", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS, - [QuestionNames.Capabilities]: "word-taskpane", - }; - const res = await generator.getTemplateInfos(context, inputs, "./"); - chai.assert.isTrue(res.isOk()); - if (res.isOk()) { - chai.assert.equal(res.value.length, 2); - } - }); - it("happy path for word-manifest", async () => { - sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); - sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves(); - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: "./", - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS, - [QuestionNames.Capabilities]: "word-manifest", - }; - const res = await generator.getTemplateInfos(context, inputs, "./"); - chai.assert.isTrue(res.isOk()); - if (res.isOk()) { - chai.assert.equal(res.value.length, 3); - } - }); - }); - - describe("post()", () => { - const sandbox = sinon.createSandbox(); - afterEach(() => { - sandbox.restore(); - }); - it("happy", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - projectPath: "./", - }; - sandbox.stub(OfficeAddinManifest, "modifyManifestFile").resolves(); - const res = await generator.post(context, inputs, "./"); - chai.assert.isTrue(res.isOk()); - }); - }); -}); diff --git a/packages/fx-core/tests/question/create.test.ts b/packages/fx-core/tests/question/create.test.ts index a8253998ab..61aa322278 100644 --- a/packages/fx-core/tests/question/create.test.ts +++ b/packages/fx-core/tests/question/create.test.ts @@ -40,7 +40,6 @@ import { CustomCopilotRagOptions, MeArchitectureOptions, NotificationTriggerOptions, - OfficeAddinHostOptions, ProgrammingLanguage, ProjectTypeOptions, QuestionNames, @@ -57,7 +56,6 @@ import { getLanguageOptions, getSolutionName, officeAddinFrameworkQuestion, - officeAddinHostingQuestion, programmingLanguageQuestion, projectTypeQuestion, } from "../../src/question"; @@ -568,76 +566,7 @@ describe("scaffold question", () => { QuestionNames.AppName, ]); }); - it("traverse in vscode Office XML addin", async () => { - const inputs: Inputs = { - platform: Platform.VSCode, - }; - const questions: string[] = []; - const visitor: QuestionTreeVisitor = async ( - question: Question, - ui: UserInteraction, - inputs: Inputs - ) => { - questions.push(question.name); - await callFuncs(question, inputs); - if (question.name === QuestionNames.ProjectType) { - const select = question as SingleSelectQuestion; - const options = await select.dynamicOptions!(inputs); - return ok({ type: "success", result: ProjectTypeOptions.officeXMLAddin().id }); - } else if (question.name === QuestionNames.OfficeAddinHost) { - const select = question as SingleSelectQuestion; - const options = await select.staticOptions; - assert.deepEqual(options, [ - OfficeAddinHostOptions.outlook(), - OfficeAddinHostOptions.word(), - OfficeAddinHostOptions.excel(), - OfficeAddinHostOptions.powerpoint(), - ]); - const title = - typeof question.title === "function" ? await question.title(inputs) : question.title; - assert.equal( - title, - getLocalizedString("core.createProjectQuestion.officeXMLAddin.create.title") - ); - return ok({ type: "success", result: OfficeAddinHostOptions.excel().id }); - } else if (question.name === QuestionNames.Capabilities) { - const select = question as SingleSelectQuestion; - const options = await select.dynamicOptions!(inputs); - const items = CapabilityOptions.officeAddinDynamicCapabilities( - ProjectTypeOptions.officeXMLAddin().id, - OfficeAddinHostOptions.excel().id - ); - assert.deepEqual(options, items); - const title = - typeof question.title === "function" ? await question.title(inputs) : question.title; - assert.equal( - title, - getLocalizedString("core.createProjectQuestion.officeXMLAddin.excel.create.title") - ); - return ok({ type: "success", result: "excel-react" }); - } else if (question.name === QuestionNames.ProgrammingLanguage) { - const select = question as SingleSelectQuestion; - const options = await select.dynamicOptions!(inputs); - assert.isTrue(options.length === 2); - return ok({ type: "success", result: "typescript" }); - } else if (question.name === QuestionNames.Folder) { - return ok({ type: "success", result: "./" }); - } else if (question.name === QuestionNames.AppName) { - return ok({ type: "success", result: "test001" }); - } - return ok({ type: "success", result: undefined }); - }; - await traverse(createProjectQuestionNode(), inputs, ui, undefined, visitor); - assert.deepEqual(questions, [ - QuestionNames.ProjectType, - QuestionNames.OfficeAddinHost, - QuestionNames.Capabilities, - QuestionNames.ProgrammingLanguage, - QuestionNames.Folder, - QuestionNames.AppName, - ]); - }); it("traverse in vscode Office addin", async () => { const inputs: Inputs = { platform: Platform.VSCode, @@ -3383,15 +3312,9 @@ describe("scaffold question", () => { }); describe("officeAddinStaticCapabilities()", () => { - it("should return correct capabilities for specific host", () => { - const capabilities = CapabilityOptions.officeAddinStaticCapabilities( - OfficeAddinHostOptions.word().id - ); - assert.equal(capabilities.length, 4); - }); it("should return correct capabilities without specific host", () => { const capabilities = CapabilityOptions.officeAddinStaticCapabilities(); - assert.equal(capabilities.length, 16); + assert.equal(capabilities.length, 2); }); }); @@ -3408,20 +3331,6 @@ describe("scaffold question", () => { ); assert.equal(capabilities.length, 3); }); - it("should return correct capabilities for office xml addin with outlook host", () => { - const capabilities = CapabilityOptions.officeAddinDynamicCapabilities( - ProjectTypeOptions.officeXMLAddin().id, - OfficeAddinHostOptions.outlook().id - ); - assert.equal(capabilities.length, 2); - }); - it("should return correct capabilities for office xml addin with word host", () => { - const capabilities = CapabilityOptions.officeAddinDynamicCapabilities( - ProjectTypeOptions.officeXMLAddin().id, - OfficeAddinHostOptions.word().id - ); - assert.equal(capabilities.length, 4); - }); }); }); @@ -3516,37 +3425,6 @@ describe("scaffold question", () => { assert.equal(lang, "typescript"); }); - it("office xml addin: normal project have ts and js", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: "word-react", - }; - assert.isDefined(question.dynamicOptions); - if (question.dynamicOptions) { - const options = await question.dynamicOptions(inputs); - assert.deepEqual(options, [ - { label: "TypeScript", id: "typescript" }, - { label: "JavaScript", id: "javascript" }, - ]); - } - }); - - it("office xml addin: manifest-only project only have js option as default", async () => { - const inputs: Inputs = { - platform: Platform.CLI, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: "word-manifest", - }; - assert.isDefined(question.dynamicOptions); - if (question.dynamicOptions) { - const options = await question.dynamicOptions(inputs); - assert.deepEqual(options, [{ label: "JavaScript", id: "javascript" }]); - } - }); - it("office addin: should have typescript as options", async () => { const inputs: Inputs = { platform: Platform.CLI }; inputs[QuestionNames.Capabilities] = "json-taskpane"; @@ -3635,26 +3513,6 @@ describe("scaffold question", () => { } } }); - - it("office xml addin: patch coverage getLanguageOptions", async () => { - sandbox.stub(OfficeAddinProjectConfig, "word").value({ - "word-taskpane": { - localTemplate: "word-taskpane", - title: "core.createProjectQuestion.officeXMLAddin.taskpane.title", - detail: "core.createProjectQuestion.officeXMLAddin.taskpane.detail", - framework: { - default: {}, - }, - }, - }); - const inputs: Inputs = { - platform: Platform.CLI, - [QuestionNames.ProjectType]: ProjectTypeOptions.officeXMLAddin().id, - [QuestionNames.OfficeAddinHost]: OfficeAddinHostOptions.word().id, - [QuestionNames.Capabilities]: "word-taskpane", - }; - assert.deepEqual(getLanguageOptions(inputs), []); - }); }); describe("folderQuestion", () => { @@ -3673,16 +3531,6 @@ describe("scaffold question", () => { }); }); - describe("officeAddinHostingQuestion", async () => { - const q = officeAddinHostingQuestion(); - const options = await q.dynamicOptions!({ platform: Platform.VSCode }); - assert.equal(options.length, 4); - if (typeof q.default === "function") { - const defaultV = await q.default({ platform: Platform.VSCode }); - assert.isDefined(defaultV); - } - }); - describe("officeAddinFrameworkQuestion", () => { const question = officeAddinFrameworkQuestion(); it("office taskpane addin: should have default as options", async () => { @@ -3742,18 +3590,6 @@ describe("scaffold question", () => { afterEach(() => { mockedEnvRestore(); }); - it("trigger from agent", async () => { - const question = projectTypeQuestion(); - const inputs: Inputs = { platform: Platform.CLI, agent: "office" }; - assert.isDefined(question.dynamicOptions); - if (question.dynamicOptions) { - const options = (await question.dynamicOptions(inputs)) as OptionItem[]; - const officeAddinOption = options.find( - (o) => o.id === ProjectTypeOptions.officeXMLAddin().id - ); - assert.isDefined(officeAddinOption); - } - }); it("show customize GPT if CLI and enable declarative GPT() ", async () => { mockedEnvRestore = mockedEnv({ [FeatureFlagName.CustomizeGpt]: "true", diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index 8de31ef4da..0f6261a726 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -1739,6 +1739,7 @@ "jsonc-parser": "^3.0.0", "log4js": "^6.4.0", "node-rsa": "^1.1.1", + "office-addin-manifest": "^1.13.1", "query-string": "6.14.1", "react-collapsible": "^2.10.0", "react-copy-to-clipboard": "^5.1.0", diff --git a/packages/vscode-extension/pnpm-lock.yaml b/packages/vscode-extension/pnpm-lock.yaml index 7b426f8be2..cb22fda36a 100644 --- a/packages/vscode-extension/pnpm-lock.yaml +++ b/packages/vscode-extension/pnpm-lock.yaml @@ -86,6 +86,9 @@ dependencies: node-rsa: specifier: ^1.1.1 version: 1.1.1 + office-addin-manifest: + specifier: ^1.13.1 + version: 1.13.2 query-string: specifier: 6.14.1 version: 6.14.1 @@ -2269,6 +2272,20 @@ packages: resolution: {integrity: sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==} dev: true + /@microsoft/teams-manifest@0.1.4: + resolution: {integrity: sha512-VVFnItrOi2MS7seQC/EkFGyqJNkR2jRASTeSaUhyJ+pdnrUszYPRqyOwBzFw4HmXBmlnOD1WTfRgwdeav/KpgA==} + dependencies: + '@types/fs-extra': 11.0.4 + '@types/node-fetch': 2.6.11 + ajv: 8.12.0 + ajv-draft-04: 1.0.0(ajv@8.12.0) + ajv-formats: 3.0.1(ajv@8.12.0) + fs-extra: 9.1.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + /@microsoft/tiktokenizer@1.0.4: resolution: {integrity: sha512-M3jur8c4gwungkRyT0q0zXjp5rBWRmBMdE/VwW5yQtKDKCQkoms/1GTKEkeFOM2GKyfpxfMqj+n7G90Sz3fI6g==} engines: {node: '>=18.0.0'} @@ -2647,7 +2664,6 @@ packages: dependencies: '@types/jsonfile': 6.1.4 '@types/node': 14.14.21 - dev: true /@types/fs-extra@9.0.5: resolution: {integrity: sha512-wr3t7wIW1c0A2BIJtdVp4EflriVaVVAsCAIHVzzh8B+GiFv9X1xeJjCs4upRXtzp7kQ6lP5xvskjoD4awJ1ZeA==} @@ -2706,7 +2722,6 @@ packages: resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} dependencies: '@types/node': 14.14.21 - dev: true /@types/lodash@4.14.181: resolution: {integrity: sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==} @@ -2740,9 +2755,15 @@ packages: resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} dev: true + /@types/node-fetch@2.6.11: + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} + dependencies: + '@types/node': 14.14.21 + form-data: 4.0.0 + dev: false + /@types/node@14.14.21: resolution: {integrity: sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==} - dev: true /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3412,6 +3433,11 @@ packages: engines: {node: '>= 10.0.0'} dev: true + /adm-zip@0.5.12: + resolution: {integrity: sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==} + engines: {node: '>=6.0'} + dev: false + /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -3435,6 +3461,28 @@ packages: indent-string: 4.0.0 dev: true + /ajv-draft-04@1.0.0(ajv@8.12.0): + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.12.0 + dev: false + + /ajv-formats@3.0.1(ajv@8.12.0): + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.12.0 + dev: false + /ajv-keywords@3.5.2(ajv@6.12.6): resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -3459,7 +3507,6 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: true /ansi-colors@4.1.1: resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} @@ -3519,6 +3566,15 @@ packages: default-require-extensions: 3.0.1 dev: true + /applicationinsights@1.8.10: + resolution: {integrity: sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A==} + dependencies: + cls-hooked: 4.2.2 + continuation-local-storage: 3.2.1 + diagnostic-channel: 0.3.1 + diagnostic-channel-publishers: 0.4.4(diagnostic-channel@0.3.1) + dev: false + /aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} dev: true @@ -3666,6 +3722,21 @@ packages: engines: {node: '>=8'} dev: true + /async-hook-jl@1.7.6: + resolution: {integrity: sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==} + engines: {node: ^4.7 || >=6.9 || >=7.3} + dependencies: + stack-chain: 1.3.7 + dev: false + + /async-listener@0.6.10: + resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==} + engines: {node: <=0.11.8 || >0.11.10} + dependencies: + semver: 5.7.2 + shimmer: 1.2.1 + dev: false + /async-mutex@0.3.1: resolution: {integrity: sha512-vRfQwcqBnJTLzVQo72Sf7KIUbcSUP5hNchx6udI1U6LuPQpfePgdjJzlCe76yFZ8pxlLjn9lwcl/Ya0TSOv0Tw==} dependencies: @@ -3686,7 +3757,6 @@ packages: /at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - dev: true /atob@2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} @@ -4261,6 +4331,15 @@ packages: kind-of: 6.0.3 shallow-clone: 3.0.1 + /cls-hooked@4.2.2: + resolution: {integrity: sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==} + engines: {node: ^4.7 || >=6.9 || >=7.3 || >=8.2.1} + dependencies: + async-hook-jl: 1.7.6 + emitter-listener: 1.1.2 + semver: 5.7.2 + dev: false + /collection-visit@1.0.0: resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} engines: {node: '>=0.10.0'} @@ -4328,6 +4407,11 @@ packages: engines: {node: '>= 6'} dev: true + /commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + dev: false + /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -4389,6 +4473,13 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + /continuation-local-storage@3.2.1: + resolution: {integrity: sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==} + dependencies: + async-listener: 0.6.10 + emitter-listener: 1.1.2 + dev: false + /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true @@ -5132,6 +5223,20 @@ packages: - supports-color dev: true + /diagnostic-channel-publishers@0.4.4(diagnostic-channel@0.3.1): + resolution: {integrity: sha512-l126t01d2ZS9EreskvEtZPrcgstuvH3rbKy82oUhUrVmBaGx4hO9wECdl3cvZbKDYjMF3QJDB5z5dL9yWAjvZQ==} + peerDependencies: + diagnostic-channel: '*' + dependencies: + diagnostic-channel: 0.3.1 + dev: false + + /diagnostic-channel@0.3.1: + resolution: {integrity: sha512-6eb9YRrimz8oTr5+JDzGmSYnXy5V7YnK5y/hd8AUDK1MssHjQKm9LlD6NSrHx4vMDF3+e/spI2hmWTviElgWZA==} + dependencies: + semver: 5.7.2 + dev: false + /diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -5290,6 +5395,12 @@ packages: resolution: {integrity: sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==} dev: true + /emitter-listener@1.1.2: + resolution: {integrity: sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==} + dependencies: + shimmer: 1.2.1 + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5928,7 +6039,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} @@ -6184,6 +6294,15 @@ packages: universalify: 2.0.1 dev: true + /fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + /fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} @@ -6203,6 +6322,16 @@ packages: universalify: 1.0.0 dev: true + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: false + /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -6781,6 +6910,10 @@ packages: once: 1.4.0 wrappy: 1.0.2 + /inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + dev: false + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -7290,7 +7423,6 @@ packages: /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true /json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -7332,7 +7464,6 @@ packages: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} @@ -8431,7 +8562,18 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false /node-gyp-build@4.8.0: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} @@ -8634,6 +8776,34 @@ packages: es-abstract: 1.22.3 dev: true + /office-addin-manifest@1.13.2: + resolution: {integrity: sha512-+IBmcMbgoAsjE7FOO15HeVQD91GbWd3mcdmq43xulFaI5uC5bYhw70TI7XEUUYRrPU1iLFGbdYNHvsjFfNdqzQ==} + hasBin: true + dependencies: + '@microsoft/teams-manifest': 0.1.4 + adm-zip: 0.5.12 + chalk: 2.4.2 + commander: 6.2.1 + fs-extra: 7.0.1 + node-fetch: 2.6.7 + office-addin-usage-data: 1.6.11 + path: 0.12.7 + uuid: 8.3.2 + xml2js: 0.5.0 + transitivePeerDependencies: + - encoding + dev: false + + /office-addin-usage-data@1.6.11: + resolution: {integrity: sha512-8n86S1PkAktGFtrM2kYVX8zbgo/i8VyH6RzO3ApX6GeFOeTWJPtYVWmGs7WklkoTlZGTwDjfiR+noB0vWA9Vpg==} + hasBin: true + dependencies: + applicationinsights: 1.8.10 + commander: 6.2.1 + readline-sync: 1.4.10 + uuid: 8.3.2 + dev: false + /on-exit-leak-free@0.2.0: resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} dev: true @@ -8866,6 +9036,13 @@ packages: engines: {node: '>=8'} dev: true + /path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + dependencies: + process: 0.11.10 + util: 0.10.4 + dev: false + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -9094,7 +9271,6 @@ packages: /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - dev: true /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} @@ -9168,7 +9344,6 @@ packages: /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true /qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} @@ -9394,6 +9569,11 @@ packages: picomatch: 2.3.1 dev: true + /readline-sync@1.4.10: + resolution: {integrity: sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==} + engines: {node: '>= 0.8.0'} + dev: false + /real-require@0.1.0: resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} engines: {node: '>= 12.13.0'} @@ -9574,7 +9754,6 @@ packages: /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - dev: true /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} @@ -9763,7 +9942,6 @@ packages: /sax@1.3.0: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} - dev: true /scheduler@0.20.2: resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} @@ -9940,6 +10118,10 @@ packages: engines: {node: '>=8'} dev: true + /shimmer@1.2.1: + resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} + dev: false + /side-channel@1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -10174,6 +10356,10 @@ packages: minipass: 3.3.6 dev: true + /stack-chain@1.3.7: + resolution: {integrity: sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==} + dev: false + /static-extend@0.1.2: resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} engines: {node: '>=0.10.0'} @@ -10645,7 +10831,6 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true /ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} @@ -10976,7 +11161,6 @@ packages: /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - dev: true /unix-crypt-td-js@1.1.4: resolution: {integrity: sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==} @@ -11013,7 +11197,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 - dev: true /urix@0.1.0: resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} @@ -11053,6 +11236,12 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true + /util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + dependencies: + inherits: 2.0.3 + dev: false + /utila@0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} dev: true @@ -11225,7 +11414,6 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true /webpack-cli@5.1.4(webpack@5.88.2): resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} @@ -11341,7 +11529,6 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -11438,6 +11625,19 @@ packages: typedarray-to-buffer: 3.1.5 dev: true + /xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.3.0 + xmlbuilder: 11.0.1 + dev: false + + /xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: false + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} diff --git a/packages/vscode-extension/src/officeChat/commands/create/helper.ts b/packages/vscode-extension/src/officeChat/commands/create/helper.ts index 4c74c42b3e..092ac44df9 100644 --- a/packages/vscode-extension/src/officeChat/commands/create/helper.ts +++ b/packages/vscode-extension/src/officeChat/commands/create/helper.ts @@ -2,11 +2,9 @@ // Licensed under the MIT license. import * as tmp from "tmp"; -import * as crypto from "crypto"; import * as officeTemplateMeatdata from "./officeTemplateMetadata.json"; import * as fs from "fs-extra"; import * as path from "path"; -import * as vscode from "vscode"; import { ChatRequest, CancellationToken, @@ -21,12 +19,12 @@ import { ProjectMetadata } from "../../../chat/commands/create/types"; import { getCopilotResponseAsString } from "../../../chat/utils"; import { getOfficeProjectMatchSystemPrompt } from "../../officePrompts"; import { officeSampleProvider } from "./officeSamples"; -import { CommandKey } from "../../../constants"; -import { TelemetryTriggerFrom } from "../../../telemetry/extTelemetryEvents"; -import { CHAT_EXECUTE_COMMAND_ID } from "../../../chat/consts"; import { fileTreeAdd, buildFileTree } from "../../../chat/commands/create/helper"; import { getOfficeSampleDownloadUrlInfo } from "../../utils"; import { getSampleFileInfo } from "@microsoft/teamsfx-core/build/component/generator/utils"; +import { OfficeXMLAddinGenerator } from "./officeXMLAddinGenerator/generator"; +import { CreateProjectInputs } from "@microsoft/teamsfx-api"; +import { core } from "../../../globalVariables"; export async function matchOfficeProject( request: ChatRequest, @@ -122,43 +120,41 @@ export async function showOfficeTemplateFileTree( codeSnippet?: string ): Promise { const tempFolder = tmp.dirSync({ unsafeCleanup: true }).name; - const tempAppName = `office-addin-${crypto.randomBytes(8).toString("hex")}`; - const nodes = await buildTemplateFileTree(data, tempFolder, tempAppName, codeSnippet); - response.filetree(nodes, Uri.file(path.join(tempFolder, tempAppName))); - return path.join(tempFolder, tempAppName); + const nodes = await buildTemplateFileTree(data, tempFolder, data.capabilities, codeSnippet); + response.filetree(nodes, Uri.file(path.join(tempFolder, data.capabilities))); + return path.join(tempFolder, data.capabilities); } export async function buildTemplateFileTree( data: any, tempFolder: string, - tempAppName: string, + appName: string, codeSnippet?: string ): Promise { - const createInputs = { + const createInputs: CreateProjectInputs = { ...data, folder: tempFolder, - "app-name": tempAppName, + "app-name": appName, }; - await vscode.commands.executeCommand( - CHAT_EXECUTE_COMMAND_ID, - CommandKey.Create, - TelemetryTriggerFrom.CopilotChat, - createInputs - ); - const rootFolder = path.join(tempFolder, tempAppName); + const generator = new OfficeXMLAddinGenerator(); + const result = await core.createProjectByCustomizedGenerator(createInputs, generator); + if (result.isErr()) { + throw new Error("Failed to generate the project."); + } + const projectPath = result.value.projectPath; const isCustomFunction = data.capabilities.includes("excel-custom-functions"); if (!!isCustomFunction && !!codeSnippet) { - await mergeCFCode(rootFolder, codeSnippet); + await mergeCFCode(projectPath, codeSnippet); } else if (!!codeSnippet) { - await mergeTaskpaneCode(rootFolder, codeSnippet); + await mergeTaskpaneCode(projectPath, codeSnippet); } const root: ChatResponseFileTree = { - name: rootFolder, + name: projectPath, children: [], }; - await fs.ensureDir(rootFolder); - traverseFiles(rootFolder, (fullPath) => { - const relativePath = path.relative(rootFolder, fullPath); + await fs.ensureDir(projectPath); + traverseFiles(projectPath, (fullPath) => { + const relativePath = path.relative(projectPath, fullPath); fileTreeAdd(root, relativePath); }); return root.children ?? []; diff --git a/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/generator.ts b/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/generator.ts new file mode 100644 index 0000000000..c81c1dd581 --- /dev/null +++ b/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/generator.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + DefaultTemplateGenerator, + QuestionNames, + HelperMethods, + ActionContext, + ProgrammingLanguage, + TemplateInfo, +} from "@microsoft/teamsfx-core"; +import { Context, FxError, GeneratorResult, Inputs, Result, err, ok } from "@microsoft/teamsfx-api"; +import { merge, toLower } from "lodash"; +import { promisify } from "util"; +import { getOfficeXMLAddinTemplateConfig } from "./projectConfig"; +import { OfficeAddinManifest } from "office-addin-manifest"; +import { join } from "path"; +import * as childProcess from "child_process"; + +const TEMPLATE_BASE = "office-xml-addin"; +const TEMPLATE_COMMON_NAME = "office-xml-addin-common"; + +const enum OfficeXMLAddinTelemetryProperties { + host = "office-xml-addin-host", + project = "office-xml-addin-project", + lang = "office-xml-addin-lang", +} + +export class OfficeXMLAddinGenerator extends DefaultTemplateGenerator { + componentName = "office-xml-addin-generator"; + + public activate(context: Context, inputs: Inputs): boolean { + const projectType = inputs[QuestionNames.ProjectType]; + const addinHost = inputs[QuestionNames.OfficeAddinHost]; + return ( + projectType === "office-xml-addin-type" && + addinHost && + addinHost !== "outlook" && + inputs.agent === "office" // Triggered by Office agent + ); + } + + public async getTemplateInfos( + context: Context, + inputs: Inputs, + destinationPath: string, + actionContext?: ActionContext + ): Promise> { + const host = inputs[QuestionNames.OfficeAddinHost] as string; + const capability = inputs[QuestionNames.Capabilities]; + const lang = toLower(inputs[QuestionNames.ProgrammingLanguage]) as "javascript" | "typescript"; + const templateConfig = getOfficeXMLAddinTemplateConfig(host); + const templateName = templateConfig[capability].localTemplate; + const projectLink = templateConfig[capability].framework["default"][lang]; + merge(actionContext?.telemetryProps, { + [OfficeXMLAddinTelemetryProperties.host]: host, + [OfficeXMLAddinTelemetryProperties.project]: capability, + [OfficeXMLAddinTelemetryProperties.lang]: lang, + }); + + const templates: TemplateInfo[] = []; + if (!!projectLink) { + // [Condition]: Project have remote repo (not manifest-only proj) + + // -> Step: Download the project from GitHub + const fetchRes = await HelperMethods.fetchAndUnzip( + this.componentName, + projectLink, + destinationPath + ); + if (fetchRes.isErr()) { + return err(fetchRes.error); + } + process.chdir(destinationPath); + // -> Step: Convert to single Host + await OfficeXMLAddinGenerator.childProcessExec( + `npm run convert-to-single-host --if-present -- ${toLower(host)}` + ); + } else { + templates.push({ + templateName: `${TEMPLATE_BASE}-manifest-only`, + language: lang as ProgrammingLanguage, + }); + } + // -> Common Step: Copy the README (or with manifest for manifest-only proj) + templates.push({ + templateName: `${TEMPLATE_BASE}-${templateName}`, + language: lang as ProgrammingLanguage, + }); + templates.push({ + templateName: TEMPLATE_COMMON_NAME, + language: ProgrammingLanguage.Common, + }); + return ok(templates); + } + + public async post( + context: Context, + inputs: Inputs, + destinationPath: string, + actionContext?: ActionContext + ): Promise> { + const appName = inputs[QuestionNames.AppName] as string; + // -> Common Step: Modify the Manifest + await OfficeAddinManifest.modifyManifestFile( + `${join(destinationPath, "manifest.xml")}`, + "random", + `${appName}` + ); + return ok({}); + } + + public static async childProcessExec(cmdLine: string): Promise<{ + stdout: string; + stderr: string; + }> { + return promisify(childProcess.exec)(cmdLine); + } +} diff --git a/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/projectConfig.ts b/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/projectConfig.ts new file mode 100644 index 0000000000..687e7dcf11 --- /dev/null +++ b/packages/vscode-extension/src/officeChat/commands/create/officeXMLAddinGenerator/projectConfig.ts @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +interface IOfficeXMLAddinHostConfig { + [property: string]: { + localTemplate: string; + manifestPath?: string; + framework: { + [property: string]: { + typescript?: string; + javascript?: string; + }; + }; + }; +} + +interface IOfficeXMLAddinProjectConfig { + [property: string]: IOfficeXMLAddinHostConfig; +} + +const CommonProjectConfig = { + taskpane: { + framework: { + default: { + typescript: "https://aka.ms/ccdevx-fx-taskpane-ts", + javascript: "https://aka.ms/ccdevx-fx-taskpane-js", + }, + }, + }, + sso: { + framework: { + default: { + typescript: "https://aka.ms/ccdevx-fx-sso-ts", + javascript: "https://aka.ms/ccdevx-fx-sso-js", + }, + }, + }, + react: { + framework: { + default: { + typescript: "https://aka.ms/ccdevx-fx-react-ts", + javascript: "https://aka.ms/ccdevx-fx-react-js", + }, + }, + }, + manifest: { + framework: { + default: {}, + }, + }, +}; + +export const OfficeXMLAddinProjectConfig: IOfficeXMLAddinProjectConfig = { + word: { + "word-taskpane": { + localTemplate: "word-taskpane", + ...CommonProjectConfig.taskpane, + }, + "word-sso": { + localTemplate: "word-sso", + ...CommonProjectConfig.sso, + }, + "word-react": { + localTemplate: "word-react", + ...CommonProjectConfig.react, + }, + "word-manifest": { + localTemplate: "word-manifest-only", + ...CommonProjectConfig.manifest, + }, + }, + excel: { + "excel-taskpane": { + localTemplate: "excel-taskpane", + ...CommonProjectConfig.taskpane, + }, + "excel-sso": { + localTemplate: "excel-sso", + ...CommonProjectConfig.sso, + }, + "excel-react": { + localTemplate: "excel-react", + ...CommonProjectConfig.react, + }, + "excel-custom-functions-shared": { + localTemplate: "excel-cf", + framework: { + default: { + typescript: "https://aka.ms/ccdevx-fx-cf-shared-ts", + javascript: "https://aka.ms/ccdevx-fx-cf-shared-js", + }, + }, + }, + "excel-custom-functions-js": { + localTemplate: "excel-cf", + framework: { + default: { + typescript: "https://aka.ms/ccdevx-fx-cf-js-ts", + javascript: "https://aka.ms/ccdevx-fx-cf-js-js", + }, + }, + }, + "excel-manifest": { + localTemplate: "excel-manifest-only", + ...CommonProjectConfig.manifest, + }, + }, + powerpoint: { + "powerpoint-taskpane": { + localTemplate: "powerpoint-taskpane", + ...CommonProjectConfig.taskpane, + }, + "powerpoint-sso": { + localTemplate: "powerpoint-sso", + ...CommonProjectConfig.sso, + }, + "powerpoint-react": { + localTemplate: "powerpoint-react", + ...CommonProjectConfig.react, + }, + "powerpoint-manifest": { + localTemplate: "powerpoint-manifest-only", + ...CommonProjectConfig.manifest, + }, + }, +}; + +export function getOfficeXMLAddinTemplateConfig(addinHost: string): IOfficeXMLAddinHostConfig { + return OfficeXMLAddinProjectConfig[addinHost]; +} diff --git a/packages/vscode-extension/test/officeChat/commands/create/helper.test.ts b/packages/vscode-extension/test/officeChat/commands/create/helper.test.ts index abce172d96..85997e2a11 100644 --- a/packages/vscode-extension/test/officeChat/commands/create/helper.test.ts +++ b/packages/vscode-extension/test/officeChat/commands/create/helper.test.ts @@ -5,7 +5,6 @@ import * as vscode from "vscode"; import * as tmp from "tmp"; import * as fs from "fs-extra"; import * as path from "path"; -import * as crypto from "crypto"; import * as telemetry from "../../../../src/chat/telemetry"; import * as util from "../../../../src/chat/utils"; import * as officeChatUtils from "../../../../src/officeChat/utils"; @@ -17,6 +16,8 @@ import { ExtTelemetry } from "../../../../src/telemetry/extTelemetry"; import { CancellationToken } from "../../../mocks/vsc"; import { officeSampleProvider } from "../../../../src/officeChat/commands/create/officeSamples"; import { ProjectMetadata } from "../../../../src/chat/commands/create/types"; +import { core } from "../../../../src/globalVariables"; +import { CreateProjectResult, FxError, err, ok } from "@microsoft/teamsfx-api"; chai.use(chaiPromised); @@ -139,16 +140,15 @@ describe("File: office chat create helper", () => { }); describe("Method: showOfficeTemplateFileTree", () => { + const result: CreateProjectResult = { projectPath: path.join("tempDir", "test") }; beforeEach(() => { sandbox.stub(tmp, "dirSync").returns({ name: "tempDir", } as unknown as tmp.DirResult); - const mockBuffer = Buffer.from("0"); - sandbox.stub(crypto, "randomBytes").returns(mockBuffer as unknown as void); sandbox.stub(fs, "ensureDir").resolves(); sandbox.stub(fs, "readFile").resolves(Buffer.from("")); sandbox.stub(fs, "writeFile").resolves(); - sandbox.stub(vscode.commands, "executeCommand"); + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(result)); sandbox.stub(fs, "readdirSync").returns([]); }); afterEach(() => { @@ -174,7 +174,7 @@ describe("File: office chat create helper", () => { codeSnippet ); chai.assert.isTrue(response.filetree.calledOnce); - chai.assert.strictEqual(result, path.join("tempDir", "office-addin-30")); + chai.assert.strictEqual(result, path.join("tempDir", "test")); }); it("call filetree API with cf project", async () => { @@ -196,7 +196,7 @@ describe("File: office chat create helper", () => { codeSnippet ); chai.assert.isTrue(response.filetree.calledOnce); - chai.assert.strictEqual(result, path.join("tempDir", "office-addin-30")); + chai.assert.strictEqual(result, path.join("tempDir", "excel-custom-functions-test")); }); it("code snippet is null", async () => { @@ -225,20 +225,32 @@ describe("File: office chat create helper", () => { }); describe("Method: buildTemplateFileTree", () => { + const result: CreateProjectResult = { projectPath: path.join("testFolder", "test") }; let tempFolder: string; - let tempAppName: string; beforeEach(() => { sandbox.stub(fs, "ensureDir").resolves(); sandbox.stub(fs, "writeFile").resolves(); tempFolder = "testFolder"; - tempAppName = "testAppName"; }); afterEach(() => { sandbox.restore(); }); + it("fail to generate the project", async () => { + sandbox + .stub(core, "createProjectByCustomizedGenerator") + .resolves(err(undefined as any as FxError)); + try { + await officeChathelper.buildTemplateFileTree({}, tempFolder, "test", "test"); + chai.assert.fail("should not reach here"); + } catch (error) { + chai.assert.strictEqual((error as Error).message, "Failed to generate the project."); + } + }); + it("traverse the folder", async () => { sandbox.stub(fs, "readFile").resolves(Buffer.from("")); + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(result)); const data = { capabilities: "test", "project-type": "test", @@ -264,18 +276,22 @@ describe("File: office chat create helper", () => { .returns(subdirFiles as any); const fileTreeAddStub = sandbox.stub(chatHelper, "fileTreeAdd"); const lstatSyncStub = sandbox.stub(fs, "lstatSync"); - lstatSyncStub.withArgs(path.join(tempFolder, tempAppName, "file1")).returns(nonDirStats); - lstatSyncStub.withArgs(path.join(tempFolder, tempAppName, "subdir")).returns(dirStat); - lstatSyncStub - .withArgs(path.join(tempFolder, tempAppName, "subdir", "file2")) - .returns(nonDirStats); + lstatSyncStub.withArgs(path.join(tempFolder, "test", "file1")).returns(nonDirStats); + lstatSyncStub.withArgs(path.join(tempFolder, "test", "subdir")).returns(dirStat); + lstatSyncStub.withArgs(path.join(tempFolder, "test", "subdir", "file2")).returns(nonDirStats); - await officeChathelper.buildTemplateFileTree(data, tempFolder, tempAppName, codeSnippet); + await officeChathelper.buildTemplateFileTree( + data, + tempFolder, + data.capabilities, + codeSnippet + ); chai.assert.isTrue(fileTreeAddStub.calledTwice); }); it("fail to merge taskpane code snippet", async () => { sandbox.stub(fs, "readFile").rejects(new Error("test")); + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(result)); const data = { capabilities: "test", "project-type": "test", @@ -285,7 +301,12 @@ describe("File: office chat create helper", () => { }; const codeSnippet = "test"; try { - await officeChathelper.buildTemplateFileTree(data, tempFolder, tempAppName, codeSnippet); + await officeChathelper.buildTemplateFileTree( + data, + tempFolder, + data.capabilities, + codeSnippet + ); chai.assert.fail("should not reach here"); } catch (error) { chai.assert.strictEqual((error as Error).message, "Failed to merge the taskpane project."); @@ -294,6 +315,7 @@ describe("File: office chat create helper", () => { it("fail to merge taskpane code snippet", async () => { sandbox.stub(fs, "readFile").rejects(new Error("test")); + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(result)); const data = { capabilities: "excel-custom-functions-test", "project-type": "test", @@ -303,7 +325,12 @@ describe("File: office chat create helper", () => { }; const codeSnippet = "test"; try { - await officeChathelper.buildTemplateFileTree(data, tempFolder, tempAppName, codeSnippet); + await officeChathelper.buildTemplateFileTree( + data, + tempFolder, + data.capabilities, + codeSnippet + ); chai.assert.fail("should not reach here"); } catch (error) { chai.assert.strictEqual((error as Error).message, "Failed to merge the CF project."); diff --git a/packages/vscode-extension/test/officeChat/commands/create/officeXMLAddinGenerator.test.ts b/packages/vscode-extension/test/officeChat/commands/create/officeXMLAddinGenerator.test.ts new file mode 100644 index 0000000000..a89da03515 --- /dev/null +++ b/packages/vscode-extension/test/officeChat/commands/create/officeXMLAddinGenerator.test.ts @@ -0,0 +1,108 @@ +import { Context, Inputs, Platform, ok } from "@microsoft/teamsfx-api"; +import { QuestionNames, HelperMethods, ProgrammingLanguage } from "@microsoft/teamsfx-core"; +import * as chai from "chai"; +import * as sinon from "sinon"; +import * as childProcess from "child_process"; +import "mocha"; +import { OfficeXMLAddinGenerator } from "../../../../src/officeChat/commands/create/officeXMLAddinGenerator/generator"; +import { OfficeAddinManifest } from "office-addin-manifest"; + +describe("OfficeXMLAddinGenerator", () => { + const generator = new OfficeXMLAddinGenerator(); + const context: Context = { + userInteraction: undefined as any, + logProvider: undefined as any, + telemetryReporter: undefined as any, + tokenProvider: undefined as any, + }; + describe("activate", () => { + it(`should return true`, async () => { + const inputs: Inputs = { + platform: Platform.VSCode, + projectPath: "./", + [QuestionNames.ProjectType]: "office-xml-addin-type", + [QuestionNames.OfficeAddinHost]: "word", + agent: "office", + }; + const res = generator.activate(context, inputs); + chai.assert.isTrue(res); + }); + + it(`should return false`, async () => { + const inputs: Inputs = { + platform: Platform.VSCode, + projectPath: "./", + [QuestionNames.ProjectType]: "office-xml-addin-type", + [QuestionNames.OfficeAddinHost]: "outlook", + }; + const res = generator.activate(context, inputs); + chai.assert.isFalse(res); + }); + }); + + describe("getTemplateInfos", () => { + const sandbox = sinon.createSandbox(); + afterEach(() => { + sandbox.restore(); + }); + it("happy path for word-taskpane", async () => { + sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); + sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves(); + const inputs: Inputs = { + platform: Platform.CLI, + projectPath: "./", + [QuestionNames.ProjectType]: "office-xml-addin-type", + [QuestionNames.OfficeAddinHost]: "word", + [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS, + [QuestionNames.Capabilities]: "word-taskpane", + agent: "office", + }; + const res = await generator.getTemplateInfos(context, inputs, "./"); + chai.assert.isTrue(res.isOk()); + if (res.isOk()) { + chai.assert.equal(res.value.length, 2); + } + }); + it("happy path for word-manifest", async () => { + sandbox.stub(HelperMethods, "fetchAndUnzip").resolves(ok(undefined)); + sandbox.stub(OfficeXMLAddinGenerator, "childProcessExec").resolves(); + const inputs: Inputs = { + platform: Platform.CLI, + projectPath: "./", + [QuestionNames.ProjectType]: "office-xml-addin-type", + [QuestionNames.OfficeAddinHost]: "word", + [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.TS, + [QuestionNames.Capabilities]: "word-manifest", + agent: "office", + }; + const res = await generator.getTemplateInfos(context, inputs, "./"); + chai.assert.isTrue(res.isOk()); + if (res.isOk()) { + chai.assert.equal(res.value.length, 3); + } + }); + }); + + describe("post()", () => { + const sandbox = sinon.createSandbox(); + afterEach(() => { + sandbox.restore(); + }); + it("happy", async () => { + const inputs: Inputs = { + platform: Platform.CLI, + projectPath: "./", + }; + sandbox.stub(OfficeAddinManifest, "modifyManifestFile").resolves(); + const res = await generator.post(context, inputs, "./"); + chai.assert.isTrue(res.isOk()); + }); + }); + + describe("childProcessExec()", () => { + it("should run childProcessExec command success", async function () { + sinon.stub(childProcess, "exec").yields(null, "test", null); + chai.assert(await OfficeXMLAddinGenerator.childProcessExec(`echo 'test'`), "test"); + }); + }); +}); diff --git a/packages/vscode-extension/test/officeChat/common/samples/officeAddinTemplateModelProvider.test.ts b/packages/vscode-extension/test/officeChat/common/samples/officeAddinTemplateModelProvider.test.ts index e331337901..c3b9a1a88f 100644 --- a/packages/vscode-extension/test/officeChat/common/samples/officeAddinTemplateModelProvider.test.ts +++ b/packages/vscode-extension/test/officeChat/common/samples/officeAddinTemplateModelProvider.test.ts @@ -20,7 +20,7 @@ describe("OfficeTemplateModelPorvider", () => { const bm25ModelPowerPointCached = await provider.getBM25Model("PowerPoint"); expect(bm25ModelPowerPointCached).to.equal(bm25ModelPowerPoint); - }); + }).timeout(5000); it("invalid host", async () => { const bm25ModelFake = await provider.getBM25Model("Fake" as WXPAppName); diff --git a/packages/vscode-extension/test/officeChat/common/skills/projectCreator.test.ts b/packages/vscode-extension/test/officeChat/common/skills/projectCreator.test.ts index 1785e5682a..86eedd154c 100644 --- a/packages/vscode-extension/test/officeChat/common/skills/projectCreator.test.ts +++ b/packages/vscode-extension/test/officeChat/common/skills/projectCreator.test.ts @@ -9,6 +9,8 @@ import * as helper from "../../../../src/chat/commands/create/helper"; import * as fs from "fs-extra"; import * as vscode from "vscode"; import { SampleData } from "../../../../src/officeChat/common/samples/sampleData"; +import { CreateProjectResult, ok } from "@microsoft/teamsfx-api"; +import { core } from "../../../../src/globalVariables"; describe("projectCreator", () => { let invokeParametersInit: () => any; @@ -122,6 +124,8 @@ describe("projectCreator", () => { /* traverseFiles */ sandbox.stub(path, "relative").returns("relative path"); sandbox.stub(helper, "fileTreeAdd"); + const res: CreateProjectResult = { projectPath: path.join("testFolder", "test") }; + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(res)); const lstatSyncStub = sandbox.stub(fs, "lstatSync"); @@ -168,6 +172,8 @@ describe("projectCreator", () => { /* traverseFiles */ sandbox.stub(path, "relative").returns("relative path"); sandbox.stub(helper, "fileTreeAdd"); + const res: CreateProjectResult = { projectPath: path.join("testFolder", "test") }; + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(res)); const lstatSyncStub = sandbox.stub(fs, "lstatSync"); @@ -216,6 +222,8 @@ describe("projectCreator", () => { /* traverseFiles */ sandbox.stub(path, "relative").returns("relative path"); sandbox.stub(helper, "fileTreeAdd"); + const res: CreateProjectResult = { projectPath: path.join("testFolder", "test") }; + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(res)); const lstatSyncStub = sandbox.stub(fs, "lstatSync"); @@ -263,6 +271,8 @@ describe("projectCreator", () => { /* traverseFiles */ sandbox.stub(path, "relative").returns("relative path"); sandbox.stub(helper, "fileTreeAdd"); + const res: CreateProjectResult = { projectPath: path.join("testFolder", "test") }; + sandbox.stub(core, "createProjectByCustomizedGenerator").resolves(ok(res)); const lstatSyncStub = sandbox.stub(fs, "lstatSync");