diff --git a/src/commands/Folders.ts b/src/commands/Folders.ts index ea39ae10..74238d0a 100644 --- a/src/commands/Folders.ts +++ b/src/commands/Folders.ts @@ -7,7 +7,7 @@ import uniqBy = require("lodash.uniqby"); import { Template } from "./Template"; import { Notifications } from "../helpers/Notifications"; import { Logger, Settings } from "../helpers"; -import { existsSync, mkdirSync } from 'fs'; +import { existsSync } from 'fs'; import { format } from 'date-fns'; import { Dashboard } from './Dashboard'; import { parseWinPath } from '../helpers/parseWinPath'; @@ -16,6 +16,8 @@ import { MediaListener, PagesListener, SettingsListener } from '../listeners/das import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes'; import { Telemetry } from '../helpers/Telemetry'; import { glob } from 'glob'; +import { mkdirAsync } from '../utils/mkdirAsync'; +import { existsAsync } from '../utils'; export const WORKSPACE_PLACEHOLDER = `[[workspace]]`; @@ -62,8 +64,8 @@ export class Folders { parentFolders.push(folder); - if (!existsSync(folderPath)) { - mkdirSync(folderPath); + if (!(await existsAsync(folderPath))) { + await mkdirAsync(folderPath); } } @@ -210,9 +212,9 @@ export class Folders { if (!projectFolder) { window.showWorkspaceFolderPick({ placeHolder: `Please select the main workspace folder for Front Matter to use.` - }).then(selectedFolder => { + }).then(async (selectedFolder) => { if (selectedFolder) { - Settings.createGlobalFile(selectedFolder.uri); + await Settings.createGlobalFile(selectedFolder.uri); // Full reload to make sure the whole extension is reloaded correctly commands.executeCommand(`workbench.action.reloadWindow`); } diff --git a/src/commands/Project.ts b/src/commands/Project.ts index d7cb3488..a6303a8d 100644 --- a/src/commands/Project.ts +++ b/src/commands/Project.ts @@ -2,13 +2,13 @@ import { DEFAULT_CONTENT_TYPE } from './../constants/ContentType'; import { Telemetry } from './../helpers/Telemetry'; import { workspace, Uri } from "vscode"; import { join } from "path"; -import * as fs from "fs"; import { Notifications } from "../helpers/Notifications"; import { Template } from "./Template"; import { Folders } from "./Folders"; import { FrameworkDetector, Logger, Settings } from "../helpers"; import { SETTING_CONTENT_DEFAULT_FILETYPE, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants"; import { SettingsListener } from '../listeners/dashboard'; +import { existsAsync, writeFileAsync } from '../utils'; export class Project { @@ -34,7 +34,7 @@ categories: [] */ public static async init(sampleTemplate?: boolean) { try { - Settings.createTeamSettings(); + await Settings.createTeamSettings(); // Add the default content type Settings.update(SETTING_TAXONOMY_CONTENT_TYPES, [DEFAULT_CONTENT_TYPE], true); @@ -49,10 +49,10 @@ categories: [] // Check if you can find the framework const wsFolder = Folders.getWorkspaceFolder(); - const framework = FrameworkDetector.get(wsFolder?.fsPath || ""); + const framework = await FrameworkDetector.get(wsFolder?.fsPath || ""); if (framework) { - SettingsListener.setFramework(framework.name); + await SettingsListener.setFramework(framework.name); } SettingsListener.getSettings(true); @@ -79,12 +79,12 @@ categories: [] const article = Uri.file(join(templatePath.fsPath, `article.${fileType}`)); - if (!fs.existsSync(templatePath.fsPath)) { + if (!(await existsAsync(templatePath.fsPath))) { await workspace.fs.createDirectory(templatePath); } if (sampleTemplate) { - fs.writeFileSync(article.fsPath, Project.content, { encoding: "utf-8" }); + await writeFileAsync(article.fsPath, Project.content, { encoding: "utf-8" }); Notifications.info("Sample template created."); } } diff --git a/src/commands/Template.ts b/src/commands/Template.ts index 03b6119c..6201c2c3 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -1,7 +1,6 @@ import { Questions } from './../helpers/Questions'; import * as vscode from 'vscode'; import * as path from 'path'; -import * as fs from 'fs'; import { SETTING_CONTENT_DEFAULT_FILETYPE, SETTING_TEMPLATES_FOLDER, TelemetryEvent } from '../constants'; import { ArticleHelper, Settings } from '../helpers'; import { Article } from '.'; @@ -12,6 +11,7 @@ import { ContentType as IContentType } from '../models'; import { PagesListener } from '../listeners/dashboard'; import { extname } from 'path'; import { Telemetry } from '../helpers/Telemetry'; +import { writeFileAsync, copyFileAsync } from '../utils'; export class Template { @@ -60,7 +60,7 @@ export class Template { let fileContents = ArticleHelper.stringifyFrontMatter(keepContents === "no" ? "" : clonedArticle.content, clonedArticle.data); const templateFile = path.join(templatePath.fsPath, `${titleValue}.${fileType}`); - fs.writeFileSync(templateFile, fileContents, { encoding: "utf-8" }); + await writeFileAsync(templateFile, fileContents, { encoding: "utf-8" }); Notifications.info(`Template created and is now available in your ${folder} folder.`); } @@ -120,23 +120,23 @@ export class Template { return; } - const templateData = ArticleHelper.getFrontMatterByPath(template.fsPath); + const templateData = await ArticleHelper.getFrontMatterByPath(template.fsPath); let contentType: IContentType | undefined; if (templateData && templateData.data && templateData.data.type) { contentType = contentTypes?.find(t => t.name === templateData.data.type); } const fileExtension = extname(template.fsPath).replace(".", ""); - let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue, fileExtension); + let newFilePath: string | undefined = await ArticleHelper.createContent(contentType, folderPath, titleValue, fileExtension); if (!newFilePath) { return; } // Start the new file creation - fs.copyFileSync(template.fsPath, newFilePath); + await copyFileAsync(template.fsPath, newFilePath); // Update the properties inside the template - let frontMatter = ArticleHelper.getFrontMatterByPath(newFilePath); + let frontMatter = await ArticleHelper.getFrontMatterByPath(newFilePath); if (!frontMatter) { Notifications.warning(`Something failed when retrieving the newly created file.`); return; @@ -147,7 +147,7 @@ export class Template { frontMatter = Article.updateDate(frontMatter); - fs.writeFileSync(newFilePath, ArticleHelper.stringifyFrontMatter(frontMatter.content, frontMatter.data), { encoding: "utf8" }); + await writeFileAsync(newFilePath, ArticleHelper.stringifyFrontMatter(frontMatter.content, frontMatter.data), { encoding: "utf8" }); await vscode.commands.executeCommand('vscode.open', vscode.Uri.file(newFilePath)); } diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 2fa1ba5c..ed051543 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -4,7 +4,6 @@ import { Uri, workspace } from 'vscode'; import { MarkdownFoldingProvider } from './../providers/MarkdownFoldingProvider'; import { DEFAULT_CONTENT_TYPE, DEFAULT_CONTENT_TYPE_NAME } from './../constants/ContentType'; import * as vscode from 'vscode'; -import * as fs from "fs"; import { DefaultFields, SETTING_CONTENT_DEFAULT_FILETYPE, SETTING_CONTENT_PLACEHOLDERS, SETTING_CONTENT_SUPPORTED_FILETYPES, SETTING_FILE_PRESERVE_CASING, SETTING_COMMA_SEPARATED_FIELDS, SETTING_DATE_FIELD, SETTING_DATE_FORMAT, SETTING_INDENT_ARRAY, SETTING_REMOVE_QUOTES, SETTING_SITE_BASEURL, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_TEMPLATES_PREFIX, SETTING_MODIFIED_FIELD, DefaultFieldValues } from '../constants'; import { DumpOptions } from 'js-yaml'; import { FrontMatterParser, ParsedFrontMatter } from '../parsers'; @@ -15,7 +14,6 @@ import { Article } from '../commands'; import { join } from 'path'; import { EditorHelper } from '@estruyf/vscode'; import sanitize from '../helpers/Sanitize'; -import { existsSync, mkdirSync } from 'fs'; import { ContentType } from '../models'; import { DateHelper } from './DateHelper'; import { DiagnosticSeverity, Position, window, Range } from 'vscode'; @@ -26,6 +24,8 @@ import { Content } from 'mdast'; import { processKnownPlaceholders } from './PlaceholderHelper'; import { CustomScript } from './CustomScript'; import { Folders } from '../commands/Folders'; +import { existsAsync, readFileAsync } from '../utils'; +import { mkdirAsync } from '../utils/mkdirAsync'; export class ArticleHelper { private static notifiedFiles: string[] = []; @@ -70,8 +70,8 @@ export class ArticleHelper { * Retrieve the file's front matter by its path * @param filePath */ - public static getFrontMatterByPath(filePath: string) { - const file = fs.readFileSync(filePath, { encoding: "utf-8" }); + public static async getFrontMatterByPath(filePath: string) { + const file = await readFileAsync(filePath, { encoding: "utf-8" }); return ArticleHelper.parseFile(file, filePath); } @@ -328,7 +328,7 @@ export class ArticleHelper { * @param titleValue * @returns The new file path */ - public static createContent(contentType: ContentType | undefined, folderPath: string, titleValue: string, fileExtension?: string): string | undefined { + public static async createContent(contentType: ContentType | undefined, folderPath: string, titleValue: string, fileExtension?: string): Promise { FrontMatterParser.currentContent = null; const prefix = Settings.get(SETTING_TEMPLATES_PREFIX); @@ -341,11 +341,11 @@ export class ArticleHelper { // Create a folder with the `index.md` file if (contentType?.pageBundle) { const newFolder = join(folderPath, sanitizedName); - if (existsSync(newFolder)) { + if (await existsAsync(newFolder)) { Notifications.error(`A page bundle with the name ${sanitizedName} already exists in ${folderPath}`); return; } else { - mkdirSync(newFolder); + await mkdirAsync(newFolder); newFilePath = join(newFolder, `index.${fileExtension || contentType.fileType || fileType}`); } } else { @@ -357,7 +357,7 @@ export class ArticleHelper { newFilePath = join(folderPath, newFileName); - if (existsSync(newFilePath)) { + if (await existsAsync(newFilePath)) { Notifications.warning(`Content with the title already exists. Please specify a new title.`); return; } diff --git a/src/helpers/ContentType.ts b/src/helpers/ContentType.ts index 7b64a2d9..5308a92c 100644 --- a/src/helpers/ContentType.ts +++ b/src/helpers/ContentType.ts @@ -6,13 +6,13 @@ import { ContentType as IContentType, DraftField, Field, FieldGroup, FieldType, import { Uri, commands, window, ProgressLocation, workspace } from 'vscode'; import { Folders } from "../commands/Folders"; import { Questions } from "./Questions"; -import { existsSync, writeFileSync } from "fs"; import { Notifications } from "./Notifications"; import { DEFAULT_CONTENT_TYPE_NAME } from "../constants/ContentType"; import { Telemetry } from './Telemetry'; import { processKnownPlaceholders } from './PlaceholderHelper'; import { basename } from 'path'; import { ParsedFrontMatter } from '../parsers'; +import { existsAsync, writeFileAsync } from '../utils'; export class ContentType { @@ -197,9 +197,9 @@ export class ContentType { Settings.update(SETTING_TAXONOMY_CONTENT_TYPES, contentTypes, true); const configPath = Settings.projectConfigPath; - const notificationAction = await Notifications.info(`Content type ${contentTypeName} has been ${overrideBool ? `updated` : `generated`}.`, configPath && existsSync(configPath) ? `Open settings` : undefined); + const notificationAction = await Notifications.info(`Content type ${contentTypeName} has been ${overrideBool ? `updated` : `generated`}.`, configPath && await existsAsync(configPath) ? `Open settings` : undefined); - if (notificationAction === "Open settings" && configPath && existsSync(configPath)) { + if (notificationAction === "Open settings" && configPath && await existsAsync(configPath)) { commands.executeCommand('vscode.open', Uri.file(configPath)); } } @@ -231,9 +231,9 @@ export class ContentType { Settings.update(SETTING_TAXONOMY_CONTENT_TYPES, contentTypes, true); const configPath = Settings.projectConfigPath; - const notificationAction = await Notifications.info(`Content type ${contentType.name} has been updated.`, configPath && existsSync(configPath) ? `Open settings` : undefined); + const notificationAction = await Notifications.info(`Content type ${contentType.name} has been updated.`, configPath && await existsAsync(configPath) ? `Open settings` : undefined); - if (notificationAction === "Open settings" && configPath && existsSync(configPath)) { + if (notificationAction === "Open settings" && configPath && await existsAsync(configPath)) { commands.executeCommand('vscode.open', Uri.file(configPath)); } } @@ -558,10 +558,10 @@ export class ContentType { let templateData: ParsedFrontMatter | null = null; if (templatePath) { templatePath = Folders.getAbsFilePath(templatePath); - templateData = ArticleHelper.getFrontMatterByPath(templatePath); + templateData = await ArticleHelper.getFrontMatterByPath(templatePath); } - let newFilePath: string | undefined = ArticleHelper.createContent(contentType, folderPath, titleValue); + let newFilePath: string | undefined = await ArticleHelper.createContent(contentType, folderPath, titleValue); if (!newFilePath) { return; } @@ -586,7 +586,7 @@ export class ContentType { const content = ArticleHelper.stringifyFrontMatter(templateData?.content || ``, data); - writeFileSync(newFilePath, content, { encoding: "utf8" }); + await writeFileAsync(newFilePath, content, { encoding: "utf8" }); // Check if the content type has a post script to execute if (contentType.postScript) { diff --git a/src/helpers/CustomScript.ts b/src/helpers/CustomScript.ts index 5f2db7db..95525db5 100644 --- a/src/helpers/CustomScript.ts +++ b/src/helpers/CustomScript.ts @@ -14,7 +14,7 @@ import { DashboardCommand } from '../dashboardWebView/DashboardCommand'; import { ParsedFrontMatter } from '../parsers'; import { TelemetryEvent } from '../constants/TelemetryEvent'; import { SETTING_CUSTOM_SCRIPTS } from '../constants'; -import { existsSync } from 'fs'; +import { existsAsync } from '../utils'; export class CustomScript { @@ -77,7 +77,7 @@ export class CustomScript { articlePath = editor.document.uri.fsPath; article = ArticleHelper.getFrontMatter(editor); } else { - article = ArticleHelper.getFrontMatterByPath(path); + article = await ArticleHelper.getFrontMatterByPath(path); } if (articlePath && article) { @@ -119,7 +119,7 @@ export class CustomScript { if (folder.lastModified.length > 0) { for await (const file of folder.lastModified) { try { - const article = ArticleHelper.getFrontMatterByPath(file.filePath); + const article = await ArticleHelper.getFrontMatterByPath(file.filePath); if (article) { const crntOutput = await CustomScript.runScript(wsPath, article, file.filePath, script); if (crntOutput) { @@ -220,7 +220,7 @@ export class CustomScript { articlePath = editor.document.uri.fsPath; article = ArticleHelper.getFrontMatter(editor); } else { - article = ArticleHelper.getFrontMatterByPath(articlePath); + article = await ArticleHelper.getFrontMatterByPath(articlePath); } if (article && article.data) { @@ -264,7 +264,7 @@ export class CustomScript { * @returns */ public static async executeScript(script: ICustomScript, wsPath: string, args: string): Promise { - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { // Check the command to use let command = script.nodeBin || "node"; @@ -274,7 +274,7 @@ export class CustomScript { const scriptPath = join(wsPath, script.script); - if (!existsSync(scriptPath)) { + if (!await existsAsync(scriptPath)) { reject(new Error(`Script not found: ${scriptPath}`)); return; } diff --git a/src/helpers/DashboardSettings.ts b/src/helpers/DashboardSettings.ts index 6119a1fb..b31c6286 100644 --- a/src/helpers/DashboardSettings.ts +++ b/src/helpers/DashboardSettings.ts @@ -53,7 +53,7 @@ export class DashboardSettings { customSorting: Settings.get(SETTING_CONTENT_SORTING), contentFolders: Folders.get(), crntFramework: Settings.get(SETTING_FRAMEWORK_ID), - framework: (!isInitialized && wsFolder) ? FrameworkDetector.get(wsFolder.fsPath) : null, + framework: (!isInitialized && wsFolder) ? await FrameworkDetector.get(wsFolder.fsPath) : null, scripts: (Settings.get(SETTING_CUSTOM_SCRIPTS) || []), date: { format: Settings.get(SETTING_DATE_FORMAT) || "" diff --git a/src/helpers/DataFileHelper.ts b/src/helpers/DataFileHelper.ts index e7c59d12..aa04dc7b 100644 --- a/src/helpers/DataFileHelper.ts +++ b/src/helpers/DataFileHelper.ts @@ -1,4 +1,3 @@ -import { existsSync, readFileSync } from "fs"; import { Folders } from "../commands/Folders"; import { DataFile } from "../models"; import * as yaml from 'js-yaml'; @@ -7,6 +6,7 @@ import { Notifications } from "./Notifications"; import { commands } from "vscode"; import { COMMAND_NAME, SETTING_DATA_FILES } from "../constants"; import { Settings } from "./SettingsHelper"; +import { existsAsync, readFileAsync } from "../utils"; export class DataFileHelper { @@ -16,10 +16,10 @@ export class DataFileHelper { * @param filePath * @returns */ - public static get(filePath: string) { + public static async get(filePath: string) { const absPath = Folders.getAbsFilePath(filePath); - if (existsSync(absPath)) { - return readFileSync(absPath, 'utf8'); + if (await existsAsync(absPath)) { + return await readFileAsync(absPath, 'utf8'); } return null; @@ -53,7 +53,7 @@ export class DataFileHelper { public static async process(data: DataFile) { try { const { file, fileType } = data; - const dataFile = DataFileHelper.get(file); + const dataFile = await DataFileHelper.get(file); if (fileType === "yaml") { return yaml.safeLoad(dataFile || ""); diff --git a/src/helpers/Extension.ts b/src/helpers/Extension.ts index 4ab882ec..6a01ad69 100644 --- a/src/helpers/Extension.ts +++ b/src/helpers/Extension.ts @@ -154,7 +154,7 @@ export class Extension { // Create team settings if (Settings.hasSettings()) { - Settings.createTeamSettings(); + await Settings.createTeamSettings(); } const hideDateDeprecation = await Extension.getInstance().getState(ExtensionState.Updates.v7_0_0.dateFields, "workspace"); diff --git a/src/helpers/FrameworkDetector.ts b/src/helpers/FrameworkDetector.ts index d1607e0c..1c5a54e5 100644 --- a/src/helpers/FrameworkDetector.ts +++ b/src/helpers/FrameworkDetector.ts @@ -1,5 +1,4 @@ import * as jsoncParser from 'jsonc-parser'; -import { existsSync, readFileSync } from "fs"; import jsyaml = require("js-yaml"); import { join, resolve } from "path"; import { commands, Uri } from "vscode"; @@ -8,6 +7,7 @@ import { COMMAND_NAME } from "../constants"; import { FrameworkDetectors } from "../constants/FrameworkDetectors"; import { Framework } from "../models"; import { Logger } from "./Logger"; +import { existsAsync, readFileAsync } from '../utils'; export class FrameworkDetector { @@ -19,7 +19,7 @@ export class FrameworkDetector { return FrameworkDetectors.map((detector: any) => detector.framework); } - private static check(folder: string) { + private static async check(folder: string) { let dependencies = null; let devDependencies = null; let gemContent = null; @@ -27,8 +27,8 @@ export class FrameworkDetector { // Try fetching the package JSON file try { const pkgFile = join(folder, 'package.json'); - if (existsSync(pkgFile)) { - let packageJson: any = readFileSync(pkgFile, "utf8"); + if (await existsAsync(pkgFile)) { + let packageJson: any = await readFileAsync(pkgFile, "utf8"); if (packageJson) { packageJson = typeof packageJson === "string" ? jsoncParser.parse(packageJson) : packageJson; @@ -43,8 +43,8 @@ export class FrameworkDetector { // Try fetching the Gemfile try { const gemFile = join(folder, 'Gemfile'); - if (existsSync(gemFile)) { - gemContent = readFileSync(gemFile, "utf8"); + if (await existsAsync(gemFile)) { + gemContent = await readFileAsync(gemFile, "utf8"); } } catch (e) { // do nothing @@ -70,7 +70,7 @@ export class FrameworkDetector { // Verify by files for (const filename of detector.requiredFiles ?? []) { - const fileExists = existsSync(resolve(folder, filename)); + const fileExists = await existsAsync(resolve(folder, filename)); if (fileExists) { return detector.framework; } @@ -81,21 +81,21 @@ export class FrameworkDetector { return undefined; } - public static checkDefaultSettings(framework: Framework) { + public static async checkDefaultSettings(framework: Framework) { if (framework.name.toLowerCase() === "jekyll") { - FrameworkDetector.jekyll(); + await FrameworkDetector.jekyll(); } } - private static jekyll() { + private static async jekyll() { try { const wsFolder = Folders.getWorkspaceFolder(); const jekyllConfig = join(wsFolder?.fsPath || "", '_config.yml'); let collectionDir = ""; - if (existsSync(jekyllConfig)) { - const content = readFileSync(jekyllConfig, "utf8"); + if (await existsAsync(jekyllConfig)) { + const content = await readFileAsync(jekyllConfig, "utf8"); // Convert YAML to JSON const config = jsyaml.safeLoad(content); @@ -107,7 +107,7 @@ export class FrameworkDetector { const draftsPath = join(wsFolder?.fsPath || "", collectionDir, "_drafts"); const postsPath = join(wsFolder?.fsPath || "", collectionDir, "_posts"); - if (existsSync(draftsPath)) { + if (await existsAsync(draftsPath)) { const folderUri = Uri.file(draftsPath); commands.executeCommand(COMMAND_NAME.registerFolder, { title: "drafts", @@ -115,7 +115,7 @@ export class FrameworkDetector { }); } - if (existsSync(postsPath)) { + if (await existsAsync(postsPath)) { const folderUri = Uri.file(postsPath); commands.executeCommand(COMMAND_NAME.registerFolder, { title: "posts", diff --git a/src/helpers/MediaHelpers.ts b/src/helpers/MediaHelpers.ts index d6295df5..68d77bc6 100644 --- a/src/helpers/MediaHelpers.ts +++ b/src/helpers/MediaHelpers.ts @@ -4,15 +4,16 @@ import { Folders } from "../commands/Folders"; import { DEFAULT_CONTENT_TYPE, ExtensionState, HOME_PAGE_NAVIGATION_ID, SETTING_MEDIA_SUPPORTED_MIMETYPES } from "../constants"; import { SortingOption } from "../dashboardWebView/models"; import { MediaInfo, MediaPaths, SortOrder, SortType } from "../models"; -import { basename, extname, join, parse, dirname, relative } from "path"; -import { existsSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs"; -import { commands, Uri, workspace, window, Position } from "vscode"; +import { basename, join, parse, dirname, relative } from "path"; +import { statSync } from "fs"; +import { Uri, workspace, window, Position } from "vscode"; import imageSize from "image-size"; import { EditorHelper } from "@estruyf/vscode"; import { SortOption } from "../dashboardWebView/constants/SortOption"; import { DataListener, MediaListener } from "../listeners/panel"; import { ArticleHelper } from "./ArticleHelper"; import { lookup } from "mime-types"; +import { existsAsync, readdirAsync, unlinkAsync, writeFileAsync } from "../utils"; export class MediaHelpers { @@ -48,7 +49,7 @@ export class MediaHelpers { if (viewData?.data?.filePath && (viewData?.data?.filePath.endsWith('index.md') || viewData?.data?.filePath.endsWith('index.mdx'))) { const folderPath = parse(viewData.data.filePath).dir; selectedFolder = folderPath; - } else if (stateValue && existsSync(stateValue)) { + } else if (stateValue && await existsAsync(stateValue)) { selectedFolder = stateValue; } } @@ -150,23 +151,23 @@ export class MediaHelpers { let allFolders: string[] = []; if (selectedFolder) { - if (existsSync(selectedFolder)) { - allFolders = readdirSync(selectedFolder, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(selectedFolder, dir.name))); + if (await existsAsync(selectedFolder)) { + allFolders = (await readdirAsync(selectedFolder, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(selectedFolder, dir.name))); } } else { if (pageBundleContentTypes.length > 0) { for (const contentFolder of contentFolders) { const contentPath = contentFolder.path; - if (contentPath && existsSync(contentPath)) { - const subFolders = readdirSync(contentPath, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(contentPath, dir.name))); + if (contentPath && await existsAsync(contentPath)) { + const subFolders = (await readdirAsync(contentPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(contentPath, dir.name))); allContentFolders = [...allContentFolders, ...subFolders]; } } } const staticPath = join(parseWinPath(wsFolder?.fsPath || ""), staticFolder || ""); - if (staticPath && existsSync(staticPath)) { - allFolders = readdirSync(staticPath, { withFileTypes: true }).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(staticPath, dir.name))); + if (staticPath && await existsAsync(staticPath)) { + allFolders = (await readdirAsync(staticPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(staticPath, dir.name))); } } @@ -218,11 +219,11 @@ export class MediaHelpers { absFolderPath = folder; } - if (!existsSync(absFolderPath)) { + if (!(await existsAsync(absFolderPath))) { absFolderPath = join(wsPath, folder || ""); } - if (!existsSync(absFolderPath)) { + if (!(await existsAsync(absFolderPath))) { Notifications.error(`We couldn't find your selected folder.`); return; } @@ -231,7 +232,7 @@ export class MediaHelpers { const imgData = decodeBase64(contents); if (imgData) { - writeFileSync(staticPath, imgData.data); + await writeFileAsync(staticPath, imgData.data); Notifications.info(`File ${fileName} uploaded to: ${folder}`); return true; @@ -255,7 +256,7 @@ export class MediaHelpers { } try { - unlinkSync(file); + await unlinkAsync(file); MediaHelpers.media = []; return true; @@ -350,14 +351,14 @@ export class MediaHelpers { * Update the metadata of a media file * @param data */ - public static updateMetadata(data: any) { + public static async updateMetadata(data: any) { const { file, filename, page, folder, ...metadata }: { file:string; filename:string; page: number; folder: string | null; metadata: any; } = data; const mediaLib = MediaLibrary.getInstance(); mediaLib.set(file, metadata); // Check if filename needs to be updated - mediaLib.updateFilename(file, filename); + await mediaLib.updateFilename(file, filename); } /** diff --git a/src/helpers/MediaLibrary.ts b/src/helpers/MediaLibrary.ts index 430966df..5edc0ff4 100644 --- a/src/helpers/MediaLibrary.ts +++ b/src/helpers/MediaLibrary.ts @@ -3,10 +3,10 @@ import { workspace } from 'vscode'; import { JsonDB } from 'node-json-db/dist/JsonDB'; import { basename, dirname, join, parse } from 'path'; import { Folders, WORKSPACE_PLACEHOLDER } from '../commands/Folders'; -import { existsSync, renameSync } from 'fs'; import { Notifications } from './Notifications'; import { parseWinPath } from './parseWinPath'; import { LocalStore } from '../constants'; +import { existsAsync, renameAsync } from '../utils'; interface MediaRecord { description: string; @@ -75,7 +75,7 @@ export class MediaLibrary { } } - public updateFilename(filePath: string, filename: string) { + public async updateFilename(filePath: string, filename: string) { const name = basename(filePath); if (name !== filename && filename) { @@ -84,10 +84,10 @@ export class MediaLibrary { const newFileInfo = parse(filename); const newPath = join(dirname(filePath), `${newFileInfo.name}${oldFileInfo.ext}`); - if (existsSync(newPath)) { + if (await existsAsync(newPath)) { Notifications.warning(`The name "${filename}" already exists at the file location.`); } else { - renameSync(filePath, newPath); + await renameAsync(filePath, newPath); this.rename(filePath, newPath); MediaHelpers.resetMedia(); } diff --git a/src/helpers/SettingsHelper.ts b/src/helpers/SettingsHelper.ts index b566345c..20aa8dee 100644 --- a/src/helpers/SettingsHelper.ts +++ b/src/helpers/SettingsHelper.ts @@ -7,11 +7,12 @@ import { ContentFolder, ContentType, CustomPlaceholder, CustomTaxonomy, DataFile import { SETTING_TAXONOMY_TAGS, SETTING_TAXONOMY_CATEGORIES, CONFIG_KEY, CONTEXT, ExtensionState, SETTING_TAXONOMY_CUSTOM, TelemetryEvent, COMMAND_NAME, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_PAGE_FOLDERS, SETTING_CONTENT_SNIPPETS, SETTING_CONTENT_PLACEHOLDERS, SETTING_CUSTOM_SCRIPTS, SETTING_DATA_FILES, SETTING_DATA_TYPES, SETTING_DATA_FOLDERS } from '../constants'; import { Folders } from '../commands/Folders'; import { join, basename, dirname, parse } from 'path'; -import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { existsSync } from 'fs'; import { Extension } from './Extension'; import { debounceCallback } from './DebounceCallback'; import { Logger } from './Logger'; import * as jsoncParser from 'jsonc-parser'; +import { existsAsync, readFileAsync, writeFileAsync } from '../utils'; export class Settings { public static globalFile = "frontmatter.json"; @@ -181,11 +182,11 @@ export class Settings { const fmConfig = Settings.projectConfigPath; if (updateGlobal) { - if (fmConfig && existsSync(fmConfig)) { - const localConfig = readFileSync(fmConfig, 'utf8'); + if (fmConfig && await existsAsync(fmConfig)) { + const localConfig = await readFileAsync(fmConfig, 'utf8'); Settings.globalConfig = jsoncParser.parse(localConfig); Settings.globalConfig[`${CONFIG_KEY}.${name}`] = value; - writeFileSync(fmConfig, JSON.stringify(Settings.globalConfig, null, 2), 'utf8'); + await writeFileAsync(fmConfig, JSON.stringify(Settings.globalConfig, null, 2), 'utf8'); const workspaceSettingValue = Settings.hasWorkspaceSettings(name); if (workspaceSettingValue) { @@ -215,24 +216,24 @@ export class Settings { /** * Create team settings */ - public static createTeamSettings() { + public static async createTeamSettings() { const wsFolder = Folders.getWorkspaceFolder(); - this.createGlobalFile(wsFolder); + await this.createGlobalFile(wsFolder); } /** * Create the frontmatter.json file * @param wsFolder */ - public static createGlobalFile(wsFolder: Uri | undefined | null) { + public static async createGlobalFile(wsFolder: Uri | undefined | null) { const initialConfig = { "$schema": `https://${Extension.getInstance().isBetaVersion() ? `beta.` : ``}frontmatter.codes/frontmatter.schema.json` }; if (wsFolder) { const configPath = join(wsFolder.fsPath, Settings.globalFile); - if (!existsSync(configPath)) { - writeFileSync(configPath, JSON.stringify(initialConfig, null, 2), 'utf8'); + if (!(await existsAsync(configPath))) { + await writeFileAsync(configPath, JSON.stringify(initialConfig, null, 2), 'utf8'); } } } @@ -418,8 +419,8 @@ export class Settings { private static async readConfig() { try { const fmConfig = Settings.projectConfigPath; - if (fmConfig && existsSync(fmConfig)) { - const localConfig = readFileSync(fmConfig, 'utf8'); + if (fmConfig && await existsAsync(fmConfig)) { + const localConfig = await readFileAsync(fmConfig, 'utf8'); Settings.globalConfig = jsoncParser.parse(localConfig); commands.executeCommand('setContext', CONTEXT.isEnabled, true); } else { diff --git a/src/helpers/TaxonomyHelper.ts b/src/helpers/TaxonomyHelper.ts index 1327f321..1ffeac24 100644 --- a/src/helpers/TaxonomyHelper.ts +++ b/src/helpers/TaxonomyHelper.ts @@ -4,13 +4,13 @@ import { CustomTaxonomy, TaxonomyType, ContentType as IContentType } from "../mo import { FilesHelper } from "./FilesHelper"; import { ProgressLocation, window } from "vscode"; import { parseWinPath } from "./parseWinPath"; -import { readFileSync, writeFileSync } from "fs"; import { FrontMatterParser } from "../parsers"; import { DumpOptions } from "js-yaml"; import { Settings } from "./SettingsHelper"; import { Notifications } from "./Notifications"; import { ArticleHelper } from './ArticleHelper'; import { ContentType } from './ContentType'; +import { readFileAsync, writeFileAsync } from '../utils'; export class TaxonomyHelper { @@ -186,7 +186,7 @@ export class TaxonomyHelper { for (const file of allFiles) { progress.report({ increment: (++i/progressNr) }); - const mdFile = readFileSync(parseWinPath(file.fsPath), { encoding: "utf8" }); + const mdFile = await readFileAsync(parseWinPath(file.fsPath), { encoding: "utf8" }); if (mdFile) { try { @@ -217,7 +217,7 @@ export class TaxonomyHelper { const spaces = window.activeTextEditor?.options?.tabSize; // Update the file - writeFileSync(parseWinPath(file.fsPath), FrontMatterParser.toFile(article.content, article.data, mdFile, { + await writeFileAsync(parseWinPath(file.fsPath), FrontMatterParser.toFile(article.content, article.data, mdFile, { indent: spaces || 2 } as DumpOptions as any), { encoding: "utf8" }); } @@ -291,7 +291,7 @@ export class TaxonomyHelper { for (const file of allFiles) { progress.report({ increment: (++i/progressNr) }); - const mdFile = readFileSync(parseWinPath(file.fsPath), { encoding: "utf8" }); + const mdFile = await readFileAsync(parseWinPath(file.fsPath), { encoding: "utf8" }); if (mdFile) { try { @@ -324,7 +324,7 @@ export class TaxonomyHelper { const spaces = window.activeTextEditor?.options?.tabSize; // Update the file - writeFileSync(parseWinPath(file.fsPath), FrontMatterParser.toFile(article.content, article.data, mdFile, { + await writeFileAsync(parseWinPath(file.fsPath), FrontMatterParser.toFile(article.content, article.data, mdFile, { indent: spaces || 2 } as DumpOptions as any), { encoding: "utf8" }); } diff --git a/src/listeners/dashboard/DataListener.ts b/src/listeners/dashboard/DataListener.ts index 10530503..fa9e3e32 100644 --- a/src/listeners/dashboard/DataListener.ts +++ b/src/listeners/dashboard/DataListener.ts @@ -4,10 +4,11 @@ import { DashboardMessage } from "../../dashboardWebView/DashboardMessage"; import { BaseListener } from "./BaseListener"; import { DashboardCommand } from '../../dashboardWebView/DashboardCommand'; import { Folders } from '../../commands/Folders'; -import { existsSync, writeFileSync, mkdirSync, readFileSync } from 'fs'; import { dirname } from 'path'; import * as yaml from 'js-yaml'; import { DataFileHelper } from '../../helpers'; +import { existsAsync, readFileAsync, writeFileAsync } from '../../utils'; +import { mkdirAsync } from '../../utils/mkdirAsync'; export class DataListener extends BaseListener { @@ -35,28 +36,28 @@ export class DataListener extends BaseListener { * Process the data update * @param msgData */ - private static processDataUpdate(msgData: any) { + private static async processDataUpdate(msgData: any) { const { file, fileType, entries } = msgData as { file: string, fileType: string, entries: unknown | unknown[] }; const absPath = Folders.getAbsFilePath(file); - if (!existsSync(absPath)) { + if (!await existsAsync(absPath)) { const dirPath = dirname(absPath); - if (!existsSync(dirPath)) { - mkdirSync(dirPath, { recursive: true }); + if (!await existsAsync(dirPath)) { + await mkdirAsync(dirPath, { recursive: true }); } } - const fileContent = readFileSync(absPath, 'utf8'); + const fileContent = await readFileAsync(absPath, 'utf8'); // check if file content ends with newline const newFileContent = fileContent.endsWith('\n'); const insertFinalNewLine = newFileContent || workspace.getConfiguration().get('files.insertFinalNewline'); if (fileType === 'yaml') { const yamlData = yaml.safeDump(entries); - writeFileSync(absPath, insertFinalNewLine ? `${yamlData}\n` : yamlData, 'utf8'); + await writeFileAsync(absPath, insertFinalNewLine ? `${yamlData}\n` : yamlData, 'utf8'); } else { const jsonData = JSON.stringify(entries, null, 2); - writeFileSync(absPath, insertFinalNewLine ? `${jsonData}\n` : jsonData, 'utf8'); + await writeFileAsync(absPath, insertFinalNewLine ? `${jsonData}\n` : jsonData, 'utf8'); } this.processDataFile(msgData); diff --git a/src/listeners/dashboard/MediaListener.ts b/src/listeners/dashboard/MediaListener.ts index cd940b7c..6be6ac55 100644 --- a/src/listeners/dashboard/MediaListener.ts +++ b/src/listeners/dashboard/MediaListener.ts @@ -113,11 +113,11 @@ export class MediaListener extends BaseListener { * Update media metadata * @param data */ - private static update(data: any) { + private static async update(data: any) { try { const { page, folder } = data; - MediaHelpers.updateMetadata(data); + await MediaHelpers.updateMetadata(data); this.sendMediaFiles(page || 0, folder || ""); } catch {} diff --git a/src/listeners/dashboard/PagesListener.ts b/src/listeners/dashboard/PagesListener.ts index 37531d6b..2d167318 100644 --- a/src/listeners/dashboard/PagesListener.ts +++ b/src/listeners/dashboard/PagesListener.ts @@ -1,4 +1,3 @@ -import { unlinkSync } from "fs"; import { basename } from "path"; import { commands, FileSystemWatcher, RelativePattern, TextDocument, Uri, workspace } from "vscode"; import { Dashboard } from "../../commands/Dashboard"; @@ -12,6 +11,7 @@ import { BaseListener } from "./BaseListener"; import { DataListener } from '../panel'; import Fuse from 'fuse.js'; import { PagesParser } from '../../services/PagesParser'; +import { unlinkAsync } from "../../utils"; export class PagesListener extends BaseListener { @@ -106,7 +106,7 @@ export class PagesListener extends BaseListener { Logger.info(`Deleting file: ${path}`) - unlinkSync(path); + await unlinkAsync(path); this.lastPages = this.lastPages.filter(p => p.fmFilePath !== path); this.sendPageData(this.lastPages); @@ -128,7 +128,7 @@ export class PagesListener extends BaseListener { if (pageIdx !== -1) { const stats = await workspace.fs.stat(file); const crntPage = this.lastPages[pageIdx]; - const updatedPage = PagesParser.processPageContent(file.fsPath, stats.mtime, basename(file.fsPath), crntPage.fmFolder); + const updatedPage = await PagesParser.processPageContent(file.fsPath, stats.mtime, basename(file.fsPath), crntPage.fmFolder); if (updatedPage) { this.lastPages[pageIdx] = updatedPage; this.sendPageData(this.lastPages); diff --git a/src/listeners/dashboard/SettingsListener.ts b/src/listeners/dashboard/SettingsListener.ts index e9c7ee9b..ffce8394 100644 --- a/src/listeners/dashboard/SettingsListener.ts +++ b/src/listeners/dashboard/SettingsListener.ts @@ -59,7 +59,7 @@ export class SettingsListener extends BaseListener { * Set the current site-generator or framework + related settings * @param frameworkId */ - public static setFramework(frameworkId: string | null) { + public static async setFramework(frameworkId: string | null) { Settings.update(SETTING_FRAMEWORK_ID, frameworkId, true); if (frameworkId) { @@ -68,7 +68,7 @@ export class SettingsListener extends BaseListener { if (framework) { Settings.update(SETTING_CONTENT_STATIC_FOLDER, framework.static, true); - FrameworkDetector.checkDefaultSettings(framework); + await FrameworkDetector.checkDefaultSettings(framework); } else { Settings.update(SETTING_CONTENT_STATIC_FOLDER, "", true); } diff --git a/src/services/PagesParser.ts b/src/services/PagesParser.ts index 24bb3b8a..df4e9dfa 100644 --- a/src/services/PagesParser.ts +++ b/src/services/PagesParser.ts @@ -1,5 +1,4 @@ import { parseWinPath } from './../helpers/parseWinPath'; -import { existsSync } from "fs"; import { dirname, join } from "path"; import { StatusBarAlignment, Uri, window } from "vscode"; import { Dashboard } from "../commands/Dashboard"; @@ -7,6 +6,7 @@ import { Folders } from "../commands/Folders"; import { DefaultFields, DEFAULT_CONTENT_TYPE_NAME, ExtensionState, SETTING_SEO_DESCRIPTION_FIELD } from "../constants"; import { Page } from "../dashboardWebView/models"; import { ArticleHelper, ContentType, DateHelper, Extension, isValidFile, Logger, Notifications, Settings } from "../helpers"; +import { existsAsync } from '../utils'; export class PagesParser { @@ -72,7 +72,7 @@ export class PagesParser { let page = await PagesParser.getCachedPage(file.filePath, file.mtime); if (!page) { - page = this.processPageContent(file.filePath, file.mtime, file.fileName, folder.title); + page = await this.processPageContent(file.filePath, file.mtime, file.fileName, folder.title); } if (page && !pages.find(p => p.fmFilePath === page?.fmFilePath)) { @@ -123,8 +123,8 @@ export class PagesParser { * @param folderTitle * @returns */ - public static processPageContent(filePath: string, fileMtime: number, fileName: string, folderTitle: string): Page | undefined { - const article = ArticleHelper.getFrontMatterByPath(filePath); + public static async processPageContent(filePath: string, fileMtime: number, fileName: string, folderTitle: string): Promise { + const article = await ArticleHelper.getFrontMatterByPath(filePath); if (article?.data.title) { const wsFolder = Folders.getWorkspaceFolder(); @@ -240,9 +240,9 @@ export class PagesParser { const contentFolderPath = join(dirname(filePath), fieldValue); let previewUri = null; - if (existsSync(staticPath)) { + if (await existsAsync(staticPath)) { previewUri = Uri.file(staticPath); - } else if (existsSync(contentFolderPath)) { + } else if (await existsAsync(contentFolderPath)) { previewUri = Uri.file(contentFolderPath); } diff --git a/src/utils/copyFileAsync.ts b/src/utils/copyFileAsync.ts new file mode 100644 index 00000000..e5d1924e --- /dev/null +++ b/src/utils/copyFileAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { copyFile as copyFileCb } from "fs"; + +export const copyFileAsync = promisify(copyFileCb); \ No newline at end of file diff --git a/src/utils/existsAsync.ts b/src/utils/existsAsync.ts new file mode 100644 index 00000000..c4f793d8 --- /dev/null +++ b/src/utils/existsAsync.ts @@ -0,0 +1,6 @@ +import { stat } from "fs"; +import { promisify } from "util"; + +export const existsAsync = async (path: string) => { + return promisify(stat)(path).then(() => true).catch(() => false); +}; \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..c23da193 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,8 @@ +export * from './copyFileAsync'; +export * from './existsAsync'; +export * from './mkdirAsync'; +export * from './readFileAsync'; +export * from './readdirAsync'; +export * from './renameAsync'; +export * from './unlinkAsync'; +export * from './writeFileAsync'; diff --git a/src/utils/mkdirAsync.ts b/src/utils/mkdirAsync.ts new file mode 100644 index 00000000..6c52bbcf --- /dev/null +++ b/src/utils/mkdirAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { mkdir as mkdirCb } from "fs"; + +export const mkdirAsync = promisify(mkdirCb); \ No newline at end of file diff --git a/src/utils/readFileAsync.ts b/src/utils/readFileAsync.ts new file mode 100644 index 00000000..3f4ba8cb --- /dev/null +++ b/src/utils/readFileAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { readFile as readFileCb } from "fs"; + +export const readFileAsync = promisify(readFileCb); \ No newline at end of file diff --git a/src/utils/readdirAsync.ts b/src/utils/readdirAsync.ts new file mode 100644 index 00000000..82fd807c --- /dev/null +++ b/src/utils/readdirAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { readdir as readdirCb } from "fs"; + +export const readdirAsync = promisify(readdirCb); \ No newline at end of file diff --git a/src/utils/renameAsync.ts b/src/utils/renameAsync.ts new file mode 100644 index 00000000..ed28c3a1 --- /dev/null +++ b/src/utils/renameAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { rename as renameCb } from "fs"; + +export const renameAsync = promisify(renameCb); \ No newline at end of file diff --git a/src/utils/unlinkAsync.ts b/src/utils/unlinkAsync.ts new file mode 100644 index 00000000..46d8d917 --- /dev/null +++ b/src/utils/unlinkAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { unlink as unlinkCb } from "fs"; + +export const unlinkAsync = promisify(unlinkCb); \ No newline at end of file diff --git a/src/utils/writeFileAsync.ts b/src/utils/writeFileAsync.ts new file mode 100644 index 00000000..6250fdd3 --- /dev/null +++ b/src/utils/writeFileAsync.ts @@ -0,0 +1,4 @@ +import { promisify } from "util"; +import { writeFile as writeFileCb } from "fs"; + +export const writeFileAsync = promisify(writeFileCb); \ No newline at end of file