Files
vscode-front-matter/src/helpers/CustomScript.ts
2022-03-30 11:47:25 +02:00

178 lines
5.9 KiB
TypeScript

import { CustomScript as ICustomScript, ScriptType } from '../models/PanelSettings';
import { window, env as vscodeEnv, ProgressLocation } from 'vscode';
import { ArticleHelper, Telemetry } from '.';
import { Folders } from '../commands/Folders';
import { exec } from 'child_process';
import * as os from 'os';
import { join } from 'path';
import { Notifications } from './Notifications';
import ContentProvider from '../providers/ContentProvider';
import { Dashboard } from '../commands/Dashboard';
import { DashboardCommand } from '../dashboardWebView/DashboardCommand';
import { ParsedFrontMatter } from '../parsers';
import { TelemetryEvent } from '../constants/TelemetryEvent';
export class CustomScript {
public static async run(script: ICustomScript, path: string | null = null): Promise<void> {
const wsFolder = Folders.getWorkspaceFolder();
if (wsFolder) {
const wsPath = wsFolder.fsPath;
if (script.type === ScriptType.MediaFile || script.type === ScriptType.MediaFolder) {
Telemetry.send(TelemetryEvent.runMediaScript);
CustomScript.runMediaScript(wsPath, path, script);
} else {
Telemetry.send(TelemetryEvent.runCustomScript);
if (script.bulk) {
// Run script on all files
CustomScript.bulkRun(wsPath, script);
} else if (path) {
// Run script for provided path
CustomScript.singleRun(wsPath, script, path);
} else {
// Run script on current file.
CustomScript.singleRun(wsPath, script);
}
}
}
}
private static async singleRun(wsPath: string, script: ICustomScript, path: string | null = null): Promise<void> {
let articlePath: string | null = path;
let article: ParsedFrontMatter | null = null;
if (!path) {
const editor = window.activeTextEditor;
if (!editor) return;
articlePath = editor.document.uri.fsPath;
article = ArticleHelper.getFrontMatter(editor);
} else {
article = ArticleHelper.getFrontMatterByPath(path);
}
if (articlePath && article) {
window.withProgress({
location: ProgressLocation.Notification,
title: `Executing: ${script.title}`,
cancellable: false
}, async () => {
const output = await CustomScript.runScript(wsPath, article, articlePath as string, script);
CustomScript.showOutput(output, script);
});
} else {
Notifications.warning(`${script.title}: Article couldn't be retrieved.`);
}
}
private static async bulkRun(wsPath: string, script: ICustomScript): Promise<void> {
const folders = await Folders.getInfo();
if (!folders || folders.length === 0) {
Notifications.warning(`${script.title}: No files found.`);
return;
}
let output: string[] = [];
window.withProgress({
location: ProgressLocation.Notification,
title: `Executing: ${script.title}`,
cancellable: false
}, async (progress, token) => {
for await (const folder of folders) {
if (folder.lastModified.length > 0) {
for await (const file of folder.lastModified) {
try {
const article = ArticleHelper.getFrontMatterByPath(file.filePath);
if (article) {
const crntOutput = await CustomScript.runScript(wsPath, article, file.filePath, script);
if (crntOutput) {
output.push(crntOutput);
}
}
} catch (error) {
// Skipping file
}
}
}
}
CustomScript.showOutput(output.join(`\n`), script);
});
}
private static async runMediaScript(wsPath: string, path: string | null, script: ICustomScript): Promise<void> {
if (!path) {
Notifications.error(`${script.title}: There was no folder or media path specified.`);
return;
}
return new Promise((resolve, reject) => {
window.withProgress({
location: ProgressLocation.Notification,
title: `Executing: ${script.title}`,
cancellable: false
}, async () => {
exec(`${script.nodeBin || "node"} ${join(wsPath, script.script)} "${wsPath}" "${path}"`, (error, stdout) => {
if (error) {
Notifications.error(`${script.title}: ${error.message}`);
resolve();
return;
}
CustomScript.showOutput(stdout, script);
Dashboard.postWebviewMessage({
command: DashboardCommand.mediaUpdate
});
resolve();
return;
});
});
});
}
private static async runScript(wsPath: string, article: ParsedFrontMatter | null, contentPath: string, script: ICustomScript): Promise<string | null> {
return new Promise((resolve, reject) => {
let articleData = "";
if (os.type() === "Windows_NT") {
articleData = `"${JSON.stringify(article?.data).replace(/"/g, `""`)}"`;
} else {
articleData = JSON.stringify(article?.data).replace(/'/g, "%27");
articleData = `'${articleData}'`;
}
exec(`${script.nodeBin || "node"} ${join(wsPath, script.script)} "${wsPath}" "${contentPath}" ${articleData}`, (error, stdout) => {
if (error) {
Notifications.error(`${script.title}: ${error.message}`);
resolve(null);
return;
}
resolve(stdout);
});
});
}
private static showOutput(output: string | null, script: ICustomScript): void {
if (output) {
if (script.output === "editor") {
ContentProvider.show(output, script.title, script.outputType || "text");
} else {
window.showInformationMessage(`${script.title}: ${output}`, 'Copy output').then(value => {
if (value === 'Copy output') {
vscodeEnv.clipboard.writeText(output);
}
});
}
} else {
Notifications.info(`${script.title}: Executed your custom script.`);
}
}
}