Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(prettier): Allow a Prettier instance to be optional #81

Merged
merged 5 commits into from Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@ node_modules
*.js
*.map
*.tgz
.DS_Store
johnsoncodehk marked this conversation as resolved.
Show resolved Hide resolved
125 changes: 66 additions & 59 deletions packages/prettier/index.ts
Expand Up @@ -44,6 +44,10 @@ export function create(
*/
prettier?: typeof import('prettier') | undefined;
getPrettier?: (serviceEnv: ServiceEnvironment) => typeof import('prettier') | undefined,
/**
* If true, the plugin will not throw an error if it can't load Prettier either through the `prettier`, or `getPrettier` properties or through a normal `import('prettier')`.
*/
allowImportError?: boolean;
} = {},
getPrettierConfig = async (filePath: string, prettier: typeof import('prettier'), config?: ResolveConfigOptions) => {
return await prettier.resolveConfig(filePath, config) ?? {};
Expand All @@ -52,82 +56,85 @@ export function create(
return {
name: 'prettier',
create(context): ServicePluginInstance {
const languages = options.languages ?? ['html', 'css', 'scss', 'typescript', 'javascript'];

let prettier: typeof import('prettier');
try {
prettier = options.prettier
?? options.getPrettier?.(context.env)
?? require('prettier');
} catch (e) {
throw new Error("Could not load Prettier: " + e);
}
const languages = options.languages ?? ['html', 'css', 'scss', 'typescript', 'javascript'];

johnsoncodehk marked this conversation as resolved.
Show resolved Hide resolved
return {
async provideDocumentFormattingEdits(document, _, formatOptions) {
if (!languages.includes(document.languageId)) {
return;
}
return {
async provideDocumentFormattingEdits(document, _, formatOptions) {
if (!prettier) return;
if (!languages.includes(document.languageId)) {
return;
}

const filePath = URI.parse(document.uri).fsPath;
const fileInfo = await prettier.getFileInfo(filePath, { ignorePath: '.prettierignore', resolveConfig: false });

const filePath = URI.parse(document.uri).fsPath;
const fileInfo = await prettier.getFileInfo(filePath, { ignorePath: '.prettierignore', resolveConfig: false });
if (fileInfo.ignored) {
return;
}

if (fileInfo.ignored) {
return;
}
const filePrettierOptions = await getPrettierConfig(
filePath,
prettier,
options.resolveConfigOptions
);

const filePrettierOptions = await getPrettierConfig(
filePath,
prettier,
options.resolveConfigOptions
);
const editorPrettierOptions = await context.env.getConfiguration?.('prettier', document.uri);
const ideFormattingOptions =
formatOptions !== undefined && options.useIdeOptionsFallback // We need to check for options existing here because some editors might not have it
? {
tabWidth: formatOptions.tabSize,
useTabs: !formatOptions.insertSpaces,
}
: {};

const editorPrettierOptions = await context.env.getConfiguration?.('prettier', document.uri);
const ideFormattingOptions =
formatOptions !== undefined && options.useIdeOptionsFallback // We need to check for options existing here because some editors might not have it
? {
tabWidth: formatOptions.tabSize,
useTabs: !formatOptions.insertSpaces,
}
: {};
// Return a config with the following cascade:
// - Prettier config file should always win if it exists, if it doesn't:
// - Prettier config from the VS Code extension is used, if it doesn't exist:
// - Use the editor's basic configuration settings
const prettierOptions = returnObjectIfHasKeys(filePrettierOptions) || returnObjectIfHasKeys(editorPrettierOptions) || ideFormattingOptions;

// Return a config with the following cascade:
// - Prettier config file should always win if it exists, if it doesn't:
// - Prettier config from the VS Code extension is used, if it doesn't exist:
// - Use the editor's basic configuration settings
const prettierOptions = returnObjectIfHasKeys(filePrettierOptions) || returnObjectIfHasKeys(editorPrettierOptions) || ideFormattingOptions;
const currentPrettierConfig: Options = {
...(options.additionalOptions
? await options.additionalOptions(prettierOptions)
: prettierOptions),
filepath: filePath,
};

const currentPrettierConfig: Options = {
...(options.additionalOptions
? await options.additionalOptions(prettierOptions)
: prettierOptions),
filepath: filePath,
};
if (!options.ignoreIdeOptions) {
currentPrettierConfig.useTabs = !formatOptions.insertSpaces;
currentPrettierConfig.tabWidth = formatOptions.tabSize;
}

if (!options.ignoreIdeOptions) {
currentPrettierConfig.useTabs = !formatOptions.insertSpaces;
currentPrettierConfig.tabWidth = formatOptions.tabSize;
}
const fullText = document.getText();
let oldText = fullText;

const fullText = document.getText();
let oldText = fullText;
const isHTML = document.languageId === "html";
if (isHTML && options.html?.breakContentsFromTags) {
oldText = oldText
.replace(/(<[a-z][^>]*>)([^ \n])/gi, "$1 $2")
.replace(/([^ \n])(<\/[a-z][a-z0-9\t\n\r -]*>)/gi, "$1 $2");
}

const isHTML = document.languageId === "html";
if (isHTML && options.html?.breakContentsFromTags) {
oldText = oldText
.replace(/(<[a-z][^>]*>)([^ \n])/gi, "$1 $2")
.replace(/([^ \n])(<\/[a-z][a-z0-9\t\n\r -]*>)/gi, "$1 $2");
}
return [{
newText: await prettier.format(oldText, currentPrettierConfig),
range: {
start: document.positionAt(0),
end: document.positionAt(fullText.length),
},
}];
},
};
} catch (e) {
if (!options.allowImportError) throw new Error("Could not load Prettier: " + e);
}

return [{
newText: await prettier.format(oldText, currentPrettierConfig),
range: {
start: document.positionAt(0),
end: document.positionAt(fullText.length),
},
}];
},
};
return {};
},
};
}
Expand Down