@@ -5,6 +5,8 @@ const path = require("path");
55const util = require ( "util" ) ;
66const childProcess = require ( "child_process" ) ;
77const hosts = [ "excel" , "onenote" , "outlook" , "powerpoint" , "project" , "word" ] ;
8+ const commandsSupportedHosts = [ "word" , "excel" , "powerpoint" , "outlook" , "wxpo" ] ;
9+
810
911if ( process . argv . length <= 2 ) {
1012 const hostList = hosts . map ( ( host ) => `'${ host } '` ) . join ( ", " ) ;
@@ -19,7 +21,8 @@ if (process.argv.length <= 2) {
1921}
2022
2123const host = process . argv [ 2 ] ;
22- const manifestType = process . argv [ 3 ] ;
24+ const targetHosts = host == "wxpo" ? [ "excel" , "word" , "powerpoint" , "outlook" ] : [ host ] ;
25+ const manifestType = process . argv [ 3 ] || "xml" ;
2326const projectName = process . argv [ 4 ] ;
2427let appId = process . argv [ 5 ] ;
2528const testPackages = [
@@ -36,32 +39,75 @@ const unlinkFileAsync = util.promisify(fs.unlink);
3639const writeFileAsync = util . promisify ( fs . writeFile ) ;
3740
3841async function modifyProjectForSingleHost ( host ) {
39- if ( ! host ) {
40- throw new Error ( "The host was not provided." ) ;
42+ if ( ! targetHosts || targetHosts . length === 0 ) {
43+ throw new Error ( "No target hosts were provided." ) ;
44+ }
45+
46+ // Validate all target hosts
47+ for ( const targetHost of targetHosts ) {
48+ if ( ! hosts . includes ( targetHost ) ) {
49+ throw new Error ( `'${ targetHost } ' is not a supported host.` ) ;
50+ }
4151 }
42- if ( ! hosts . includes ( host ) ) {
43- throw new Error ( `'${ host } ' is not a supported host.` ) ;
52+
53+ // Check for unsupported combinations
54+ const unsupportedJSONHosts = targetHosts . filter ( h => h === "onenote" || h === "project" ) ;
55+ if ( manifestType === "json" && unsupportedJSONHosts . length > 0 ) {
56+ throw new Error ( `'${ unsupportedJSONHosts . join ( ", " ) } ' is not supported for ${ manifestType } manifest.` ) ;
57+ }
58+ if ( manifestType === "xml" && targetHosts . length > 1 ) {
59+ throw new Error ( `Multiple hosts are not supported for ${ manifestType } manifest.` ) ;
60+ }
61+ if ( ! commandsSupportedHosts . includes ( host ) ) {
62+ throw new Error ( `'${ host } ' does not support commands.` ) ;
4463 }
45- await convertProjectToSingleHost ( host ) ;
46- await updatePackageJsonForSingleHost ( host ) ;
47- await updateLaunchJsonFile ( host ) ;
48- }
4964
50- async function convertProjectToSingleHost ( host ) {
51- // Copy host-specific manifest over manifest.xml
52- const manifestContent = await readFileAsync ( `./manifest.${ host } .xml` , "utf8" ) ;
53- await writeFileAsync ( `./manifest.xml` , manifestContent ) ;
65+ await convertProjectToSingleHost ( host , manifestType ) ;
5466
55- // Copy over host-specific taskpane code to taskpane.ts
56- const srcContent = await readFileAsync ( `./src/taskpane/ ${ host } .ts` , "utf8" ) ;
57- await writeFileAsync ( `./src/taskpane/taskpane.ts` , srcContent ) ;
67+ await updatePackageJsonForSingleHost ( host , manifestType ) ;
68+ await updateLaunchJsonFile ( ) ;
69+ }
5870
59- // Delete all host-specific files
60- hosts . forEach ( async function ( host ) {
61- await unlinkFileAsync ( `./manifest.${ host } .xml` ) ;
62- await unlinkFileAsync ( `./src/taskpane/${ host } .ts` ) ;
63- } ) ;
71+ async function convertProjectToSingleHost ( host , manifestType ) {
6472
73+ // Copy host-specific manifest over manifest file
74+ const manifestPath = `./manifest.${ host } .${ manifestType } ` ;
75+ if ( fs . existsSync ( manifestPath ) ) {
76+ let manifestContent = await readFileAsync ( manifestPath , "utf8" ) ;
77+ await writeFileAsync ( `./manifest.${ manifestType } ` , manifestContent ) ;
78+ }
79+
80+ // Copy over host-specific taskpane code to taskpane.ts
81+ const taskpaneFilePath = "./src/taskpane/taskpane.ts" ;
82+ let taskpaneContent = await readFileAsync ( taskpaneFilePath , "utf8" ) ;
83+
84+ // Copy over host-specific commands code to commands.ts
85+ const commandsFilePath = "./src/commands/commands.ts" ;
86+ let commandsContent = await readFileAsync ( commandsFilePath , "utf8" ) ;
87+
88+ for ( const hostName of hosts ) {
89+ if ( ! targetHosts . includes ( hostName ) ) {
90+ if ( fs . existsSync ( `./src/taskpane/${ hostName } .ts` ) ) {
91+ await unlinkFileAsync ( `./src/taskpane/${ hostName } .ts` ) ;
92+ }
93+ // remove unneeded imports from taskpane
94+ taskpaneContent = taskpaneContent . replace ( `import "./${ hostName } ";` , "" ) . replace ( / ^ \s * [ \r \n ] / gm, "" ) ;
95+
96+ // remove unneeded commands files
97+ if ( fs . existsSync ( `./src/commands/commands.${ hostName } .ts` ) ) {
98+ await unlinkFileAsync ( `./src/commands/commands.${ hostName } .ts` ) ;
99+ }
100+ // remove unneeded imports from commands
101+ commandsContent = commandsContent . replace ( `import "./commands.${ hostName } ";` , "" ) . replace ( / ^ \s * [ \r \n ] / gm, "" ) ;
102+ }
103+ // Remove unneeded manifest templates
104+ if ( fs . existsSync ( `./manifest.${ hostName } .${ manifestType } ` ) ) {
105+ await unlinkFileAsync ( `./manifest.${ hostName } .${ manifestType } ` ) ;
106+ }
107+ }
108+
109+ await writeFileAsync ( taskpaneFilePath , taskpaneContent ) ;
110+ await writeFileAsync ( commandsFilePath , commandsContent ) ;
65111 // Delete test folder
66112 deleteFolder ( path . resolve ( `./test` ) ) ;
67113
@@ -75,73 +121,62 @@ async function convertProjectToSingleHost(host) {
75121 await deleteSupportFiles ( ) ;
76122}
77123
78- async function updatePackageJsonForSingleHost ( host ) {
124+ async function updatePackageJsonForSingleHost ( host , manifestType ) {
79125 // Update package.json to reflect selected host
80126 const packageJson = `./package.json` ;
81- const data = await readFileAsync ( packageJson , "utf8" ) ;
127+ let data = await readFileAsync ( packageJson , "utf8" ) ;
128+
129+ if ( manifestType === "json" ) {
130+ // Change manifest file name extension
131+ data = data . replace ( / \. x m l / g, ".json" ) ;
132+ }
133+
82134 let content = JSON . parse ( data ) ;
83135
84136 // Update 'config' section in package.json to use selected host
85- content . config [ "app_to_debug" ] = host ;
137+ content . config [ "app_to_debug" ] = targetHosts [ 0 ] ;
86138
87139 // Remove 'engines' section
88140 delete content . engines ;
89141
90142 // Remove scripts that are unrelated to the selected host
91- Object . keys ( content . scripts ) . forEach ( function ( key ) {
143+ for ( const key of Object . keys ( content . scripts ) ) {
92144 if ( key === "convert-to-single-host" ) {
93145 delete content . scripts [ key ] ;
94146 }
95- } ) ;
147+ }
96148
97149 // Remove test-related scripts
98- Object . keys ( content . scripts ) . forEach ( function ( key ) {
150+ for ( const key of Object . keys ( content . scripts ) ) {
99151 if ( key . includes ( "test" ) ) {
100152 delete content . scripts [ key ] ;
101153 }
102- } ) ;
154+ }
103155
104156 // Remove test-related packages
105- Object . keys ( content . devDependencies ) . forEach ( function ( key ) {
157+ for ( const key of Object . keys ( content . devDependencies ) ) {
106158 if ( testPackages . includes ( key ) ) {
107159 delete content . devDependencies [ key ] ;
108160 }
109- } ) ;
161+ }
110162
111163 // Write updated JSON to file
112164 await writeFileAsync ( packageJson , JSON . stringify ( content , null , 2 ) ) ;
113165}
114166
115- async function updateLaunchJsonFile ( host ) {
167+ async function updateLaunchJsonFile ( ) {
116168 // Remove 'Debug Tests' configuration from launch.json
117169 const launchJson = `.vscode/launch.json` ;
118170 const launchJsonContent = await readFileAsync ( launchJson , "utf8" ) ;
119171 let content = JSON . parse ( launchJsonContent ) ;
120172 content . configurations = content . configurations . filter ( function ( config ) {
121- return config . name . startsWith ( getHostName ( host ) ) ;
173+ return targetHosts . some ( ( host ) => {
174+ return config . name . toLowerCase ( ) . startsWith ( host ) ;
175+ } ) ;
122176 } ) ;
123177 await writeFileAsync ( launchJson , JSON . stringify ( content , null , 2 ) ) ;
124178}
125179
126- function getHostName ( host ) {
127- switch ( host ) {
128- case "excel" :
129- return "Excel" ;
130- case "onenote" :
131- return "OneNote" ;
132- case "outlook" :
133- return "Outlook" ;
134- case "powerpoint" :
135- return "PowerPoint" ;
136- case "project" :
137- return "Project" ;
138- case "word" :
139- return "Word" ;
140- default :
141- throw new Error ( `'${ host } ' is not a supported host.` ) ;
142- }
143- }
144-
145180function deleteFolder ( folder ) {
146181 try {
147182 if ( fs . existsSync ( folder ) ) {
@@ -173,72 +208,22 @@ async function deleteSupportFiles() {
173208
174209async function deleteJSONManifestRelatedFiles ( ) {
175210 await unlinkFileAsync ( "manifest.json" ) ;
211+ for ( const host of hosts ) {
212+ if ( fs . existsSync ( `./manifest.${ host } .json` ) ) {
213+ await unlinkFileAsync ( `manifest.${ host } .json` ) ;
214+ }
215+ }
176216 await unlinkFileAsync ( "assets/color.png" ) ;
177217 await unlinkFileAsync ( "assets/outline.png" ) ;
178218}
179219
180220async function deleteXMLManifestRelatedFiles ( ) {
181221 await unlinkFileAsync ( "manifest.xml" ) ;
182- }
183-
184- async function updatePackageJsonForXMLManifest ( ) {
185- const packageJson = `./package.json` ;
186- const data = await readFileAsync ( packageJson , "utf8" ) ;
187- let content = JSON . parse ( data ) ;
188-
189- // Write updated JSON to file
190- await writeFileAsync ( packageJson , JSON . stringify ( content , null , 2 ) ) ;
191- }
192-
193- async function updatePackageJsonForJSONManifest ( ) {
194- const packageJson = `./package.json` ;
195- const data = await readFileAsync ( packageJson , "utf8" ) ;
196- let content = JSON . parse ( data ) ;
197-
198- // Change manifest file name extension
199- content . scripts . start = "office-addin-debugging start manifest.json" ;
200- content . scripts . stop = "office-addin-debugging stop manifest.json" ;
201- content . scripts . validate = "office-addin-manifest validate manifest.json" ;
202-
203- // Write updated JSON to file
204- await writeFileAsync ( packageJson , JSON . stringify ( content , null , 2 ) ) ;
205- }
206-
207- async function updateTasksJsonFileForJSONManifest ( ) {
208- const tasksJson = `.vscode/tasks.json` ;
209- const data = await readFileAsync ( tasksJson , "utf8" ) ;
210- let content = JSON . parse ( data ) ;
211-
212- content . tasks . forEach ( function ( task ) {
213- if ( task . label . startsWith ( "Build" ) ) {
214- task . dependsOn = [ "Install" ] ;
215- }
216- if ( task . label === "Debug: Outlook Desktop" ) {
217- task . script = "start" ;
218- task . dependsOn = [ "Check OS" , "Install" ] ;
222+ hosts . forEach ( async function ( host ) {
223+ if ( fs . existsSync ( `./manifest.${ host } .xml` ) ) {
224+ await unlinkFileAsync ( `manifest.${ host } .xml` ) ;
219225 }
220226 } ) ;
221-
222- const checkOSTask = {
223- label : "Check OS" ,
224- type : "shell" ,
225- windows : {
226- command : "echo 'Sideloading in Outlook on Windows is supported'" ,
227- } ,
228- linux : {
229- command : "echo 'Sideloading on Linux is not supported' && exit 1" ,
230- } ,
231- osx : {
232- command : "echo 'Sideloading in Outlook on Mac is not supported' && exit 1" ,
233- } ,
234- presentation : {
235- clear : true ,
236- panel : "dedicated" ,
237- } ,
238- } ;
239-
240- content . tasks . push ( checkOSTask ) ;
241- await writeFileAsync ( tasksJson , JSON . stringify ( content , null , 2 ) ) ;
242227}
243228
244229async function updateWebpackConfigForJSONManifest ( ) {
@@ -249,9 +234,7 @@ async function updateWebpackConfigForJSONManifest() {
249234}
250235
251236async function modifyProjectForJSONManifest ( ) {
252- await updatePackageJsonForJSONManifest ( ) ;
253237 await updateWebpackConfigForJSONManifest ( ) ;
254- await updateTasksJsonFileForJSONManifest ( ) ;
255238 await deleteXMLManifestRelatedFiles ( ) ;
256239}
257240
@@ -266,10 +249,9 @@ modifyProjectForSingleHost(host).catch((err) => {
266249
267250let manifestPath = "manifest.xml" ;
268251
269- if ( host !== "outlook" || manifestType !== "json" ) {
252+ if ( manifestType !== "json" ) {
270253 // Remove things that are only relevant to JSON manifest
271254 deleteJSONManifestRelatedFiles ( ) ;
272- updatePackageJsonForXMLManifest ( ) ;
273255} else {
274256 manifestPath = "manifest.json" ;
275257 modifyProjectForJSONManifest ( ) . catch ( ( err ) => {
@@ -289,8 +271,10 @@ if (projectName) {
289271 if ( error ) {
290272 console . error ( `Error updating the manifest: ${ error } ` ) ;
291273 process . exitCode = 1 ;
274+ Promise . reject ( stdout ) ;
292275 } else {
293276 console . log ( stdout ) ;
277+ Promise . resolve ( ) ;
294278 }
295279 } ) ;
296280}
0 commit comments