Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Creating VS Code Extensions for JSON Formatting
Visual Studio Code is a powerful and popular editor, extensible in many ways. One common task developers need assistance with is formatting structured data like JSON. While VS Code includes a built-in JSON formatter, you might encounter scenarios where you need custom formatting rules, integration with specific tools, or different default settings. This guide will walk you through the process of building your own VS Code extension specifically for formatting JSON documents.
Understanding VS Code Extensions
A VS Code extension is essentially a Node.js application that runs in a separate process, called the Extension Host. It communicates with the main VS Code window (the Renderer process) via a well-defined API. The core of any extension is:
package.json
: This is the extension manifest. It declares its name, version, description, dependencies, and most importantly, its "contribution points" - how the extension integrates with VS Code features (like commands, keybindings, settings, language support, and formatters).extension.ts
(orextension.js
): This is the main code file containing the extension's logic. It exports anactivate
function which is called when the extension is enabled and ready to run, and an optionaldeactivate
function called when the extension is disabled.
JSON Formatting in VS Code
VS Code allows extensions to register as formatters for specific languages. When a user triggers the format action (e.g., Save with format, Shift+Alt+F, or the "Format Document" command), VS Code asks registered formatters for the active document's language if they can handle the request. If multiple formatters exist for the same language, the user can choose or configure a default.
To provide formatting, your extension needs to implement the vscode.DocumentFormattingEditProvider
interface (or RangeFormattingEditProvider
for formatting selections). The core method you'll implement is provideDocumentFormattingEdits
(or provideDocumentRangeFormattingEdits
). This method receives the text document and returns an array of vscode.TextEdit
objects, which describe the changes to be applied to the document (insertions, deletions, or replacements of text).
Setting up Your Development Environment
The easiest way to start is by using the Yeoman extension generator for VS Code:
- Ensure you have Node.js and npm installed.
- Install Yeoman and the VS Code Extension generator globally:
npm install -g yo generator-code
- Run the generator:
yo code
- Choose "New Extension (TypeScript)" or "New Extension (JavaScript)". TypeScript is recommended for better type safety.
- Fill in the project details (name, identifier, description).
- Open the generated folder in VS Code.
The generator creates a basic project structure, including `package.json`, `src/extension.ts`, and `tsconfig.json` (if using TypeScript).
Declaring the Formatter in `package.json`
Your extension needs to tell VS Code that it provides formatting capabilities for JSON files. You do this in the package.json
file under the contributes
section. Add a formatters
entry like this:
`package.json` (Snippet)
{ "name": "my-json-formatter", "displayName": "My JSON Formatter", "description": "A custom JSON formatter extension", "version": "0.0.1", "engines": { "vscode": "^1.80.0" }, "categories": [ "Formatters" ], "contributes": { "formatters": [ { "language": "json", "displayName": "My Custom JSON Formatter" }, { "language": "jsonc", "displayName": "My Custom JSON Formatter" } ], // ... other contributions like commands, settings, etc. }, "main": "./out/extension.js", // Entry point for JS (if using TS, compile creates out/extension.js) "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "lint": "eslint src --ext ts", "test": "jest" }, "devDependencies": { // ... dev dependencies } }
The language
property specifies the language identifier (json
and jsonc
for JSON with comments). The displayName
is what appears in the "Format Document With..." menu.
Implementing the Formatter Logic (`extension.ts`)
Now, write the code that performs the formatting in your extension.ts
file. You'll need to:
- Import the
vscode
module. - Define a class or object that implements
vscode.DocumentFormattingEditProvider
. - Implement the
provideDocumentFormattingEdits
method. - Inside
activate
, register your provider usingvscode.languages.registerDocumentFormattingEditProvider
.
`src/extension.ts` (Basic Structure)
import * as vscode from 'vscode'; // Implement the formatting provider class JsonFormatter implements vscode.DocumentFormattingEditProvider { // This method is called when the document is formatted provideDocumentFormattingEdits( document: vscode.TextDocument, options: vscode.FormattingOptions, // Contains info like indentation (spaces or tabs, size) token: vscode.CancellationToken ): vscode.ProviderResult<vscode.TextEdit[]> { const text = document.getText(); let formattedText: string; try { // --- Formatting Logic Goes Here --- // A simple example: parse and stringify to re-indent const parsed = JSON.parse(text); // Use options.tabSize and options.insertSpaces for indentation const indent = options.insertSpaces ? ' '.repeat(options.tabSize) : '\t'; formattedText = JSON.stringify(parsed, null, indent); // --- End Formatting Logic --- } catch (e: any) { // Handle parsing errors gracefully console.error("JSON formatting error:", e.message); vscode.window.showErrorMessage(`Failed to format JSON: ${e.message}`); return []; // Return empty array if formatting fails } // Create a TextEdit to replace the entire document content with the formatted text const fullRange = new vscode.Range( document.positionAt(0), document.positionAt(text.length) ); return [vscode.TextEdit.replace(fullRange, formattedText)]; } } // This method is called when your extension is activated export function activate(context: vscode.ExtensionContext) { console.log('Congratulations, "my-json-formatter" is now active!'); // Create an instance of your formatter const formatter = new JsonFormatter(); // Register the formatter for JSON and JSONC languages context.subscriptions.push( vscode.languages.registerDocumentFormattingEditProvider('json', formatter) ); context.subscriptions.push( vscode.languages.registerDocumentFormattingEditProvider('jsonc', formatter) ); // You can also register range formatters if needed // context.subscriptions.push( // vscode.languages.registerDocumentRangeFormattingEditProvider('json', formatter) // ); } // This method is called when your extension is deactivated export function deactivate() { console.log('"my-json-formatter" is now deactivated!'); }
In the example above, the formatting logic is very basic: it uses JSON.parse
and JSON.stringify
. For a real-world extension, you would likely use a more robust library like Prettier, js-beautify, or a custom parser/formatter to handle specific requirements not covered by the built-in JSON.stringify
(like sorting keys, specific line breaks, etc.).
The vscode.TextEdit.replace(fullRange, formattedText)
part is crucial. It tells VS Code to replace the entire content of the document (from start to end) with the new formattedText
.
Testing and Debugging
VS Code provides an "Extension Host Development" window to test your extension.
- Open your extension project folder in VS Code.
- Go to the "Run and Debug" view (Ctrl+Shift+D or Cmd+Shift+D).
- Select the "Run Extension" launch configuration (usually created by the generator).
- Click the green play button.
This will open a new VS Code window (the Extension Host). In this new window:
- Open a JSON file.
- The
console.log
messages from your extension will appear in the "Debug Console" back in your original VS Code window. - Trigger the format action (e.g., right-click in the editor and select "Format Document", or use the keybinding). If multiple formatters are registered, you might be prompted to choose or can select "Format Document With..." to pick yours.
- Set breakpoints in your
extension.ts
code in the original window to step through the logic when formatting is triggered.
Adding Configuration
A good formatter often provides configuration options (e.g., indentation style, quote style, sorting keys). You can add settings to your extension by defining them in package.json
under the contributes.configuration
section.
`package.json` (Adding Configuration)
{ // ... existing package.json content "contributes": { "formatters": [ // ... formatter declaration ], "configuration": { "title": "My JSON Formatter Configuration", "properties": { "myJsonFormatter.spaceIndentation": { "type": "number", "default": 2, "description": "Number of spaces for indentation. Set to 0 for tabs." }, "myJsonFormatter.sortKeys": { "type": "boolean", "default": false, "description": "Sort object keys alphabetically." } } } }, // ... rest of package.json }
Then, in your extension.ts
, you can read these settings using vscode.workspace.getConfiguration('myJsonFormatter')
.
`src/extension.ts` (Reading Configuration)
// Inside JsonFormatter class or provideDocumentFormattingEdits method: const config = vscode.workspace.getConfiguration('myJsonFormatter'); const spaceIndentation = config.get<number>('spaceIndentation', 2); // Get setting, default to 2 const sortKeys = config.get<boolean>('sortKeys', false); // Get setting, default to false // Use spaceIndentation and sortKeys in your formatting logic let indent = ' '.repeat(spaceIndentation); if (spaceIndentation <= 0) { indent = '\t'; // Use tab if 0 or less spaces configured } // If sortKeys is true, you'd need a custom stringify function or library // JSON.stringify doesn't sort keys by default. // const parsed = JSON.parse(text); // ... your logic here potentially sorting keys before stringify ... // const formattedText = JSON.stringify(parsed, null, indent);
Publishing Your Extension
Once your extension is ready, you can publish it to the VS Code Marketplace using the vsce
tool.
- Install
vsce
globally:npm install -g vsce
- Get a Personal Access Token (PAT) from Azure DevOps with permissions to manage VS Code extensions.
- Create a publisher:
(You'll be prompted for your PAT).vsce create-publisher <publisher-name>
- Package your extension from your project root:
This creates avsce package
.vsix
file. - Publish the extension:
Or to publish a specific vsix file:vsce publish
(Replacevsce publish -p <your-pat>
<your-pat>
with your actual token or set theVSCE_PAT
environment variable).
Best Practices and Considerations
- Performance: For very large JSON files, standard
JSON.parse
andJSON.stringify
might be slow. Consider streaming parsers/formatters if performance is critical. Formatting should be fast enough not to block the UI. - Error Handling: Robustly handle invalid JSON input. Your formatter should catch parsing errors and ideally report them to the user without crashing the extension host. Returning an empty array of edits on error is a common pattern.
- Configuration: Provide clear and intuitive settings. Use the configuration contribution point in
package.json
and document them in your extension's README. - Dependencies: If using external formatting libraries, be mindful of their size and potential compatibility issues.
- Localization: If you plan for international users, consider using VS Code's localization features.
- README: Write a clear README.md file explaining what your extension does, how to install and use it, configuration options, and any known issues.
Further Exploration
The VS Code API is extensive. You could enhance your formatter extension by adding:
- Commands to format specific selections or apply different formatting styles.
- Code Actions to fix minor JSON issues before formatting.
- Integration with task runners or build systems.
- Status bar items to show formatter status.
Exploring the VS Code Extension API documentation and looking at the source code of other formatter extensions (like Prettier or specific language formatters) on GitHub can provide deeper insights and examples.
Conclusion
Building a VS Code extension for JSON formatting is a practical way to learn about VS Code extensibility and provide a useful tool for yourself and the community. By understanding the core concepts of contribution points and API providers, you can tailor the editor's behavior to your specific JSON formatting needs, moving beyond the default capabilities. Happy coding and formatting!
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool