Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Creating Atom Editor Packages for JSON Formatting

If you still maintain an Atom workflow, a JSON formatter package is one of the fastest useful extensions you can build: one command, one parser pass, and an immediate quality-of-life improvement for minified API payloads or hand-edited config files. The important 2026 caveat is that GitHub sunset Atom on December 15, 2022, and the official atom/atom repository is now archived and read-only. The package API is still worth learning for local tools, but if you want a maintained editor and a live package registry, build with Pulsar's package docs in mind because Pulsar keeps the Atom-compatible ecosystem alive.

Current Reality First

  • Use Atom if you are maintaining an existing internal workflow or a legacy package.
  • Use Pulsar if you are starting a new public package or want current documentation and publishing.
  • Keep the package itself simple and Atom-compatible: the same command-based formatter pattern works in both editors.

Pick the Right Starting Point

For strict compatibility, write your package using the classic Atom package shape: a top-level package.json, a main module in lib/, and optional keymaps/, menus/, and spec/ folders. In Atom you can still create that skeleton from Edit > Developer > Generate New Package.... In Pulsar, the official generator is available through the Command Palette as Generate Package.

The generated scaffold is often noisier than a formatter package needs. For a JSON formatter, the minimal structure usually looks like this:

json-formatter-package/
├─ keymaps/
│  └─ json-formatter-package.json
├─ lib/
│  └─ json-formatter-package.js
├─ menus/
│  └─ json-formatter-package.json
├─ spec/
│  └─ json-formatter-package-spec.js
└─ package.json

If your generator creates view files, modal panels, or starter styles you do not need, delete them early. Formatter packages are command-driven and should stay small.

Use a Practical package.json

The generated metadata needs cleanup before the package is actually useful. Fill in the package name, description, repository URL, and a couple of formatter settings immediately so you do not forget later.

Recommended package.json

{
  "name": "json-formatter-package",
  "main": "./lib/json-formatter-package",
  "version": "0.0.0",
  "description": "Format strict JSON in Atom and Pulsar",
  "keywords": ["json", "formatter", "atom", "pulsar"],
  "activationCommands": {
    "atom-workspace": "json-formatter-package:format"
  },
  "repository": "https://github.com/your-name/json-formatter-package",
  "license": "MIT",
  "engines": {
    "atom": ">=1.0.0 <2.0.0"
  },
  "config": {
    "indentation": {
      "title": "Indentation Spaces",
      "description": "Number of spaces to use when pretty-printing JSON.",
      "type": "integer",
      "default": 2,
      "minimum": 0,
      "maximum": 8
    },
    "sortKeys": {
      "title": "Sort Object Keys",
      "description": "Alphabetically sort keys before writing formatted output.",
      "type": "boolean",
      "default": false
    }
  },
  "dependencies": {}
}
  • activationCommands keeps startup lightweight. The package is activated only when the command is invoked.
  • The Atom-compatible engines.atom field is still what Pulsar expects for package compatibility.
  • For a JSON formatter, configuration usually only needs indentation and an optional key-sorting toggle.

If you publish to Pulsar later, the official docs also support delayed activation via activationHooks, but activationCommands is the simplest starting point for a command-driven formatter.

Build the Formatter Around a Single Command

For this kind of package, the safest pattern is a single command registered from activate(), plus a formatter method that works on either one selection or the entire buffer. Use the generated CommonJS style unless you already have a build step; that is still the most direct path for Atom-compatible packages.

lib/json-formatter-package.js

const { CompositeDisposable } = require("atom");

function sortObjectKeys(value) {
  if (Array.isArray(value)) {
    return value.map(sortObjectKeys);
  }

  if (value && typeof value === "object") {
    return Object.keys(value)
      .sort()
      .reduce((result, key) => {
        result[key] = sortObjectKeys(value[key]);
        return result;
      }, {});
  }

  return value;
}

module.exports = {
  subscriptions: null,

  activate() {
    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(
      atom.commands.add("atom-workspace", {
        "json-formatter-package:format": () => this.formatJson(),
      })
    );
  },

  deactivate() {
    if (this.subscriptions) {
      this.subscriptions.dispose();
      this.subscriptions = null;
    }
  },

  formatJson() {
    const editor = atom.workspace.getActiveTextEditor();
    if (!editor) {
      atom.notifications.addWarning("JSON Formatter: No active editor.");
      return;
    }

    const grammar = editor.getGrammar();
    const scopeName = grammar ? grammar.scopeName : "";
    if (scopeName !== "source.json") {
      atom.notifications.addInfo(
        "JSON Formatter: This example targets strict JSON files only."
      );
      return;
    }

    const selections = editor.getSelections().filter((selection) => !selection.isEmpty());
    if (selections.length > 1) {
      atom.notifications.addInfo(
        "JSON Formatter: Use one selection or format the entire file."
      );
      return;
    }

    const selection = selections[0] || null;
    const sourceText = selection ? selection.getText() : editor.getText();

    if (!sourceText.trim()) {
      atom.notifications.addInfo("JSON Formatter: Nothing to format.");
      return;
    }

    const indentation = atom.config.get("json-formatter-package.indentation");
    const sortKeys = atom.config.get("json-formatter-package.sortKeys");

    let formattedJson;
    try {
      const parsed = JSON.parse(sourceText);
      const normalized = sortKeys ? sortObjectKeys(parsed) : parsed;
      formattedJson = JSON.stringify(normalized, null, indentation);
    } catch (error) {
      atom.notifications.addError("JSON Formatter: Invalid JSON.", {
        detail: error.message,
        dismissable: true,
      });
      return;
    }

    editor.transact(() => {
      if (selection) {
        editor.setTextInBufferRange(selection.getBufferRange(), formattedJson);
      } else {
        editor.setText(formattedJson);
      }
    });

    atom.notifications.addSuccess("JSON Formatter: JSON formatted successfully.");
  },
};
  • CompositeDisposable is the standard way to clean up registered commands on deactivation.
  • Register the command on atom-workspace so it appears in the command palette anywhere in the editor.
  • Use editor.transact() so a full format operation becomes one undo step instead of several.
  • Use setTextInBufferRange() for a single selection. That is clearer than relying on insertText() behavior when multiple cursors or selections are involved.

Keep the JSON Rules Explicit

The example above is intentionally strict: it only accepts data that JSON.parse() accepts. That means no comments, no trailing commas, and no JSON5-style syntax. This matters because many developers think they need a “JSON formatter” when what they really have is JSONC or JSON5.

  • If your users edit API payloads, exported data, or minified production JSON, strict JSON is usually the right choice.
  • If they edit config files with comments, swap the parser for something like jsonc-parser and adjust the grammar checks accordingly.
  • If key order matters for readability, offer a sortKeys option, but make it opt-in because it changes output beyond whitespace formatting.

Add Keymaps, Menus, and Testing

Your package becomes discoverable when the command is easy to trigger. Start with one key binding and one menu item, then test in development mode before thinking about publishing.

Example keymaps/json-formatter-package.json

{
  "atom-text-editor": {
    "ctrl-alt-j": "json-formatter-package:format"
  }
}

Example menus/json-formatter-package.json

{
  "menu": [
    {
      "label": "Packages",
      "submenu": [
        {
          "label": "JSON Formatter Package",
          "submenu": [
            {
              "label": "Format JSON",
              "command": "json-formatter-package:format"
            }
          ]
        }
      ]
    }
  ],
  "context-menu": {
    "atom-text-editor": [
      {
        "label": "Format JSON",
        "command": "json-formatter-package:format"
      }
    ]
  }
}

For testing, use the smallest loop possible:

  • In Atom, open the package with Edit > Developer > Open in Dev Mode....
  • In Pulsar, you can also launch a package directly with pulsar --dev /path/to/package.
  • Reload after edits with Window: Reload, then run your command from the Command Palette.
  • Open developer tools if something is not registering; package activation errors usually surface there immediately.

Troubleshooting the Common Failures

  • Command does not appear: make sure activationCommands contains the exact command name and then reload the window.
  • Package loads but formatting does nothing: confirm you have an active text editor and the open file is using the expected JSON grammar.
  • “Invalid JSON” on a config file: you probably have comments or trailing commas, which means you need JSONC support rather than strict JSON.
  • Pulsar will not load the package after generation: the package name may collide with an existing bundled or published package name.

Publishing in 2026

This is where the Atom sunset matters most. For public distribution, do not plan around the original Atom package ecosystem. The maintained path is the Pulsar package registry.

cd json-formatter-package
pulsar -p publish minor
  • Check that the package name is available before publishing.
  • Make sure the repository URL in package.json is real and matches the GitHub repo.
  • Keep the engines.atom field even for Pulsar publishing; that is still the compatibility marker the docs require.
  • If this formatter is only for your team, skip registry publishing entirely and keep it as a local linked package.

Conclusion

Creating an Atom editor package for JSON formatting still makes sense when you treat it as a small, command-driven extension and stay honest about the platform state. Build the formatter with strict JSON rules, a clear command, and a minimal package surface area. If the package needs a future beyond your own machine or team, target Pulsar for testing and publishing while keeping the package code Atom-compatible.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool