<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Franco Victorio</title>
    <description>The latest articles on Forem by Franco Victorio (@fvictorio).</description>
    <link>https://forem.com/fvictorio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F132647%2F7c7e655a-2872-4727-a252-f102b7033a79.png</url>
      <title>Forem: Franco Victorio</title>
      <link>https://forem.com/fvictorio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fvictorio"/>
    <language>en</language>
    <item>
      <title>Debugging transactions in Ethereum. Part 2: Truffle and Buidler</title>
      <dc:creator>Franco Victorio</dc:creator>
      <pubDate>Tue, 17 Mar 2020 13:37:59 +0000</pubDate>
      <link>https://forem.com/fvictorio/debugging-transactions-in-ethereum-part-2-truffle-and-buidler-36pp</link>
      <guid>https://forem.com/fvictorio/debugging-transactions-in-ethereum-part-2-truffle-and-buidler-36pp</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/fvictorio/debugging-transactions-in-ethereum-part-1-the-long-and-winding-road-c51"&gt;previous post&lt;/a&gt; we looked at some ways to debug transactions that were mined in a testnet or in the mainnet, using &lt;a href="http://etherscan.io/"&gt;etherscan&lt;/a&gt; and &lt;a href="https://github.com/protofire/eth-cli"&gt;eth-cli&lt;/a&gt;. In this post we'll move to transactions that we execute in "local" blockchains, like &lt;a href="https://github.com/trufflesuite/ganache-cli"&gt;ganache-cli&lt;/a&gt; and the &lt;a href="https://buidler.dev/buidler-evm/"&gt;Buidler EVM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm going to use the Truffle MetaCoin box for the examples, so if you want to follow along you can start by running &lt;code&gt;npx truffle unbox metacoin&lt;/code&gt; in an empty directory. You'll also have to edit the &lt;code&gt;truffle-config.js&lt;/code&gt; file, uncomment it, and change the port of the development network from 7545 to 8545.&lt;/p&gt;

&lt;h2&gt;
  
  
  Truffle debug
&lt;/h2&gt;

&lt;p&gt;If your project is built using &lt;a href="https://www.trufflesuite.com/docs/truffle/overview"&gt;Truffle&lt;/a&gt;, you can use its debugger to inspect a transaction step by step. This is a command line tool similar to &lt;code&gt;gdb&lt;/code&gt; or &lt;code&gt;pdb&lt;/code&gt;; if you've used something like that in the past, the experience is very similar.&lt;/p&gt;

&lt;p&gt;In our example, if we start &lt;code&gt;ganache-cli&lt;/code&gt; in another terminal and then run &lt;code&gt;npx truffle test&lt;/code&gt;, we'll see a bunch of transactions being executed. Copy the hash of the last transaction and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx truffle compile # this might be necessary if the build/ directory isn't there
npx truffle debug 0x3e3299b90e92efeccfe806f7b67e4683fb2c6ad2e114cbbe4b1308e4402ce090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Your hash could be different.)&lt;/p&gt;

&lt;p&gt;And you'll get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i95ewN6X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ro5006my2yyixljzzmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i95ewN6X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4ro5006my2yyixljzzmf.png" alt="Truffle debugger 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can do things like seting a breakpoint with &lt;code&gt;b&lt;/code&gt;, stepping over to the next line with &lt;code&gt;o&lt;/code&gt; or evaluating an expression with &lt;code&gt;:&lt;/code&gt;. Let's step over twice and inspect the value of the &lt;code&gt;amount&lt;/code&gt; parameter with &lt;code&gt;:amount&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---7edBbDx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6zsmyvyxb5kvbpkn1tfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---7edBbDx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6zsmyvyxb5kvbpkn1tfu.png" alt="Truffle debugger 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check &lt;a href="https://www.trufflesuite.com/docs/truffle/getting-started/debugging-your-contracts"&gt;the docs&lt;/a&gt; to learn more about this feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging tests
&lt;/h3&gt;

&lt;p&gt;Another tool you can use is the global &lt;code&gt;debug()&lt;/code&gt; function in your tests. Go to &lt;code&gt;test/metacoin.js&lt;/code&gt; and replace this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-const balance = await metaCoinInstance.getBalance.call(accounts[0]);
&lt;/span&gt;&lt;span class="gi"&gt;+const balance = await debug(metaCoinInstance.getBalance.call(accounts[0]));
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then run your tests with &lt;code&gt;npx truffle test --debug&lt;/code&gt; (notice the extra flag). Your tests will be interrupted when that method is called and you'll be able to inspect it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TalU82hu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cc07fxleyvvaf7tjue8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TalU82hu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cc07fxleyvvaf7tjue8v.png" alt="Truffle debugger 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great not only because you don't need to get the hash of some transaction, but also because you can use it for plain calls that don't even send a transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging non-local transactions
&lt;/h3&gt;

&lt;p&gt;What about transactions in a testnet or in the mainnet? As far as I know, &lt;code&gt;truffle debug&lt;/code&gt; can be used against any node that supports the &lt;code&gt;debug_traceTransaction&lt;/code&gt; JSON-RPC method. And (again, AFAIK; here I am in the "I don't really know what I'm talking about" territory) besides local blockchains, this method is supported mainly by geth when syncing in archive mode. I haven't tested it because this requires syncing more than 2 TB of data.&lt;/p&gt;

&lt;p&gt;Are there any other alternatives? Not that I'm aware of. &lt;a href="https://infura.io/"&gt;Infura&lt;/a&gt; doesn't support &lt;code&gt;debug_traceTransaction&lt;/code&gt; calls. I also tried using &lt;code&gt;ganache --fork&lt;/code&gt; but this didn't work either (it actually kind of worked once? I think it might if the transaction is recent enough).&lt;/p&gt;

&lt;p&gt;Anyway, if anyone knows how to do this, please let me know in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buidler
&lt;/h2&gt;

&lt;p&gt;Buidler is a task runner for smart contract projects that comes with a lot of useful tools. You can use it on its own, or you can complement a truffle project with it, which is what we're going to do here. First, install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev @nomiclabs/buidler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then run &lt;code&gt;npx buidler&lt;/code&gt; and select the "Create an empty buidler.config.js" option.&lt;/p&gt;

&lt;h3&gt;
  
  
  console.log
&lt;/h3&gt;

&lt;p&gt;One of the things that come with Buidler is the Buidler EVM, that lets you do things like logging stuff inside your contracts or having stack traces that work across solidity and javascript. Let's start with the console.&lt;/p&gt;

&lt;p&gt;First, open the &lt;code&gt;contracts/MetaCoin.sol&lt;/code&gt; file and add these two lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; pragma solidity &amp;gt;=0.4.25 &amp;lt;0.7.0;

 import "./ConvertLib.sol";
&lt;span class="gi"&gt;+import "@nomiclabs/buidler/console.sol";
&lt;/span&gt;
...

    function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
&lt;span class="gi"&gt;+       console.log(msg.sender, receiver, amount);
&lt;/span&gt;        if (balances[msg.sender] &amp;lt; amount) return false;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, kill &lt;code&gt;ganache-cli&lt;/code&gt; (if it's still running) and execute &lt;code&gt;npx buidler node&lt;/code&gt;, which starts a node that uses the Buidler EVM.&lt;/p&gt;

&lt;p&gt;Now just run &lt;code&gt;npx truffle test&lt;/code&gt; and you'll be able to see the console messages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6k8DoBQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/de014pmqqgs90apdjeu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6k8DoBQu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/de014pmqqgs90apdjeu0.png" alt="Buidler 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice that here we are logging the same information that is emitted in the &lt;code&gt;Transfer&lt;/code&gt; event, so what's the point? Well, first of all, events are not emitted for failed transactions, but the console works just fine. And second, you can also use logs for method calls that don't send transactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack traces
&lt;/h3&gt;

&lt;p&gt;The Buidler EVM also supports stack traces that look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5cdZHNdO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6nvdwqikkrglgqzi97xk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5cdZHNdO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6nvdwqikkrglgqzi97xk.png" alt="Buidler 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, here we get both the line of the contract that failed, and the line of the javascript test that triggered the transaction!&lt;/p&gt;

&lt;p&gt;Getting this to work is a little more involved, but worth it. First, install the truffle and web3 buidler plugins:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev @nomiclabs/buidler-truffle5 "@nomiclabs/buidler-web3@^1.2.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;code&gt;buidler.config.js&lt;/code&gt; and add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usePlugin("@nomiclabs/buidler-truffle5")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to the beginning of the file.&lt;/p&gt;

&lt;p&gt;Then create a file called &lt;code&gt;test/truffle-fixture.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MetaCoin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MetaCoin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ConvertLib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ConvertLib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;convertLib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ConvertLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;ConvertLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAsDeployed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;convertLib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;MetaCoin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;convertLib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metacoin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MetaCoin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;MetaCoin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAsDeployed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;metacoin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just some glue code we need so that our contracts are deployed before running our tests with buidler (so far we've been running them with truffle).&lt;/p&gt;

&lt;p&gt;You'll also need to remove the solidity test that comes with the MetaCoin box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm test/TestMetaCoin.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is necessary because buidler doesn't support Solidity tests yet.&lt;/p&gt;

&lt;p&gt;Now everything is ready: run &lt;code&gt;npx buidler test&lt;/code&gt; to run your tests in the Buidler EVM. Of course, tests still pass so we won't get a stack trace. Let's modify our contract to trigger an error. Open &lt;code&gt;contracts/MetaCoin.sol&lt;/code&gt; and add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  ...

    function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
&lt;span class="gi"&gt;+       require(amount &amp;lt;= 5);
&lt;/span&gt;    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run &lt;code&gt;npx buidler test&lt;/code&gt; again. You'll get a stack trace like the one we saw at the beginning.&lt;/p&gt;




&lt;p&gt;Both Truffle and Buidler offer some nice functionalities to help make sense of what's happening inside your contracts.  The &lt;code&gt;MetaCoin&lt;/code&gt; contract is really simple, so this might seem overkill, but you've surely run into issues where you wished you'd had a debugger, a logger or a stack trace. Or, even better, all three of them!&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Debugging transactions in Ethereum. Part 1: The Long and Winding Road</title>
      <dc:creator>Franco Victorio</dc:creator>
      <pubDate>Fri, 28 Feb 2020 14:00:33 +0000</pubDate>
      <link>https://forem.com/fvictorio/debugging-transactions-in-ethereum-part-1-the-long-and-winding-road-c51</link>
      <guid>https://forem.com/fvictorio/debugging-transactions-in-ethereum-part-1-the-long-and-winding-road-c51</guid>
      <description>&lt;p&gt;Do you know that happy feeling when a transaction fails and you are the one that gets to debug it? Of course you don't.&lt;/p&gt;

&lt;p&gt;Debugging transactions in Ethereum is still a major pain point. While there's been a lot of progress (and I hope to cover much of it in this series), it remains an unpleasant activity. So the more tools you have at your disposal, the better.&lt;/p&gt;

&lt;p&gt;We'll start by exploring the data we get from etherscan. All of the transactions I'll use as examples were executed in Rinkeby, but everything should be valid for Kovan or Mainnet. I think. I hope.&lt;/p&gt;

&lt;p&gt;(I'll also use &lt;a href="https://github.com/protofire/eth-cli"&gt;&lt;code&gt;eth-cli&lt;/code&gt;&lt;/a&gt; for performing some simple tasks. You can install it by doing &lt;code&gt;npm install -g eth-cli&lt;/code&gt;, but you don't need to.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Function selectors
&lt;/h2&gt;

&lt;p&gt;Let's start with a very simple contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;Box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's say we are interacting with this contract somehow (maybe we are building a dapp for it) and our transaction fails. Check for example &lt;a href="https://rinkeby.etherscan.io/tx/0x950100d9e81fa188e79302d538392564ae46bbc57f9008265136dae303e4010d"&gt;this transaction&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T9qGfAM9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hgjocaflcftcb13wx219.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T9qGfAM9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hgjocaflcftcb13wx219.png" alt="A failing transaction"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There isn't a lot of data here, but we can manage to get some useful information out of it.&lt;/p&gt;

&lt;p&gt;If you click on "Click to see More", you'll see more data about this transaction. The part we care about now is the Input Data, a bunch of bytes that make up our transaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NqJfRriN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tknchfi16ot4zr2nkrzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NqJfRriN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tknchfi16ot4zr2nkrzs.png" alt="More data about our tx"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Input data always starts with a function selector: 8 characters (4 bytes) that identify the method being called. So you can start by checking that you are calling the proper method. In this case, since there's only one function, you can use &lt;code&gt;eth method:hash 'inc()'&lt;/code&gt; to find out its selector. Turns out it's &lt;code&gt;371303c0&lt;/code&gt;, but in the failing transaction the 4 bytes are &lt;code&gt;33da8f9c&lt;/code&gt;. So we found the problem!&lt;/p&gt;

&lt;p&gt;In this case I artificially made the situation harder by using a weird name (it's &lt;code&gt;incrementPlease()&lt;/code&gt;, in case you care). But in other cases it's even easier.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://rinkeby.etherscan.io/tx/0xde961d1cf914cc4f96eafd894d187014fff3aa9bf74cec4a5c22cb7f6f80d0e3"&gt;this transaction&lt;/a&gt;, etherscan correctly decodes the method being called.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R-Kdeet1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uv0lbmww4iz1rqb8m4j5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R-Kdeet1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uv0lbmww4iz1rqb8m4j5.png" alt="Automatically decoded function selector"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't know exactly when it does this and when it doesn't (maybe it leverages &lt;a href="https://www.4byte.directory/"&gt;the 4byte directory&lt;/a&gt;?), but in any case if the method being called is common enough, then it will probably be automatically decoded here, as in this case where we are calling &lt;code&gt;increment()&lt;/code&gt; instead of the correct one, &lt;code&gt;inc()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revert reasons
&lt;/h2&gt;

&lt;p&gt;Let's add another method to our contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Box {
    // ...

    function dec() external {
        require(value &amp;gt; 0, "Value must always be positive");
        value--;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a &lt;code&gt;require&lt;/code&gt; with a revert reason. In &lt;a href="https://rinkeby.etherscan.io/tx/0x19fe30122dde5d29c973c60c45b2b96e4bd75b6573572e4e04daf5c0200230db"&gt;this transaction&lt;/a&gt; we get an error, but we can easily guess what happened thanks to the message in the "Status" row.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4STZ-X6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w9fpqrkoxuehyh72vrls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4STZ-X6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w9fpqrkoxuehyh72vrls.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This helps a lot, so the take-away is simple: always add reason strings to your &lt;code&gt;revert&lt;/code&gt;s!&lt;/p&gt;

&lt;p&gt;Of course, if you don't include a reason string, like &lt;a href="https://rinkeby.etherscan.io/tx/0xf7cd8cabdc3fc7f01110e0ac12fac30b2ea2ffae208e8385de931524b3bdc77b"&gt;here&lt;/a&gt;, then you'll need to try other approaches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digression: how revert reasons work
&lt;/h3&gt;

&lt;p&gt;Curious about how to recover the error manually? (Hopefully you will never have to do this.) First, we make an &lt;code&gt;eth_call&lt;/code&gt; with the same data, and at the same block number (&lt;code&gt;0x5c471e&lt;/code&gt; is &lt;code&gt;6047518&lt;/code&gt;, the block number where the failed transaction was mined)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl -H "Content-Type: application/json" -X POST --data \
        '{"id":1, \
        "jsonrpc":"2.0", \
        "method":"eth_call", \
        "params":[ \
          {"from": "0x9A2015Ed446E7A7450b9175413DEb04Fe4e555c2", "to": "0x23c1fd51DD362D87A9E20F7370B7E9A0CbC40D4f", "value": "0x0", "data": "0xb3bcfa82"}, \
          "0x5c471e" \
        ]}' https://rinkeby.infura.io/

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001d56616c7565206d75737420616c7761797320626520706f736974697665000000"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we interpret the result as the data of a call to the function &lt;code&gt;Error(string)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ eth method:decode 'Error(string)' '0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001d56616c7565206d75737420616c7761797320626520706f736974697665000000'

[
  "Value must always be positive"
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Invalid opcodes
&lt;/h2&gt;

&lt;p&gt;Now let's add a third method to our contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Box {
    // ...

    function divideBy(uint256 x) external {
        value = value / x;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, this is a very simple code, so you can probably guess what's coming, but let's do it anyway.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rinkeby.etherscan.io/tx/0xb85f585d0540001fefb490a7bfb6107eb4541a29d8c27c4af0a6176d97382c26"&gt;This transaction&lt;/a&gt; fails and we don't get an error message. Instead, there's an &lt;code&gt;invalid opcode 0xfe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AVf-m9Pa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/myfadjltl8w72lvs7v3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AVf-m9Pa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/myfadjltl8w72lvs7v3n.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you check the &lt;a href="https://github.com/crytic/evm-opcodes"&gt;list of op codes&lt;/a&gt; you'll see that &lt;code&gt;0xFE&lt;/code&gt; means "INVALID". If we decode the data that was sent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ eth method:decode 'divideBy(uint256)' 0x1fcc4afb0000000000000000000000000000000000000000000000000000000000000000
["0"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the error is clear: there was a division by zero that triggered this. Another example of an invalid opcode being thrown happens when you try to access an array using and index that is out of bounds.&lt;/p&gt;

&lt;p&gt;We had to manually decode the data because the contract is not verified. If it were, then etherscan would've decoded it for us.&lt;/p&gt;




&lt;p&gt;Of course, in most real life scenarios your code won't be so easy to read as it was in these examples. In the next post, we'll continue to explore what can be done in those cases.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>blockchain</category>
      <category>solidity</category>
    </item>
    <item>
      <title>A comparison of BigNumber libraries in JavaScript</title>
      <dc:creator>Franco Victorio</dc:creator>
      <pubDate>Wed, 06 Nov 2019 00:14:23 +0000</pubDate>
      <link>https://forem.com/fvictorio/a-comparison-of-bignumber-libraries-in-javascript-2gc5</link>
      <guid>https://forem.com/fvictorio/a-comparison-of-bignumber-libraries-in-javascript-2gc5</guid>
      <description>&lt;p&gt;If you've ever wanted to handle big numbers in JavaScript, you've probably noticed that there are &lt;strong&gt;a lot&lt;/strong&gt; of different libraries, even for JavaScript standards. This article compares seven of them and hopefully will help you choose one.&lt;/p&gt;

&lt;p&gt;I'll start by comparing some of the features that they do or don't support. Then I'll show some snippets of code for each one to give you a feeling of their API. After that I'll make a brief comment on the libraries used in the Ethereum ecosystem, since that's where I work on and it's an area where this kind of libraries is very present. Finally I'll give you my advice on which one to use (spoiler alert: it's &lt;code&gt;big.js&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature comparison
&lt;/h2&gt;

&lt;p&gt;The following table shows the libraries I picked and some aspects of each one. There are a lot of other things you might want to consider, like their API, performance, supported operations, etc., but this should give you a place to start.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Integers&lt;/th&gt;
&lt;th&gt;Floating-point&lt;/th&gt;
&lt;th&gt;Other bases&lt;/th&gt;
&lt;th&gt;Scientific Notation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/big.js"&gt;big.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Throws&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/bignumber.js/"&gt;bignumber.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/decimal.js/"&gt;decimal.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/indutny/bn.js"&gt;bn.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Throws&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Throws&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/peterolson/BigInteger.js"&gt;BigInteger.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Throws&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/GoogleChromeLabs/jsbi"&gt;JSBI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Wrong&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/andyperlitch/jsbn"&gt;jsbn&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Wrong&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Wrong&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Integer values
&lt;/h3&gt;

&lt;p&gt;All of them support integer values, but &lt;code&gt;decimal.js&lt;/code&gt;, by design, can lose precision (more on this later).&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;BigInteger.js&lt;/code&gt; and &lt;code&gt;JSBI&lt;/code&gt; can act as some sort of polyfill for the &lt;a href="https://tc39.es/proposal-bigint/"&gt;ECMAScript BigInt proposal&lt;/a&gt;, although their approaches differ. Check the &lt;a href="https://github.com/GoogleChromeLabs/jsbi#why"&gt;Why?&lt;/a&gt; section in &lt;code&gt;JSBI&lt;/code&gt;'s readme to find out more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Floating-point values
&lt;/h3&gt;

&lt;p&gt;Only the first three support floating point numbers, and they were all developed by the same author. He wrote &lt;a href="https://github.com/MikeMcl/big.js/wiki"&gt;an explanation&lt;/a&gt; on how they differ, but the &lt;em&gt;tl;dr&lt;/em&gt; is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;big.js&lt;/code&gt; is a minimalist library. Use it if you don't need a lot of features and/or you care about the size of your dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bignumber.js&lt;/code&gt; and &lt;code&gt;decimal.js&lt;/code&gt; are similar, the main difference is that &lt;code&gt;bignumber.js&lt;/code&gt; expresses its precision in terms of decimals (appropriate for financial applications, for example) and &lt;code&gt;decimal.js&lt;/code&gt; does it in terms of significant digits (better for scientific applications). That's why &lt;code&gt;decimal.js&lt;/code&gt; is not a good choice for arbitrary &lt;strong&gt;integer&lt;/strong&gt; arithmetic&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the libraries don't support floating-point numbers, but they have different behaviors when you try to create an instance with, for example, &lt;code&gt;3.14&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bn.js&lt;/code&gt; and &lt;code&gt;BigInteger.js&lt;/code&gt; throw an error.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSBI&lt;/code&gt; accepts it, but it parses it as &lt;code&gt;3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jsbn&lt;/code&gt; accepts it, but it parses it as &lt;code&gt;314&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other bases
&lt;/h3&gt;

&lt;p&gt;All of them, except &lt;code&gt;big.js&lt;/code&gt;, support inputs in different bases. &lt;code&gt;big.js&lt;/code&gt; throws an error if used that way. &lt;code&gt;bn.js&lt;/code&gt; and &lt;code&gt;jsbn&lt;/code&gt; do support different bases, but you have to be explicit: if you do &lt;code&gt;new BN('0x1f3')&lt;/code&gt; it will return &lt;code&gt;33253&lt;/code&gt; for some reason, but &lt;code&gt;new BN('1f3', 16)&lt;/code&gt; works fine. The same comments apply to &lt;code&gt;jsbn&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scientific notation
&lt;/h3&gt;

&lt;p&gt;Scientific notation works for all of them except &lt;code&gt;bn.js&lt;/code&gt; (that throws an error) and &lt;code&gt;jsbn&lt;/code&gt; (that, again, returns some very wrong value)&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;How do they look like? Let's see how to add 2+2 in each one of them. This is not enough to make a judgement on their API, but it showcases some important details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// big.js&lt;/span&gt;
&lt;span class="nx"&gt;Big&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// bignumber.js&lt;/span&gt;
&lt;span class="nx"&gt;BigNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// decimal.js&lt;/span&gt;
&lt;span class="nx"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// bn.js&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// BigInteger.js&lt;/span&gt;
&lt;span class="nx"&gt;BigInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// JSBI&lt;/span&gt;
&lt;span class="nx"&gt;JSBI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;JSBI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;JSBI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// jsbn&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;jsbn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BigInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;jsbn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BigInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a bunch of things you can see here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some of them require the use of &lt;code&gt;new&lt;/code&gt;, while it's optional for the rest.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;add&lt;/code&gt; method in &lt;code&gt;bn.js&lt;/code&gt; has to receive a BN instance as its argument. If you want to use a number, you need to use &lt;code&gt;addn&lt;/code&gt;. &lt;code&gt;jsbn&lt;/code&gt; &lt;strong&gt;requires&lt;/strong&gt; that the argument to &lt;code&gt;add&lt;/code&gt; be another instance.&lt;/li&gt;
&lt;li&gt;Instances of &lt;code&gt;JSBI&lt;/code&gt; don't have methods like &lt;code&gt;add&lt;/code&gt;, you need to use the static methods of the library.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSBI&lt;/code&gt; and &lt;code&gt;jsbn&lt;/code&gt; &lt;strong&gt;require&lt;/strong&gt; strings as the arguments to their constructors. The other libraries accept both numbers and strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Size and popularity
&lt;/h2&gt;

&lt;p&gt;The following table shows the (minified) size of each library and their weekly number of downloads at the time of writing this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Weekly downloads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/big.js"&gt;big.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;8K&lt;/td&gt;
&lt;td&gt;9.272.986&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/bignumber.js/"&gt;bignumber.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;20K&lt;/td&gt;
&lt;td&gt;2.390.156&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/MikeMcl/decimal.js/"&gt;decimal.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;290.392&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/indutny/bn.js"&gt;bn.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;56K&lt;/td&gt;
&lt;td&gt;7.101.573&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/peterolson/BigInteger.js"&gt;BigInteger.js&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;32K&lt;/td&gt;
&lt;td&gt;899.179&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/GoogleChromeLabs/jsbi"&gt;JSBI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;28K&lt;/td&gt;
&lt;td&gt;16.508&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/andyperlitch/jsbn"&gt;jsbn&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;24K&lt;/td&gt;
&lt;td&gt;11.648.984&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A note on Ethereum
&lt;/h2&gt;

&lt;p&gt;Arbitrary-precision libraries are important in the Ethereum ecosystem because smart contracts can return numbers with up to 256 bits, and JavaScript can't handle that precision. That's why the main client libraries come with some sort of big number library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;web3@0.x&lt;/code&gt; uses &lt;code&gt;bignumber.js&lt;/code&gt; (actually, &lt;a href="https://github.com/frozeman/bignumber.js-nolookahead"&gt;a fork of it&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;web3@1.x&lt;/code&gt; uses &lt;code&gt;bn.js&lt;/code&gt;. There is &lt;a href="https://github.com/ethereum/web3.js/issues/2171"&gt;a discussion&lt;/a&gt; about changing it again.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ethers.js&lt;/code&gt; exposes a custom big number library that uses &lt;code&gt;bn.js&lt;/code&gt; under the hood but which also adds some extra functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that the most used clients (web3 after 0.x and ethers.js) use a library that doesn't support floating-point numbers. This kind of makes sense, since Solidity doesn't (yet) support them, but it also makes some things harder (e.g., computing some percentage of a value).&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one should I use?
&lt;/h2&gt;

&lt;p&gt;Which library you'll choose will depend, of course, on your use case, but my advice is that you can't go wrong with &lt;code&gt;big.js&lt;/code&gt;. The API is very nice and its feature set should cover most use cases. You can check it out and, if you need a feature that it doesn't support or if it has some behavior that makes life harder for you, then you can check some of the other ones.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;For example, if you are using 10 significant digits, then &lt;code&gt;Decimal('22222222222222222222').div(2).toFixed(0)&lt;/code&gt; is equal to &lt;code&gt;11111111110000000000&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;I think it has to do with some base inferring, but couldn't find any documentation on this. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>math</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>A Dictionary of Modern Programming Usage</title>
      <dc:creator>Franco Victorio</dc:creator>
      <pubDate>Sat, 16 Mar 2019 15:04:54 +0000</pubDate>
      <link>https://forem.com/fvictorio/a-dictionary-of-modern-programming-usage-4i2d</link>
      <guid>https://forem.com/fvictorio/a-dictionary-of-modern-programming-usage-4i2d</guid>
      <description>&lt;p&gt;You know the &lt;a href="https://martinfowler.com/bliki/TwoHardThings.html"&gt;old saying&lt;/a&gt;: «There are only two hard things in programming: cache invalidation and naming things», or its tongue-in-cheek variant: «There are two hard problems in programming: cache invalidation, naming things, and off-by-1 errors». They are misguiding, though, because naming things is &lt;em&gt;way harder&lt;/em&gt; than the other two problems. Off-by-1 errors are annoying, but they can be solved just by being methodical. Cache invalidation is harder, but at least you have a lot of research around it. But if you are having trouble naming a variable, you are on your own.&lt;/p&gt;

&lt;p&gt;Is there something we can do about this? Does it even make sense to think about doing something? I think it does.&lt;/p&gt;

&lt;p&gt;Choosing the proper words to express an idea is not a new problem. I bet it exists since writing was invented, and maybe even before that. And there are tools meant to help with this, like dictionaries, thesauruses and usage dictionaries. What exactly are usage dictionaries? Well, I just used one to check if it was OK to use "thesauruses". Here's what &lt;a href="https://en.wikipedia.org/wiki/Garner%27s_Modern_English_Usage"&gt;Garner's Modern English Usage&lt;/a&gt; has to say about it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;thesaurus&lt;/strong&gt; (= a book or online resource that supplies synonyms) has long formed the standard plural &lt;em&gt;thesauri&lt;/em&gt;. But since 1960, &lt;em&gt;thesauruses&lt;/em&gt; has climbed in frequency, especially in AmE.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's not a dictionary. Even if it has short definitions, it also —and mainly— offers commentary about the word: how it's used and how it &lt;em&gt;should&lt;/em&gt; be used.&lt;/p&gt;

&lt;p&gt;Should? Who is to say how words should be used? Language is organic, you can't stop it from changing, etc. I'm not going to get into the war between prescriptivists and descriptivists. Suffice it to say that I am on the side of (moderate) prescriptivists. Otherwise I wouldn't consult a usage dictionary in the first place. (If this subject interests you, go read David Foster Wallace's essay "Authority and American Usage"; if it doesn't, go read it anyway: Wallace can make &lt;em&gt;any&lt;/em&gt; subject interesting.)&lt;/p&gt;

&lt;p&gt;Garner's has another usage dictionary called "Garner's Dictionary of Legal Usage", that is limited to the vocabulary and style of legal texts. It makes sense: lawyers have their own dialect, and how they use it is very important.&lt;/p&gt;

&lt;p&gt;Sounds familiar?&lt;/p&gt;

&lt;p&gt;We as programmers have a similar problem. Using a bad name won't affect a trial, but it will hurt maintainability in the long run. Bad names contribute to technical debt and are mentally taxing. How comes, then, that nobody has written a "Dictionary of Modern Programming Usage"?&lt;/p&gt;

&lt;p&gt;Of course, this would get outdated. But so did usage dictionaries from the 1920s. Does that mean they weren't useful when they came out? And yes: programming languages change much faster than natural languages, but I would argue that the way we choose names for variables, functions or classes doesn't change as fast as available syntax features or libraries.&lt;/p&gt;

&lt;p&gt;It's interesting to think about the implementation issues that arise from this idea, the first one being who would write it —or rather, how many people. Can this be a one person job? Or do you need a group of people that come from different backgrounds? Or, going further, maybe this should be a crowdsourced effort, like a wiki?&lt;/p&gt;

&lt;p&gt;Another question is how do you define the scope of such a thing. This would require serious thought, but I think some things can be said for sure. First, you don't get into anything that is already in an English usage dictionary. Second, you don't talk about domain specific things (like networking concepts, for example), since this would make the work impossible and, besides, it wouldn't make sense to talk about the usage of well-defined technical terms.&lt;/p&gt;

&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; in scope then? I can think of some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does &lt;em&gt;qualified&lt;/em&gt; means? How it's different from &lt;em&gt;canonical&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;What's the difference between formatting, serializing, pretty-printing, etc.? (See &lt;a href="https://twitter.com/sebmck/status/1101286535486365696"&gt;this discussion&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;When do you use get, compute, select, fetch?&lt;/li&gt;
&lt;li&gt;There are a lot of words for (what I call) maps: maps, dictionaries, associative arrays, hashes (a perl/ruby monstrosity). Can they be differentiated or it just depends on the programming language?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point takes us to the third question: should this hypothetical dictionary be specific to some programming language? I'm inclined to say no, since I feel most things would be language-agnostic. But some terms should include clarifications on their different usages among languages.&lt;/p&gt;

&lt;p&gt;There's something that should make a project like this easier, or at least more interesting and valuable. The fourth edition of Garner's Dictionary takes advantage of a tool that wasn't available when its previous editions came out: the &lt;a href="https://books.google.com/ngrams"&gt;Google Ngram Viewer&lt;/a&gt;. You can imagine how useful this can be for a lexicographer.&lt;/p&gt;

&lt;p&gt;Something similar could be used for a programming usage dictionary. For starters, we have GitHub, where we can search any term across millions of repositories. But more complex things could be done. You could use parsers to get the names of every defined function. How many of them start with &lt;code&gt;compute&lt;/code&gt;? And then you could sample some of them, or the ones from the most famous projects, to get a better understanding of how they are used and why they are named that way. Again, this runs into the issue of which subset of the existing programming languages should you use. But you can start small, with two or three of the most prevalent ones, and work your way from there.&lt;/p&gt;

&lt;p&gt;This doesn't mean that the effort could be automated, not even close. A project like this would require a lot of reading and exploring. But open source and tools that analyze code could amplify the work of programming lexicographers and give more certainty to their judgements.&lt;/p&gt;

&lt;p&gt;I'm not aware of the existence of something like this, nor of someone working on it. Maybe it wouldn't be as useful as it seems to me, or maybe the necessary effort is just too large. I don't know. At the very least, I think it would be worth the shot.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published in &lt;a href="https://buttondown.email/fvictorio/archive/c1b11753-62be-41f5-9ace-275a47f7e1f9"&gt;my newsletter&lt;/a&gt;. You can subscribe &lt;a href="https://buttondown.email/fvictorio"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to write a plugin for Prettier</title>
      <dc:creator>Franco Victorio</dc:creator>
      <pubDate>Wed, 13 Mar 2019 22:50:49 +0000</pubDate>
      <link>https://forem.com/fvictorio/how-to-write-a-plugin-for-prettier-6gi</link>
      <guid>https://forem.com/fvictorio/how-to-write-a-plugin-for-prettier-6gi</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted &lt;a href="https://medium.com/@fvictorio/how-to-write-a-plugin-for-prettier-a0d98c845e70"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post I will show you how to build a very simple plugin for &lt;a href="https://prettier.io/"&gt;Prettier&lt;/a&gt;. You will learn how to structure, test and, of course, write a plugin. I'm far from being an expert on this, but I learned a lot by contributing to the &lt;a href="https://github.com/prettier-solidity/prettier-plugin-solidity/"&gt;Solidity plugin&lt;/a&gt;, and noticed that there doesn't seem to be a lot of material on this subject, except for the official documentation.&lt;/p&gt;

&lt;p&gt;We'll be using &lt;a href="https://github.com/toml-lang/toml"&gt;TOML&lt;/a&gt; as the example language. I chose TOML because it has an easy syntax and, as far as I know, there's no Prettier plugin for it. The result won't be a usable plugin, as you'll see, but with any luck you will learn enough to develop a proper one.&lt;/p&gt;

&lt;p&gt;Why would you want to learn this? Well, there are two strong reasons. First, you'll be able to create a plugin for any language that is not supported yet (like TOML and Dockerfile, but there probably are many others). And second, you'll be able to contribute to one of the &lt;a href="https://prettier.io/docs/en/plugins.html#official-plugins"&gt;existing plugins&lt;/a&gt;. Moreover, since the core of Prettier itself is written using the plugin API, you could even contribute to the main repository if you wanted to.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Prettier works?
&lt;/h2&gt;

&lt;p&gt;At its core, what Prettier does is very simple: it takes some code (a string), converts it to an AST (Abstract Syntax Tree, a representation of the code) and then prints the code using only the AST. That means that the style of the original code is (almost) completely ignored. You can learn more in the &lt;a href="https://jlongster.com/A-Prettier-Formatter"&gt;original blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For our purposes, the important part is that we need a parser that transforms the code to an AST, and a function that takes this and pretty-prints it. Our initial setup already has a configured parser, using toml-node, so we only need to worry about the printer function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First we'll clone &lt;a href="https://github.com/fvictorio/prettier-plugin-toml"&gt;this repository&lt;/a&gt; that has all the boilerplate you'll need to start. I'll explain its contents soon. After cloning it, go the top level directory and run &lt;code&gt;npm install&lt;/code&gt; to install the dependencies. You should now be able to run the plugin in the example file (&lt;code&gt;example.toml&lt;/code&gt;) with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./node_modules/.bin/prettier --plugin . example.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also a npm script for this, so &lt;code&gt;npm run example&lt;/code&gt; should work too, but this shows how to run the plugin in any file you want.&lt;/p&gt;

&lt;p&gt;After running the command, you won't see any output, and that's OK. For now, our plugin doesn't emit anything: when the printer function receives the AST, it just returns an empty string.&lt;/p&gt;

&lt;p&gt;There's also an initial test that you can run with &lt;code&gt;npm test&lt;/code&gt;. Our tests will be written in jest, using &lt;a href="https://jestjs.io/docs/en/snapshot-testing"&gt;snapshots&lt;/a&gt;, but since the setup is already there the only thing you have to do is to add new fixtures. This initial test will format the contents of &lt;code&gt;tests/StringAssignements/example.toml&lt;/code&gt; and compare the result with the expected output in the snapshot. All of our tests will be like this one: a TOML file and a snapshot with the correct format. This test will fail, of course, but our first goal is to make it pass.&lt;/p&gt;

&lt;p&gt;All the code we'll write will be in the &lt;code&gt;src/index.js&lt;/code&gt; file. In fact, everything will be inside a single function: &lt;code&gt;printToml&lt;/code&gt;. You can take a look at the rest of the file, but don't worry about the details. If you are curious, it's all explained &lt;a href="https://github.com/prettier/prettier/blob/master/docs/plugins.md#developing-plugins"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want to read the finished code instead of writing it, just checkout the &lt;code&gt;finished&lt;/code&gt; branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The printer function
&lt;/h2&gt;

&lt;p&gt;The printToml function is very simple. It takes three arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;path&lt;/code&gt;, that represents a node in the AST&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt;, that represents the configuration given to prettier (the combination of &lt;code&gt;.prettierrc&lt;/code&gt; and the flags given to the command, among other things)&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;print&lt;/code&gt;, that is how we call the printer function recursively&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that I said that &lt;code&gt;path&lt;/code&gt; is &lt;strong&gt;some&lt;/strong&gt; node in the AST, not the root. That's because the function is called recursively. For example, if I have the body of a function, I may want to pretty-print each individual statement separately and then do something with this result. This will become clearer as we continue.&lt;/p&gt;

&lt;p&gt;This is the boilerplate of our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;printToml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line just extracts the AST node from the &lt;code&gt;path&lt;/code&gt;. This is because &lt;code&gt;path&lt;/code&gt; has some extra information and logic related to the AST node.&lt;/p&gt;

&lt;p&gt;Then we have a strange block that checks if the node is an array. This will only be necessary in the initial call, because the parser that we are using represents the code as a list of nodes, not as a tree of nodes. Don't worry about this, but keep it in mind, because later this will impose some serious limitations to our plugin.&lt;/p&gt;

&lt;p&gt;Finally, we have the switch. Here's where we'll spend most of our time. The logic we have is very simple: we check the type of the AST node and act accordingly. Let's start to fill it in.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple assignement
&lt;/h2&gt;

&lt;p&gt;If you take a look at our test, you'll see that it contains two key/value pairs. The node that represents the first pair is something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  type: 'Assign',
  value: {
    type: 'String',
    value: 'TOML Example',
    line: 1,
    column: 9
  },
  line: 1,
  column: 1,
  key: 'title'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(How do we know this? There are a lot of ways of obtaining it: a good old &lt;code&gt;console.log&lt;/code&gt;, using the parser in the node REPL, or running the plugin using &lt;a href="https://github.com/GoogleChromeLabs/ndb"&gt;ndb&lt;/a&gt; and inspecting the value.)&lt;/p&gt;

&lt;p&gt;There are two interesting things here. First, the &lt;code&gt;type&lt;/code&gt; property, that is what we use in our switch. The second one is that, while the &lt;code&gt;key&lt;/code&gt; of our pair is a simple string, &lt;em&gt;our value is another AST node&lt;/em&gt;, whose type is &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the first thing we'll do is to add a clause for &lt;code&gt;Assign&lt;/code&gt; nodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Assign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; = &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;hardline&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot to unpack here, but the main idea is easy to grasp: we are telling prettier that an assignment is printed by concatenating four things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The key. Remember that this is just a plain string&lt;/li&gt;
&lt;li&gt;A literal equal sign, padded with spaces&lt;/li&gt;
&lt;li&gt;The result of pretty-printing the value of the assignment, whatever that is&lt;/li&gt;
&lt;li&gt;And a &lt;code&gt;hardline&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What are &lt;code&gt;concat&lt;/code&gt; and &lt;code&gt;hardline&lt;/code&gt;? They are called &lt;strong&gt;builders&lt;/strong&gt;, and they are functions and values -exposed by Prettier- that we use to build the result we want. We already have imported &lt;code&gt;concat&lt;/code&gt;, but we need to add &lt;code&gt;hardline&lt;/code&gt; to the list of builders we are using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;builders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hardline&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prettier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;concat&lt;/code&gt; builder is easy to understand: it tells prettier to just concatenate the list of parts it's given. And &lt;code&gt;hardline&lt;/code&gt; just means "put a line break", no matter what. You can see the full list of builders &lt;a href="https://github.com/prettier/prettier/blob/master/commands.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What about the &lt;code&gt;path.call(print, 'value')&lt;/code&gt; part? This is a prettier idiom and it just means "call the printer function recursively, using the node that is in the &lt;code&gt;'value'&lt;/code&gt; key". Why can't we just do &lt;code&gt;print(node.value)&lt;/code&gt;? Well, remember that the printer function expects a path, that is, a wrapped node, not a node. So you have to do it like this.&lt;/p&gt;

&lt;p&gt;If we add just this and run our test, it will fail. The diff tells us that the keys and the equal sign were printed, but not the value. This makes sense, since the values are nodes of type &lt;code&gt;String&lt;/code&gt; and we don't have a clause for that yet. Fortunately, that clause is very simple. Take a look at the AST sub-node again and see if you can guess it.&lt;/p&gt;

&lt;p&gt;Yes, it's that easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may have guessed just &lt;code&gt;return node.value&lt;/code&gt;, but that would've been wrong, because in that case we would be printing just the content of the string, not the full string. For example, &lt;code&gt;foo = "bar"&lt;/code&gt; would've been printed as &lt;code&gt;foo = bar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we run our test again, it should pass now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding support for other values
&lt;/h2&gt;

&lt;p&gt;TOML supports other data types besides strings, and we should support them too. If you look at the example in the root directory, you'll see that it has numbers, booleans, dates, and lists.&lt;/p&gt;

&lt;p&gt;Numbers and booleans are easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Integer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have to convert them to strings, because that's what prettier expects, but that's it.&lt;/p&gt;

&lt;p&gt;Dates are a little trickier and here we'll run into the first limitation of the parser we are using. Here's the AST representation of a date assignment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  type: 'Assign',
  value: {
    type: 'Date',
    value: 1979-05-27T15:32:00.000Z,
    line: 5,
    column: 7
  },
  line: 5,
  column: 1,
  key: 'dob'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the value of the date. That is a &lt;code&gt;Date&lt;/code&gt; object, a unique representation of a date. But if you take a look at the &lt;a href="https://github.com/toml-lang/toml"&gt;TOML spec&lt;/a&gt;, you'll see that you can specify dates in many different formats. That is lost to us during parsing, so we'll always print dates with the same representation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's not nice at all! But to do it properly, we should know the original representation of the date. We could get it using the position of the node and the original text (that we receive in &lt;code&gt;options.originalText&lt;/code&gt;), but it would be even better to have a parser that keeps the original value in the AST. Since our parser doesn't do this, we'll have to settle for this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tables
&lt;/h2&gt;

&lt;p&gt;In TOML, we can separate different sections with what the spec calls "Tables", but our parser assigns the type &lt;code&gt;ObjectPath&lt;/code&gt;. An AST node looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  type: 'ObjectPath',
  value: [ 'owner' ],
  line: 3,
  column: 1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the value of the node is not a string but an array. This is because we can have nested sections like &lt;code&gt;[servers.alpha]&lt;/code&gt;. We print this with the following clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ObjectPath&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hardline&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing new here. We join each part of the value with a period and surround everything with square brackets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrays
&lt;/h2&gt;

&lt;p&gt;So far, everything we've done has been very straightforward. Arrays are a little more complex, and we'll have to make some decisions. There are several ways in which an array can be printed, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr1 = [1, 2, 3]
arr2 = [ 1, 2, 3 ]
arr3 = [1,2,3]
arr4 = [
  1,
  2,
  3
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what prettier usually does in situations like this: if the array fits in one line, print it in one line. Otherwise, print everything on its own line. So we'll do the &lt;code&gt;arr1&lt;/code&gt; approach when the array fits, and we'll print something like &lt;code&gt;arr4&lt;/code&gt; when it doesn't.&lt;/p&gt;

&lt;p&gt;That seems hard, doesn't it? But prettier can help us. This is the clause that does what we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Array&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
          &lt;span class="nx"&gt;softline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;softline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know this is quite a jump from what we've been doing so far. And the bad news is that a lot of plugin code looks somewhat like this. The good news is that you get used to it quickly.&lt;/p&gt;

&lt;p&gt;Let's start from the innermost part of that expression and work our way out.&lt;/p&gt;

&lt;p&gt;First we have a &lt;code&gt;path.map(print, 'value')&lt;/code&gt; expression. This is similar to the &lt;code&gt;path.call&lt;/code&gt; idiom we discussed before, but here we are saying "in the &lt;code&gt;value&lt;/code&gt; key of this node I have an array of sub-nodes; call the printer function on each one and give me an array with the results". In other words, it's like doing &lt;code&gt;node.value.map(print)&lt;/code&gt;, but remember that we can't do that.&lt;/p&gt;

&lt;p&gt;So we have an array with the result of pretty-printing each element in our list. The next step is adding our commas. We use the &lt;code&gt;join&lt;/code&gt; builder for that. Its signature is &lt;code&gt;join(separator, list)&lt;/code&gt;, and it just joins the list of parts with the given separator. For example, &lt;code&gt;concat(["1", ",", "2", ",", "3"])&lt;/code&gt; is equivalent to &lt;code&gt;join(",", ["1", "2", "3"])&lt;/code&gt;. And we could do that here, right? Just &lt;code&gt;join(",", path.map(print, 'value'))&lt;/code&gt;. But we want to have a space after the comma when the list fits in one line, and a line break when we split it. That is done with the &lt;code&gt;line&lt;/code&gt; builder, and that why we join by &lt;code&gt;concat([",", line])&lt;/code&gt;. The documentation is clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Specify a line break. If an expression fits on one line, the line break will be replaced with a space. Line breaks always indent the next line with the current level of indentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we print each value separated by a comma and a space if the list fits in one line, and we replace the spaces with line breaks if it doesn't fit. We should be ready, right? Just add the opening and closing square brackets and be done with it. Well, no. Because we want to indent each element of the list when we split it.&lt;/p&gt;

&lt;p&gt;We do that by surrounding what we have done so far with &lt;code&gt;indent(concat([softline, ...]))&lt;/code&gt;. What is going on here? First we put a &lt;code&gt;softline&lt;/code&gt; at the beginning of the list. &lt;code&gt;softline&lt;/code&gt; is very similar to &lt;code&gt;line&lt;/code&gt;, but the difference is that, if everything fits in one line, &lt;code&gt;softline&lt;/code&gt; is replaced with an empty string. We also use the &lt;code&gt;indent&lt;/code&gt; builder, that just increases the indentation. When everything fits in one line, we won't have line breaks, so &lt;code&gt;indent&lt;/code&gt; won't do anything.&lt;/p&gt;

&lt;p&gt;Almost there! After that, we surround everything with &lt;code&gt;concat('[', ..., softline, ']')&lt;/code&gt;. We are just adding the brackets. We also add a &lt;code&gt;softline&lt;/code&gt; before the closing bracket, and since it's outside the &lt;code&gt;indent&lt;/code&gt; builder, the &lt;code&gt;]&lt;/code&gt; will have the same indentation we started with. Otherwise our lists would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arr = [TOML spec
  1,
  2
  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;strong&gt;finally&lt;/strong&gt; we surround everything with a call to &lt;code&gt;group&lt;/code&gt;. This is a builder that tries to fit everything inside it in one line. If it doesn't, it will start replacing lines and softlines with line breaks. It's actually a little more complex, but that explanation will do for now. Check the documentation to see the nuances of it.&lt;/p&gt;

&lt;p&gt;Again, this seems hard, but you'll get it quickly when you start playing with prettier. All of this also shows how powerful prettier is, if you think about it. We've used just a few building blocks to pretty-print any list. In fact, this will work even with nested list, no matter how deep they are!&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside: How to experiment
&lt;/h2&gt;

&lt;p&gt;How can you check how builders interact, besides reading the documentation and running your full plugin with some examples? It turns out you can use the node REPL to interact with prettier. First start the REPL and import some stuff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; const prettier = require('prettier')
&amp;gt; const print = prettier.doc.printer.printDocToString
&amp;gt; const { concat, group, join, line, softline } = prettier.doc.builders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you can experiment with the builders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print(concat(['foo', 'bar', 'baz']), {})
{ formatted: 'foobarbaz' }
&amp;gt; print(join('|', ['foo', 'bar', 'baz']), {})
{ formatted: 'foo|bar|baz' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test things like group, you'll need to specify a printWidth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; print(group(join(line, ['foo', 'bar', 'baz', 'qux'])), { printWidth: 20 })
{ formatted: 'foo bar baz qux' }
&amp;gt; print(group(join(line, ['foo', 'bar', 'baz', 'qux'])), { printWidth: 10 })
{ formatted: 'foo\nbar\nbaz\nqux' }
&amp;gt; print(group(join(softline, ['foo', 'bar', 'baz', 'qux'])), { printWidth: 20 })
{ formatted: 'foobarbazqux' }
&amp;gt; print(group(join(softline, ['foo', 'bar', 'baz', 'qux'])), { printWidth: 10 })
{ formatted: 'foo\nbar\nbaz\nqux' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn this way. I know it's not a great user experience, and it would be nice to have something better (maybe a web playground where you can run expressions like this and see the result with different inputs?), but I'm not aware of anything better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pending things
&lt;/h2&gt;

&lt;p&gt;If we run our example again, we'll see that we have an equivalent TOML printed as we specified it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; prettier-plugin-toml@0.0.1 example /home/fvictorio/repos/prettier-plugin-toml
&amp;gt; prettier --plugin . example.toml
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T15:32:00.000Z
[database]
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true
[servers]
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [["gamma", "delta"], [1, 2]]
hosts = ["alpha", "omega"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it would be hard to argue that this is prettier. There are too very important things we are not doing, and that we can't do easily with the parser we are using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are not preserving &lt;strong&gt;blank lines&lt;/strong&gt;. Prettier's philosophy is to keep them (although if there are two or more blank lines together, they are replaced by a single blank line). This can be done, but to do that we need an easy way to get the start and end indices of the node. As you see in the nodes examples, we only have the starting line and column.&lt;/li&gt;
&lt;li&gt;We are not &lt;strong&gt;indenting the tables&lt;/strong&gt;. This would be relatively easy if the representation of the AST would be a proper tree, but remember that we have instead a list of nodes for each line. If under the table objects we'd have a, say, "children" key, we could do something like &lt;code&gt;path.map(print, 'children')&lt;/code&gt;, join that by hardlines and indent them, for example.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Hopefully you learned enough to start your own plugin or contribute to one. Take a look at the &lt;a href="https://prettier.io/docs/en/plugins.html#official-plugins"&gt;list of plugins&lt;/a&gt;: if the language you would like to see prettified isn't there, you can create your own! And if it is, you can jump on and contribute.&lt;/p&gt;

&lt;p&gt;A nice thing about prettier plugins is that it's very easy to do TDD with them. If you want to contribute to a plugin, just add a fixture with an example that it's not working and try to make all tests pass. If you are creating a new plugin you can start small: add tests with some simple examples using a subset of the syntax and make them prettier!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>prettier</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
