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,