<?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>DEV Community: Eugene Chernyshov</title>
    <description>The latest articles on DEV Community by Eugene Chernyshov (@evgenus).</description>
    <link>https://dev.to/evgenus</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%2F616852%2F4c99149e-c9ee-4b8c-94a4-2d6285359fc1.jpeg</url>
      <title>DEV Community: Eugene Chernyshov</title>
      <link>https://dev.to/evgenus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/evgenus"/>
    <language>en</language>
    <item>
      <title>Analyzing AST in Go with JSON tools</title>
      <dc:creator>Eugene Chernyshov</dc:creator>
      <pubDate>Mon, 05 Sep 2022 19:10:35 +0000</pubDate>
      <link>https://dev.to/evgenus/analyzing-ast-in-go-with-json-tools-36dg</link>
      <guid>https://dev.to/evgenus/analyzing-ast-in-go-with-json-tools-36dg</guid>
      <description>&lt;p&gt;There are many specific tasks that could significantly improve and automate your ongoing maintenance of big-project. Some of them require building tools that can analyze or change source code created by developers. &lt;/p&gt;

&lt;p&gt;For example, such tools could be: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gathering metadata from comments,&lt;/li&gt;
&lt;li&gt;gathering strings that need to be translated,&lt;/li&gt;
&lt;li&gt;understanding the structure of the code to calculate some complexity metrics or build explanatory diagrams,&lt;/li&gt;
&lt;li&gt;or even apply some automatic code optimization and refactoring patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Solving such tasks seems to lead us to complicated topics of compilers and parsers. But in 2022 every modern programming language comes with batteries included. The structure of code in form of AST that is ready to be searched and manipulated is presented as a built-in library. Basically, parsing files with code and searching for specific things is not much harder as do the same for JSON or XML.&lt;/p&gt;

&lt;p&gt;In this article, we will cover AST analysis in Go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Existing approaches
&lt;/h2&gt;

&lt;p&gt;In golang there is a standard package &lt;code&gt;ast&lt;/code&gt; that provides structs of AST nodes and functions for parsing source files. It is quite easy and straightforward for experienced go developers to write code for the tool. Also, there is &lt;code&gt;printer&lt;/code&gt; package that can convert AST back into source code. &lt;/p&gt;

&lt;p&gt;Here is a list of articles describing how to manipulate AST in golang:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zupzup.org/go-ast-traversal/"&gt;Basic AST Traversal in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/swlh/cool-stuff-with-gos-ast-package-pt-1-981460cddcd7"&gt;Cool Stuff With Go’s AST Package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.mattermost.com/blog/instrumenting-go-code-via-ast/"&gt;Instrumenting Go Code via AST&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://eli.thegreenplace.net/2021/rewriting-go-source-code-with-ast-tooling/"&gt;Rewriting Go source code with AST tooling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One small aspect, you need to know the structure of golang AST. For me, when I first dive into the topic, the problem was to understand how nodes are combined together and figure out what exactly I need to search in terms of node structure. Of course, you can print AST using built-in capabilities. You will get output in some strange format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="mi"&gt;0&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;Package&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ident&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;3&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;NamePos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;
   &lt;span class="mi"&gt;4&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"main"&lt;/span&gt;
   &lt;span class="mi"&gt;5&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="mi"&gt;6&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;Decls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decl&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;7&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="p"&gt;.&lt;/span&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenDecl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="mi"&gt;8&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="n"&gt;TokPos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="mi"&gt;9&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="n"&gt;Tok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;
  &lt;span class="mi"&gt;10&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="n"&gt;Lparen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, since the format is very specific, you can’t use any tools to navigate it, except text search. Tools like &lt;a href="https://github.com/yuroyoro/goast-viewer"&gt;goast-viewer&lt;/a&gt; can help with this, but capabilities are limited.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KxGw7sq8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6hqdepvg1761f4rvpts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KxGw7sq8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6hqdepvg1761f4rvpts.png" alt="goast-viewer example" width="880" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposed solution
&lt;/h2&gt;

&lt;p&gt;I started thinking of the library that would allow us to convert AST into some very conventional format like JSON. JSON is easy to manipulate, and many tools (like &lt;a href="https://stedolan.github.io/jq/"&gt;jq&lt;/a&gt;) and approaches exist to search and modify JSON. &lt;/p&gt;

&lt;p&gt;So, what I end up with is &lt;a href="https://github.com/asty-org/asty"&gt;asty&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Asty is a small library written in go that allows parsing source code and presenting it in JSON structure. But, moreover, it allows also to do the reverse conversion. It means that now you can manipulate go code with a tool or algorithm developed with any programming language.&lt;/p&gt;

&lt;p&gt;You can use it as go package, as a standalone executable, or even as a docker container. Try &lt;a href="https://asty-org.github.io/"&gt;this page&lt;/a&gt; to experiment with asty in web assembly.&lt;/p&gt;

&lt;p&gt;Example go code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&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;Example JSON output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"File"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ident"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Decls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GenDecl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Tok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"import"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Specs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ImportSpec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BasicLit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STRING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;fmt&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FuncDecl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Recv"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ident"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FuncType"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"TypeParams"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FieldList"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"List"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BlockStmt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"List"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ExprStmt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CallExpr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Fun"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SelectorExpr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ident"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fmt"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Sel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ident"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Println"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"NodeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BasicLit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"Kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STRING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;hello world&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;asty is also capable to output comments, positions of tokens in original source, and reference ids. In some places, AST of go is not actually a tree but rather a DAG. So nodes may have the same ids specified in JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development principles and constraints
&lt;/h2&gt;

&lt;p&gt;In the development of asty I tried to follow some rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make JSON output as close to real golang structures as possible. There is no additional logic introduced. No normalization. No reinterpretation. The only things that were introduced are the names of some enum values. Even names of fields are preserved in the same way they exist in go &lt;code&gt;ast&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;Make it very explicit. No reflection. No listing of fields. This is done to facilitate future maintenance. If something will be changed in future versions of golang this code will probably break compile time. Literally, asty contains 2 copies for each AST node struct to define marshaling and unmarshaling of JSON.&lt;/li&gt;
&lt;li&gt;Keep polymorphism in JSON structure. If some field references an &lt;em&gt;expression&lt;/em&gt; then a particular type will be discriminated from the object type name stored in a separate field &lt;code&gt;NodeType&lt;/code&gt;. It is tricky to achieve so if you want something like this for other tasks I would recommend checking out this example &lt;a href="https://github.com/karaatanassov/go_polymorphic_json"&gt;https://github.com/karaatanassov/go_polymorphic_json&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other solutions
&lt;/h2&gt;

&lt;p&gt;I looked hard for existing implementations of this approach. Unfortunately, not much to be found. &lt;/p&gt;

&lt;p&gt;One project &lt;a href="https://github.com/ReconfigureIO/goblin"&gt;goblin&lt;/a&gt;, which I tried to use for a while, is quite good and mature, but it misses support of backward conversion from JSON to AST. It tries to reinterpret some structures in AST to (I guess) simplify and make them more human-readable. My personal opinion - it is not good. But the main issue with it is lack of maintenance. It was developed a long time ago for version 1.16 and was not updated since then. However, you can find a fork of it relatively up to date.&lt;/p&gt;

&lt;p&gt;Another project &lt;a href="https://github.com/CreativeInquiry/go2json"&gt;go2json&lt;/a&gt;, generates JSON from go code. Also missing the backward conversion and poorly maintained. And it is implemented as a standalone parser with javascript. I think in this way it is very hard to maintain and keep it up with new features in golang.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further work
&lt;/h2&gt;

&lt;p&gt;I am looking for cooperation with other developers interested in language tools development. Meanwhile, you can check &lt;a href="https://github.com/asty-org/asty-python"&gt;another repository&lt;/a&gt; with examples where I experiment with AST JSON in python.&lt;/p&gt;

</description>
      <category>go</category>
      <category>language</category>
      <category>compiler</category>
      <category>ast</category>
    </item>
    <item>
      <title>Calculating Text Width at Server-Side</title>
      <dc:creator>Eugene Chernyshov</dc:creator>
      <pubDate>Mon, 05 Sep 2022 00:20:52 +0000</pubDate>
      <link>https://dev.to/evgenus/calculating-text-width-at-server-side-bmd</link>
      <guid>https://dev.to/evgenus/calculating-text-width-at-server-side-bmd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;How is text width established when content is user-generated and the information is rendered server-side? Let's take a look at text width at the server-side.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Creators of reports and web pages are aware of the importance of readability. Text box width impacts the readability and usability of any web-based experience, but how should a developer establish text width when the content is user-generated and the information is to be delivered server-side?&lt;/p&gt;

&lt;p&gt;Opinion on the ideal line length and text box width differs among designers and developers, and the ideal width is further complicated by the array of devices, layouts, and fonts available. &lt;a href="https://baymard.com/blog/line-length-readability"&gt;Popular guidance&lt;/a&gt; suggests a line length of 45-85 characters, but text box width is not measured by character count alone. Font widths vary widely, and in the user-generated text, the fonts available are practically endless.&lt;/p&gt;

&lt;p&gt;My team ran into this challenge when building a new project with a requirement to support the export of diagrams as images. The product being built provides various sophisticated views on data obtained from many sources and uses the React library for diagram rendering in SVG, which offers excellent capabilities inside the Node.js environment. However, the Node.js runtime does not offer a text renderer and the information about font properties is not easily accessible.&lt;/p&gt;

&lt;p&gt;The project also contains many micro-services for gathering information from a range of sources and in a variety of data formats. Text can be added by the user and the output is sophisticated visualizations that power the entire product. The bottom line is we process the text but do not control it.&lt;/p&gt;

&lt;p&gt;When preparing text width for a browser experience, the browser has capabilities built in to estimate the width of each font and can cut or split text wherever it needs to. The issue is on the server-side, and the development team needed to find or build an instrument that would estimate the font sizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring a Solution
&lt;/h2&gt;

&lt;p&gt;The simplest solution that comes to mind is to create a table with the width of each character and then the width of the text in pixels, which will be a sum of widths for all the characters it contains.&lt;/p&gt;

&lt;p&gt;That’s it! End of story! Well, not exactly.&lt;/p&gt;

&lt;p&gt;Characters in different fonts and font sizes all have different widths. Additional factors like font weight and font presentation, such as the angle of incline when italicized, also impact width. For this specific project, the developers needed to consider the range of character width in different languages, including Cyrillic, Arabic, Latin, Hebrew, Asian, and so forth. This created a much more complex set of requirements for the table-based solution. Also, it is for user-generated text, which will mean the potential for a wide variety of text lengths that must be optimized into the codebase.&lt;/p&gt;

&lt;p&gt;Another requirement of the project is the ability to generate an image that could be exportable in different formats, including presentation software or word processing formats. The product analyzes data using Natural Language Processing (NLP) and Artificial Intelligence (AI), generating diagrams and charts with various filters and queries and customizable by the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text Width Mapping Tool
&lt;/h2&gt;

&lt;p&gt;What we ended up creating took just one weekend. In fact, it is a rather tiny (yet smart) move that really helped solve the challenge. The development team was very collaborative, working off a Kanban board and working each task through until it was complete. The first day was spent building one part of it, and the second day was spent improvising and testing.&lt;/p&gt;

&lt;p&gt;There was &lt;a href="https://github.com/adambisek/string-pixel-width"&gt;one project&lt;/a&gt; on GitHub that was very close to what this project needed, but it lacked some of the customization and flexibility required. Other insights were pulled from suggestions on Q&amp;amp;A forums. As with anything, sometimes you can spend a lot of time trying to struggle with an existing instrument or fix it to make it work for you. In this case, I quickly realized we needed to develop our own solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GEObXtLC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqowtgu3holu0877c4pq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GEObXtLC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqowtgu3holu0877c4pq.jpg" alt="Fonts mapping tool" width="880" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We &lt;a href="https://github.com/Evgenus/js-server-text-width"&gt;created a function&lt;/a&gt; for calculating text width in pixels for server-side rendering. The development built a tool to aid with table generation that would be optimized in the codebase. It started with a single HTML page with vanilla JavaScript. It was not very pretty, but it ran everywhere it needed to and it does the job. In that tool, users can select font, size, weight, presentation, and the set of characters they will use as a Unicode page. With input at the top, users can experiment with characters and test the table. If a character is missing, it will be highlighted with red. In the text area at the very bottom, the result table is generated.&lt;/p&gt;

&lt;p&gt;In font rendering, each character’s width might be fractional, so we decided to store numbers as floats. Numbers are stored in JavaScript in a &lt;a href="https://www.bitdegree.org/learn/javascript-number"&gt;single-precision number&lt;/a&gt;, so to make the code more concise, Base64 was used for encoding for numbers. When encoded, each number is presented with two Base64 characters, one for the integer and one for the fractional.&lt;/p&gt;

&lt;p&gt;In the tool, the table is generated for a single font, size, and weight. When several fonts are used in one project, the user could manage tables by developing a registry of font tables, or by merging them into one dictionary manually. For our project, we did not predefine a solution for simplicity.&lt;/p&gt;

&lt;p&gt;As stated above, visualizations are one of the key features of the product being developed so the impact was immediate. My team was happy because we found a simple and manageable solution and did not overcomplicate it. The product owner was happy because we did exactly what they wanted according to the requirements defined. The project manager was also satisfied that the time estimates were met. Most importantly, potential customers will be happy because it all comes together beautifully inside the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source Solution
&lt;/h2&gt;

&lt;p&gt;As a result, I decided to make this an &lt;a href="https://github.com/Evgenus/js-server-text-width"&gt;open-source project&lt;/a&gt;. Calculating text width could be a part of a lot of different tasks, and if another developer is seeking something like this, I would be happy to know they found it useful. Some aspects of our implementation make it unique, but it is very flexible and could be adapted to the particular needs of another project by simply adjusting the fonts, the sizes, the font weights, and other parameters.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cover image was taken from this &lt;a href="https://www.25yearsofprogramming.com/developing-s60-apps/text-and-font-measurements.html"&gt;page&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>font</category>
      <category>ssr</category>
      <category>measure</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
