diff --git a/.changeset/old-forks-grin.md b/.changeset/old-forks-grin.md
new file mode 100644
index 000000000..3dfa54497
--- /dev/null
+++ b/.changeset/old-forks-grin.md
@@ -0,0 +1,5 @@
+---
+'theme-check-vscode': minor
+---
+
+Respect .prettierignore when formatting local VSCode files
diff --git a/packages/vscode-extension/src/node/formatter.spec.ts b/packages/vscode-extension/src/node/formatter.spec.ts
new file mode 100644
index 000000000..a8282814e
--- /dev/null
+++ b/packages/vscode-extension/src/node/formatter.spec.ts
@@ -0,0 +1,74 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import type * as vscode from 'vscode';
+import * as prettier from 'prettier';
+import { vscodePrettierFormat, nodePrettierFormat } from './formatter';
+
+vi.mock('prettier', () => ({
+ format: vi.fn(),
+ getFileInfo: vi.fn(),
+ resolveConfig: vi.fn(),
+}));
+
+vi.mock('vscode', () => ({
+ workspace: {
+ getWorkspaceFolder: vi.fn(() => ({
+ uri: { fsPath: '/workspace' },
+ })),
+ },
+}));
+
+describe('formatter', () => {
+ const localFile = {
+ uri: {
+ scheme: 'file',
+ fsPath: '/snippets/button.liquid',
+ },
+ getText: vi.fn(() => '
{{ product.title }}
'),
+ } as unknown as vscode.TextDocument;
+
+ const remoteFile = {
+ ...localFile,
+ uri: { ...localFile.uri, scheme: 'vscode-remote' },
+ } as vscode.TextDocument;
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('vscodePrettierFormat', () => {
+ it('should format remote files without config options', async () => {
+ await vscodePrettierFormat(remoteFile);
+
+ expect(prettier.getFileInfo).not.toHaveBeenCalled();
+ expect(prettier.resolveConfig).not.toHaveBeenCalled();
+ expect(prettier.format).toHaveBeenCalledWith('{{ product.title }}
', {
+ parser: 'liquid-html',
+ plugins: [expect.anything()],
+ });
+ });
+
+ it('should format local files with config options', async () => {
+ await vscodePrettierFormat(localFile);
+
+ expect(prettier.getFileInfo).toHaveBeenCalled();
+ expect(prettier.resolveConfig).toHaveBeenCalled();
+ expect(prettier.format).toHaveBeenCalledWith('{{ product.title }}
', {
+ parser: 'liquid-html',
+ plugins: [expect.anything()],
+ });
+ });
+
+ it('should not format ignored local files', async () => {
+ vi.mocked(prettier.getFileInfo).mockResolvedValue({
+ ignored: true,
+ } as prettier.FileInfoResult);
+
+ const result = await nodePrettierFormat(localFile);
+
+ expect(prettier.getFileInfo).toHaveBeenCalled();
+ expect(prettier.resolveConfig).not.toHaveBeenCalled();
+ expect(prettier.format).not.toHaveBeenCalled();
+ expect(result).toBe('{{ product.title }}
');
+ });
+ });
+});
diff --git a/packages/vscode-extension/src/node/formatter.ts b/packages/vscode-extension/src/node/formatter.ts
index d8a8f1e52..b1685e011 100644
--- a/packages/vscode-extension/src/node/formatter.ts
+++ b/packages/vscode-extension/src/node/formatter.ts
@@ -1,3 +1,5 @@
+import path from 'node:path';
+import { workspace } from 'vscode';
import LiquidPrettierPlugin from '@shopify/prettier-plugin-liquid';
import * as prettier from 'prettier';
import { Format } from '../common/formatter';
@@ -18,6 +20,18 @@ export const vscodePrettierFormat: Format = async (textDocument) => {
export const nodePrettierFormat: Format = async (textDocument) => {
const text = textDocument.getText();
+
+ const workspaceFolder = workspace.getWorkspaceFolder(textDocument.uri);
+ const fileInfo =
+ workspaceFolder &&
+ (await prettier.getFileInfo(textDocument.uri.fsPath, {
+ ignorePath: path.join(workspaceFolder.uri.fsPath, '.prettierignore'),
+ }));
+
+ if (fileInfo?.ignored) {
+ return text;
+ }
+
const options = await prettier.resolveConfig(textDocument.uri.fsPath, { useCache: false });
return prettier.format(text, {
...options,