<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="217081" data-post-id="217081">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dorgan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/120/22107_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dorgan
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sourceror 0.7.0 is out <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>This release adds a zipper API to improve the ergonomics of navigating and modifying the Elixir AST at will.</p>
<p>I added an introduction livebook to zippers: <a href="https://github.com/doorgan/sourceror/blob/main/notebooks/zippers.livemd" class="inline-onebox" rel="noopener nofollow ugc">sourceror/notebooks/zippers.livemd at main · doorgan/sourceror · GitHub</a></p>
<p>With this API, removing nodes or adding siblings is a straghtforward task in contrast with <code>Macro.postwalk</code>/<code>Macro.prewalk</code>. The livebook for the multi alias expansion demo was also updated with a new chapter that uses the zipper api to simplify the code.</p>
<p>It’s worth noting that it’s not a Sourceror specific implementation, it works for <em>any</em> Elixir AST. If you find yourself in the need of a zipper for your macros, Sourceror can help there too <img src="https://forum.elixirforum.com/images/emoji/apple/slightly_smiling_face.png?v=15" title=":slightly_smiling_face:" class="emoji" alt=":slightly_smiling_face:" loading="lazy" width="20" height="20"></p>
<p><strong>Changelog:</strong></p>
<p><strong>1. Enhancements</strong></p>
<ul>
<li>[Sourceror.Zipper] - Added a Zipper implementation for the Elixir AST based<br>
on <a href="https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf" rel="noopener nofollow ugc">Huet</a>’s paper.</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="217081" data-batch-url="/posts/batch_likers">
                        6
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/sourceror-utilities-to-work-with-elixir-source-code/40003/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-217081" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="217081"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="218199" data-post-id="218199">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dorgan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/120/22107_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dorgan
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sourceror 0.8.0 is out <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>This one is a bit small, just bug fixes and the addition of <a href="https://hexdocs.pm/sourceror/Sourceror.html#patch_string/2" rel="noopener nofollow ugc"><code>Sourceror.patch_string/2</code></a> which allows you to modify just some parts of a string, instead of having to print the whole tree. It receives the original string and a list of patches to be applied.</p>
<p>A patch is just a map with a <code>:range</code> pointing to the start and end positions to be replaced, and a <code>:change</code> that can be either a string, in which case the range will be replaced with it, or a function that accepts the original code in that range, and returns the string that replaces it.</p>
<p>This allows you to perform more fine grained changes to the source code, as you can use <code>Sourceror.get_range/1</code> in combination with a traversal to generate the patches.</p>
<p>Also, now <code>Sourceror.to_string/2</code> can receive a <code>format: :splicing</code> option that makes it easier to print elements of a keyword list without having to string the brackets yourself.</p>
<p>To illustrate these changes, here’s how a transformation for the Surface converter that renames the slot <code>props: ...</code> to <code>args: ...</code> would look like (from a discussion in the <a href="https://github.com/doorgan/sourceror/issues/13#issuecomment-865429036" rel="noopener nofollow ugc">issue tracker</a>):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Mix.install([{:sourceror, "~&gt; 0.8"}])

code = """
defmodule Card do
  use Surface.Component

  slot footer
  slot header, props: [:item]
  slot default, required: true, props: [:item]
end
"""

{_, patches} =
  code
  |&gt; Sourceror.parse_string!()
  |&gt; Sourceror.postwalk([], fn
    {:slot, _, args} = quoted, state -&gt;
      opts_node = Enum.at(args, 1, [])
      props_node = Enum.find(opts_node, &amp;match?({{:__block__, _, [:props]}, _}, &amp;1))

      if props_node do
        range = Sourceror.get_range(props_node)
        {{:__block__, meta, [:props]}, body} = props_node
        args_node = {{:__block__, meta, [:args]}, body}
        new_code = Sourceror.to_string([args_node], format: :splicing)
        patch = %{change: new_code, range: range}

        {quoted, %{state | acc: [patch | state.acc]}}
      else
        {quoted, state}
      end

    quoted, state -&gt;
      {quoted, state}
  end)

code
|&gt; Sourceror.patch_string(patches)
|&gt; IO.puts
</code></pre>
<p>The next versions will be focused on exploring ways to make it easier to create the patches, and to make the apis more stable <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p><strong>Changelog:</strong></p>
<p><strong>1. Enhancements</strong></p>
<ul>
<li>[Sourceror] Added <code>Sourceror.patch_string/2</code></li>
<li>[Sourceror] Added the <code>format: :splicing</code> option to <code>Sourceror.to_string/2</code></li>
</ul>
<p><strong>2. Bug fixes</strong></p>
<ul>
<li>[Sourceror] Now <code>Sourceror.to_string/2</code> won’t produce invalid Elixir code when a keyword list element is at the beginning of a non-keyword list.</li>
<li>[Sourceror] Now <code>Sourceror.get_range/1</code> will take the leading comments into account when calculating the range.</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218199" data-batch-url="/posts/batch_likers">
                        6
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/sourceror-utilities-to-work-with-elixir-source-code/40003/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-218199" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218199"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="234110" data-post-id="234110">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dorgan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/120/22107_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dorgan
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I finally got some time work on Sourceror, and there have been a bunch of bug fixes, and a new 0.9 version! Thanks to the folks that helped to test and iron out issues in both my comments syncer and Elixir 1.13 release candidate <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>There are some slight changes to the API, and more functionality is exposed. Also, the notebooks are now available as guide pages in <a href="https://hexdocs.pm/sourceror/zippers.html#content" rel="noopener nofollow ugc">hexdocs</a>.</p>
<h2><a name="p-234110-v090-1" class="anchor" href="#p-234110-v090-1" aria-label="Heading link" rel="nofollow"></a>v0.9.0</h2>
<h3><a name="p-234110-h-1-enhancements-2" class="anchor" href="#p-234110-h-1-enhancements-2" aria-label="Heading link" rel="nofollow"></a>1. Enhancements</h3>
<ul>
<li>[Sourceror] <code>to_string/2</code> now supports options for <code>Code.quoted_to_algebra</code>, like <code>locals_without_parens</code></li>
<li>[Sourceror] <code>get_range/2</code> no longer considers comments when calculating the range. This can be enabled by passing the <code>include_comments: true</code> option</li>
<li>[Sourceror.Patch] Introduced <code>Sourceror.Patch</code> with utilities to generate patches for the most common rewriting operations</li>
<li>[Sourceror.Identifier] <code>Sourceror.Identifier</code> is now public</li>
</ul>
<h2><a name="p-234110-v08x-summary-of-bug-fixes-3" class="anchor" href="#p-234110-v08x-summary-of-bug-fixes-3" aria-label="Heading link" rel="nofollow"></a>v0.8.x summary of bug fixes</h2>
<ul>
<li>[Sourceror] Fixed comment spacing on binary operators</li>
<li>[Sourceror] Take comment end of line counts into account to preserve spacing</li>
<li>[Sourceror] Fixed an issue that caused comments in lists to be misplaced</li>
<li>[Sourceror] Fixed issues that caused comments to be misplaced.</li>
<li>[Sourceror] Updated internal normalizer to match latest Elixir 1.13 version.</li>
<li>[Sourceror] Fixed an issue that caused newlines to be wrongly removed.</li>
<li>[Sourceror] Fixed an issue that caused comments in pipelines to be misplaced.</li>
<li>[Sourceror] Fixed issue that prevented keyword lists from preserving their<br>
original format in tuples.</li>
<li>[Sourceror] <code>get_range/1</code> now properly handles naked AST lists, like the ones<br>
coming from partial keyword lists, or stabs like <code>a -&gt; b</code>.</li>
<li>[Sourceror] <code>get_range/1</code> now handles partial keyword list syntax instead of<br>
crashing.</li>
<li>[Sourceror.Zipper] <code>down/1</code> now correctly uses <code>nil</code> as the right siblings if<br>
the branch node has a single child.</li>
<li>[Sourceror] <code>Sourceror.get_range/1</code> now correctly calculates the range when<br>
there is a comment in the same line as the node.</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="234110" data-batch-url="/posts/batch_likers">
                        7
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/sourceror-utilities-to-work-with-elixir-source-code/40003/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-234110" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="234110"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-most-liked cat-most-liked" title="One of the top 3 liked posts in this thread!"></div>
  </section>
</div>
    <div class="postbit" id="277233" data-post-id="277233">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dorgan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dorgan/120/22107_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dorgan
                      <span class="op-star" title="Thread Starter">
                        <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                      </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sourceror v0.12.0 is out!</p>
<p>It’s a small release, but it includes some small yet potentially breaking changes that warranted an increase in the minor version nubmer.</p>
<h2><a name="p-277233-h-1-bug-fixes-1" class="anchor" href="#p-277233-h-1-bug-fixes-1" aria-label="Heading link" rel="nofollow"></a>1. Bug fixes</h2>
<ul>
<li>[Sourceror] <code>Sourceror.patch_string</code> now produces better results when patching a single line with a multiline replacement</li>
<li>[Sourceror.Zipper] the concept of an “ended” zipper was removed, so now you can traverse the same zipper multiple times without having to manualy reset it</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="277233" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/sourceror-utilities-to-work-with-elixir-source-code/40003/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-277233" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="277233"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>