Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env node
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Command } from "commander";
import { logErrorMessage } from "office-addin-usage-data";
import * as commands from "./commands";
/* global process */
const commander = new Command();
commander.name("office-addin-project");
commander.version(process.env.npm_package_version || "(version not available)");
// if the command is not known, display an error
commander.on("command:*", function () {
logErrorMessage(`The command syntax is not valid.\n`);
process.exitCode = 1;
commander.help();
});
commander
.command("convert")
.option(
"-m, --manifest <manifest-path>",
"Specify the location of the manifest file. Default is './manifest.xml'"
)
.option(
"-b, --backup <backup-path>",
"Specify the location of the backup folder for the project. Default is './backup.zip'"
)
.option(
"-p, --project <project-path>",
"Specify the location of the root directory of the project. Default is the directory of the manifest file."
)
.option(
"--preview-manifest-schema",
"Use the devPreview version of the json schema in the manifest output"
)
.option("--confirm", "Confirmes the conversion")
.action(commands.convert);
if (process.argv.length > 2) {
commander.parse(process.argv);
} else {
commander.help();
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { OptionValues } from "commander";
import inquirer from "inquirer";
import { logErrorMessage } from "office-addin-usage-data";
import { usageDataObject } from "./defaults";
import { convertProject } from "./convert";
export async function convert(options: OptionValues) {
try {
const manifestPath: string = options.manifest ?? "./manifest.xml";
const backupPath: string = options.backup ?? "./backup.zip";
const projectPath: string = options.project ?? "";
const devPreview: boolean = options.preview ?? false;
const shouldContinue = options.confirm ?? (await asksForUserConfirmation());
if (shouldContinue) {
await convertProject(manifestPath, backupPath, projectPath, devPreview);
usageDataObject.reportSuccess("convert", { result: "Project converted" });
} else {
usageDataObject.reportSuccess("convert", {
result: "Conversion cancelled",
});
}
} catch (err: any) {
usageDataObject.reportException("convert", err);
logErrorMessage(err);
}
}
async function asksForUserConfirmation(): Promise<boolean> {
const question = {
message: `This command will convert your current xml manifest to a json manifest and then proceed to upgrade your project dependencies to ensure compatibility with the new project structure.\nHowever, in order for this newly updated project to function correctly you must be using a compatible version of Outlook.\nWould you like to continue?`,
name: "didUserConfirm",
type: "confirm",
};
const answers = await inquirer.prompt([question]);
return (answers as any).didUserConfirm;
}
+152
View File
@@ -0,0 +1,152 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import AdmZip from "adm-zip";
import fs from "fs";
import fsExtra from "fs-extra";
import path from "path";
import util from "util";
import { exec } from "child_process";
import { convert } from "office-addin-manifest-converter";
import { ExpectedError } from "office-addin-usage-data";
/* global console process */
const execAsync = util.promisify(exec);
const skipBackup: string[] = ["node_modules"];
export async function convertProject(
manifestPath: string = "./manifest.xml",
backupPath: string = "./backup.zip",
projectDir: string = "",
devPreview: boolean = false
) {
if (manifestPath.endsWith(".json")) {
throw new ExpectedError(`The convert command only works on xml manifest based projects`);
}
if (!fs.existsSync(manifestPath)) {
throw new ExpectedError(`The manifest file '${manifestPath}' does not exist`);
}
const outputPath: string = path.dirname(manifestPath);
const currentDir: string = process.cwd();
await backupProject(backupPath);
try {
// assume project dir is the same as manifest dir if not specified
projectDir = projectDir === "" ? outputPath : projectDir;
process.chdir(projectDir);
if (!devPreview) {
await convert(manifestPath, outputPath, false /* imageDownload */);
} else {
// override the schema used in the json manifest to use the devPreview schema
await convert(
manifestPath,
outputPath,
false /* imageDownload */,
"https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json",
"devPreview"
);
}
await updatePackages();
await updateManifestXmlReferences();
fs.unlinkSync(manifestPath);
} catch (err: any) {
console.log(`Error in conversion. Restoring project initial state.`);
await restoreBackup(backupPath);
throw err;
} finally {
process.chdir(currentDir);
}
}
async function backupProject(backupPath: string) {
const zip: AdmZip = new AdmZip();
const outputPath: string = path.resolve(backupPath);
const rootDir: string = path.resolve();
const files: string[] = fs.readdirSync(rootDir);
files.forEach((entry) => {
const fullPath = path.resolve(entry);
const entryStats = fs.lstatSync(fullPath);
if (skipBackup.includes(entry)) {
// Don't add it to the backup
} else if (entryStats.isDirectory()) {
zip.addLocalFolder(entry, entry);
} else {
zip.addLocalFile(entry);
}
});
fsExtra.ensureDirSync(path.dirname(outputPath));
if (await zip.writeZipPromise(outputPath)) {
console.log(`A backup of your project was created to ${outputPath}`);
} else {
throw new Error(`Error writting zip file to ${outputPath}`);
}
}
async function restoreBackup(backupPath: string) {
var zip = new AdmZip(backupPath); // reading archives
zip.extractAllTo("./", true); // overwrite
}
async function updatePackages(): Promise<void> {
// Contains name of the package and minimum version
const depedentPackages: string[] = ["office-addin-debugging", "office-addin-manifest"];
let command: string = "npm install";
let messageToBePrinted: string = "Installing latest versions of";
for (let i = 0; i < depedentPackages.length; i++) {
const depedentPackage = depedentPackages[i];
command += ` ${depedentPackage}@latest`;
messageToBePrinted += ` ${depedentPackage}`;
if (i === depedentPackages.length - 2) {
messageToBePrinted += " and";
} else {
messageToBePrinted += ",";
}
}
command += ` --save-dev`;
console.log(messageToBePrinted.slice(0, -1));
await execAsync(command);
}
async function updateManifestXmlReferences(): Promise<void> {
await updatePackageJson();
await updateWebpackConfig();
}
async function updatePackageJson(): Promise<void> {
const packageJson = `./package.json`;
const readFileAsync = util.promisify(fs.readFile);
const data = await readFileAsync(packageJson, "utf8");
let content = JSON.parse(data);
// Change .xml references to .json
Object.keys(content.scripts).forEach(function (key) {
content.scripts[key] = content.scripts[key].replace(/manifest.xml/gi, `manifest.json`);
});
// write updated json to file
const writeFileAsync = util.promisify(fs.writeFile);
await writeFileAsync(packageJson, JSON.stringify(content, null, 2));
}
async function updateWebpackConfig(): Promise<void> {
const weppackConfig = `./webpack.config.js`;
const readFileAsync = util.promisify(fs.readFile);
const data = await readFileAsync(weppackConfig, "utf8");
// switching to json extension is the easy fix.
// TODO: update to remove the manifest copy plugin since it's not needed in webpack
let content = data.replace(/"(manifest\*\.)xml"/gi, '"$1json"');
const writeFileAsync = util.promisify(fs.writeFile);
await writeFileAsync(weppackConfig, content);
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import {
instrumentationKeyForOfficeAddinCLITools,
OfficeAddinUsageData,
} from "office-addin-usage-data";
// Usage data defaults
export const usageDataObject: OfficeAddinUsageData = new OfficeAddinUsageData({
projectName: "office-addin-project",
instrumentationKey: instrumentationKeyForOfficeAddinCLITools,
raisePrompt: false,
});
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
export * from "./convert";