prettier-plugin-apex-imo
v0.2.0
Published
Opinionated multiline formatting for Apex Lists and Maps - extends prettier-plugin-apex
Maintainers
Readme
prettier-plugin-apex-imo
IMO = In My Opinion. Because Prettier is opinionated, and so am I.
An opinionated enhancement for prettier-plugin-apex that provides comprehensive Apex code formatting including multiline collection formatting, casing normalization, annotation formatting, modifier ordering, and ApexDoc code block formatting.
The Problem
When using prettier-plugin-apex, code like this:
final String expectedJson = String.join(new List<String>{
'{',
' "tags" : [ "reading", "gaming", "coding" ]',
'}'
}, '\n');Gets reformatted to a single line, defeating the purpose of readable formatting:
final String expectedJson = String.join(new List<String>{ '{', ' \"tags\" : [ \"reading\", \"gaming\", \"coding\" ]', '}' }, '\n');The Solution
This plugin wraps prettier-plugin-apex and modifies the printing behaviour
with comprehensive formatting enhancements:
- Collection formatting → Lists, Sets, and Maps with 2+ entries are always multiline with braces on separate lines
- Casing normalization → Type names, reserved words, and annotations are normalized to proper casing
- ApexDoc
{@code}blocks → Code inside is formatted using Prettier - Annotation formatting → Annotations are normalized and properly formatted
- Modifier ordering → Modifiers are sorted in a consistent order
- Enhanced comment handling → Better comment placement and attachment using Prettier's comment system
This is non-configurable behaviour. Once installed, it just works.
Architecture
This plugin has been architected with AST-based processing as the primary approach, minimizing regex usage and maximizing leverage of Prettier's infrastructure:
- AST-First Processing: Works with comment AST nodes and token structures rather than raw text parsing
- Prettier Integration: Uses Prettier's doc builders (
fill,join) for text formatting instead of regex-based word splitting - Minimal Regex: Only uses regex where absolutely necessary (complex annotation parsing, preprocessing)
- Character-Based Fallbacks: Uses simple character scanning only for text content within AST nodes (like code blocks in comments)
Benefits
- Better Performance: Reduced regex compilation overhead
- Improved Reliability: AST operations are more predictable than complex regex patterns
- Enhanced Maintainability: Structured processing is easier to understand and modify
- Future Compatibility: Leverages Prettier's AST infrastructure for better long-term compatibility
Features
Collection Formatting
Collections (Lists, Sets, and Maps) with 2 or more entries are always formatted multiline with opening and closing braces on separate lines:
// Before
List<String> items = new List<String>{ 'one', 'two', 'three' };
// After
List<String> items = new List<String>{
'one',
'two',
'three'
};Single-item collections remain on one line for compactness.
Casing Normalization
The plugin normalizes casing throughout your codebase:
- Type names:
string→String,account→Account,list<integer>→List<Integer> - Reserved words:
PUBLIC→public,Class→class,STATIC→static - Standard objects:
account→Account,contact→Contact - Object suffixes:
MyObject__C→MyObject__c,Custom__datacategoryselection→Custom__DataCategorySelection - Annotation names:
auraenabled→AuraEnabled,testmethod→TestMethod - Annotation options:
cacheable→cacheable(normalized to camelCase)
This ensures consistent casing across your entire codebase, making it easier to read and maintain.
Annotation Formatting
Annotations are normalized and formatted with proper multiline support:
// Before
@auraenabled(cacheable=true)
@testmethod
// After
@AuraEnabled(cacheable = true)
@TestMethodAnnotations with multiple parameters are automatically formatted multiline when needed.
Modifier Ordering
Modifiers are automatically sorted in a consistent order:
- Fields: Access modifier →
static→final→transient→ other - Methods: Access modifier →
static→override→virtual→abstract→ other - Annotations: Always appear before keyword modifiers
This ensures a consistent code style across your project.
ApexDoc Formatting
Code inside ApexDoc {@code} blocks is automatically formatted using Prettier,
with proper indentation and alignment:
/**
* Example method.
* {@code
* List<String> items = new List<String>{
* 'a',
* 'b',
* 'c'
* };
* }
*/The formatting maintains the * vertical alignment and handles nested braces
correctly.
Comment Handling Improvements
This plugin includes enhanced comment handling that leverages Prettier's built-in comment attachment system:
- Smart comment placement for Apex-specific constructs (classes, interfaces, block statements)
- Dangling comment support for empty code blocks
- Binary expression comments properly attached to right operands
- Block statement leading comments moved into block bodies for better formatting
- ApexDoc normalization → Missing or extra asterisks are normalized, indentation is corrected
These improvements ensure comments are placed more intelligently and consistently with Prettier's standards.
Installation
pnpm add -D prettier prettier-plugin-apex prettier-plugin-apex-imoOr with npm:
npm install --save-dev prettier prettier-plugin-apex prettier-plugin-apex-imoUsage in Salesforce Projects
If you're working with a Salesforce project (created with sf project generate
or Salesforce DX), follow these steps:
Install the plugin:
npm install --save-dev prettier-plugin-apex-imoStandard Salesforce projects already include
prettierandprettier-plugin-apexin theirpackage.json, so you only need to installprettier-plugin-apex-imo.Update your
.prettierrcfile:Replace
prettier-plugin-apexwithprettier-plugin-apex-imoin the plugins array:{ "trailingComma": "none", "plugins": ["prettier-plugin-apex-imo", "@prettier/plugin-xml"] }The
prettier-plugin-apex-imoplugin wrapsprettier-plugin-apex, so you only need to specifyprettier-plugin-apex-imoin your config. However, both plugins must be installed sinceprettier-plugin-apexis a peer dependency.Verify the configuration:
npm run prettier:verifyOr format your files:
npm run prettierStandard Salesforce projects typically include a
prettierscript inpackage.jsonthat formats all relevant files including Apex classes (.cls) and triggers (.trigger).
Examples
Before (prettier-plugin-apex)
List<String> items = new List<String>{ 'one', 'two', 'three' };
Set<String> tags = new Set<String>{ 'reading', 'gaming', 'coding' };
Map<String, Integer> counts = new Map<String, Integer>{ 'a' => 1, 'b' => 2 };After (prettier-plugin-apex-imo)
List<String> items = new List<String>{
'one',
'two',
'three'
};
Set<String> tags = new Set<String>{
'reading',
'gaming',
'coding'
};
Map<String, Integer> counts = new Map<String, Integer>{
'a' => 1,
'b' => 2
};Single Items (unchanged)
// These stay on one line
List<String> single = new List<String>{ 'only' };
Set<String> singleSet = new Set<String>{ 'only' };
Map<String, Integer> singleMap = new Map<String, Integer>{ 'key' => 1 };Additional Examples
Casing Normalization
// Before
public class myclass {
private string name;
private account acc;
private list<integer> numbers;
}
// After
public class MyClass {
private String name;
private Account acc;
private List<Integer> numbers;
}Modifier Ordering
// Before
final public static Integer count;
// After
public static final Integer count;Annotation Normalization
// Before
@auraenabled(cacheable=true)
@testmethod
public void myMethod() {}
// After
@AuraEnabled(cacheable = true)
@TestMethod
public void myMethod() {}Requirements
- Node.js >= 20
- Prettier >= 3.0.0
- prettier-plugin-apex >= 2.0.0
Why "imo"?
Prettier has a strict option philosophy that discourages adding new formatting options. While I respect this philosophy, I believe the current behaviour for multi-item Lists and Maps is suboptimal for code readability.
Rather than fork prettier-plugin-apex or maintain options, this plugin
provides a simple, opinionated wrapper that enforces the behaviour I (and
hopefully others) prefer.
Contributing
Contributions are welcome! Please read CONTRIBUTING.md for details.
Security
For security issues, please email [email protected]. See SECURITY.md for details.
License
This project is licensed under the MIT License. See the LICENSE.md file for details.
Acknowledgements
- prettier-plugin-apex by Dang Mai
- Inspiration for some of the prettying functionality is also taken from
Ilya Matsuev's
prettier-plugin-apexfork - Prettier for the amazing formatting engine
