sort-package-json
A Rust implementation of sort-package-json that sorts package.json files according to well-established npm conventions.
Features
- Sorts top-level fields according to npm ecosystem conventions (138 predefined fields)
- Preserves all data - only reorders fields, never modifies values
- Fast and safe - pure Rust implementation with no unsafe code
- Idempotent - sorting multiple times produces the same result
- Handles edge cases - unknown fields sorted alphabetically, private fields (starting with
_) sorted last
Usage
The tool will recursively find all package.json files in the current directory and sort them in place.
Example
Given an unsorted package.json:
Running cargo run package.json produces:
Field Ordering
Fields are sorted according to this priority:
- Known fields - 138 predefined fields organized into 12 logical groups
- Unknown fields - any custom fields sorted alphabetically
- Private fields - fields starting with
_sorted alphabetically at the end
The complete field order is based on both the original sort-package-json and prettier's package.json sorting implementations.
Known Field Groups
1. Core Package Metadata
$schema, name, displayName, version, stableVersion, gitHead, private, description, categories, keywords, homepage, bugs
2. License & People
license, author, maintainers, contributors
3. Repository & Funding
repository, funding, donate, sponsor, qna, publisher
4. Package Content & Distribution
man, style, example, examplestyle, assets, bin, source, directories, workspaces, binary, files, os, cpu, libc
5. Package Entry Points
type, sideEffects, main, module, browser, types, typings, typesVersions, typeScriptVersion, typesPublisherContentHash, react-native, svelte, unpkg, jsdelivr, jsnext:main, umd, umd:main, es5, esm5, fesm5, es2015, esm2015, fesm2015, es2020, esm2020, fesm2020, esnext, imports, exports, publishConfig
6. Scripts
scripts, betterScripts
7. Dependencies
dependencies, devDependencies, dependenciesMeta, peerDependencies, peerDependenciesMeta, optionalDependencies, bundledDependencies, bundleDependencies, resolutions, overrides
8. Git Hooks & Commit Tools
husky, simple-git-hooks, pre-commit, lint-staged, nano-staged, commitlint
9. VSCode Extension Specific
l10n, contributes, activationEvents, extensionPack, extensionDependencies, extensionKind, icon, badges, galleryBanner, preview, markdown
10. Build & Tool Configuration
napi, flat, config, nodemonConfig, browserify, babel, browserslist, xo, prettier, eslintConfig, eslintIgnore, standard, npmpkgjsonlint, npmPackageJsonLintConfig, npmpackagejsonlint, release, auto-changelog, remarkConfig, stylelint, typescript, typedoc, tshy, tsdown, size-limit
11. Testing
ava, jest, jest-junit, jest-stare, mocha, nyc, c8, tap, tsd, typeCoverage, oclif
12. Runtime & Package Manager
languageName, preferGlobal, devEngines, engines, engineStrict, volta, packageManager, pnpm
Why Not simd-json?
While investigating performance optimizations, we considered using simd-json instead of serde_json. However, simd-json is not suitable for this project due to several technical limitations:
1. No preserve_order Support
Our sorting algorithm requires maintaining custom insertion order. We insert fields in a specific sequence (known fields � unknown fields � private fields) and need the Map to preserve that exact order during serialization.
simd-json lacks the equivalent of serde_json's preserve_order feature, which uses IndexMap to maintain insertion order. Without this, the Map implementation would re-sort keys alphabetically, completely breaking our field ordering logic.
Status: Blocking issue - makes simd-json incompatible with our core functionality.
2. Wrong Performance Profile
simd-json is optimized for large files (1MB+) through SIMD acceleration, but is slower for small files due to SIMD overhead:
- For small objects: serde_json is 1.6x faster
- For large objects (1.8MB): simd-json is 3x faster
Package.json files are typically 1-5 KB, rarely exceeding 50 KB even for large monorepos. This makes them squarely in the "small file" category where simd-json would actually decrease performance.
3. Platform Compatibility Issues
simd-json does not work correctly on big-endian architectures (e.g., s390x/IBM Z mainframe). Projects using simd-json must implement conditional compilation to fall back to serde_json on big-endian platforms.
See simd-json issue #437 for details.
4. Additional Complexity
- Contains substantial unsafe code (C++ port)
- Requires specific allocators (mimalloc/jemalloc) for optimal performance
- More complex dependency tree
Conclusion
For a package.json sorting tool, serde_json is the optimal choice:
- Faster for small files (our use case)
- Supports preserve_order (required feature)
- Safe, stable, cross-platform
- Simpler dependency tree
- No platform-specific limitations
Development
Building
Running Tests
Tests use snapshot testing via insta. To review and accept snapshot changes:
Or to accept all changes:
Test Coverage
- Field ordering test - verifies correct sorting of all field types
- Idempotency test - ensures sorting is stable (sorting twice = sorting once)
License
MIT
References
- Original sort-package-json (JavaScript)
- simd-json issue #437 - Big Endian Compatibility
- Surprises in the Rust JSON Ecosystem