prettier-solidity / prettier-plugin-solidity Goto Github PK
View Code? Open in Web Editor NEWA Prettier plugin for automatically formatting your Solidity code.
Home Page: https://t.me/+kgTgkFgIwJkwMjcx
License: MIT License
A Prettier plugin for automatically formatting your Solidity code.
Home Page: https://t.me/+kgTgkFgIwJkwMjcx
License: MIT License
as per @maxsam4 comment on Gitter:
The JSON AST field isConstructor of the FunctionDefinition node was replaced by a field called kind which can have the value "constructor", "fallback" or "function".
this is also a breaking change.
contract test {
function fun(uint256 a) returns (uint) {
if (something) foo();
// comment
else if (somethingElse) bar();
else whatever();
}
}
gets formatted as
contract test {
function fun(uint256 a) returns(uint) {
if (something) foo();
else // comment
if (somethingElse) bar();
else whatever();
}
}
This also happens if the first if
body has braces.
Originally posted by @fvictorio in #68
May be related to #81.
AssemblyFor
AST nodes are not supported.
One of the things that I like about Prettier is the fact that is opinionated and makes some desitions around the formatting using standard industry practices.
I want to open the discussion on whether this formatter should take care of the visibility of variables and functions when the developer forgets to add them explicitly.
The compiled bytecode of the resulting code would not be altered and the resulting code will be more descriptive.
#40 makes the plugin preserve comments, but creates a new problem. If you have some documentation above a function:
/*
* This function does stuff.
*/
function doStuff() public {
...
}
The prettified version will be:
/*
* This function does stuff.
*/
function doStuff() public {
...
}
The cause of this is that we prepend function definitions with empty lines. Possible solutions:
printer
function to separate functions with empty lines in a more intelligent way (for example, append an empty line to all function definitions except the last).Running prettier on this contract with a printWidth
of 56:
contract Foo {
function foo() {
address validatorAddress = signature.popLast20Bytes();
}
}
outputs this:
contract Foo {
function foo() {
address validatorAddress = signature.popLast20Bytes(
);
}
}
I think this shouldn't break like this. In this particular case, I think a proper output might be:
contract Foo {
function foo() {
address validatorAddress =
signature.popLast20Bytes();
}
}
or
contract Foo {
function foo() {
address validatorAddress = signature
.popLast20Bytes();
}
}
(I prefer the first one and I think it's what prettier-js does.)
what is the best strategy to implement the print
function? Reading the documentation is not clear to me what it should happen when there is an AST returned from a parser.
should I read this: https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf ?
should I watch this: https://www.youtube.com/watch?v=0Q4kUNx85_4&feature=youtu.be ?
any other recommendations?
// cc @lipis @duailibe @azz @czosel @kachkaev @warrenseine @ikatyang @j-f1
as per @maxsam4 comment on Gitter:
Another bug: It did not refactor the assembly code in https://github.com/PolymathNetwork/polymath-core/blob/dev-3.0.0/contracts/proxy/Proxy.sol
it skipped a couple of parts
should this plugin implement the "official" Solidity Style Guide?
I've been testing the plugin with some well-known projects, mainly 0x and OpenZeppelin. In both I noticed that they add a space after the returns
keyword, while we just put the parentheses without any space. I mean, we do this:
returns(uint)
and they do this:
returns (uint)
I don't really have a preference, but since they do it this way, maybe we should adhere to that.
@mattiaerre Since this is an easy change, I'll just go ahead and create a PR for this, but this is of course open for discussion.
Is this library publish to npm?
Do I need directly install from git repository, like this?
npm install git+https://github.com/mattiaerre/prettier-plugin-solidity.git
Maybe braces should be in the same line if a contract/function is empty. Right now, this:
contract Foo {
}
is not modified.
For comparison, in javascript this:
class Foo {
}
is prettified as:
class Foo {}
Something similar happens with empty functions.
If I want to run prettier in my library, I get the following error:
$ yarn format
yarn run v1.12.3
$ prettier --write src/**/*.ts
internal/modules/cjs/loader.js:583
throw err;
^
Error: Cannot find module 'emoji-regex'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
at Function.Module._load (internal/modules/cjs/loader.js:507:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object.<anonymous> (/Users/schmidsi/Development/@melonproject/protocol/node_modules/prettier-plugin-solidity/src/prettier-comments/common/util.js:4:20)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
error Command failed with exit code 1.
It suppose that the error comes from this line of code:
A possible fix was to install 'emoji-regex' in the consuming project, but that is a bad work around. You could probably remove this dependency completely?
This
contract Foo {
function f() {
g(
1, // one
2, // two
3 // three
);
assembly {
g(
1, // one
2, // two
3 // three
)
}
}
}
is being printed as:
contract Foo {
function f() {
g(
1, // one
2, // two
3 // three
);
assembly {
g(1, 2, 3) // one // two // three
}
}
}
Notice that it seems to work fine for normal function calls; the problem seems to be inside assembly blocks.
Current output:
while (condition)
{
...
Desired output:
while (condition) {
...
A contract like this:
contract test {
function fun(uint256 a) returns (address b) {
if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;
}
}
is prettified like this:
contract test {
function fun(uint256 a) returns(address b) {
if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;
}
}
Almost no changes.
I'm not sure what is the best output here. Should we add the braces or is that too opinionated?
There typescript typeings for solidity-parser-antlr and prettier.
I'm currently improving the AST typings to the point where most of the grammar rules are checked at compile time. With this you can write code transforms that don't corrupt the AST.
It also helps to track changes in the grammar over time. As the Solidity syntax evolves, the new typings will show where the printer and transforms need to be changed.
Finally it allows us to use more modern features of JS like lambda functions safely. Functional programming features are very useful for language processing.
Run the plugin 2 times against this contract
[error] contracts/05_greeter.sol: ParserError: extraneous input 'default' expecting {'from', 'constant', 'internal', 'private', 'public', Identifier}
[error] at Object.parse (/Users/mrichetto/projects/prettier-plugin-solidity/node_modules/solidity-parser-antlr/dist/index.js:74:11)
[error] at Object.parse (/Users/mrichetto/projects/prettier-plugin-solidity/src/parser.js:4:30)
[error] at Object.parse$2 [as parse] (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:7140:19)
[error] at coreFormat (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10400:23)
[error] at format (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10572:16)
[error] at formatWithCursor (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10584:12)
[error] at Object.formatWithCursor (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:34926:15)
[error] at format$1 (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:36846:21)
[error] at /Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:37035:16
[error] at /Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:36981:14
Run the plugin against the following contract
/*
This is a very simple demonstration of a while loops. Same as JS/c.
*/
contract BasicIterator {
address creator; // reserve one "address"-type spot
uint8[10] integers; // reserve a chunk of storage for 10 8-bit unsigned integers in an array
function BasicIterator()
{
creator = msg.sender; // set the creator address
uint8 x = 0; // initialize an 8-bit, unsigned integer to zero
while(x < integers.length) // the variable integers was initialized to length 10
{
integers[x] = x; // set integers to [0,1,2,3,4,5,6,7,8,9] over ten iterations
x++;
}
}
function getSum() constant returns (uint) // "constant" just means this function returns something to the caller
{ // which is immediately followed by what type gets returned, in this case a full uint256
uint8 sum = 0;
uint8 x = 0;
while(x < integers.length)
{
sum = sum + integers[x];
x++;
}
return sum;
}
/**********
Standard kill() function to recover funds
**********/
function kill()
{
if (msg.sender == creator)
{
suicide(creator); // kills this contract and sends remaining funds back to creator
}
}
}
[error] contracts/08_basiciterator.sol: TypeError: Cannot read property 'type' of undefined
[error] at propagateBreaksOnEnterFn (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:9195:13)
[error] at traverseDoc (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:9053:11)
[error] at Object.propagateBreaks (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:9220:3)
[error] at printAstToDoc (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10095:14)
[error] at coreFormat (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10414:16)
[error] at format (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10572:16)
[error] at formatWithCursor (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:10584:12)
[error] at Object.formatWithCursor (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:34926:15)
[error] at format$1 (/Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:36846:21)
[error] at /Users/mrichetto/projects/solidity-baby-steps/node_modules/prettier/bin-prettier.js:37035:16
as per @maxsam4 comment on Gitter:
[the plugin] prettifies (success, )
to (success)
which is incorrect.
If the file has more than one contract, and they are already separated by one line, the prettified output will separate them by two lines.
We should format function definitions like this:
contract Foo {
function f()
modifier1
modifier2
modifier3
modifier4
returns (bool)
{
return true;
}
function h() modifier1 returns (bool) {
return true;
}
}
This may be somewhat inconsistent, but I think it's more readable. If the function definition has a lot of parameters and also a lot of modifiers, maybe it should be formatted like this:
contract Foo {
function f(
uint a,
uint b,
uint c
) modifier1
modifier2
modifier3
modifier4
returns (bool)
{
return true;
}
}
This won't be written on stone, of course, we can change it later. But it's much better that what we have now, with all the modifiers always in the same line no matter how long it is.
This
contract Foo {
function foo() modifier1 modifier2 aLongModifier anotherVeryLongModifier returns (uint aVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongParameterName) {
a = 42;
}
}
is prettified as:
contract Foo {
function foo()
modifier1
modifier2
aLongModifier
anotherVeryLongModifier
returns (
uint aVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongParameterName
)
{
a = 42;
}
}
Two things are wrong here: the indentation of the returns parameter and closing parentheses, and that the closing parentheses and the opening body brace are not in the same line.
implicit-arrow-linebreak
There is some misalignment when the printWidth
is shorter than a single modifier line. See this example: https://github.com/0xProject/0x-monorepo/compare/feat/contracts/prettier#diff-1b7ac3458f8bab7e6b28979b9e83204eR45
This
contract Foo {
function foo() {
address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_;
}
}
is prettified as
contract Foo {
function foo() {
address contextAddress = currentContextAddress_ == address(
0
) ? msg.sender : currentContextAddress_;
}
}
I'm not sure what the expected output should be here, though. Suggestions are welcome (cc @abandeali1, @mattiaerre).
As discussed in 0xProject/0x-monorepo#1495, if a contract has a lot of base contracts, these should be split to respect the print width.
contract Foo is AContract, AnotherContract, YetAnotherContract, ThisShouldBeSplit {
function foo(uint x, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8) {
a = 1;
}
}
This should split the base contracts, but just the function parameters are split.
I'm adding a todo list of things we should be doing prior the 1st publishing on npm of this plugin; feel free to comment on this issue if I've missed something
integrate @federicobond 's genericPrint
function
add additional examples (more complex contracts)
update README.md; check official-plugins and community-plugins for examples
Formatting this:
contract Box {
uint public value = 0;
function set(uint _value) public {
value = _value;
}
function inc() public {
value++;
}
}
outputs this:
contract Box {
uint public value = 0;
function set(uint _value) public {
value = _value;
}
function inc() public {
value++;
}
}
I think functions should be separated by a blank line. An output like this:
contract Box {
uint public value = 0;
function set(uint _value) public {
value = _value;
}
function inc() public {
value++;
}
}
should be enough IMO. Separating the field declarations from the functions would probably be another issue.
as per now the lenght of the printer.js
file is almost 500 lines of code; I'd love to refactor the genericPrint
function so that we can incrementally add and replace inner "printers" w/o modifying too much the very same file; an option that I have in mind is the following:
// omissis
default: {
try {
return [require('./node-types/for-statement')]
.find(element => element.name === node.type)
.print(node, path, print);
} catch (error) {
throw new Error(`Unknown type: ${JSON.stringify(node.type)}`);
}
}
// omissis
where every module inside the node-type
folder, exports an object w/ a name
property and a print
method; e.g.:
/* eslint-disable implicit-arrow-linebreak */
const {
doc: {
builders: { concat }
}
} = require('prettier');
const ForStatement = {
name: 'ForStatement',
print: (node, path, print) =>
concat([
'for (',
node.initExpression ? path.call(print, 'initExpression') : '',
'; ',
node.conditionExpression ? path.call(print, 'conditionExpression') : '',
'; ',
path.call(print, 'loopExpression'),
') ',
path.call(print, 'body')
])
};
module.exports = ForStatement;
what do you think?
Output right now:
if (condition){
Desired output:
if (condition) {
address payable[]
is getting prettified to address[]
For example,
pragma solidity ^0.5.0;
contract test {
address payable[] yo;
function hello(address payable[] memory _yo) public {
yo = _yo;
yo[0].transfer(1337);
}
}
Got prettified to
pragma solidity ^0.5.0;
contract test {
address[] yo;
function hello(address[] memory _yo) public {
yo = _yo;
yo[0].transfer(1337);
}
}
Comments are being dropped out right now. They should at least be preserved; properly formatting them could be another issue (which will probably need some definition: for example, should long comment lines be split? What does prettier do in js?).
missing a semicolon if for statement body is not included in braces.
function count(string[] data) public pure returns (uint) {
uint result;
for(uint i = 0; i < data.length; i++)
result += 1;
return result;
}
function count(string[] data) public pure returns(uint) {
uint result;
for (uint i = 0; i < data.length; i++) result += 1
return result;
}
N.B. there is a missing
;
at the end of the for body
It would be fantastic if the plugin would consume the rules defined in the linter ruleset, such as
{
"extends": "solium:recommended",
"plugins": ["security"],
"rules": {
"quotes": ["error", "double"],
"indentation": ["warning", 2],
"arg-overflow": ["warning", 3],
"security/enforce-explicit-visibility": ["error"],
"security/no-block-members": ["warning"],
"security/no-inline-assembly": ["warning"]
}
}
So that when printing, if it sees arg-overflow: 3
, then it prints only 3 args per line
If a function has only a comment as body:
function foo() public {
// to be defined
}
prettier fails with a Comment "to be defined" was not printed.
I created a branch https://github.com/prettier-solidity/prettier-plugin-solidity/tree/function-body-with-comment that has a failing test.
A pragma like this:
pragma solidity >=0.4.21 <0.6.0;
gets formatted like this:
pragma solidity >=0.4.21<0.6.0;
Notice the missing space.
I'll be moving this repo to the prettier-plugin organization that I've just created in GitHub as @federicobond suggested. he wrote the parser used in this plugin as well as started working on the print
function he shares in this Gist. I'll send an invite also to @j-f1 as he is tremendously helping me to properly shape this prettier plugin.
As discussed int 0xProject/0x-monorepo#1495, it seems like we are always using double quotes.
In which other places besides string literals should we use this option? Import directives?
A for statement like this:
for (uint256 i = 0; i < 10; i++) {}
is formatted as:
for (uint256 i = 0;i < 10; i++;) {
}}
Things to notice:
I think this is a blocker (hopefully the last one) for publishing an alpha version.
Right now, linting a contract:
contract Box {
uint public value = 0;
function set(uint _value) public {
value = _value;
}
}
produces this output:
contract Box {
uint public value = 0;
function set(uint _value) public {
value = _value;
}
}%
where %
represents the end-of-file. I think contracts should have a newline at the end.
as per @maxsam4 comment on Gitter:
one thing about solidity 0.5. Address datatype can now be address payable
. prettier cannot handle that.
I cannot share this contract atm but I assume it is this line:
pragma experimental ABIEncoderV2;
[error] contracts/provenance/statemachine/StateMachine.sol: Error: Unknown type: "FunctionTypeName"
[error] at Object.genericPrint [as print] (/Users/roderik/Development/solidity-mint/node_modules/prettier-plugin-solidity/src/printer.js:458:13)
[error] at genericPrint (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10130:18)
[error] at /Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10076:16
[error] at Object.printComments (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:9838:17)
[error] at printGenerically (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10075:22)
[error] at FastPath.call (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:9949:16)
[error] at Object.genericPrint [as print] (/Users/roderik/Development/solidity-mint/node_modules/prettier-plugin-solidity/src/printer.js:300:14)
[error] at genericPrint (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10130:18)
[error] at /Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10076:16
[error] at Object.printComments (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:9838:17)
prettier does not like when I have a standalone comment in the body of a constructor (or any other function):
constructor() public setMsgFields {
// This constructor will be used to test the creation via multi-sig wallet
}
[error] @noridoteco/contracts/contracts/wallet/TestCalls.sol: Error: Comment "This constructor will be used to test the creation via multi-sig wallet" was not printed. Please report this error!
[error] at /home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:10371:13
[error] at Array.forEach (<anonymous>)
[error] at ensureAllCommentsPrinted (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:10369:15)
[error] at coreFormat (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:10417:3)
[error] at format (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:10572:16)
[error] at formatWithCursor (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:10584:12)
[error] at Object.formatWithCursor (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:34926:15)
[error] at format$1 (/home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:36846:21)
[error] at /home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:37035:16
[error] at /home/ubuntu/dev/nori/node_modules/prettier/bin-prettier.js:36981:14
Source here
as per the prettier plugins doc, "Parsers convert code as a string into an AST." and so I'd love to take advantage of one of these libraries if they produce the right AST
// cc @federicobond @lydell
We're opening this issue to inform you about problems with your dependencies.io configuration or build failures.
We'll add a comment here when we see problems. You can close this issue when
you have things resolved -- we'll open it back up if we detect new problems.
Helpful links:
Note: To help keep your repo as clean as possible, this is the only issue
that we're going to open and comment on. Feel free to delete the comments
that are made as you resolve them, if you want to keep this issue short and tidy.
Source file: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol#L48
Line 48 has the assembly call that freaks out the parser. The same thing happens with my Proxy contracts.
[error] contracts/external/strings.sol: Error: Unknown type: "AssemblyLocalDefinition"
[error] at Object.genericPrint [as print] (/Users/roderik/Development/solidity-mint/node_modules/prettier-plugin-solidity/src/printer.js:458:13)
[error] at genericPrint (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10130:18)
[error] at /Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10076:16
[error] at Object.printComments (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:9838:17)
[error] at printGenerically (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10075:22)
[error] at FastPath.map (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10007:21)
[error] at Object.genericPrint [as print] (/Users/roderik/Development/solidity-mint/node_modules/prettier-plugin-solidity/src/printer.js:427:25)
[error] at genericPrint (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10130:18)
[error] at /Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:10076:16
[error] at Object.printComments (/Users/roderik/Development/solidity-mint/node_modules/prettier/bin-prettier.js:9838:17)
Similar to #87, there some examples of well-known solidity code that adds a space after the mapping
keyword:
mapping (address => uint256)
But, unlike #87, here I've seen the two variations being used. And, speaking just for myself, I have a strong preference for the non-space form:
mapping(address => uint256)
Some numbers:
There doesn't seem to be a strong preference for one or another, so it's probably up to us.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.