Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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",
Expand Down
6 changes: 5 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -22,6 +22,7 @@ async function formatJavaDocument(

if (!isEnabled) {
log("Prettier Plugin Java VSCode is disabled\n");
void flushLogs();
return null;
}

Expand Down Expand Up @@ -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,
Expand Down
16 changes: 15 additions & 1 deletion src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
// 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();
}
69 changes: 48 additions & 21 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { constants, promises } from "fs";
import path from "path";
import { Options, resolveConfig } from "prettier";
import { TextDocument, workspace } from "vscode";

Expand All @@ -21,45 +22,71 @@ async function doesFileExist(filePath: string): Promise<boolean> {
}
}

async function getPretterConfigPath(document: TextDocument): Promise<string> {
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<string> {
const userProvidedConfigPath = workspace
.getConfiguration("prettier-plugin-java-vscode")
.get<string | null>("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<Options | null> {
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;
Expand Down