A Prettier plugin for automatically formatting Solidity smart contract code.
npx @tessl/cli install tessl/npm-prettier-plugin-solidity@1.4.0A Prettier plugin that provides automatic code formatting for Solidity smart contracts. The plugin integrates seamlessly with Prettier's formatting ecosystem to ensure consistent, readable Solidity code across blockchain and Ethereum development projects.
npm install --save-dev prettier prettier-plugin-solidity// Default plugin import (ESM) - exports plugin object
import prettierPluginSolidity from "prettier-plugin-solidity";
// For use with Prettier API (same as default import)
import prettier from "prettier";
import solidityPlugin from "prettier-plugin-solidity";For CommonJS environments:
// CommonJS import (uses standalone build)
const prettierPluginSolidity = require("prettier-plugin-solidity");
// Explicit standalone build import
const solidityPlugin = require("prettier-plugin-solidity/standalone");For browser environments:
<script src="https://unpkg.com/prettier@latest"></script>
<script src="https://unpkg.com/prettier-plugin-solidity@latest"></script># Format Solidity files with explicit plugin
npx prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'
# Add to package.json scripts
{
"scripts": {
"format": "prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'",
"lint": "prettier --list-different --plugin=prettier-plugin-solidity 'contracts/**/*.sol'"
}
}{
"plugins": ["prettier-plugin-solidity"],
"overrides": [
{
"files": "*.sol",
"options": {
"parser": "solidity-parse",
"printWidth": 80,
"tabWidth": 4,
"useTabs": false,
"singleQuote": false,
"bracketSpacing": false
}
}
]
}import prettier from "prettier";
import solidityPlugin from "prettier-plugin-solidity";
const solidityCode = `
contract Example{function test(){uint256 x=1+2;}}
`;
const formatted = await prettier.format(solidityCode, {
parser: "solidity-parse",
plugins: [solidityPlugin]
});
console.log(formatted);
// Output: properly formatted Solidity code// After loading scripts
async function formatSolidity(code) {
return await prettier.format(code, {
parser: "solidity-parse",
plugins: [prettierPlugins.solidityPlugin]
});
}
const originalCode = 'contract Foo {}';
const formattedCode = await formatSolidity(originalCode);The plugin follows Prettier's plugin architecture with these core components:
The default export provides the complete Prettier plugin configuration.
/**
* Default export containing the complete Prettier plugin configuration
*/
interface PrettierPluginSolidity {
/** Language definitions for Solidity */
languages: LanguageSupport[];
/** Parser configurations */
parsers: { [parserName: string]: Parser };
/** Printer configurations */
printers: { [astFormat: string]: Printer };
/** Plugin-specific options */
options: OptionsDefinition;
/** Default formatting options */
defaultOptions: DefaultOptions;
}
interface LanguageSupport {
/** Linguist language identifier */
linguistLanguageId: number;
/** Language name */
name: string;
/** Programming language type */
type: string;
/** Syntax highlighting color */
color: string;
/** ACE editor mode */
aceMode: string;
/** TextMate scope */
tmScope: string;
/** File extensions */
extensions: string[];
/** Available parsers */
parsers: string[];
/** VS Code language identifiers */
vscodeLanguageIds: string[];
}Solidity source code parsing with AST generation and compiler-specific transformations.
/**
* Parser configuration for Solidity code
*/
interface Parser {
/** AST format identifier */
astFormat: string;
/** Parse function */
parse: (text: string, parsers?: any, options?: ParseOptions) => SolidityAST;
/** Location start function */
locStart: (node: ASTNode) => number;
/** Location end function */
locEnd: (node: ASTNode) => number;
}
interface ParseOptions {
/** Solidity compiler version for compatibility */
compiler?: string;
/** Enable experimental ternary formatting */
experimentalTernaries?: boolean;
/** Quote preference for hex literals */
singleQuote?: boolean;
[key: string]: any;
}
interface SolidityAST {
/** AST node type */
type: string;
/** Child nodes */
children?: SolidityAST[];
/** Source location information */
loc?: SourceLocation;
/** Source range information */
range?: [number, number];
/** Associated comments */
comments?: Comment[];
[key: string]: any;
}AST to formatted code conversion with support for all Solidity language constructs.
/**
* Printer configuration for Solidity AST
*/
interface Printer {
/** Main print function */
print: (path: ASTPath, options: PrintOptions, print: PrintFunction) => string;
/** Comment attachment predicate */
canAttachComment: (node: ASTNode) => boolean;
/** Comment handling functions */
handleComments: CommentHandlers;
/** Block comment detection */
isBlockComment: (comment: Comment) => boolean;
/** AST cleaning function */
massageAstNode: (node: ASTNode, newNode: ASTNode, parent: ASTNode) => ASTNode;
/** Comment printer */
printComment: (commentPath: CommentPath) => string;
}
interface CommentHandlers {
/** Handle own-line comments */
ownLine: (comment: Comment, text: string, options: PrintOptions) => void;
/** Handle end-of-line comments */
endOfLine: (comment: Comment, text: string, options: PrintOptions) => void;
/** Handle remaining comments */
remaining: (comment: Comment, text: string, options: PrintOptions) => void;
}
interface PrintOptions {
/** Line width for wrapping */
printWidth: number;
/** Tab width in spaces */
tabWidth: number;
/** Use tabs instead of spaces */
useTabs: boolean;
/** Spaces around brackets */
bracketSpacing: boolean;
/** Use single quotes */
singleQuote: boolean;
/** Solidity compiler version */
compiler?: string;
/** Enable experimental ternaries */
experimentalTernaries?: boolean;
[key: string]: any;
}Configurable options for customizing Solidity code formatting behavior.
/**
* Available formatting options for Solidity code
*/
interface OptionsDefinition {
/** Line width configuration */
printWidth: OptionDefinition<number>;
/** Tab width configuration */
tabWidth: OptionDefinition<number>;
/** Tab usage configuration */
useTabs: OptionDefinition<boolean>;
/** Bracket spacing configuration */
bracketSpacing: OptionDefinition<boolean>;
/** Quote style configuration */
singleQuote: OptionDefinition<boolean>;
/** Experimental ternary configuration */
experimentalTernaries: OptionDefinition<boolean>;
/** Compiler version configuration */
compiler: OptionDefinition<string>;
}
interface OptionDefinition<T> {
/** Option introduction version */
since?: string;
/** Option category */
category: string;
/** Option type */
type: string;
/** Default value */
default: T;
/** Option description */
description: string;
/** Opposite description for boolean options */
oppositeDescription?: string;
/** Numeric range constraints */
range?: { start: number; end: number; step: number };
}
interface DefaultOptions {
/** Default bracket spacing setting */
bracketSpacing: boolean;
/** Default tab width setting */
tabWidth: number;
}The plugin provides formatting support for all Solidity language constructs through specialized node printers.
/**
* Supported Solidity AST node types with dedicated formatters
*/
type SupportedNodeTypes =
// Core language constructs
| "SourceUnit" | "PragmaDirective" | "ImportDirective"
// Contract structures
| "ContractDefinition" | "InheritanceSpecifier"
| "StateVariableDeclaration" | "FunctionDefinition"
| "ModifierDefinition" | "EventDefinition" | "CustomErrorDefinition"
| "StructDefinition" | "EnumDefinition" | "EnumValue"
// Type system
| "ElementaryTypeName" | "UserDefinedTypeName" | "FunctionTypeName"
| "ArrayTypeName" | "Mapping" | "TypeDefinition"
// Statements
| "Block" | "ExpressionStatement" | "VariableDeclarationStatement"
| "IfStatement" | "ForStatement" | "WhileStatement" | "DoWhileStatement"
| "BreakStatement" | "ContinueStatement" | "ReturnStatement"
| "EmitStatement" | "RevertStatement" | "TryStatement" | "CatchClause"
| "UncheckedStatement" | "ThrowStatement"
// Expressions
| "BinaryOperation" | "UnaryOperation" | "Conditional"
| "FunctionCall" | "MemberAccess" | "IndexAccess" | "IndexRangeAccess"
| "NewExpression" | "TupleExpression" | "NameValueExpression"
// Literals
| "BooleanLiteral" | "NumberLiteral" | "DecimalNumber" | "HexNumber"
| "StringLiteral" | "HexLiteral" | "Identifier"
// Assembly
| "InlineAssemblyStatement" | "AssemblyBlock" | "AssemblyCall"
| "AssemblyIf" | "AssemblyFor" | "AssemblySwitch" | "AssemblyCase"
| "AssemblyAssignment" | "AssemblyLocalDefinition" | "AssemblyStackAssignment"
| "AssemblyFunctionDefinition" | "AssemblyMemberAccess"
// Declarations
| "VariableDeclaration" | "UsingForDeclaration" | "FileLevelConstant"
| "ModifierInvocation" | "NameValueList" | "LabelDefinition";Intelligent comment preservation and formatting that maintains code readability.
/**
* Comment handling utilities
*/
interface CommentUtilities {
/** Check if comment is block-style */
isBlockComment: (comment: Comment) => boolean;
/** Print comment with appropriate formatting */
printComment: (commentPath: CommentPath) => string;
/** Handle prettier-ignore comments */
hasNodeIgnoreComment: (node: ASTNode) => boolean;
}Version-specific formatting adaptations for different Solidity compiler versions.
/**
* Compiler version compatibility features
*/
interface CompilerCompatibility {
/** Check if compiler version satisfies range */
satisfies: (version: string, range: string) => boolean;
/** Apply version-specific AST transformations */
applyVersionTransforms: (ast: SolidityAST, version: string) => SolidityAST;
}
/**
* Compiler version milestones affecting formatting
*/
type CompilerMilestones = {
/** v0.7.4: Multi-line import support */
"0.7.4": "multiline-imports";
/** v0.8.0: Exponentiation operator precedence changes */
"0.8.0": "exponentiation-precedence";
};Helper functions for string formatting and compatibility checks.
/**
* Utility functions used throughout the plugin
*/
interface PluginUtilities {
/** Format string literals with proper quoting */
printString: (content: string, options: PrintOptions) => string;
/** Check Prettier version compatibility */
prettierVersionSatisfies: (range: string) => boolean;
/** Detect prettier-ignore comments on nodes */
hasNodeIgnoreComment: (node: ASTNode) => boolean;
}interface ASTNode {
/** Node type identifier */
type: string;
/** Source location information */
loc?: SourceLocation;
/** Source range */
range?: [number, number];
/** Associated comments */
comments?: Comment[];
[key: string]: any;
}
interface SourceLocation {
/** Start position */
start: Position;
/** End position */
end: Position;
}
interface Position {
/** Line number (1-based) */
line: number;
/** Column number (0-based) */
column: number;
}
interface ASTPath {
/** Get current node */
getValue: () => ASTNode;
/** Get parent node */
getParentNode: (level?: number) => ASTNode;
/** Call function with child path */
call: <T>(fn: (path: ASTPath) => T, ...names: (string | number)[]) => T;
/** Map over child paths */
map: <T>(fn: (path: ASTPath, index: number) => T, ...names: (string | number)[]) => T[];
}
interface Comment {
/** Comment type */
type: "BlockComment" | "LineComment";
/** Comment content */
value: string;
/** Source location */
loc: SourceLocation;
/** Source range */
range: [number, number];
}
interface CommentPath {
/** Get current comment */
getValue: () => Comment;
[key: string]: any;
}
type PrintFunction = (path: ASTPath) => string;