prettier-plugin-solidity

repository·main·Indexed 20 days ago

https://github.com/prettier-solidity/prettier-plugin-solidity

A Prettier plugin for automatically formatting Solidity code. It supports multiple compiler versions, high-fidelity parsing via the recommended 'slang' parser (or deprecated 'antlr' parser), and integrates with environments including NodeJS, browsers, Vim, and VSCode. Version 2.4.0 provides specific formatting adjustments for Solidity v0.7.4+ and v0.8.0+.

Tokens
4.5K
Snippets
16
Records
24
Agent score
73%

What's inside prettier-plugin-solidity

  1. Edge Case: Modifier formatting in constructors

    main

    Prettier Solidity cannot always distinguish between a modifier and a base constructor. Consequently, modifiers with no arguments are formatted with their parentheses removed in standard functions, but not in constructors.

    Example behavior:

    contract Foo is Bar {
      // Parentheses are KEPT in constructors
      constructor() Bar() modifier1 modifier2() modifier3(42) {}
    
      // Parentheses are REMOVED in functions
      function f() modifier1 modifier2 modifier3(42) {}
    }
  2. Solidity Indentation and Whitespace Standards

    main

    The prettier-plugin-solidity enforces the following indentation and whitespace rules:

    • Indentation: Use 4 spaces per indentation level. Spaces are preferred over tabs; mixing them should be avoided.
    • Blank Lines:
      • Surround top-level declarations (like contracts) with two blank lines.
      • Surround function declarations within a contract with a single blank line (unless they are related one-liners/stubs).
    • Whitespace in Expressions:
      • Avoid whitespace immediately inside parentheses (), brackets [], or braces {} (except in single-line function declarations).
      • Avoid whitespace immediately before a comma , or semicolon ;.
      • Do not use multiple spaces to align assignments or operators.
      • Do not include whitespace in the fallback function function() external { ... }.
    • Operators: Surround operators with a single space on either side (e.g., x = 3 + 4).
  3. Format Mappings and Variable Declarations

    main

    The following rules apply to variable and mapping declarations:

    • Mappings: Do not include a space between the mapping keyword and its type. This applies to both standard and nested mappings.
    • Arrays: Do not include a space between the type and the square brackets [].
    • Strings: Use double-quotes (") instead of single-quotes (') for strings.
    mapping(uint => uint) map;
    mapping(address => bool) registeredAddresses;
    mapping(uint => mapping(bool => Data[])) public data;
    
    uint[] x;
    
    str = "foo";
  4. Format Control Structures and Braces

    main

    The plugin enforces specific brace placement for contracts, libraries, functions, structs, and control structures (if, else, while, for):

    • Brace Placement: The opening brace { should be on the same line as the declaration, preceded by a single space. The closing brace } should be on its own line at the same indentation level as the declaration.
    • Control Structures:
      • There should be a single space between the keyword (if, while, for) and the parenthetical block.
      • There should be a single space between the parenthetical block and the opening brace.
      • Else Clauses: For if blocks with else or else if, the else keyword must be on the same line as the if block's closing brace.
    • Single Statement Bodies: For control structures with a single statement, you may omit braces if the statement is on a single line.
    if (x < 3) {
        x += 1;
    } else if (x > 7) {
        x -= 1;
    } else {
        x = 5;
    }
  5. Configure the Solidity compiler version

    main

    The compiler option allows you to specify a Solidity version to ensure formatting is compatible with specific compiler behaviors.

    • v0.7.4+: Enables multi-line import statements. Prior to this, imports were forced to a single line to avoid compiler bugs.
    • v0.8.0+: Adjusts formatting for changes like the removal of the byte type and the change to right-associative exponentiation (a**b**c).

    You can use Prettier overrides to apply different compiler settings to different directories in a multi-version project.

    {
      "overrides": [
        {
          "files": "contracts/v1/**/*.sol",
          "options": {
            "compiler": "0.6.3"
          }
        },
        {
          "files": "contracts/v2/**/*.sol",
          "options": {
            "compiler": "0.8.4"
          }
        }
      ]
    }
  6. Handle Maximum Line Length and Wrapped Lines

    main

    To maintain readability, keep lines under 79 or 99 characters. When lines are wrapped, follow these rules:

    1. The first argument must not be attached to the opening parenthesis.
    2. Use exactly one level of indentation for wrapped elements.
    3. Each argument must fall on its own line.
    4. The terminating element (e.g., ); or ];) must be placed on its own line at the end.

    This applies to:

    • Function Calls
    • Assignment Statements
    • Event Definitions and Emitters
    thisFunctionCallIsReallyLong(
        longArgument1,
        longArgument2,
        longArgument3
    );
    
    thisIsALongNestedMapping[being][set][to_some_value] = someFunction(
        argument1,
        argument2,
        argument3,
        argument4
    );
    
    event LongAndLotsOfArgs(
        address sender,
        address recipient,
        uint256 publicKey,
        uint256 amount,
        bytes32[] options
    );
  7. Format Function Declarations

    main

    Function declarations follow different rules based on length:

    • Short Functions: Keep the opening brace on the same line as the declaration. The visibility modifier must come before any custom modifiers.
    • Long Functions:
      • Drop each argument onto its own line at the same indentation level as the function body.
      • The closing parenthesis and opening brace should be on their own lines at the same indentation level as the function declaration.
      • If the function has modifiers, drop each modifier onto its own line.
    • Return Statements: Multiline output parameters and return statements should follow the same wrapping rules as long lines (one argument per line).
    • Inherited Constructors: For long or complex constructors in inherited contracts, drop base constructors onto new lines similar to how modifiers are handled.
    // Long function with modifiers
    function thisFunctionNameIsReallyLong(
        address x,
        address y,
        address z,
    )
        public
        onlyowner
        priced
        returns (address)
    {
        doSomething();
    }
    
    // Constructor with base arguments
    contract A is B, C, D {
        uint x;
    
        constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
            B(param1)
            C(param2, param3)
            D(param4)
            public
        {
            x = param5;
        }
    }
  8. Run Prettier on Solidity contracts via CLI

    main

    Use the Prettier CLI to format your contracts. You must explicitly specify the plugin using the --plugin flag.

    Note: The plugin only works with valid Solidity code. Syntax errors will cause a parser error and no formatting will be performed.

    npx prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'
  9. Use prettier-plugin-solidity in the Browser

    main

    To use the plugin in a browser environment, you must load Prettier's standalone bundle before the plugin. When using unpkg, the plugin populates the global prettierPlugins object.

    To format code, use prettier.format with the slang parser and include prettierPlugins.solidity in the plugins array.

    <script type="module">
      await import('https://unpkg.com/prettier@latest');
      await import('https://unpkg.com/prettier-plugin-solidity@latest');
    
      // The global variables `prettier` and `prettierPlugins` are automatically
      // created and populated by importing each module.
    
      async function format(code) {
        return await prettier.format(code, {
          parser: 'slang',
          plugins: [prettierPlugins.solidity]
        });
      }
    
      const originalCode = 'contract Foo    {}';
      const formattedCode = format(originalCode);
    </script>
  10. Integrate with VSCode using prettier-vscode

    main

    For more granular control, use the prettier-vscode extension. To ensure it works with this plugin, you must have prettier and prettier-plugin-solidity installed locally in your project's node_modules via package.json.

    1. Install the extension: esbenp.prettier-vscode.
    2. Install local dependencies: npm install --save-dev prettier prettier-plugin-solidity.
    3. Configure the language-specific default formatter in VSCode settings.

    Important: If a .prettierrc file exists in your project, it will take precedence over VSCode's settings.json rules.

    code --install-extension esbenp.prettier-vscode
    npm install --save-dev prettier prettier-plugin-solidity

    After configuring via Command Palette:

    {
      "editor.formatOnSave": true,
      "[solidity]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      }
    }
  11. Migrate from v1 to v2

    main

    To upgrade, install the latest version:

    npm install prettier-plugin-solidity@latest

    If you previously had an explicit parser defined in your .prettierrc, you will encounter an error: [error] Couldn't resolve parser "solidity-parse". To fix this, update your .prettierrc to use the new parser name: slang.

    {
      "parser": "slang"
    }
  12. Integrate with VSCode using Hardhat Solidity

    main

    VSCode requires a Solidity language extension for formatting support. The recommended approach is using the hardhat-solidity extension.

    1. Install the extension: NomicFoundation.hardhat-solidity.
    2. Ensure editor.formatOnSave is enabled.
    3. Set the default formatter for Solidity to NomicFoundation.hardhat-solidity in your settings.json.

    Note: These extensions typically provide basic integration with Prettier automatically.

    code --install-extension NomicFoundation.hardhat-solidity
    {
      "editor.formatOnSave": true,
      "solidity.formatter": "prettier",
      "[solidity]": {
        "editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
      }
    }