diff --git a/CHANGELOG.md b/CHANGELOG.md index 98bc8fc..3446dbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.3] + +- Add support for relative and workspace-relative config paths + ## [1.0.2] - Update logo to follow VSCode guidelines diff --git a/README.md b/README.md index 2e6f90f..5ebda82 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,22 @@ To set this formatter as the default formatter for Java files, add the following This extension contributes the following settings: - `prettier-plugin-java-vscode.enabled`: Enable/disable the plugin. -- `prettier-plugin-java-vscode.prettierConfigPath`: Provide an absolution path to your prettier configuration file. +- `prettier-plugin-java-vscode.prettierConfigPath`: Provide an absolute, relative, or workspace-relative path to a Prettier config file. If not provided or missing, the extension will attempt to resolve the config file from the document file name. + +Examples of valid config paths include: + +- An absolute path: `/home/user/my-project/.prettierrc` +- A relative path `.prettierrc` +- A workspace-relative path `${workspaceFolder}/.prettierrc` + +The `Output` channel will display information about how this config file path is resolved. ## Release Notes +### 1.0.3 + +- Add support for relative and workspace-relative config paths + ### 1.0.2 - Update logo to follow VSCode guidelines diff --git a/package.json b/package.json index 6386c50..a3f9223 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "prettier-plugin-java-vscode", "displayName": "Prettier Java Plugin", "description": "Format Java files with Prettier using prettier-plugin-java.", - "version": "1.0.2", + "version": "1.0.3", "publisher": "RudraPatel", "license": "MIT", "scripts": { @@ -47,9 +47,12 @@ "title": "Prettier Java Plugin", "properties": { "prettier-plugin-java-vscode.prettierConfigPath": { - "type": ["string", "null"], + "type": [ + "string", + "null" + ], "default": null, - "description": "Provide a absolution path to your prettier configuration file." + "description": "Provide an absolute, relative, or workspace-relative path to a Prettier config file. If not provided or missing, the extension will attempt to resolve the config file from the document file name." }, "prettier-plugin-java-vscode.enabled": { "type": "boolean", diff --git a/src/extension.ts b/src/extension.ts index 14c2144..d8b6674 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,7 +10,7 @@ import { TextEdit, } from "vscode"; -import { log } from "./logger"; +import { flushLogs, log } from "./logger"; import { checkIfEnabled, getPrettierOptions } from "./utils"; async function formatJavaDocument( @@ -22,6 +22,7 @@ async function formatJavaDocument( if (!isEnabled) { log("Prettier Plugin Java VSCode is disabled\n"); + void flushLogs(); return null; } @@ -52,11 +53,14 @@ async function formatJavaDocument( log(`Formatted ${document.fileName} in ${elapsedTime}ms\n`); + void flushLogs(); + return [TextEdit.replace(entireDocumentRange, formattedText)]; } export function activate(context: ExtensionContext) { log("Prettier Plugin Java VSCode activated\n"); + void flushLogs(); const disposable = languages.registerDocumentFormattingEditProvider("java", { provideDocumentFormattingEdits: formatJavaDocument, diff --git a/src/logger.ts b/src/logger.ts index 4649b18..917b275 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -7,8 +7,22 @@ function getFormattedTime(): string { return new Date().toLocaleTimeString("en-US"); } +const logs: string[] = []; + export function log(message: string | null): void { const time = getFormattedTime(); - outputChannel.appendLine(`[${time}] ${message}`); + logs.push(`[${time}] ${message}`); +} + +export async function flushLogs(): Promise { + // asynchronously flush the logs to the output channel + // This is asynchronous to not slow down the formatting process + for (const log of logs) { + outputChannel.appendLine(log); + } + + logs.length = 0; + + return Promise.resolve(); } diff --git a/src/utils.ts b/src/utils.ts index a52989f..8972fb0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,5 @@ import { constants, promises } from "fs"; +import path from "path"; import { Options, resolveConfig } from "prettier"; import { TextDocument, workspace } from "vscode"; @@ -21,45 +22,71 @@ async function doesFileExist(filePath: string): Promise { } } -async function getPretterConfigPath(document: TextDocument): Promise { +function transformUserProvidedConfigPath(configPath: string): string { + /** + * Prettier wants an absolute path to a config file + * This function supports the following scenarios: + * 1. The user wants to inject their workspace folder into the config path + * 2. The user provides a relative path which will attempt to be coerced into an absolute path + */ + const workspaceFolder = workspace.workspaceFolders?.[0]?.uri.fsPath; + + if (workspaceFolder && configPath.includes("${workspaceFolder}")) { + return configPath.replace("${workspaceFolder}", workspaceFolder); + } + + if (workspaceFolder && !path.isAbsolute(configPath)) { + return path.join(workspaceFolder, configPath); + } + + return configPath; +} + +async function getPrettierConfigPath(document: TextDocument): Promise { const userProvidedConfigPath = workspace .getConfiguration("prettier-plugin-java-vscode") .get("prettierConfigPath"); - if (userProvidedConfigPath) { - const fileExists = await doesFileExist(userProvidedConfigPath); + if (!userProvidedConfigPath) { + log( + `No specified Prettier config file. Prettier will attempt to resolve the config file from the document file name (${document.fileName})`, + ); - if (!fileExists) { - log( - `Specified Prettier config file (${userProvidedConfigPath}) does not exist`, - ); - log( - `Prettier will attempt to resolve the config file from the document file name (${document.fileName})`, - ); + return document.fileName; + } + + const transformedConfigPath = transformUserProvidedConfigPath( + userProvidedConfigPath, + ); - return document.fileName; - } + if (userProvidedConfigPath !== transformedConfigPath) { + log( + `Transformed provided config path '${userProvidedConfigPath}' into '${transformedConfigPath}'`, + ); + } + + const fileExists = await doesFileExist(transformedConfigPath); - log(`Using prettier config path: ${userProvidedConfigPath}`); + if (!fileExists) { + log( + `Specified Prettier config file (${transformedConfigPath}) does not exist. Prettier will attempt to resolve the config file from the document file name (${document.fileName})`, + ); - return userProvidedConfigPath; + return document.fileName; } - log("No specified Prettier config file"); - log( - `Prettier will attempt to resolve the config file from the document file name (${document.fileName})`, - ); + log(`Using prettier config path: ${transformedConfigPath}`); - return document.fileName; + return transformedConfigPath; } export async function getPrettierOptions( document: TextDocument, ): Promise { - const prettierConfigPath = await getPretterConfigPath(document); + const prettierConfigPath = await getPrettierConfigPath(document); try { - return resolveConfig(prettierConfigPath, { editorconfig: true }); + return await resolveConfig(prettierConfigPath, { editorconfig: true }); } catch (error) { log(`Error parsing Prettier config: ${error}`); return null;