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 (or extension.js): This is the main code file containing the extension's logic. It exports an activate function which is called when the extension is enabled and ready to run, and an optional deactivate 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:

  1. Ensure you have Node.js and npm installed.
  2. Install Yeoman and the VS Code Extension generator globally:
    npm install -g yo generator-code
  3. Run the generator:
    yo code
  4. Choose "New Extension (TypeScript)" or "New Extension (JavaScript)". TypeScript is recommended for better type safety.
  5. Fill in the project details (name, identifier, description).
  6. 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:

  1. Import the vscode module.
  2. Define a class or object that implements vscode.DocumentFormattingEditProvider.
  3. Implement the provideDocumentFormattingEdits method.
  4. Inside activate, register your provider using vscode.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.

  1. Open your extension project folder in VS Code.
  2. Go to the "Run and Debug" view (Ctrl+Shift+D or Cmd+Shift+D).
  3. Select the "Run Extension" launch configuration (usually created by the generator).
  4. 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.

  1. Install vsce globally:
    npm install -g vsce
  2. Get a Personal Access Token (PAT) from Azure DevOps with permissions to manage VS Code extensions.
  3. Create a publisher:
    vsce create-publisher <publisher-name>
    (You'll be prompted for your PAT).
  4. Package your extension from your project root:
    vsce package
    This creates a .vsix file.
  5. Publish the extension:
    vsce publish
    Or to publish a specific vsix file:
    vsce publish -p <your-pat>
    (Replace <your-pat> with your actual token or set the VSCE_PAT environment variable).

Best Practices and Considerations

  • Performance: For very large JSON files, standard JSON.parse and JSON.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