<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>REPL adventures</title>
  <link href="https://blog.michielborkent.nl/atom.xml" rel="self"/>
  <link href="https://blog.michielborkent.nl/"/>
  <updated>2026-05-04T12:26:23+00:00</updated>
  <id>https://blog.michielborkent.nl/</id>
  <author>
    <name>Michiel Borkent</name>
  </author>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-mar-apr-2026.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-mar-apr-2026.html"/>
    <title>OSS updates March and April 2026</title>
    <updated>2026-05-04T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during March and April 2026.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babashka</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><h2 id="updates">Updates</h2><h3 id="babashka-conf-and-dutch-clojure-days-2026">Babashka conf and Dutch Clojure Days 2026</h3><p><a href="https://babashka.org/conf/">Babashka Conf 2026</a> is happening on May 8th in the OBA Oosterdok library in Amsterdam! David Nolen, primary maintainer of ClojureScript, will be our keynote speaker. We&apos;re excited to have <a href="https://international.nubank.com.br/careers/">Nubank</a>, <a href="https://www.exoscale.com/jobs/">Exoscale</a>, <a href="https://github.com/bobisageek">Bob</a>, <a href="https://flexiana.com">Flexiana</a> and <a href="https://itonomi.com">Itonomi</a> as sponsors. Nubank and Exoscale are hiring. Wendy Randolph will be our event host. For the schedule and other info, see <a href="https://babashka.org/conf/">babashka.org/conf</a>. Join the babashka-conf Slack channel on Clojurians Slack for last minute communication. The day after babashka conf, <a href="https://clojuredays.org/">Dutch Clojure Days 2026</a> will be happening, so you can enjoy a whole weekend of Clojure in Amsterdam. Hope to see many of you there!</p><h3 id="projects">Projects</h3><p>In the last two months I spent significant time organizing babashka conf, but made progress in several projects as well.</p><p>My upstream work to enable <code>async/await</code> in ClojureScript was merged in the beginning of March. The implementation mirrors squint. Thanks David for reviewing and merging. Also <code>deftest</code> now supports an <code>^:async</code> annotation so you can use <code>async/await</code> and don&apos;t need to mess around with the <code>cljs.test/async</code> macro anymore:</p><ul><li><a href="https://clojure.atlassian.net/browse/CLJS-3470">CLJS-3470</a> <code>async/await</code></li><li><a href="https://clojure.atlassian.net/browse/CLJS-3476">CLJS-3476</a> <code>async deftest</code></li></ul><p>I&apos;ll be presenting this work at the Dutch Clojure Days.</p><p><a href="https://github.com/bhauman/rebel-readline/tree/master/rebel-readline">Rebel-readline</a> is now bb compatible. The work involved mainly exposing more JLine stuff and making sure rebel-readline didn&apos;t hit any internal JLine APIs. One step to drive this to completion was to make a dependency, <a href="https://github.com/alexander-yakushev/compliment/">compliment</a>, bb compatible. Thanks both to Bruce and Alexander for the cooperation.</p><p><a href="https://github.com/squint-cljs/squint">Squint</a> now supports <code>cljs.test</code> and multimethods! <a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a> was ported to use the new <code>cljs.test</code>.</p><p>On the <a href="https://github.com/borkdude/cream">cream</a> front, I put in effort to make the binary smaller and have been keeping up with the new GraalVM EA releases. I&apos;ve been posting bug reports to the crema maintainer. Currently there&apos;s still an unfixed bug around core.async that I have trouble reproducing in pure Java. I also added lots of library tests to CI so I can ensure stability in the long run. For now it remains experimental, but the direction is promising.</p><p>A performance PR to <a href="https://github.com/weavejester/dependency">weavejester/dependency</a> speeds up <code>depend</code>, <code>depends?</code> and <code>topo-sort</code> significantly, so <a href="https://github.com/nextjournal/clerk">clerk</a> notebooks render faster.</p><p>The <a href="https://github.com/weavejester/cljfmt">cljfmt</a> library, also by <a href="https://github.com/weavejester">@weavejester</a>, now fully runs from source in babashka. The Java diff library that wasn&apos;t bb-compatible was replaced with <a href="https://github.com/borkdude/text-diff">text-diff</a>, but only for the babashka path. The JVM build of cljfmt still uses the original Java diff library, with a possible switch later once text-diff has matured.</p><p>Several SCI fixes were made to improve Clojure compatibility between babashka and Clojure. E.g. records can now support extending to <code>IFn</code> which was a blocker for some Clojure libs that tried to run in <code>bb</code> so far.</p><p>Clj-kondo <code>2026.04.15</code> got a few new linters thanks to <a href="https://github.com/jramosg">@jramosg</a> for stewarding most of these. It also has better out of the box <a href="https://github.com/clj-commons/potemkin">potemkin</a> support, and <a href="https://github.com/alexander-yakushev">@alexander-yakushev</a> contributed a wave of performance improvements.</p><p>Updates per project below. Bullets are highlights; see each project&apos;s <code>CHANGELOG.md</code> for the full list.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Released 1.12.216, 1.12.217 and 1.12.218</li><li>Support rebel-readline as external REPL provider:<ul><li>Add proxy support for <code>Completer</code>, <code>Highlighter</code>, <code>ParsedLine</code>, <code>Writer</code>, <code>Reader</code></li><li>Add <code>clojure.repl/special-doc</code> and <code>clojure.repl/set-break-handler!</code></li><li>Add <code>clojure.main/repl-read</code></li><li>Add <code>org.jline.reader.Buffer</code> to class allowlist</li></ul></li><li>Add <code>clojure.java.javadoc</code> namespace with <code>javadoc</code> available in REPL <a href="https://github.com/babashka/babashka/issues/1933">#1933</a></li><li>Fix <code>(doc var)</code>, <code>(doc set!)</code> and other special forms <a href="https://github.com/babashka/babashka/issues/1932">#1932</a></li><li>Support <code>(source inc)</code> and <code>(source babashka.fs/exists?)</code> for built-in vars <a href="https://github.com/babashka/babashka/issues/1935">#1935</a></li><li>Support <code>BABASHKA_REPL_HISTORY</code> env var for configurable REPL history location <a href="https://github.com/babashka/babashka/issues/1930">#1930</a></li><li>Fix <code>deftype</code> and <code>defrecord</code> inside non-top-level forms (e.g. <code>let</code>, <code>testing</code>) <a href="https://github.com/babashka/babashka/issues/1936">#1936</a></li><li><a href="https://github.com/babashka/babashka/issues/1948">#1948</a>: add <code>java.util.HexFormat</code> interop support</li><li><a href="https://github.com/babashka/babashka/issues/1403">#1403</a>: fix uberscript warnings with <code>:as-alias</code></li><li><a href="https://github.com/babashka/babashka/issues/1955">#1955</a>: support <code>-version</code> as an alias for <code>--version</code></li><li><a href="https://github.com/babashka/babashka/issues/1954">#1954</a>: add <code>clojure.lang.EdnReader$ReaderException</code></li><li><a href="https://github.com/babashka/babashka/issues/1951">#1951</a>: fix <code>--prepare</code> flag skipping next token</li><li><a href="https://github.com/babashka/babashka/issues/1967">#1967</a>: expose <code>clojure.data.xml.tree/{flatten-elements,event-tree}</code>, <code>clojure.data.xml.event</code> record constructors, and <code>clojure.data.xml.jvm.parse/string-source</code></li><li><a href="https://github.com/babashka/babashka/issues/1969">#1969</a>: include <code>java.net.Proxy</code> and <code>java.net.Proxy$Type</code> Java classes (<a href="https://github.com/jeeger">@jeeger</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1939">#1939</a>: disable JLine backslash escaping/shell history commands (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li>Performance improvements for math operations and for calling functions on locals</li><li>Add many new classes to reflection config: <code>java.lang.reflect.Constructor</code>, <code>java.lang.reflect.Executable</code>, <code>java.util.stream.Collectors</code>, <code>java.util.Comparator</code> (for <code>reify</code>), and more</li><li>Bump JLine to 4.0.12, cheshire to 6.2.0, <code>nextjournal.markdown</code> to 0.7.255, edamame to 1.5.39, <code>data.xml</code> to 0.2.0-alpha11, <code>jsoup</code> to 1.22.2, rewrite-clj to 1.2.54, tools.cli to 1.4.256, transit-clj to 1.1.357, fs to 0.5.32</li><li><a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Fix <code>recur</code> with 20+ args in <code>loop</code> (<a href="https://github.com/babashka/sci/issues/1035">#1035</a>)</li><li>Check <code>recur</code> arity, throw when it doesn&apos;t match (<a href="https://github.com/babashka/sci/issues/1034">#1034</a>)</li><li>Support <code>IFn</code> on <code>defrecord</code>, <code>deftype</code> and <code>reify</code> (<a href="https://github.com/babashka/sci/issues/808">#808</a>, <a href="https://github.com/babashka/sci/pull/1036">#1036</a>)</li><li>Validate single binding pair in let-like conditional macros (<a href="https://github.com/babashka/sci/pull/1037">#1037</a>)</li><li>Normalize SCI types in hierarchy lookups (<a href="https://github.com/babashka/sci/pull/1033">#1033</a>)</li><li>Expose <code>IPrintWithWriter</code> as protocol (<a href="https://github.com/babashka/sci/pull/1032">#1032</a>)</li><li>Optimize tight loops: fused binding nodes + specialized inlined calls (<a href="https://github.com/babashka/sci/pull/1031">#1031</a>)</li><li>Support special form documentation in <code>doc</code> macro</li><li>Include SCI types in <code>ns-map</code></li><li><a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.</p><ul><li>Released 2026.04.15</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2788">#2788</a>: NEW linter: <code>:not-nil?</code> which suggests <code>(some? x)</code> instead of <code>(not (nil? x))</code>, and similar patterns with <code>when-not</code> and <code>if-not</code> (default level: <code>:off</code>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2520">#2520</a>: NEW linter: <code>:protocol-method-arity-mismatch</code> which warns when a protocol method is implemented with an arity that doesn&apos;t match any arity declared in the protocol (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2520">#2520</a>: NEW linter: <code>:missing-protocol-method-arity</code> (off by default) which warns when a protocol method is implemented but not all declared arities are covered</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2768">#2768</a>: NEW linter: <code>:redundant-declare</code> which warns when <code>declare</code> is used after a var is already defined (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1878">#1878</a>: support potemkin&apos;s <code>import-fn</code>, <code>import-macro</code>, and <code>import-def</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2498">#2498</a>: support new potemkin <code>import-vars</code> <code>:refer</code> and <code>:rename</code> syntax</li><li>Performance optimizations across many linting paths (<a href="https://github.com/alexander-yakushev">@alexander-yakushev</a>) and hook-fn lookup caching to avoid repeated SCI evaluation</li><li>Add type support for <code>pmap</code> and future-related functions (<code>future</code>, <code>future-call</code>, <code>future-done?</code>, <code>future-cancel</code>, <code>future-cancelled?</code>) (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2762">#2762</a>: fix false positive: <code>throw</code> with string in CLJS no longer warns about type mismatch (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2770">#2770</a>: linter-specific ignores now correctly respect the specified linters</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2773">#2773</a>: align executable path for images to be <code>/bin/clj-kondo</code> (<a href="https://github.com/harryzcy">@harryzcy</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2621">#2621</a>: load imports from symlinked config dir (<a href="https://github.com/walterl">@walterl</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2798">#2798</a>: report correct filename and error details when <code>StackOverflowError</code> occurs during analysis</li><li><a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/borkdude/cream">cream</a>: Clojure + GraalVM <a href="https://github.com/oracle/graal/issues/11327">Crema</a> native binary</p><ul><li>Followed each GraalVM EA release: EA21 shrunk the binary to ~175MB, EA22 brought a virtual-thread fix, EA23 fixed the forkjoin segfault, EA24 finally allowed re-enabling <code>clojure.core.async-test</code></li><li>Added smoke tests for <code>httpkit</code>, <code>nextjournal/markdown</code>, <code>clj-yaml</code>, core.async ioc-macros</li><li>Updated 10M loop benchmark numbers for EA21</li><li>Added Windows test status notes (still some failures on EA22)</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Released 0.10.186, 0.11.187, 0.11.188 and 0.11.189</li><li>Add multimethod support: <code>defmulti</code>, <code>defmethod</code>, <code>get-method</code>, <code>methods</code>, <code>remove-method</code>, <code>remove-all-methods</code>, <code>prefer-method</code>, <code>prefers</code>, plus hierarchy ops <code>isa?</code>, <code>derive</code>, <code>underive</code>, <code>make-hierarchy</code>, <code>parents</code>, <code>ancestors</code>, <code>descendants</code> (<a href="https://github.com/squint-cljs/squint/issues/806">#806</a>)</li><li><code>cljs.test/report</code> is now a multimethod, extensible via <code>defmethod</code>. <code>test-var</code> now fires <code>:begin-test-var</code> / <code>:end-test-var</code> events.</li><li>Accept plain <code>await</code> in async functions, in anticipation of CLJS next. The legacy <code>js-await</code> and <code>js/await</code> forms continue to work as aliases for now.</li><li>Add built-in <code>cljs.test</code> / <code>clojure.test</code> support: <code>deftest</code>, <code>is</code>, <code>testing</code>, <code>are</code>, <code>use-fixtures</code>, <code>async</code>, <code>run-tests</code></li><li>Fix <code>with-meta</code> now preserves callability when applied to a function</li><li><a href="https://github.com/squint-cljs/squint/issues/783">#783</a>: auto-load macros from <code>.cljc</code> files via <code>:require</code> (no need for <code>:require-macros</code>); resolve qualified symbols from macro expansions</li><li><a href="https://github.com/squint-cljs/squint/issues/784">#784</a>: resolve transitive macro deps and auto-import runtime deps from macro expansion</li><li><a href="https://github.com/squint-cljs/squint/issues/809">#809</a>: add <code>squint.compiler/compile*</code> and <code>squint.compiler/transpile*</code> which accept either a string or a sequence of pre-parsed forms, skipping the <code>forms -&gt; string -&gt; forms</code> roundtrip for SSR use cases</li><li><a href="https://github.com/squint-cljs/squint/issues/810">#810</a>: shorthand classes in <code>#html</code> / <code>#jsx</code> were erased when an attrs map was present without a <code>:class</code> key</li><li><a href="https://github.com/squint-cljs/squint/blob/main/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Accept plain <code>await</code> as a special form, in anticipation of CLJS next</li><li>Multiple <code>:require-macros</code> clauses with <code>:refer</code> now properly accumulate instead of overwriting each other</li><li>Add <code>cherry.test</code> with <code>clojure.test</code>-compatible testing API: <code>deftest</code>, <code>is</code>, <code>testing</code>, <code>are</code>, <code>use-fixtures</code>, <code>async</code>, <code>run-tests</code>. Macros are compiler built-ins (shared with squint), so no <code>:require-macros</code> plumbing is needed in user code.</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Released 1.4.207</li><li><a href="https://github.com/babashka/nbb/issues/408">#408</a>: support <code>IFn</code> on <code>defrecord</code> and <code>reify</code></li><li>Fix REPL and nREPL not awaiting promesa thenables (e.g. <code>p/then</code> results)</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a>: file system utility library for Clojure</p><ul><li>Released 0.5.32 and 0.5.33</li><li><a href="https://github.com/babashka/fs/issues/232">#232</a>: add <code>touch</code> fn (<a href="https://github.com/lread">@lread</a> &amp; <a href="https://github.com/borkdude">@borkdude</a>)</li><li><a href="https://github.com/babashka/fs/issues/197">#197</a>: docstring review: consistent arg naming, improved docstrings, added <code>Coercions and Returns</code> / <code>Argument Naming Conventions</code> sections to README (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/231">#231</a>: get/set attribute functions were never following links. They now respect the <code>:nofollow-links</code> option (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/254">#254</a>: fix <code>split-ext</code> and <code>extension</code> on dotfiles with parent dirs (e.g. <code>foo/.gitignore</code>)</li><li><a href="https://github.com/babashka/fs/issues/202">#202</a>: <code>gzip</code> &amp; <code>gunzip</code> now honor dest dir when specified (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/215">#215</a>: document effect of <code>umask</code> on created files and directories (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/182">#182</a>: enable soft &amp; hard link tests on Windows (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/242">#242</a>: test: add JDK 26 to CI test matrix (<a href="https://github.com/lread">@lread</a>)</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Improve analysis performance by bumping <code>weavejester/dependency</code> (<a href="https://github.com/nextjournal/clerk/pull/808">#808</a>)</li><li>Bump SCI to <code>v0.12.51</code> (<a href="https://github.com/nextjournal/clerk/pull/793">#793</a>), enables <code>async</code>/<code>await</code> in viewer functions</li><li>Improve presentation performance (<a href="https://github.com/nextjournal/clerk/pull/803">#803</a>)</li><li>Remove bb-specific code for array-map data structure (<a href="https://github.com/nextjournal/clerk/pull/805">#805</a>)</li><li>Preserve TOC opts (<a href="https://github.com/nextjournal/clerk/pull/806">#806</a>)</li><li>Remove redundant declare of <code>present+reset!</code> (<a href="https://github.com/nextjournal/clerk/pull/809">#809</a>)</li><li>Fix <code>build-graph</code> crash on non-Clojure source files (<a href="https://github.com/nextjournal/clerk/pull/810">#810</a>)</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more</p><ul><li>Released 1.5.38 and 1.5.39</li><li><code>parse-ns-form</code>: include <code>:use</code> and <code>:require-macros</code> in <code>:requires</code></li><li>Check if object is iobj before attaching metadata <a href="https://github.com/borkdude/edamame/issues/141">#141</a> <a href="https://github.com/borkdude/edamame/pull/142">#142</a></li></ul></li><li><p><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a>: A cross-platform Clojure/Script parser for Markdown</p><ul><li>Released 0.7.225</li><li>Add option <code>:disable-footnotes true</code> to disable parsing footnotes <a href="https://github.com/nextjournal/markdown/issues/67">#67</a></li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li>Released 0.2.6</li><li><a href="https://github.com/borkdude/quickdoc/issues/42">#42</a>: fix var name not recognized in docstring when preceded by multiline backtick expression</li><li><a href="https://github.com/borkdude/quickdoc/issues/52">#52</a>: fix formatting of function signature when <code>:or</code> destructuring uses namespaced keyword fallback value</li><li>Dedent indented docstrings before rendering <a href="https://github.com/borkdude/quickdoc/issues/53">#53</a></li></ul></li><li><p><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</p><ul><li>Released 0.2.5</li><li>Bump SCI to 0.12.51, Clojure to 1.12.4</li><li>Upgrade CI to GraalVM 25; move Windows CI from Appveyor to GitHub Actions</li><li>Fix bug in native which dropped all match results (<a href="https://github.com/bsless">@bsless</a>)</li><li>Fix circular reference in <code>grasp.impl</code></li></ul></li><li><p><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library</p><ul><li>Lock output stream in <code>send</code> to prevent interleaved bencode frames from concurrent writes</li><li><code>info</code> and <code>lookup</code> op refinements: <code>lookup</code> carries nested <code>info</code> map whereas <code>info</code> is a flatmap</li></ul></li><li><p><a href="https://github.com/babashka/pod-babashka-instaparse">pod-babashka-instaparse</a>: instaparse from babashka</p><ul><li>Expose <code>add-line-and-column-info-to-metadata</code></li><li>Drop macOS Intel builds, now building for macOS aarch64 only</li><li>Migrate Windows CI from Appveyor to GitHub Actions</li><li>Upgrade CI to GraalVM 25</li><li>Add <code>--features=clj_easy.graal_build_time.InitClojureClasses</code> to native-image</li></ul></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</p><ul><li>Released 0.0.7</li><li>Bump pod to 0.0.7</li><li>Add <code>add-line-and-column-info-to-metadata</code> and <code>get-failure</code></li><li>Fix opts passing in <code>parser</code> (e.g. <code>:output-format :enlive</code>)</li><li>Support <code>java.net.URL</code> for grammars</li></ul></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">babashka-sql-pods</a>: babashka pods for SQL databases</p><ul><li>Released 0.1.5 and 0.1.6</li><li><a href="https://github.com/babashka/babashka-sql-pods/issues/74">#74</a>: add DB2 support (<a href="https://github.com/janezj">@janezj</a>)</li><li><a href="https://github.com/babashka/babashka-sql-pods/issues/72">#72</a>: handle concurrent requests (<a href="https://github.com/katangafor">@katangafor</a>)</li><li>Upgrade to Oracle GraalVM 25.0.2; bump <code>next.jdbc</code>, <code>cheshire</code> (Jackson 2.12 -&gt; 2.20), PostgreSQL, MSSQL, HSQLDB, MySQL Connector/J drivers</li><li>Remove DuckDB support</li><li><a href="https://github.com/babashka/babashka-sql-pods/issues/51">#51</a>: macOS binaries are now aarch64 only</li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: HTTP client built on java.net.http</p><ul><li>Replace defunct <code>httpstat.us</code> examples with <code>httpbin.org</code> in tests</li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</p><ul><li>Fix README instructions for dev installation (<a href="https://github.com/teodorlu">@teodorlu</a>)</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: a faithful port of the clojure CLI bash script to Clojure</p><ul><li>Released 1.12.4.1618</li><li><a href="https://github.com/borkdude/deps.clj/pull/145">#145</a>: support for installing in FreeBSD and Windows bash environments including MINGW64, MSYS_NT and Cygwin (<a href="https://github.com/ikappaki">@ikappaki</a>)</li><li>Catch up with Clojure CLI 1.12.4.1618</li></ul></li></ul><p>Contributions to third party projects:</p><ul><li><a href="https://github.com/clojure/clojurescript">ClojureScript</a>:<ul><li><a href="https://clojure.atlassian.net/browse/CLJS-3470">CLJS-3470</a>: added <code>async/await</code> support (merged!)</li><li><a href="https://clojure.atlassian.net/browse/CLJS-3476">CLJS-3476</a>: added <code>async deftest</code> support (merged!)</li></ul></li><li><a href="https://github.com/weavejester/dependency">weavejester/dependency</a>: improve performance of <code>depend</code>, <code>depends?</code>, and <code>topo-sort</code></li><li><a href="https://github.com/weavejester/cljfmt">weavejester/cljfmt</a>: <a href="https://github.com/weavejester/cljfmt/pull/404">#404</a> babashka compatibility via new <a href="https://github.com/borkdude/text-diff">text-diff</a> lib (merged!)</li><li><a href="https://github.com/Engelberg/instaparse">Engelberg/instaparse</a>: submitted <a href="https://github.com/Engelberg/instaparse/pull/242">#242</a> for babashka compatibility. Required <code>:bb</code> reader conditionals to replace the <code>AutoFlattenSeq</code> deftype with plain vectors plus metadata markers, swap the <code>Segment</code> deftype for a <code>reify</code>-based <code>CharSequence</code>, and add a CI test runner. Open, awaiting review.</li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past two months.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only)</li></ul></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/speculative">speculative</a></li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/parmezan">parmezan</a>: fixes unbalanced or unexpected parens or other delimiters in Clojure files</li><li><a href="https://github.com/borkdude/reagami">reagami</a>: A minimal zero-deps Reagent-like for Squint and CLJS</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jan-feb-2026.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jan-feb-2026.html"/>
    <title>OSS updates January and February 2026</title>
    <updated>2026-03-05T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during January and February 2026.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babashka</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><h2 id="updates">Updates</h2><h3 id="babashka-conf-and-dutch-clojure-days-2026">Babashka conf and Dutch Clojure Days 2026</h3><p>Babashka Conf 2026 is happening on May 8th in the OBA Oosterdok library in Amsterdam! David Nolen, primary maintainer of ClojureScript, will be our keynote speaker! We&apos;re excited to have Nubank, Exoscale, Bob and Itonomi as sponsors. Wendy Randolph will be our event host / MC / speaker liaison :-). The CfP is now closed. More information <a href="https://babashka.org/conf/">here</a>. Get your ticket via <a href="https://www.meetup.com/the-dutch-clojure-meetup/events/312079164/">Meetup.com</a> (there is a waiting list, but more places may become available). The day after babashka conf, <a href="https://clojuredays.org/">Dutch Clojure Days 2026</a> will be happening, so you can enjoy a whole weekend of Clojure in Amsterdam. Hope to see many of you there!</p><h3 id="projects">Projects</h3><p>I spent a lot of time making SCI&apos;s <code>deftype</code>, <code>case</code>, and <code>macroexpand-1</code> match JVM Clojure more closely. As a result, libraries like riddley, cloverage, specter, editscript, and compliment now work in babashka.</p><p>After seeing <a href="https://codeberg.org/timokramer/charm.clj">charm.clj</a>, a terminal UI library, I decided to incorporate JLine3 into babashka so people can build terminal UIs. Since I had JLine anyway, I also gave babashka&apos;s console REPL a major upgrade with multi-line editing, tab completion, ghost text, and persistent history. A next goal is to run rebel-readline + nREPL from source in babashka, but that&apos;s still work in progress (e.g. the compliment PR is still pending).</p><p>I&apos;ve been working on <code>async/await</code> support for ClojureScript (<a href="https://clojure.atlassian.net/browse/CLJS-3470">CLJS-3470</a>), inspired by how squint handles it. I also implemented it in SCI (scittle, nbb etc. use SCI as a library), though the approach there is different since SCI is an interpreter.</p><p>Last but not least, I started <a href="https://github.com/borkdude/cream">cream</a>, an experimental native binary that runs full JVM Clojure with fast startup using GraalVM&apos;s Crema. Unlike babashka, it supports runtime bytecode generation (<code>definterface</code>, <code>deftype</code>, <code>gen-class</code>). It currently depends on a fork of Clojure and GraalVM EA, so it&apos;s not production-ready yet.</p><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months in detail.</p><ul><li><p>NEW: <a href="https://github.com/borkdude/cream">cream</a>: Clojure + GraalVM <a href="https://github.com/oracle/graal/issues/11327">Crema</a> native binary</p><ul><li>A native binary that runs full JVM Clojure with fast startup, using GraalVM&apos;s Crema (RuntimeClassLoading) to enable runtime <code>eval</code>, <code>require</code>, and library loading</li><li>Unlike babashka, supports <code>definterface</code>, <code>deftype</code>, <code>gen-class</code>, and other constructs that generate JVM bytecode at runtime</li><li>Can run <code>.java</code> source files directly, as a fast alternative to JBang</li><li>Cross-platform: Linux, macOS, Windows</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Released 1.12.214 and 1.12.215</li><li><a href="https://github.com/babashka/babashka/issues/1909">#1909</a>: add JLine3 for TUI support</li><li>Console REPL (<code>bb repl</code>) improvements: multi-line editing, tab completion, ghost text, eldoc, doc-at-point (<code>C-x</code> <code>C-d</code>), persistent history</li><li>Support <code>deftype</code> with map interfaces (e.g. <code>IPersistentMap</code>, <code>ILookup</code>, <code>Associative</code>). Libraries like core.cache and linked now work in babashka.</li><li>Compatibility with riddley, cloverage, editscript, charm.clj</li><li><a href="https://github.com/babashka/babashka/issues/1299">#1299</a>: add new <code>babashka.terminal</code> namespace that exposes <code>tty?</code></li><li>Add keyword completions to nREPL and console REPL</li><li><code>deftype</code> supports <code>Object</code> + <code>hashCode</code></li><li><a href="https://github.com/babashka/babashka/issues/1923">#1923</a>: support <code>reify</code> with <code>java.time.temporal.TemporalQuery</code></li><li>Fix <code>reify</code> with methods returning <code>int</code>/<code>short</code>/<code>byte</code>/<code>float</code></li><li><a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Released 0.12.51</li><li><code>deftype</code> now macroexpands to <code>deftype*</code>, matching JVM Clojure, enabling code walkers like riddley</li><li><code>case</code> now macroexpands to JVM-compatible <code>case*</code> format, enabling tools like riddley and cloverage</li><li>Support <code>async/await</code> in ClojureScript. See <a href="https://github.com/babashka/sci/blob/master/doc/async-await.md">docs</a>.</li><li>Support functional interface adaptation for instance targets</li><li>Infer type tags from let binding values to binding names</li><li><code>defrecord</code> now expands to <code>deftype*</code> (like Clojure), with factory fns emitted directly in the macro expansion</li><li><code>macroexpand-1</code> now accepts an optional env map as first argument</li><li>Add <code>proxy-super</code>, <code>proxy-call-with-super</code>, <code>update-proxy</code> and <code>proxy-mappings</code></li><li>Support <a href="https://github.com/babashka/sci/issues/564">#564</a>: <code>this-as</code> in ClojureScript</li><li>Store current analysis context during macro invocation, enabling tools like riddley to access outer locals</li><li><a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br> <a href="https://github.com/jramosg">@jramosg</a>, <a href="https://github.com/tomdl89">@tomdl89</a> and <a href="https://github.com/hugod">@hugod</a> have been on fire with contributions this period. Six new linters!</p><ul><li>Released 2026.01.12 and 2026.01.19</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2735">#2735</a>: NEW linter: <code>:duplicate-refer</code> which warns on duplicate entries in <code>:refer</code> of <code>:require</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2734">#2734</a>: NEW linter: <code>:aliased-referred-var</code>, which warns when a var is both referred and accessed via an alias in the same namespace (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2745">#2745</a>: NEW linter: <code>:is-message-not-string</code> which warns when <code>clojure.test/is</code> receives a non-string message argument (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2712">#2712</a>: NEW linter: <code>:redundant-format</code> to warn when format strings contain no format specifiers (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2709">#2709</a>: NEW linter: <code>:redundant-primitive-coercion</code> to warn when primitive coercion functions are applied to expressions already of that type (<a href="https://github.com/hugod">@hugod</a>)</li><li>Add new types <code>array</code>, <code>class</code>, <code>inst</code> and type checking support for related functions (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Add type checking support for <code>clojure.test</code> functions and macros (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2340">#2340</a>: Extend <code>:condition-always-true</code> linter to check first argument of <code>clojure.test/is</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2729">#2729</a>: Check for arity mismatch for bound vectors, sets &amp; maps, not just literals (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2768">#2768</a>: NEW linter: <code>:redundant-declare</code> which warns when <code>declare</code> is used after a var is already defined (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Add type support for <code>pmap</code> and future-related functions (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Upgrade to GraalVM 25</li><li><a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler <a href="https://github.com/tonsky">@tonsky</a> and <a href="https://github.com/willcohen">@willcohen</a> contributed several improvements this period.</p><ul><li>Add <code>squint.math</code>, also available as <code>clojure.math</code> namespace</li><li><a href="https://github.com/squint-cljs/squint/issues/779">#779</a>: Added <code>compare-and-swap!</code>, <code>swap-vals!</code> and <code>reset-vals!</code> (<a href="https://github.com/tonsky">@tonsky</a>)</li><li><a href="https://github.com/squint-cljs/squint/issues/788">#788</a>: Fixed compilation of <code>dotimes</code> with <code>_</code> binding (<a href="https://github.com/tonsky">@tonsky</a>)</li><li><a href="https://github.com/squint-cljs/squint/issues/790">#790</a>: Fixed <code>shuffle</code> not working on lazy sequences (<a href="https://github.com/tonsky">@tonsky</a>)</li><li>Multiple <code>:require-macros</code> with <code>:refer</code> now accumulate instead of overwriting (<a href="https://github.com/willcohen">@willcohen</a>)</li><li>Fix emitting negative zero value (<code>-0.0</code>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/792">#792</a>: <code>prn</code> <code>js/undefined</code> as <code>nil</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/793">#793</a>: fix <code>yield*</code> IIFE</li><li><a href="https://github.com/squint-cljs/squint/blob/main/CHANGELOG.md">Full changelog</a></li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li>Support <code>async/await</code>. See docs.</li><li>Implement <code>js/import</code> not using <code>eval</code></li><li>Support <code>this-as</code></li><li>nREPL: print <code>#&lt;Promise value&gt;</code> when a promise is evaluated</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Support async/await. See docs for syntax.</li><li>Print promise result value in REPL/nREPL: <code>(js/Promise.resolve 1) ;;=&gt; #&lt;Promise 1&gt;</code></li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li>Released 0.5.31</li><li><a href="https://github.com/babashka/fs/issues/212">#212</a>: Introduce <code>:keep true</code> option in <code>with-temp-dir</code></li><li><a href="https://github.com/babashka/fs/issues/188">#188</a> <code>copy-tree</code> now throws if <code>src</code> or <code>dest</code> is a symbolic link when not following links (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/201">#201</a> <code>gzip</code> now accepts <code>source-file</code> <code>Path</code> (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/207">#207</a> review and update <code>glob</code> and <code>match</code> docstrings (<a href="https://github.com/lread">@lread</a>)</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Fix browse when using random port by passing 0, fixes #801</li><li>bb now supports editscript</li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></p><ul><li><a href="https://github.com/babashka/neil/issues/258">#258</a>: <code>neil test</code> now exits with non-zero exit code when tests fail</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Multiple <code>:require-macros</code> clauses with <code>:refer</code> now properly accumulate instead of overwriting each other</li></ul></li></ul><p>Contributions to third party projects:</p><ul><li><a href="https://github.com/clojure/clojurescript">ClojureScript</a>:<ul><li>Working on <code>async/await</code> support (<a href="https://clojure.atlassian.net/browse/CLJS-3470">CLJS-3470</a>). I also implemented this in SCI, scittle, and nbb.</li><li><a href="https://clojure.atlassian.net/browse/CLJS-3471">CLJS-3471</a>: fix printing of negative zero</li><li><a href="https://clojure.atlassian.net/browse/CLJS-3472">CLJS-3472</a>: <code>str</code> on var that is <code>set!</code> returns empty string</li></ul></li><li><a href="https://github.com/juji-io/editscript">editscript</a>: Added babashka support, deps.edn for git dep usage, fixed CLJS tests</li><li><a href="https://github.com/ztellman/riddley">riddley</a>: Added babashka compatibility, clj-kondo config</li><li><a href="https://github.com/cloverage/cloverage">cloverage</a>: Added babashka compatibility, migrated tools.cli from deprecated <code>cli/cli</code> to <code>cli/parse-opts</code>, bumped riddley</li><li><a href="https://github.com/redplanetlabs/specter">specter</a>: Added babashka compatibility</li><li><a href="https://github.com/alexander-yakushev/compliment">compliment</a>: Added babashka compatibility (<a href="https://github.com/alexander-yakushev/compliment/pull/131">PR #131</a>)</li><li><a href="https://github.com/bhauman/rebel-readline">rebel-readline</a>: Removed JLine impl class dependencies for babashka compatibility, released 0.1.7</li><li><a href="https://github.com/yogthos/Selmer">Selmer</a>: Namespaced script tag context keys to avoid collisions, removed runtime require of clojure.tools.logging</li><li><a href="https://codeberg.org/timokramer/charm.clj">charm.clj</a>: Contributed JLine integration, FFM native terminal interface, babashka and native-image compatibility</li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only)</li></ul></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/speculative">speculative</a></li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</li><li><a href="https://github.com/borkdude/reagami">reagami</a>: A minimal zero-deps Reagent-like for Squint and CLJS</li><li><a href="https://github.com/borkdude/parmezan">parmezan</a>: fixes unbalanced or unexpected parens or other delimiters in Clojure files</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-1.12.215.html</id>
    <link href="https://blog.michielborkent.nl/babashka-1.12.215.html"/>
    <title>Babashka 1.12.215: Revenge of the TUIs</title>
    <updated>2026-02-17T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><a href="https://babashka.org">Babashka</a> is a fast-starting native Clojure scripting runtime. It uses <a href="https://github.com/babashka/sci">SCI</a> to interpret Clojure and compiles to a native binary via GraalVM, giving you Clojure&apos;s power with near-instant startup. It&apos;s commonly used for shell scripting, build tooling, and small CLI applications. If you don&apos;t yet have bb installed, you can with brew:</p><pre><code>brew install borkdude/brew/babashka
</code></pre><p>or bash:</p><pre><code>bash &lt;(curl -s https://raw.githubusercontent.com/babashka/babashka/master/install)
</code></pre><p>This release is, in my opinion, a game changer. With JLine3 bundled, you can now build full terminal user interfaces in babashka. The <code>bb repl</code> has been completely overhauled with multi-line editing, completions, and eldoc. <code>deftype</code> now supports map interfaces, making bb more compatible with existing libraries like <code>core.cache</code>. SCI has had many small improvements, making <code>riddley</code> compatible too. Riddley is used in Cloverage, a code coverage library for Clojure, which now also works with babashka (Cloverage PR pending).</p><h2 id="babashka-conf-2026">Babashka conf 2026</h2><p>But first, let me mention an exciting upcoming event! <a href="https://babashka.org/conf/">Babashka
conf</a> is happening again for the second time! The first time was 2023 in Berlin. This time it&apos;s in Amsterdam. The Call for Proposals is open until the end of February, so there is still time to submit your talk or workshop. We are also looking for one last gold sponsor (500 euros) to cover all costs.</p><h2 id="highlights">Highlights</h2><h3 id="jline3-and-tui-support">JLine3 and TUI support</h3><p>Babashka now bundles <a href="https://github.com/jline/jline3">JLine3</a>, a Java library for building interactive terminal applications. You get terminals, line readers with history and tab completion, styled output, keyboard bindings, and the ability to <code>reify</code> custom completers, parsers, and widgets — all from bb scripts.</p><p>JLine3 works on all platforms, including Windows PowerShell and cmd.exe.</p><p>Here&apos;s a simple interactive prompt that reads lines from the user until EOF (Ctrl+D):</p><pre><code class="language-clojure">(import &apos;[org.jline.terminal TerminalBuilder]
        &apos;[org.jline.reader LineReaderBuilder])

(let [terminal (-&gt; (TerminalBuilder/builder) (.build))
      reader   (-&gt; (LineReaderBuilder/builder)
                   (.terminal terminal)
                   (.build))]
  (try
    (loop []
      (when-let [line (.readLine reader &quot;prompt&gt; &quot;)]
        (println &quot;You typed:&quot; line)
        (recur)))
    (catch org.jline.reader.EndOfFileException _
      (println &quot;Goodbye!&quot;))
    (finally
      (.close terminal))))
</code></pre><h3 id="babashka.terminal-namespace">babashka.terminal namespace</h3><p>A new <code>babashka.terminal</code> namespace exposes a <code>tty?</code> function to detect whether stdin, stdout, or stderr is connected to a terminal:</p><pre><code class="language-clojure">(require &apos;[babashka.terminal :refer [tty?]])

(when (tty? :stdout)
  (println &quot;Interactive terminal detected, enabling colors&quot;))
</code></pre><p>This accepts <code>:stdin</code>, <code>:stdout</code>, or <code>:stderr</code> as argument. It uses JLine3&apos;s terminal provider under the hood.</p><p>This is useful for scripts that want to behave differently when piped vs. run interactively, for example enabling colored output or progress bars only in a terminal.</p><h3 id="charm.clj-compatibility">charm.clj compatibility</h3><p><a href="https://github.com/TimoKramer/charm.clj">charm.clj</a> is a new Clojure library for building terminal user interfaces using the Elm architecture (Model-Update-View). It provides components like spinners, text inputs, lists, paginators, and progress bars, with support for ANSI/256/true color styling and keyboard/mouse input handling.</p><p>charm.clj is now compatible with babashka (or rather, babashka is now compatible with charm.clj), enabled by the combination of JLine3 support and other interpreter improvements in this release. This means you can build rich TUI applications that start instantly as native binaries.</p><p>Here&apos;s a complete counter example you can save as a single file and run with <code>bb</code>:</p><pre><code class="language-clojure">#!/usr/bin/env bb

(babashka.deps/add-deps
 &apos;{:deps {io.github.TimoKramer/charm.clj {:git/sha &quot;cf7a6c2fcfcccc44fcf04996e264183aa49a70d6&quot;}}})

(require &apos;[charm.core :as charm])

(def title-style
  (charm/style :fg charm/magenta :bold true))

(def count-style
  (charm/style :fg charm/cyan
               :padding [0 1]
               :border charm/rounded-border))

(defn update-fn [state msg]
  (cond
    (or (charm/key-match? msg &quot;q&quot;)
        (charm/key-match? msg &quot;ctrl+c&quot;))
    [state charm/quit-cmd]

    (or (charm/key-match? msg &quot;k&quot;)
        (charm/key-match? msg :up))
    [(update state :count inc) nil]

    (or (charm/key-match? msg &quot;j&quot;)
        (charm/key-match? msg :down))
    [(update state :count dec) nil]

    :else
    [state nil]))

(defn view [state]
  (str (charm/render title-style &quot;Counter App&quot;) &quot;\n\n&quot;
       (charm/render count-style (str (:count state))) &quot;\n\n&quot;
       &quot;j/k or arrows to change\n&quot;
       &quot;q to quit&quot;))

(charm/run {:init {:count 0}
            :update update-fn
            :view view
            :alt-screen true})
</code></pre><img src="assets/1.12.215-counter.png" style="max-width:100%" alt="charm.clj counter example running in babashka"><p>More examples can be found <a href="https://github.com/TimoKramer/charm.clj/tree/main/docs/examples#readme">here</a>.</p><h3 id="deftype-with-map-interfaces">Deftype with map interfaces</h3><p>Until now, <code>deftype</code> in babashka couldn&apos;t implement JVM interfaces like <code>IPersistentMap</code>, <code>ILookup</code>, or <code>Associative</code>. This meant libraries that define custom map-like types, a very common Clojure pattern, couldn&apos;t work in babashka.</p><p>Starting with this release, <code>deftype</code> supports map interfaces. Your <code>deftype</code> must declare <code>IPersistentMap</code> to signal that you want a full map type. Other map-related interfaces like <code>ILookup</code>, <code>Associative</code>, <code>Counted</code>, <code>Seqable</code>, and <code>Iterable</code> are accepted freely since the underlying class already implements them.</p><p>This unlocks several libraries that were previously incompatible:</p><ul><li><a href="https://github.com/clojure/core.cache">core.cache</a>: all cache types (BasicCache, FIFOCache, LRUCache, TTLCache, LUCache) work unmodified</li><li><a href="https://github.com/frankiesardo/linked">linked</a>: insertion-ordered maps and sets</li></ul><h3 id="riddley-and-cloverage-compatibility">Riddley and Cloverage compatibility</h3><p><a href="https://github.com/clj-commons/riddley">Riddley</a> is a Clojure library for code walking that many other libraries depend on. Previously, SCI&apos;s <code>deftype</code> and <code>case</code> did not macroexpand to the same special forms as JVM Clojure, which broke riddley&apos;s walker. Several changes now align SCI&apos;s behavior with Clojure: <code>deftype</code> macroexpands to <code>deftype*</code>, <code>case</code> to <code>case*</code>, and <code>macroexpand-1</code> now accepts an optional env map as second argument (inspired by how the CLJS analyzer API works). Together these changes enable riddley and tools built on it, like <a href="https://github.com/cloverage/cloverage">cloverage</a> and <a href="https://github.com/redplanetlabs/specter">Specter</a>, to work with bb.</p><p>Riddley has moved to <a href="https://github.com/clj-commons/riddley">clj-commons</a>, thanks to <a href="https://github.com/ztellman">Zach Tellman</a> for transferring it. I&apos;d like to thank Zach for all his contributions to the Clojure community over the years. Version 0.2.2 includes bb compatibility, which was one of the first PRs merged after the transfer. Cloverage compatibility has been <a href="https://github.com/cloverage/cloverage/pull/356">submitted
upstream</a>, all 75 cloverage tests pass on both JVM and babashka.</p><h3 id="console-repl-improvements">Console REPL improvements</h3><p>The <code>bb repl</code> experience has been significantly improved with JLine3 integration. You no longer need <code>rlwrap</code> to get a comfortable console REPL:</p><ul><li>Multi-line editing: the REPL detects incomplete forms and continues reading on the next line with a <code>#_=&gt; </code> continuation prompt</li><li>Tab completion: Clojure-aware completions powered by SCI, including keywords (<code>:foo</code>, <code>::foo</code>, <code>::alias/foo</code>)</li></ul><img src="assets/1.12.215-completions.png" style="max-width:100%" alt="Tab completions in bb repl"><ul><li>Ghost text: as you type, the common completion prefix appears as faint inline text after the cursor. Press TAB to accept.</li></ul><img src="assets/1.12.215-tailtip.png" style="max-width:100%" alt="Ghost text in bb repl"><ul><li>Eldoc: automatic argument help — when your cursor is inside a function call like <code>(map |)</code>, the arglists are displayed below the prompt</li><li>Doc-at-point: press Ctrl+X Ctrl+D to show full documentation for the symbol at the cursor</li><li>Persistent history: command history saved across sessions in <code>~/.bb_repl_history</code></li><li>Ctrl+C handling: first press on an empty prompt warns, second press exits</li></ul><p>Many of these features were inspired by <a href="https://github.com/bhauman/rebel-readline">rebel-readline</a>, <a href="https://leiningen.org/">Leiningen</a>&apos;s REPL, and <a href="https://nodejs.org/">Node.js</a>&apos;s REPL.</p><h3 id="sci-improvements">SCI improvements</h3><p>Under the hood, <a href="https://github.com/babashka/sci">SCI</a> (the interpreter powering babashka) received many improvements in this cycle:</p><ul><li>Functional interface adaptation for instance targets: you can now write <code>(let [^Predicate p even?] (.test p 42))</code> and SCI will adapt the Clojure function to the functional interface automatically.</li><li>Type tag inference: SCI now infers type tags from <code>let</code> binding values to binding names, reducing the need for explicit type hints in interop-heavy code.</li><li>Several bug fixes: <code>read</code> with <code>nil</code>/<code>false</code> as eof-value, <code>letfn</code> with duplicate function names, <code>ns-map</code> not reflecting shadowed vars, NPE in <code>resolve</code>, and <code>.method</code> on class objects routing incorrectly.</li></ul><h3 id="other-improvements">Other improvements</h3><ul><li>Support multiple <code>catch</code> clauses in combination with <code>^:sci/error</code></li><li>Fix <code>satisfies?</code> on protocols with <code>proxy</code></li><li>Support <code>reify</code> with <code>java.time.temporal.TemporalQuery</code></li><li>Fix <code>reify</code> with methods returning <code>int</code>/<code>short</code>/<code>byte</code>/<code>float</code> primitives</li><li>nREPL server now uses non-daemon threads so the process stays alive without <code>@(promise)</code></li><li>Add <code>clojure.test.junit</code> as built-in source namespace</li><li>Add cp437 (IBM437) charset support in native binary via selective GraalVM charset Feature, avoiding the ~5MB binary size increase from <code>AddAllCharsets</code>. More charsets can be added on request.</li></ul><p>For the full list of changes including new Java classes and library bumps, see the <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">changelog</a>.</p><h2 id="thanks">Thanks</h2><p>Thank you to all the contributors who helped make this release possible. Special thanks to everyone who reported issues, tested pre-release builds from <a href="https://github.com/babashka/babashka-dev-builds">babashka-dev-builds</a>, and provided feedback.</p><p>Thanks to <a href="https://www.clojuriststogether.org/">Clojurists Together</a> and all babashka <a href="https://github.com/sponsors/borkdude">sponsors</a> and <a href="https://github.com/babashka/babashka/graphs/contributors">contributors</a> for their ongoing support. Your sponsorship makes it possible to keep developing babashka.</p><p>And thanks to all babashka users: you make this project what it is. Happy scripting!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-nov-dec-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-nov-dec-2025.html"/>
    <title>OSS updates November and December 2025</title>
    <updated>2026-01-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during November and December 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babashka</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><!--

- ls -lat ~/dev
- babashka sub dir checken

--><h2 id="updates">Updates</h2><h3 id="clojure-conj-2025">Clojure Conj 2025</h3><p>Last November I had the honor and pleasure to visit the Clojure Conj 2025. I met a host of wonderful and interesting long-time and new Clojurians, many that I&apos;ve known online for a long time and now met for the first time. It was especially exciting to finally meet Rich Hickey and talk to him during a meeting about Clojure dialects and Clojure tooling. The talk that I gave there: &quot;Making tools developers actually use&quot; will come online soon.</p><img src="https://photos.clojure-conj.org/uploads/medium2x/21/bb/eee18492f42518506f78b0f48587.jpg" width="100%" align="center" alt="presentation at Dutch Clojure meetup"><h3 id="babashka-conf-and-dutch-clojure-days-2026">Babashka conf and Dutch Clojure Days 2026</h3><p>In 2026 I&apos;m organizing Babashka Conf 2026. It will be an afternoon event (13:00-17:00) hosted in the Forum hall of the beautiful public library of Amsterdam. More information <a href="https://babashka.org/conf/">here</a>. Get your ticket via <a href="https://www.meetup.com/the-dutch-clojure-meetup/events/312079164/">Meetup.com</a> (currently there&apos;s a waiting list, but more places will come available once speakers are confirmed). CfP will open mid January. The day after babashka conf, Dutch Clojure Days 2026 will be happening. It&apos;s not too late to get your talk proposal in. More info <a href="https://clojuredays.org/">here</a>.</p><h3 id="clojurists-together:-long-term-funding">Clojurists Together: long term funding</h3><p>I&apos;m happy to announce that I&apos;m among the 5 developers that were granted Long term support for 2026. Thanks to all who voted! Read the announcement <a href="https://www.clojuriststogether.org/news/clojurists-together-2026-annual-funding-announcement/">here</a>.</p><h3 id="projects">Projects</h3><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months in detail.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Bump <code>process</code> to <code>0.6.25</code></li><li>Bump <code>deps.clj</code></li><li>Fix #1901: add <code>java.security.DigestOutputStream</code></li><li>Redefining namespace with <code>ns</code> should override metadata</li><li>Bump <code>nextjournal.markdown</code> to <code>0.7.222</code></li><li>Bump <code>edamame</code> to <code>1.5.37</code></li><li>Fix <a href="https://github.com/babashka/babashka/issues/1899">#1899</a>: <code>with-meta</code> followed by <code>dissoc</code> on records no longer works</li><li>Bump <code>fs</code> to <code>0.5.30</code></li><li>Bump <code>nextjournal.markdown</code> to <code>0.7.213</code></li><li>Fix <a href="https://github.com/babashka/babashka/issues/1882">#1882</a>: support for reifying <code>java.time.temporal.TemporalField</code> (<a href="https://github.com/EvenMoreIrrelevance">@EvenMoreIrrelevance</a>)</li><li>Bump Selmer to <code>1.12.65</code></li><li>SCI: <code>sci.impl.Reflector</code> was rewritten into Clojure</li><li><code>dissoc</code> on record with non-record field should return map instead of record</li><li>Bump edamame to <code>1.5.35</code></li><li>Bump <code>core.rrb-vector</code> to <code>0.2.0</code></li><li>Migrate detecting of executable name for self-executing uberjar executable from <code>ProcessHandle</code> to to native image <code>ProcessInfo</code> to avoid sandbox errors</li><li>Bump <code>cli</code> to <code>0.8.67</code></li><li>Bump <code>fs</code> to <code>0.5.29</code></li><li>Bump <code>nextjournal.markdown</code> to <code>0.7.201</code></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Add support for <code>:refer-global</code> and <code>:require-global</code></li><li>Add <code>println-str</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/997">#997</a>: Var is mistaken for local when used under the same name in a <code>let</code> body</li><li>Fix <a href="https://github.com/babashka/sci/issues/1001">#1001</a>: JS interop with reserved js keyword fails (regression of <a href="https://github.com/babashka/sci/issues/987">#987</a>)</li><li><code>sci.impl.Reflector</code> was rewritten into Clojure</li><li>Fix <a href="https://github.com/babashka/babashka/issues/1886">babashka/babashka#1886</a>: Return a map when dissociating a record basis field.</li><li>Fix <a href="https://github.com/babashka/sci/issues/1011">#1011</a>: reset ns metadata when evaluating ns form multiple times</li><li>Fix for <a href="https://github.com/babashka/babashka/issues/1899">https://github.com/babashka/babashka/issues/1899</a></li><li>Fix <a href="https://github.com/babashka/sci/issues/1010">#1010</a>: add <code>js-in</code> in CLJS</li><li>Add <code>array-seq</code></li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2600">#2600</a>: NEW linter: <code>unused-excluded-var</code> to warn on unused vars in <code>:refer-clojure :exclude</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2459">#2459</a>: NEW linter: <code>:destructured-or-always-evaluates</code> to warn on s-expressions in <code>:or</code> defaults in map destructuring (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Add type checking support for <code>sorted-map-by</code>, <code>sorted-set</code>, and <code>sorted-set-by</code> functions (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Add new type <code>array</code> and type checking support for the next functions: <code>to-array</code>, <code>alength</code>, <code>aget</code>, <code>aset</code> and <code>aclone</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2696">#2695</a>: false positive <code>:unquote-not-syntax-quoted</code> in leiningen&apos;s <code>defproject</code></li><li>Leiningen&apos;s <code>defproject</code> behavior can now be configured using <code>leiningen.core.project/defproject</code></li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2699">#2699</a>: fix false positive unresolved string var with extend-type on CLJS</li><li>Rename <code>:refer-clojure-exclude-unresolved-var</code> linter to <code>unresolved-excluded-var</code> for consistency</li><li>v2025.12.23</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2654">#2654</a>: NEW linter: <code>redundant-let-binding</code>, defaults to <code>:off</code> (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2653">#2653</a>: NEW linter: <code>:unquote-not-syntax-quoted</code> to warn on <code>~</code> and <code>~@</code> usage outside syntax-quote (<code>`</code>) (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2613">#2613</a>: NEW linter: <code>:refer-clojure-exclude-unresolved-var</code> to warn on non-existing vars in <code>:refer-clojure :exclude</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2668">#2668</a>: Lint <code>&amp;</code> syntax errors in let bindings and lint for trailing <code>&amp;</code> (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2590">#2590</a>: <code>duplicate-key-in-assoc</code> changed to <code>duplicate-key-args</code>, and now lints <code>dissoc</code>, <code>assoc!</code> and <code>dissoc!</code> too (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2651">#2651</a>: resume linting after paren mismatches</li><li><a href="https://github.com/clojure-lsp/clojure-lsp/issues/2157">clojure-lsp#2651</a>: Fix inner class name for java-class-definitions.</li><li><a href="https://github.com/clojure-lsp/clojure-lsp/issues/2157">clojure-lsp#2651</a>: Include inner class java-class-definition analysis.</li><li>Bump <code>babashka/fs</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2532">#2532</a>: Disable <code>:duplicate-require</code> in <code>require</code> + <code>:reload</code> / <code>:reload-all</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2432">#2432</a>: Don&apos;t warn for <code>:redundant-fn-wrapper</code> in case of inlined function</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2599">#2599</a>: detect invalid arity for invoking collection as higher order function</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2661">#2661</a>: Fix false positive <code>:unexpected-recur</code> when <code>recur</code> is used inside <code>clojure.core.match/match</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2617">#2617</a>: Add types for <code>repeatedly</code> (<a href="https://github.com/jramosg">@jramosg</a>)</li><li>Add <code>:ratio</code> type support for <code>numerator</code> and <code>denominator</code> functions (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2676">#2676</a>: Report unresolved namespace for namespaced maps with unknown aliases (<a href="https://github.com/jramosg">@jramosg</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2683">#2683</a>: data argument of <code>ex-info</code> may be nil since clojure 1.12</li><li>Bump built-in ClojureScript analysis info</li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2687">#2687</a>: support new <code>:refer-global</code> and <code>:require-global</code> ns options in CLJS</li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2544">#2554</a>: support inline configs in <code>.cljc</code> files</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more Edamame: configurable EDN and Clojure parser with location metadata and more</p><ul><li>Minor: leave out <code>:edamame/read-cond-splicing</code> when not splicing</li><li>Allow <code>:read-cond</code> function to override <code>:edamame/read-cond-splicing</code> value</li><li>The result from <code>:read-cond</code> with a function should be spliced. This behavior differs from <code>:read-cond</code> + <code>:preserve</code> which always returns a reader conditional object which cannot be spliced.</li><li>Support function for <code>:features</code> option to just select the first feature that occurs</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Allow macro namespaces to load <code>&quot;node:fs&quot;, etc.</code> to read config files for conditional compilation</li><li>Don&apos;t emit IIFE for top-level let so you can write <code>let</code> over <code>defn</code> to capture values.</li><li>Fix <code>js-yield</code> and <code>js-yield*</code> in expression position</li><li>Implement <code>some?</code> as macro</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/758">#758</a>: <code>volatile!</code>, <code>vswap!</code>, <code>vreset!</code></li><li><code>pr-str</code>, <code>prn</code> etc now print EDN (with the idea that you can paste it back into your program)</li><li>new <code>#js/Map</code> reader that reads a JavaScript <code>Map</code> from a Clojure map (maps are printed like this with <code>pr-str</code> too)</li><li>Support passing keyword to <code>mapv</code></li><li><a href="https://github.com/squint-cljs/squint/issues/759">#759</a>: <code>doseq</code> can&apos;t be used in expression context</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/753">#753</a>: optimize output of dotimes</li><li><code>alength</code> as macro</li></ul></li><li><p><a href="https://github.com/borkdude/reagami">reagami</a>: A minimal zero-deps Reagent-like for Squint and CLJS</p><ul><li>Performance enhancements</li><li>treat <code>innerHTML</code> as a property rather than an attribute</li><li>Drop support for camelCased properties / (css) attributes</li><li>Fix <code>:default-value</code> in input range</li><li>Support data param in <code>:on-render</code></li><li>Support default values for uncontrolled components</li><li>Fix child count mismatch</li><li>Fix re-rendering/patching of subroots</li><li>Add <code>:on-render</code> hook for mounting/updating/unmounting third part JS components</li></ul></li><li><p>NEW: <a href="https://github.com/borkdude/parmezan">parmezan</a>: fixes unbalanced or unexpected parens or other delimiters in Clojure files</p></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li><a href="https://github.com/babashka/cli/issues/126">#126</a>: <code>-</code> value accidentally parsed as option, e.g. <code>--file -</code></li><li><a href="https://github.com/babashka/cli/issues/124">#124</a>: Specifying exec fn that starts with hyphen is treated as option</li><li>Drop Clojure 1.9 support. Minimum Clojure version is now 1.10.3.</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>always analyze doc (but not deps) when no-cache is set (#786)</li><li>add option to disable inline formulas in markdown (#780)</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li><a href="https://github.com/babashka/scittle/issues/114">#114</a>: Enable source maps (<a href="https://github.com/jeroenvandijk">@jeroenvandijk</a>)</li><li><a href="https://github.com/babashka/scittle/issues/140">#140</a>: Enable customizing the nrepl websocket port (<a href="https://github.com/PEZ">@PEZ</a>)</li><li>Bump shadow-cljs and SCI</li></ul></li><li><p><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a></p><ul><li>Add config option to avoid TeX formulas</li><li>API improvements for passing options</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Fix <code>cherry compile</code> CLI command not receiving file arguments</li><li>Bump shadow-cljs to <code>3.3.4</code></li><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/163">#163</a>: Add assert to macros (<a href="https://github.com/willcohen">@willcohen</a>)</li><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/165">#165</a>: Fix ClojureScript protocol dispatch functions (<a href="https://github.com/willcohen">@willcohen</a>)</li><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/167">#167</a>: Protocol dispatch functions inside IIFEs; bump squint <a href="https://github.com/squint-cljs/squint/commit/db0e3c7b831568a3766e9ade0e2a05490446bfe5">accordingly</a></li><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/169">#169</a>: fix <code>extend-type</code> on <code>Object</code></li><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/171">#171</a>: Add <code>satisfies?</code> macro (<a href="https://github.com/willcohen">@willcohen</a>)</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Released several versions catching up with the clojure CLI</li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li>Fix extra newline in codeblock</li></ul></li><li><p><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</p><ul><li>Add support for a blog contained within another website; see <a href="https://github.com/borkdude/quickblog/README.md#serving-an-alternate-content-root">Serving an alternate content root</a> in README.  (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Upgrade babashka/http-server to 0.1.14</li><li>Fix <code>:blog-image-alt</code> option being ignored when using CLI (<code>bb quickblog render</code>)</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li><a href="https://github.com/babashka/nbb/issues/395">#395</a>: fix <code>vim-fireplace</code> infinite loop on nREPL session close.</li><li>Add <code>ILookup</code> and <code>Cons</code></li><li>Add <code>abs</code></li><li>nREPL: support <code>&quot;completions&quot;</code> op</li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></p><ul><li>neil.el - a hook that runs after finding a package (<a href="https://github.com/agzam">@agzam</a>)</li><li>neil.el - adds a function for injecting a found package into current CIDER session (<a href="https://github.com/agzam">@agzam</a>)</li><li><a href="https://github.com/babashka/neil/issues/245">#245</a>: neil.el - neil-executable-path now can be set to <code>clj -M:neil</code></li><li><a href="https://github.com/babashka/neil/issues/251">#251</a>: Upgrade library deps-new to 0.10.3</li><li><a href="https://github.com/babashka/neil/issues/255">#255</a>: update maven search URL</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li><a href="https://github.com/babashka/fs/issues/154">#154</a> reflect in directory check and docs that <code>move</code> never follows symbolic links (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/181">#181</a> <code>delete-tree</code> now deletes broken symbolic link <code>root</code> (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/193">#193</a> <code>create-dirs</code> now recognizes sym-linked dirs on JDK 11 (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/184">#184</a>: new check in <code>copy-tree</code> for copying to self too rigid</li><li><a href="https://github.com/babashka/fs/issues/165">#165</a>: <code>zip</code> now excludes <code>zip-file</code> from <code>zip-file</code> (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/167">#167</a>: add <code>root</code> fn which exposes <code>Path</code> <code>getRoot</code> (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/166">#166</a>: <code>copy-tree</code> now fails fast on attempt to copy parent to child (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/152">#152</a>: an empty-string path <code>&quot;&quot;</code> is now (typically) understood to be the current working directory (as per underlying JDK file APIs) (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/155">#155</a>: <code>fs/with-temp-dir</code> clj-kondo linting refinements (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/fs/issues/162">#162</a>: <code>unixify</code> no longer expands into absolute path on Windows (potentially BREAKING)</li><li>Add return type hint to <code>read-all-bytes</code></li></ul></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p><ul><li><a href="https://github.com/babashka/process/issues/181">#181</a>: support <code>:discard</code> or <code>ProcessBuilder$Redirect</code> as <code>:out</code> and <code>:err</code> options</li></ul></li></ul><p>Contributions to third party projects:</p><ul><li><a href="https://github.com/clojure/clojurescript">ClojureScript</a><ul><li>CLJS-3466: support qualified method in return position</li><li>CLJS-3468: :refer-global should not make unrenamed object available</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only)</li></ul></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/speculative">speculative</a></li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/thanksgiving-2025.html</id>
    <link href="https://blog.michielborkent.nl/thanksgiving-2025.html"/>
    <title>Thanks for giving!</title>
    <updated>2025-11-26T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Dear sponsors,</p><p>As we approach Thanksgiving once again, I’m reminded that sustained open source software development, supported by long term sponsors, is not something to take for granted.</p><p>I’m genuinely grateful for your ongoing support through GitHub Sponsors. Your contributions make a real difference: my Clojure projects wouldn’t be nearly as polished, maintained, or ambitious without your help.</p><p>If you’d like to look back on what happened in open source this past year, you can find an overview here: <a href="https://blog.michielborkent.nl/tags/oss-updates.html">https://blog.michielborkent.nl/tags/oss-updates.html</a>. The core projects remain clj-kondo, babashka, SCI, scittle, and squint/cherry. Each of them continues to grow in capability and adoption.</p><p>I’ve also applied for Clojurists Together again for 2026. If you’re a CT sponsor, a vote in the next long-term funding round would be appreciated.</p><p>Here are the main ideas I want to explore in 2026:</p><ul><li>Clj-kondo: run macros directly from source code</li><li>Clj-kondo: run exported configs/hooks directly from classpath (instead of having to copy files to a local dir)</li><li>Squint/Cherry: browser nREPL support</li><li>Squint/Cherry: source maps</li><li>Squint: protocolize coll functions so you can extend them to e.g. ImmutableJS or other custom collections</li><li>Scittle2 (working name): better/faster/smaller version of Scittle using Cherry (in-browser CLJS compiler)</li><li>Babashka: support CIDER middleware from source directly in bb</li><li>Babashka: distinguished parallel task output (e.g. colors or prefix)</li><li>Clj-kondo: add first-class support for Clojure dialects like ClojureDart and Jank</li><li>Clojure CLI: help improve UX via a new tools working group</li><li>Clj-kondo: performance improvements for bigger projects</li></ul><p>I can&apos;t make any promises on hard deadlines, but I definitely intend to work toward realizing the above goals.</p><p>Aside from software development, I&apos;m also organizing Babashka Conf 2026 the day before Dutch Clojure Days.</p><p>As always, feel free to reach out anytime, whether here, on Clojurians Slack, or by email at <a href="mailto:michielborkent@gmail.com">michielborkent@gmail.com</a>. I love hearing about what you are doing with my projects. Also if you are struggling with something, let me know. Your feedback and use cases continue to shape the direction of my work.</p><p>Here’s to another strong year of Clojure OSS!</p><p>Thank you for making this journey possible.</p><p>With appreciation,</p><p>Michiel Borkent / @borkdude</p><img src="https://files.mastodon.social/media_attachments/files/115/615/720/682/253/494/original/fcde91e8314702b3.png" width="50%"><p>PS: if you aren&apos;t sponsoring, but are interested, here are the main ways to do so:</p><details>
<summary>Sponsor info</summary><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-sep-oct-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-sep-oct-2025.html"/>
    <title>OSS updates September and October 2025</title>
    <updated>2025-11-02T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during September and October 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babashka</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><!--

- ls -lat ~/dev
- babashka sub dir checken

--><h2 id="updates">Updates</h2><p>The summer heat has faded, and autumn is upon us. One big focus for me is preparing my talk for <a href="https://www.2025.clojure-conj.org/schedule">Clojure Conj
2025</a>, titled &quot;Making tools developers actually use&quot;. I did a test run of the talk at the Dutch Clojure Meetup. It went a bit too long at 45 minutes, so I have to shrink it almost by half for the Conj. The more I work on the talk the more ideas come up, so it&apos;s challenging!</p><img src="assets/dutch-clojure-meetup-october-2025.jpg" width="50%" align="center" alt="presentation at Dutch Clojure meetup"><p>Of course I spent a ton of time on OSS the past two months as well. Some special mentions:</p><ul><li>I&apos;m pretty excited by <a href="https://github.com/chr15m/eucalypt">Eucalypt</a>, a remake of <a href="https://github.com/reagent-project/reagent">Reagent</a> for <a href="https://github.com/squint-cljs/squint">Squint</a> without React by Chris McCormick. It lets you build UIs with the Reagent API in less than 10kb of gzip&apos;ed JS. The code was initially generated by an LLM, but now work is going into making the code base thoroughly tested and simplified where possible.</li><li>After studying Eucalypt&apos;s code I figured that making an even more minimal Reagent-like by hand would be fun. This is where I came up with <a href="https://github.com/borkdude/reagami">Reagami</a>. The API looks like a hybrid between Reagent and <a href="https://replicant.fun/">Replicant</a>. You can build apps with Reagami starting around 5kb gzip&apos;ed.</li><li><a href="https://github.com/borkdude/edamame">Edamame</a> got <a href="https://github.com/clojure/clojure-clr">Clojure CLR</a> support thanks to Ambrose Bonnaire-Sergeant.</li><li><a href="https://github.com/babashka/sci">SCI</a> Clojure CLR support is underway. The <code>sci.impl.Reflector</code> code, based on <code>clojure.lang.Reflector</code> was ported to Clojure with the purpose that it would then be easier to translate to Clojure CLR.</li><li><a href="https://github.com/cljdoc/cljdoc/blob/488fe6282737c1237c5394a66a7e8392a000c6bb/doc/cljdoc-developer-technical-guide.adoc#front-end-code">Cljdoc</a> chose squint for its small bundle sizes and easy migration off of TypeScript towards CLJS</li><li>Via work on Squint, I found a way to optimize <code>str</code> in ClojureScript (worst case 4x, best case 200x)</li></ul><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months in detail.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Bump to clojure 1.12.3</li><li><a href="https://github.com/babashka/babashka/issues/1870">#1870</a>: add <code>.addMethod</code> to clojure.lang.MultiFn</li><li><a href="https://github.com/babashka/babashka/issues/1869">#1869</a>: add <code>clojure.lang.ITransientCollection</code> for <code>instance?</code> checks</li><li><a href="https://github.com/babashka/babashka/issues/1865">#1865</a>: support <code>reify</code> + <code>equals</code> + <code>hashCode</code> on <code>Object</code></li><li>Add <code>java.nio.charset.CharsetDecoder</code>, <code>java.nio.charset.CodingErrorAction</code>, <code>java.nio.charset.CharacterCodingException</code> in support of the <a href="https://github.com/outskirtslabs/sfv">sfv</a> library</li><li>Fix <code>nrepl-server</code> completions and lookup op to be compatible with rebel-readline</li><li>Add <code>clojure.lang.Ref</code> for <code>instance?</code> checks</li><li>Bump SCI: align unresolved symbol error message with Clojure</li><li>Use GraalVM 25</li><li>Bump deps.clj to 1.12.3.1557</li><li>Change unknown or REPL file path to <code>NO_SOURCE_PATH</code> instead of <code>&lt;expr&gt;</code> since this can cause issues on Windows when checking for absolute file paths</li><li><a href="https://github.com/babashka/babashka/issues/1001">#1001</a>: fix encoding issues on Windows in Powershell. Also see this <a href="https://github.com/oracle/graal/issues/12249">GraalVM</a> issue</li><li>Fixes around <code>java.security</code> and allowing setting deprecated Cipher suites at runtime. See this <a href="https://github.com/babashka/babashka/commit/ace237832a5844330f5f9c342e1498eb0ca5f7ac">commit</a>.</li><li>Support Windows Git Bash in bash install script</li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>ClojureCLR support in progress (with Ambrose Bonnaire Sergeant)</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more</p><ul><li>1.5.33 (2025-10-28)</li><li>Add ClojureCLR support (<a href="https://github.com/frenchy64">@frenchy64</a>)</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2651">#2651</a>: resume linting after paren mismatches</li><li>2025.10.23</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2590">#2590</a>: NEW linter: <code>duplicate-key-in-assoc</code>, defaults to <code>:warning</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2639">#2639</a>: NEW <code>:equals-nil</code> linter to detect <code>(= nil x)</code> or <code>(= x nil)</code> patterns and suggest <code>(nil? x)</code> instead (<a href="https://github.com/conao3">@conao3</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2633">#2633</a>: support new <code>defparkingop</code> macro in core.async alpha</li><li><a href="https://github.com/clj-kondo/clj-kondo/pull/2635">#2635</a>: Add <code>:interface</code> flag to <code>:flags</code> set in <code>:java-class-definitions</code> analysis output to distinguish Java interfaces from classes (<a href="https://github.com/hugoduncan">@hugoduncan</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2636">#2636</a>: set global SCI context so hooks can use <code>requiring-resolve</code> etc.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2641">#2641</a>: fix linting of <code>def</code> body, no results due to laziness bug</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1743">#1743</a>: change <code>:not-empty?</code> to only warn on objects that are already seqs</li><li>Performance optimization for <code>:ns-groups</code> (thanks <a href="https://github.com/severeoverfl0w">@severeoverfl0w</a>)</li><li>Flip <code>:self-requiring-namespace</code> level from <code>:off</code> to <code>:warning</code></li><li>2025.09.22</li><li>Remove <code>dbg</code> from <code>data_readers.clj</code> since this breaks when using together with CIDER</li><li>2025.09.19</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1894">#1894</a>: support <code>destruct</code> syntax</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2624">#2624</a>: lint argument types passed to <code>get</code> and <code>get-in</code> (especially to catch swapped arguments to get in threading macros) (<a href="https://github.com/borkdude">@borkdude</a>, <a href="https://github.com/Uthar">@Uthar</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2564">#2564</a>: detect calling set with wrong number of arguments</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2603">#2603</a>: warn on <code>:inline-def</code> with nested <code>deftest</code></li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Support passing keyword to <code>mapv</code></li><li>Inline <code>identical?</code> calls</li><li>Clean up emission of paren wrapping</li><li>Add <code>nat-int?</code>, <code>neg-int?</code>, <code>pos-int?</code> (<a href="https://github.com/eNotchy">@eNotchy</a>)</li><li>Add <code>rand</code></li><li>Fix rendering of <code>null</code> and <code>undefined</code> in <code>#html</code></li><li><a href="https://github.com/squint-cljs/squint/issues/747">#747</a>: <code>#html</code> escape fix</li><li>Optimize nested <code>assoc</code> calls, e.g. produced with <code>-&gt;</code></li><li>Avoid object spread when object isn&apos;t shared (<code>auto-transient</code>)</li><li>Optimize <code>=</code>, <code>and</code>, and <code>not=</code> even more</li><li><code>not=</code> on undefined and false should return <code>true</code></li><li>Optimize code produced for <code>assoc</code>, <code>assoc!</code> and <code>get</code> when object argument can be inferred or is type hinted with <code>^object</code></li><li>Optimize <code>str</code> using macro that compiles into template strings + <code>?? &apos;&apos;</code> for null/undefined</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/732">#732</a>: <code>take-last</code> should return <code>nil</code> or empty seq for negative numbers</li><li><a href="https://github.com/squint-cljs/squint/issues/725">#725</a>: <code>keys</code> and <code>vals</code> should work on <code>js/Map</code></li><li>Make <code>map-indexed</code> and <code>keep-indexed</code> lazy</li><li>Compile time optimization for <code>=</code> when using it on numbers, strings or keyword literals</li><li>Switch <code>=</code> to a deep-equals implementation that works on primitives, objects, <code>Arrays</code>, <code>Maps</code> and <code>Sets</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/710">#710</a>: add <code>parse-double</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/714">#714</a>: <code>assoc-in</code> on <code>nil</code> or <code>undefined</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/714">#714</a>: <code>dissoc</code> on <code>nil</code> or <code>undefined</code></li><li>Basic <code>:import-maps</code> support in <code>squint.edn</code> (just literal replacements, prefixes not supported yet)</li></ul></li><li><p><a href="https://github.com/borkdude/reagami">reagami</a>: A minimal zero-deps Reagent-like for Squint and CLJS</p><ul><li>First releases</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Support evaluation of quoted regex</li><li>Support macros defined in notebooks</li><li>Bump cherry</li></ul></li><li><p><a href="https://github.com/borkdude/cljs-str">cljs-str</a></p><ul><li>More efficient drop-in replacement for CLJS str. This work was already upstreamed into CLJS, so coming near you in the next CLJS release.</li></ul></li><li><p><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</p><ul><li>Support finding unused git deps</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li>Fix SCI regression where interop on keywords like <code>(.catch ...)</code> was accidentally munched</li></ul></li><li><p><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a></p><ul><li>Add <code>:start</code> attribute to ordered lists not starting with 1 (@spicyfalafel)</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Bump squint compiler common component and standard library</li><li>Bump other deps</li><li>Optimize <code>=</code>, <code>str</code>, <code>not=</code></li><li>Support <code>:macros</code> option + <code>:refer</code> so you can use unqualified macros using compiler state (see <code>macro-state-test</code>)</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Released several versions catching up with the clojure CLI</li></ul></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p><ul><li>Add <code>close-connection</code></li><li>Fix #38: add <code>get-connection</code> to cache connection</li><li>Fix potential memory leak</li><li>Better handling of parent process death by handling EOF of stdin</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3/issues/25">#25</a>: use musl to compile linux binaries to avoid dependency on glibc</li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li>Fix extra newline in codeblock</li></ul></li></ul><p>Contributions to third party projects:</p><ul><li><p><a href="https://github.com/clojure/clojurescript">ClojureScript</a></p><ul><li>Optimize <code>str</code> (4x worst case, 200x best case)</li><li>Make <code>munge-str</code> public</li></ul></li><li><p><a href="https://github.com/yogthos/Selmer">Selmer</a></p><ul><li><a href="https://github.com/yogthos/Selmer/commit/7588259c9e356372c0e010594ae0d3d35a89ffca">Handle error for template without closing delimiter</a></li></ul></li><li><p><a href="https://github.com/clojure-lsp/clojure-lsp">clojure-lsp</a></p><ul><li>Optimize <code>:ns-groups</code> handling by caching regex creation and usage</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only)</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/speculative">speculative</a></li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/reagami.html</id>
    <link href="https://blog.michielborkent.nl/reagami.html"/>
    <title>Reagami: a Reagent-like library in less than 100 lines of Squint CLJS</title>
    <updated>2025-10-24T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Recently I&apos;ve been excited about <a href="https://github.com/chr15m/eucalypt">Eucalypt</a>, a Reagent-clone in pure <a href="https://github.com/squint-cljs/squint">Squint</a>.  For those who don&apos;t know Squint, it is a CLJS dialect that re-uses JS features as much as possible. Maps and vectors compile directly to objects and arrays for example. The standard library mimics that of Clojure(Script). Collections, although they are mutable in JS, are treated immutably via shallow-copying.  You can build small apps in Eucalypt starting at about 9kb gzip. When looking at the code, I wondered if we could make an ultra-simple Reagent-like library with less features for even smaller apps. If I understand Eucalypt correctly, it produces DOM nodes from hiccup and then patches the already mounted DOM nodes using a diffing algorithm. I tried to do this in under 100 lines, in a more basic fashion.  I call this library <a href="https://github.com/borkdude/reagami">Reagami</a>, a library you can use to fold your state into the DOM!</p><p>Let&apos;s explain how it works.</p><h2 id="rendering-hiccup-to-dom-nodes">Rendering Hiccup to DOM nodes</h2><p>Below you see the <code>create-node</code> function, which takes hiccup, e.g. <code>[:div
&quot;Hello&quot;]</code> and transforms it into a DOM node. I placed comments in the code that help you understand it, hopefully.</p><pre><code class="language-clojure">(defn- create-node
  ([hiccup] (create-node hiccup false))
  ([hiccup in-svg?]
   (cond
;; we compile primitives directly into TexNodes
     (or (nil? hiccup)
         (string? hiccup)
         (number? hiccup)
         (boolean? hiccup))
     (js/document.createTextNode (str hiccup))
;; vectors indicate a DOM node literal or a function call
     (vector? hiccup)
     (let [[tag &amp; children] hiccup
;; here we pull apart id and class shortcuts like: `:div#my-id.my-class`
           [tag id class] (if (string? tag) (parse-tag tag) [tag])
           classes (when class (.split class &quot;.&quot;))
;; hiccup vectors can have an optional map to set attributes of the DOM node
          [attrs children] (if (map? (first children))
                              [(first children) (rest children)]
                              [nil children])
;; SVG needs special handling, SVG nodes need to be created with `createElementNS`, see below
           in-svg? (or in-svg? (= :svg tag))
;; if we encounter a function as the first element, e.g. `[my-component]`, we call it
           node (if (fn? tag)
                  (let [res (apply tag (if attrs
                                         (cons attrs children)
                                         children))]
;; and then we feed the result back into create-node
                    (create-node res in-svg?))
;; so here we create the DOM element, either a normal or an SVG one
                  (let [node (if in-svg?
                               (js/document.createElementNS svg-ns tag)
                               (js/document.createElement tag))]
;; here we iterate over all the children in the hiccup vector
                    (doseq [child children]
;; in squint, vectors are also seqs, but here we want to make sure the result is list-like,
;; e.g. the result from `(for [i xs] [my-component])`
;; if that is the case, then we map create-node over those results
                      (let [child-nodes (if (and (seq? child)
                                                 (not (vector? child)))
                                          (mapv #(create-node % in-svg?) child)
;; else, we have only one node as the result of calling create-node on the child
                                          [(create-node child in-svg?)])]
;; let&apos;s add all the child-nodes to the DOM element created from the tag!
                        (doseq [child-node child-nodes]
                          (.appendChild node child-node))))
;; attribute handling: for each key and value in the attribute map:
                    (doseq [[k v] attrs]
                      (let [key-name k]
                        (cond
;; Let&apos;s create some CSS if the style attribute is a msp!
                          (and (= &quot;style&quot; key-name) (map? v))
                          (doseq [[k v] v]
                            (aset (.-style node) k v))
;; if the attribute starts with &quot;on&quot;, then we add an event handler
                          (.startsWith key-name &quot;on&quot;)
;; we support :on-click, :on-mouse-down, :onMouseDown, etc.
                          (let [event (-&gt; (subs key-name 2)
                                          (.replaceAll &quot;-&quot; &quot;&quot;)
                                          (.toLowerCase))]
                            (.addEventListener node event v))
;; if the attribute false is false or nil, we ignore it
                          :else (when v
                                  (.setAttribute node key-name (str v))))))
;; classes parsed from the tag, e.g. `:div.my-class1.my-class2`
                    (let [class-list (.-classList node)]
                      (doseq [clazz classes]
                        (.add class-list clazz)))
;; finally we handle the id parsed from the tag, e.g. `:div#my-id`
                    (when id
                      (set! node -id id))
                    node))]
       node)
     :else
     (throw (do
              (js/console.error &quot;Invalid hiccup:&quot; hiccup)
              (js/Error. (str &quot;Invalid hiccup: &quot; hiccup)))))))
</code></pre><p>That&apos;s it! Pretty simple.</p><h2 id="patching-the-dom">Patching the DOM</h2><p>If we simply just re-insert the generated hiccup DOM nodes into the DOM every time something changes, then we have several problems. E.g. when we are typing in an input field and we insert a new input field, we lose focus. Also we lose event handlers, although this isn&apos;t really an issue if we re-generate them via the hiccup-to-DOM function above.  A better approach is to cleverly patch the DOM and re-use existing DOM nodes when possible.</p><p>The <code>patch</code> function takes a parent node, some child nodes and tries to re-use or insert the children. There are several libraries that do this far more intelligently than the below function. E.g. <a href="https://github.com/bigskysoftware/idiomorph">Idiomorph</a> is such a library. One problem I encountered with Idiomorph is that it doesn&apos;t preserve event listeners. There&apos;s also <a href="https://github.com/snabbdom/snabbdom">Snabbdom</a>, a small but effective vDOM library that you could use. But where&apos;s the fun in that, if you can make your own naive patch function. Here we go! When we render a component for the first time, Reagami calls <code>patch</code> with the root node (usually something like <code>(js/document.querySelector &quot;#app&quot;)</code>) and the rendered hiccup as the only child. Read along with the comments again.</p><pre><code class="language-clojure">(defn- patch [parent new-children]
;; First we take a look at the current children of the root node, already mounted in the DOM
  (let [old-children (.-childNodes parent)]
;; If the amount of children isn&apos;t the same, we just give up and replace all the children with the new children.
;; This typically happens on first render or when elements disappear due to conditionals in the hiccup code.
;; More mature patching libraries do much more clever things here
;; but I&apos;ve found this works well enough for the basic use cases I tested.
    (if (not= (count old-children) (count new-children))
      (parent.replaceChildren.apply parent new-children)
;; When the number of children is the same we compare them one by one.
      (doseq [[old new] (mapv vector old-children new-children)]
        (cond
          (and old new (= (.-nodeName old) (.-nodeName new)))
;; Only when the node names are the same, we consider it the same node.
;; If it&apos;s Text node, we need to copy over the text content.
          (if (= 3 (.-nodeType old))
            (let [txt (.-textContent new)]
              (set! (.-textContent old) txt))
            (let [new-attributes (.-attributes new)
                  old-attributes (.-attributes old)]
;; Here we just set all the attribues from the new node to the old node.
              (doseq [attr new-attributes]
                (.setAttribute old (.-name attr) (.-value attr)))
              (doseq [attr old-attributes]
;; When an existing attribute in the old node, doesn&apos;t occur in the new node, we remove it
                (when-not (.hasAttribute new (.-name attr))
                  (.removeAttribute old (.-name attr))))
;; Then we recursively descend into the children of the new node.
              (when-let [new-children (.-childNodes new)]
                (patch old new-children))))
;; If the node names aren&apos;t the same, we replace the node completely with the new node.
          :else (.replaceChild parent new old))))))
</code></pre><h2 id="putting-it-all-together">Putting it all together</h2><p>Reagami&apos;s only public function is called <code>render</code> which is just:</p><pre><code class="language-clojure">(defn render [root hiccup]
  (let [new-node (create-node hiccup)]
    (patch root [new-node])))
</code></pre><p>With this single function, you can write a small reactive app, if we combine it with <code>atom</code> and <code>add-watch</code>.  Here&apos;s an example of this:</p><pre><code class="language-clojure">(ns my-app
  (:require [&quot;https://esm.sh/reagami@0.0.8&quot; :as reagami]))

(def state (atom {:counter 0}))

(defn my-component []
  [:div
   [:div &quot;Counted: &quot; (:counter @state)]
   [:button {:on-click #(swap! state update :counter inc)}
    &quot;Click me!&quot;]])

(defn render []
  (reagami/render (js/document.querySelector &quot;#app&quot;) [my-component]))

(add-watch state ::render (fn [_ _ _ _]
                            (render)))

(render)
</code></pre><p>(<a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE3VQu27DMAzc%2FRWMssiDH2OhKUA%2BIaNhFKrE1G6jRySqQRDk3wvLitGl4iCCuDvekdsI5t5I7ysALgJe0xwQBjYR%2BSi6DqNp49QFlJ%2FSzIe%2B7ds3BkJGKKOxrquKazxDJEkIXJIz8BDKJUsYoH%2B%2BAHbZpJzxzqIlGMYKYBB6%2FqmgNMCOmaUFMOCbxCEr1%2BOK%2B0hEzsJDONuoy6y%2BYc%2FjTfpdMZC8Xr6NPVtVPxcqsGOGG9yxcdxMBbQaw2qHl1BdGfKv2GmnkkFL7TVhuJ%2FwgopcALaX3rMahr%2Bh1mNIrZubJDUVR0K85M4WhnfIldP8%2B%2FjKqLNe6X8BNOGTqawBAAA%3D">Open this example on the Squint playground</a>)</p><p>That&apos;s it: a Reagent-like library in less than 100 lines of code!</p><p>Further ideas:</p><ul><li>Blending hiccup and patching so we don&apos;t even need to create DOM nodes for stuff that hasn&apos;t changed</li><li>Or remember the hiccup we generated on the previous change, compare that since that&apos;s more efficient? (I believe Eucalypt does this).</li><li>Better patching by looking at IDs or keys</li></ul><h2 id="examples">Examples</h2><p>Here are some examples you can play with on the Squint playground:</p><ul><li><a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE41TO2%2FbMBDe%2FSs%2BMyhADn5MHTg0AYqsXTIKRsGI54ipRDLkyYZh%2BL8X1KOCPVUcRB6%2Fx93pJH1GZ5xfAVIn%2BupdIlSiYY5Z73aUu21udonMh%2Bncy367334X0CZjCh2UWq2kpSMyGyZIw6HDVdeh90wJe%2BjchDM49XSbsR69Q3VYAZW27rRC2bz3zMHjqoPf1K2r%2F%2BBJ5rOJ60m5j7a8RjkfWN0KD%2BKtCednCMjx5mVAqyIOeW7IP1wMpNEXV5350tKQbhsS9Eci8rdRuIBiIsiYNpnTnfBw6XzsGVd9Mm1PkNP5zmZ5SlUj4L4qk3OoMXHl5ge%2BQbNJH8QYhZW6LZb%2F26O5%2B87Xaq4G4ufA6GgtZkXpjpJO5J8hB8pjFWqpo9IR4vVEHgNi0Zj79NhMkciKf70s%2Fr8Co7itxUGVNQ1OCoHL%2BIUE%2BZl3NtR9R563Xz2lyxu1VHORezIxijEfaQOHe3CdyDC9tlROENadxJy7zMRrbJyFWCRwT38P9rKNiSJ5q9Qyp4m8pTTOqpxGfjcFS96o%2BukXMNZuzobrZvoUWo%2BwQjx6VL8xrEORKfHRZNr%2FBf022K2GAwAA">Input field + counter</a></li><li><a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE71WS28bNxC%2B61dMaBSggKwc9FJgAyQu2lx7aI5b1qDEkcR6l1yTs3IEwf%2B94GOftpz0UgkS9jHzceabb4bkxkMjtVkB8NLhY6cdQsWORK0vb2%2FRNxt%2FvHUoD7LRDErpId%2BI9Xq14gr3sLeuKbTRBJfSyAaBsRUsPiUqTdocPgO5Dp%2BzqzU7BE%2BSELgk28CllEY3svZweX6BkZHCcuOaz30YBqRSRXJ%2FB5UIGfkn2b7rF9gbqOKleInMaySoYvC8%2BJQ90koxpfWVYEAr4J4ccCeNsk3RdVqt16%2BsAMCl93ZXaJPhqyFXrURPXfwrtQKtntfh0yfnsLEnHPOTLxLsWhWj7lGVDusBD2hygpTs3kIaAh1DzCgiIPVAe421KrRpOyqO0qga3QqA%2FYnUOeNBQn4IdJSUl%2FVwknWHoA3Egjeyfb8C6IxCBw94fg9Pmo7ZaO9sA9b8dpTmgIAnNBSUVUXPBzzHwENZc0lzEuF1LkDMJJjme77ZAEJB0h2QoIjLTFlOyZxkrdVnqKLIBslwj4%2FAU5nGNxPnIHG5rTFRAlXirtAqeus98ANSoPVuKYDBcuwTkSRXlQnsUno61wiXcmtd4Ir93H4Db2utYFvL3QNb9EtJ5xaBEX6jRTeWidwfCSbkKhbaL4eC3HxPNEuk2Fs%2Fwabnf9MX4FnkZNv%2FEJaYdH565%2BxTL%2BfYz%2Bnxdche1GOGw5Ti48BK1us%2BRHLJuipJQbWoeY8opjbltiOyBj5%2B3GzJhF%2FROt1Id960XV0XTh%2BONCX5UirtA6oCbiwBn8kydOCyILXePaRWeHX0ROk%2FHdEMCV6zAuCL%2BZBVfhX25Qh6dXJMlA3G0no902vojoFw9lWekAH7ojSxq1xCJHMkMPKqgjDdnMuenhu%2BmKG5sLNA2F%2Fdhw%2B%2F%2F8KEENPZ65GK0POvbSxpxiy2pRfajK%2Bjcy%2BhkND%2F3ePjjvZKW2cNX23rifMbnSxWy2L9kOrf1jxPi98NI3ce%2BO77%2BueT08E1MfNJoWcCZb8qxcbMhFhU1%2FeVVfqUjUIqm8l%2F4cnpFvuK0xGlGoTdKzY8B%2FaHbJCJfDO5EMMI2lqVdzTeyDYlXt2DFPPs%2F76UD3hOBxQ2zsiCDYeCuaCqyRyVo0D40Mt3s2FQTaQtxIQUZy0VO9u01qChBTc391XZOgTeusBJjylgNUL6ASxihY6zDvg%2F%2FlbZXdegoc1jh%2B78FWvckXXAbmTbshQXV5bs3HjnUBJ%2BqTHcAVP6xPrsuEd6B2FbYSMEzN0D3ZvWYYtGzc9k8diSRkI%2BFt%2FmhyFuqOZMpJEShPgkaXfsj5llcukPM%2FcQvyJAhudpwXz9L76X4DewCwAA">Boring crud table</a></li><li><a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE41WW4%2BjNhR%2Bz684y6iS2YoJTLsvZGenlbqqql2pUi9PiFYOPiSeGJu1HRI6yn%2BvbJNAZpnVECngw%2BfP534g0kBDuVwAkFzjlz3XCEW0tbY1%2BXKJprk126VGuqENjyCnBoZFGceLBWFYg%2BH%2FIdylMaxWsNGcBQG5S493aRwgFQoBWYAgrbZBcA9Z2h4Di5IVgrHUolOFWtXAU24k3SEUxTvI0hKKH8PtB3crYQVccsupgABbK9Yv4HzljGsoMkgdsFEdlxvQfLO1E0itFIMiC%2BwjnRNPUFTwDh%2FA6j2ezjZL0FQy1SSBolwAFMSJEi6ttz%2BGZ%2BvysrVRHSaDaW4nMQfavrkYD0BqCcVTvsPeQBGAzhp%2FVtCm9JEw9lQOihJeA5HKDu%2Fji%2F5mNJgItFBskTIgHVZQkO%2BBSLsFUnNtbHBjDGkcpO7INB6Z5q95jmzCkcXO9pmt1OIDkHvwGjnjZlESD4OzvNKkUtKELc5mzzG8Xu%2BtoBcd4nnVj0ExT5DOIvoJIptFbLlNDlSIByBKA3kPR%2B%2B099C%2FQHnlsA%2F3cDynyId76MPziwcZFPUDEKMahJuzt75z6YXGjt6J4%2FI5g3MV%2B5p2oj01RlVg7CXJayoMzqgyUeTVe0J4R3iI0hjOUH5kUkhzTshRGPwGTRyuxWK1gr94gxqEUu2CPJqlQfubtKg7KqY1d5emAf4J%2B7WimkGlpNVKmAW5pYx97FDaz9xYlKjh0SwPXDJ1gGiHPVMHGS2GCsXg8VBWO%2ByB3CbuhpdQTCsb9i1zN9eYXs4RT8y4%2FiqY14GlBmGH%2FbdzLfpZa3X4u41Cd7j31VikkJXx%2BTHJ5kvzOckvzu5nNMmE55U0n7G21zSuQQ8siX9%2BDc0fro9f8yQTolfwMK7PeRN6sptHicbKQlEcoS%2BhUkL5KBS5Fz%2FlRyBv4eiRMeS9W%2FVhNTkrP3Bmh%2FGWb9Ep6hdTSM2FCPyncShsaINJSMcwFHxWXQ%2BB6QA4wU8%2BrUKiFDnjXTijyE23gadBEfI2TONB60GjK%2BmVp3Jje4HwlK%2BVZqghytojGCU4g7Wg1S6a9Wu%2BptVuo9VeMohuEOvodBqAq1Xox%2BeKqJWGoqV6aNNjnv%2FjbQVirAb3Pj5BMUbF74g2GlFGl%2BCuVtNZPUF7R0UaWVSOUOdhUB1q%2FyfouXrIYYtyfngWucVjiP271MU8S1PXt6RNho%2BeIZpRcM4Jol%2FdKb93qN9EZVyOH0laKTeJ%2FcB4NEumqn2D0t5%2B2aPu%2F0SBlVUaohvatlFQgDBl1TW40kgtfhToVhAx3kXxpdWgfQMJZxCNFHC93X0h3bYaW5RsmvwapYt1yLvh8245CJ3eUIzZGSyijCUHaqvt0NvyPMDPrfFf8L%2FS0Tl5OGx4%2Fh8hQm1YdAoAAA%3D%3D">Snake game</a></li><li><a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE5VWXY%2FjNBR9n19xCS%2BOtEm7EiDkIO0K2DfgAYQEiqqVG98k3nHtrO10Ekb978gfyfRr0dA%2BpI3P%2FfC5xychysKBCfUAQKjBz6MwCHXWOzdYutmgPZS23xhkHTuI99tyW36XAWUW0q1dnj88EI4t7CVrHoteSywGbeGZTvDNdgt09pfTgrKOOQTCnD4EyNsICRcmxRHfgTMjnnzaqoI%2FnZDCzdCOqnFCKxuyKGiktvgO6gnmnW%2BdKQ7kByC%2FMtdv2N4CKWACQqertvI8h2%2B3%2BQMA3OBnIHS%2Bj%2FfdpModuqKRApUrDDYOajy60IJEB7UBUnboftSj4kJ1PwXg7x5HysIx06EDPLo834UWnqnENqyFq8nfUKeHgNUDmHyh4cMRlYOeKS7RLBwc9GixOOgjFmkFat22FmM%2FrVp7W7qb%2FDZJmfr%2FK3QSSIpheeQlfuYL7N8Ldl6xuwQmogWS5jHB%2FJKDGLTovkojf17G2zJp8fRl2ATTWRs3HzrD%2FJ%2FrlyrKF30ufI3DGVsq0LfS9XHlq6rAoF8D12OMDP%2BksA4VmkhqGTFhOr%2BkFfhkN09Ccf0E2RqXQSp10w7XT%2BqlodjKJ7tptLJaYil1BzQgPdCTVlVegrBPCoMgQt2GPheBSTygcqson%2BkjzhbqoDGnh93pNSo9U0MceZjNlYBy8Enzm4HQG%2FnkvnJ%2BWpFVBRxboRBmPRoI7C48kFmPwKRBxmfo2RFBnNVIVAK5cwCSONchMs6%2FPD3G%2Bf8Z3U3OcVgzguuZS5Kxl5p5bbFxyJYtnWn0RTercLhhXcf2Eov96JxWUPvt1pSLo69V0%2F4tkMEU1hl4H05V5KOmEZ%2Bcx7pZ%2BvP2TyEUxwm%2BvxwiHbQV3nIhY3ur5egwu0JE7%2FJl7hgtZMOU5VBdxQR7iyE3XhtDrgL2rHnsjFcqZI2W2tAYVmWnKKbsN%2B2gR4MwSGQWs7BZ8tSjArK4QeIh5r4g4hVUvIaMGzpSxfs0XBNxAV7PCA3DT2f%2Fjl8swOxnwzo4YLbLd6tKjNauaPRh0Mo%2FO6JGrqWzwAPa%2B4U2wX64bkZvIeXnEc38B0psnDaQfc2GIU2IcO30JbgxyBx%2BiO4DGRfHdZokWHwhOGQvKeAyfK%2F5XA4GB1T8XO8GFffmGLwxvXZs0k3fN9SXe42vJIzz4om5pk8PFkpjyOr1EL47n9LfjwXT738B1bnPCBYJAAA%3D">Draggable button</a></li><li><a href="https://squint-cljs.github.io/squint/?src=gzip%3AH4sIAAAAAAAAE4VTuW7jMBDt9RUTpqGAlewU2YJVmgW2TykIAU2OLGZ5hRzZMYz8%2B0Ky4mNXSMRC5PDN45uL%2BwxOGl8AcJHwbTAJoWE9UcxitcLs6tyvEsqtdOZpXa%2FrnwyEzDCb2rIsCq6xg0ySELik4OAo%2BrDDBJ20GT8%2BIR424b1SwcXg0RM0bQHQCG12cBSZDhbhKPZGUw%2FsYb2O76yAfz%2FRo9n29AVgI9WfbQqD15UKNiTgpgM%2BC3qaVJbAEmoGbGMHZOUCCSXpsyETPLD%2FCNf1YwaUGX%2FAhOtCchfjkqYLbFFMVtIif6gfS3Y%2BlIu6tMnRygOwzuJi9NKara8MocvAFHrCtAR7HTKZ7lCp4GksxRfQU8xs3xtajE0NKY%2BAGMxE8XHBiOArF4aMEznc87yX8W7ulCHq8TfnwgcqFxwtyh1%2B6zg9yX5PZ4esPfdbCoEWG250aERMCDymKtO5GO10c9On7SffRDcOythUr3mlgxoceqrfBkyHZ7SoaMzEvYzxXD2uA4VbuEooCX9ZdFPqtdld1ZpnpDuojAZ2TQO3FJugD3VMGNHrsrwMWEKvMZ0C5fOIrmbjqB6a25ScxldqXe0lqX7OsBAnl%2Btq885D8wLTakfuEXB6ed7%2FBcFoSnxLBAAA">CSS transition</a></li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jul-aug-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jul-aug-2025.html"/>
    <title>OSS updates July and August 2025</title>
    <updated>2025-08-05T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during July and August 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><!--

- TODO: mention upcoming talk at Clojure Conj 2025!

- ls -lat ~/dev
- babashka sub dir checken

--><h2 id="updates">Updates</h2><p>Although summer hit Europe and I made a train trip to Switzerland for some hiking with my wife, OSS activity continued in the borkiverse. 20 projects saw updates. As usual, babashka, SCI and clj-kondo saw the most activity.</p><img src="assets/mb-switzerland-2025.jpeg" width="50%" align="center"><p>One of the big things I’m looking forward to is speaking at <a href="https://www.2025.clojure-conj.org/schedule">Clojure Conj 2025</a>. At the risk of sounding a bit pretentious, the title of my talk is &quot;Making Tools Developers Actually Use&quot;. Babashka started as a quirky interpreter &quot;nobody had asked for&quot; but now many Clojure developers don&apos;t want to live without it. Clj-kondo started out as a minimal proof-of-concept linter and now is widely used tool in Clojurian&apos;s every day toolset and available even in Cursive today. In the talk I want to reflect on what makes a tool something developers (like myself) actually want to use. I&apos;m excited about this opportunity and about my first time visiting the Conj (don&apos;t ask me how I got the Clojure Conj cap on the photo above). Given the rest of the schedule, it&apos;s something I wouldn&apos;t want to miss.</p><p>For babashka, my main focus has been making it feel even more like regular Clojure. One example is the change in how non-daemon threads are handled. Previously, people had to sometimes add <code>@(promise)</code> to keep an httpkit server alive. Now babashka behaves like <code>clojure -X</code> in this regard: if you spawn non-daemon threads, the process waits for them. It’s looks like a small change, but it brings consistency with JVM Clojure, something I&apos;m always aiming for more with babashka. If you want the old behavior, you can still use <code>--force-exit</code>. While implementing this I hit an interesting bug with <a href="https://github.com/oracle/graal/issues/12116">GraalVM</a> and also found out that <code>clojure -X</code> sometimes stalls when using agents. Maybe more on this next time.</p><p>Another change that was introduced is that when code is evaluated through <code>load-string</code> or <code>Compiler/load</code> (which is the same thing in bb), vars like <code>*warn-on-reflection*</code> are bound. This fixes a problem with loading code in non-main threads. E.g. <code>@(future (load-string &quot;(set! *warn-on-reflection* true)&quot;))</code> would fail in previous versions of babashka. You might wonder why you would ever want to do this. Well, a similar thing happens when you execute babashka tasks in parallel and that&apos;s where I ran into this problem.</p><p>SCI, the interpreter under the hood of babashka and several other projects, got some critical fixes as well. I detected one somewhat embarrasing bug when loading <code>clojure+.hashp</code> in babashka. It had code that looked like:</p><pre><code class="language-clojure">(def config {})
(let [config {}
      _ (alter-var-root #&apos;config (constantly config))
     ]
  ...)
</code></pre><p>In the expression <code>(alter-var-root #&apos;config (constantly config))</code> the var <code>#&apos;config</code> was mistaken for the local <code>config</code> since SCI&apos;s analyzer used a <code>resolve</code>-like function that also resolves locals. This fails horribly. In 6 years of SCI it&apos;s the first time I encountered this bug though. After fixing this problem, I noticed that babashka&apos;s CI acted up. On every commit, babashka CI tests dozens of Clojure libraries by running their test suites. I noticed that specter&apos;s tests were failing. It turned out that one test actually worked prior to fixing the above bug exactly because the SCI analyzer&apos;s <code>resolve</code> returned a node that evaluated to a local value. But there is no way I could just leave that bug in, so I had to make a pull request to specter as well to set this straight. A new specter version was released that works both with older version of babashka and the new version.</p><p>One other headscratcher in SCI was on the ClojureScript side of things and had to do with munging. In interop like <code>(.-foo-bar #js {:foo-bar 1})</code> ClojureScript munges the field name in the interop form to <code>foo_bar</code> but in the object it stays <code>&quot;foo-bar&quot;</code>. The munging of this name wasn&apos;t applied in SCI as an oversight. So in SCI (and thus in nbb, joyride, scittle, etc.) the above expression would return <code>1</code> whereas in ClojureScript it would return <code>nil</code>. In contrast, <code>(.-foo-bar #js {:foo_bar 1})</code> would return <code>nil</code> in SCI but <code>1</code> in CLJS. Although fixing this could mean a breaking change in SCI-based scripting environments I decided to align it with CLJS anyway, as switching between SCI and CLJS should not introduce these kinds of surprises.</p><p>Other improvements in SCI were made in the area of better using type hints on instance method interop.</p><p>And then there’s clj-kondo, the linter that is supposed to spark joy ✨, as far as a linter is able to do that in a developer&apos;s life. Two new linters were added, including one that catches suspicious uses of locking. This linter was inspired by a similar rule in splint. Lots of smaller improvements were made like sorting findings and imported files such that they are consistent across multiple runs that use the <code>--parallel</code> option and across operating systems. And as usual bugfixes and preventing false positives.</p><p>One happy improvement to <a href="">scittle</a> is that referencing a library that was introduced by a <code>&lt;script&gt;</code> tag now was made a lot easier. You can find the docs about that <a href="https://github.com/babashka/scittle/blob/main/doc/js-libraries.md">here</a>. The tl;dr of this is that when a library registers itself as a global, you can just use that global in <code>:require</code> now: <code>(require &apos;[&quot;JSConfetti&quot; :as confetti])</code>.</p><p>Of course, none of this happens in isolation. I’m deeply grateful to the community and the sponsors who make this work sustainable: Clojurists Together, Roam Research, Nextjournal, Nubank, and many other companies and individuals. Every bit of support means I can keep refining these tools, fixing edge cases, and thinking about the long-term direction.</p><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months in detail.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Bump clojure to <code>1.12.2</code></li><li><a href="https://github.com/babashka/babashka/issues/1843">#1843</a>: BREAKING (potententially): non-daemon thread handling change. Similar to JVM clojure, babashka now waits for non-daemon threads to finish. This means you don&apos;t have to append <code>@(promise)</code> anymore when you spawn an httpkit server, for example. For futures and agents, bb uses a thread pool that spawns daemon threads, so that pool isn&apos;t preventing an exit. This behavior is similar to <code>clojure -X</code>. You can get back the old behavior where bb always forced an exit and ignored running non-daemon threads with <code>--force-exit</code>.</li><li><a href="https://github.com/babashka/babashka/issues/1690">#1690</a>: bind <code>clojure.test/*test-out*</code> to same print-writer as <code>*out*</code> in nREPL server</li><li>Add <code>Compiler/demunge</code></li><li>Add <code>clojure.lang.TaggedLiteral/create</code></li><li>Add <code>java.util.TimeZone/setDefault</code></li><li>Add <code>println-str</code></li><li>SCI: Var literal or special form gets confused with local of same name</li><li><a href="https://github.com/babashka/babashka/issues/1852">#1852</a>: <code>(.getContextClassLoader (Thread/currentThread))</code> should be able to return results from babashka classpath</li><li>Bump <code>deps.clj</code> to <code>1.12.2.1565</code></li><li>Bind more vars like <code>*warn-on-reflection*</code> during <code>load{string,reader}</code> (same as JVM Clojure) so can load code in other than than the main thread</li><li><a href="https://github.com/babashka/babashka/issues/1845">#1845</a>: expose <code>cheshire.generate/{add-encoder,encode-str}</code></li><li>Bump timbre to <code>6.8.0</code></li><li>Bump clojure.tools.logging to <code>1.3.0</code></li><li>Improve interop using type hints on qualified instance methods</li><li>Bump Jsoup to <code>1.21.2</code></li><li>Bump <code>fs</code> to <code>0.5.7</code></li><li>Bump <code>cheshire</code> to <code>6.1.0</code></li><li>Pods: no exception on destroy when there&apos;s still calls in progress</li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Add <code>println-str</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/997">#997</a>: Var is mistaken for local when used under the same name in a <code>let</code> body</li><li>Fix regression introduced in <a href="https://github.com/babashka/sci/issues/987">#987</a></li><li>Fix <a href="https://github.com/babashka/sci/issues/963">#963</a>: respect <code>:param-tags</code> on qualified instance method</li><li>Add <code>*suppress-read*</code></li><li>Add <code>load-reader</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/872">#872</a>: <code>*loaded-libs*</code> is now the single source of truth about loaded libs</li><li>Fix <a href="https://github.com/babashka/sci/issues/981">#981</a>: respect type hint on instance method callee</li><li>Add core dynamic vars like <code>*warn-on-reflection*</code> and bind them during <code>load-string</code> etc. such that <code>set!</code>-ing then in a <code>future</code> works.</li><li>Fix <a href="https://github.com/babashka/sci/issues/984">#984</a>: support alternative <code>set!</code> syntax in CLJS</li><li>Fix <a href="https://github.com/babashka/sci/issues/987">#987</a>: method or property name in interop should be munged</li><li>Fix <a href="https://github.com/babashka/sci/issues/986">#986</a>: preserve error location for js static method</li><li>Fix <a href="https://github.com/babashka/sci/issues/990">#990</a>: fix <code>merge-opts</code> with <code>:bindings</code> + deprecate <code>:bindings</code> (replaced by <code>:namespaces {&apos;user ...}</code>)</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2588">#2588</a>: false positive type mismatch about <code>symbol</code> accepting var</li><li>Require clojure <code>1.10.3</code> is the minimum clojure version</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2564">#2564</a>: detect calling set with wrong number of arguments</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2257">#2257</a>: support ignore hint on invalid symbol</li><li>Sort findings on filename, row, column and now additionally on message too</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2602">#2602</a>: Sort auto-imported configs to avoid differences based on OS or file system</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2603">#2603</a>: warn on <code>:inline-def</code> with nested <code>deftest</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2606">#2606</a>: make it easy for users to know how inline-config files should be version controlled (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2610">#2610</a>: ignores may show up unordered due to macros</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2615">#2615</a>: emit <code>inline-configs</code> <code>config.edn</code> in a git-diff-friendly way (<a href="https://github.com/lread">@lread</a>)</li><li>2025.07.28</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2580">#2580</a>: false positive type mismatch with quoted value</li><li>Fix some <code>:locking-suspicious-lock</code> false positives</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2582">#2582</a>: <code>:condition-always-true</code> false positives</li><li>2025.07.26</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2560">#2560</a>: NEW linter: <code>:locking-suspicious-lock</code>: report when locking is used on a single arg, interned value or local object</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2519">#2519</a>: NEW linter: <code>:unresolved-protocol-method</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a> (<a href="https://github.com/emerson-matos">@emerson-matos</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2555">#2555</a>: false positive with <code>clojure.string/replace</code> and <code>partial</code> as replacement fn</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2566">#2566</a>: Expand <code>:condition-always-true</code> check. (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2350">#2350</a>: support <code>schema.core/defprotocol</code> (<a href="https://github.com/emerson-matos">@emerson-matos</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2571">#2571</a>: false positive unresolved symbol when ignoring expression that goes through macroexpansion hook</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2575">#2575</a>: false positive type mismatch with nested keyword call and <code>str</code></li><li>Bump SCI to <code>0.10.47</code></li><li>Drop memoization for hook fns and configuration, solves memory issue with Cursive + big projects like metabase</li><li>Optimizations to compensate for dropping caching, performance should be similar (or better depending on the size of your project)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2568">#2568</a>: support <code>:deprecated-namespace</code> for <code>.cljc</code> namespaces</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Upgrade to Reagent and fix unsafe HTML rendering</li><li>Add viewers for HTML markdown nodes</li><li>Support file watching in babashka</li><li>Support server side rendering of formulas using KaTeX</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>v0.8.153 (2025-08-31)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/704">#704</a>: <code>while</code> didn&apos;t compile correctly</li><li>Add <code>clojure.string/includes?</code></li><li>Emit less code for varargs functions</li><li>Fix solidJS example</li><li>Documentation improvements (<a href="https://github.com/lread">@lread</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/697">#697</a>: <code>ClassCastException</code> in statement function when passed Code records</li><li>v0.8.152 (2025-07-18)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/680">#680</a>: support import attributes using <code>:with</code> option in require, e.g. <code>:with {:type :json}</code></li><li>v0.8.151 (2025-07-15)</li><li>Implement <code>not=</code> as function</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/684">#684</a>: JSX output</li><li>v0.8.150 (2025-07-09)</li><li><a href="https://github.com/squint-cljs/squint/issues/678">#678</a>: Implement <code>random-uuid</code> (<a href="https://github.com/rafaeldelboni">@rafaeldelboni</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/681">#681</a>: support unsafe HTML via <code>[:$ ...]</code> tag</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li>v0.7.27 (2025-08-21)</li><li><a href="https://github.com/babashka/scittle/issues/121">#95</a>: support string requires of <code>globalThis</code> js deps (<a href="https://github.com/chr15m">@chr15m</a>). See <a href="https://github.com/babashka/scittle/blob/main/doc/js-libraries.md">docs</a>.</li><li>Potentially breaking: <code>(.-foo-bar {})</code> now behaves as <code>{}.foo_bar</code>, i.e. the property or method name is munged.</li><li>v0.7.26 (2025-08-20)</li><li><a href="https://github.com/babashka/scittle/issues/121">#121</a>: add <code>cjohansen/dataspex</code> plugin (<a href="https://github.com/jeroenvandijk">@jeroenvandijk</a>)</li><li><a href="https://github.com/babashka/scittle/issues/118">#118</a>: add <code>goog.string/format</code> (<a href="https://github.com/jeroenvandijk">@jeroenvandijk</a>)</li><li>Support alternative <code>(set! #js {} -a 1)</code> CLJS syntax (by bumping SCI)</li><li>Add source maps to distribution</li><li>Add dev versions of all modules in the <code>dev</code> folder of the distribution + a <code>dev/scitte.cljs-devtools.js</code> module</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more</p><ul><li>Fix <a href="https://github.com/borkdude/edamame/issues/132">#132</a>: Add counterpart to Clojure&apos;s <code>*suppress-read*</code>: <code>:suppress-read</code></li></ul></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p><ul><li>Add config for dataspex</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>nREPL improvement for vim-fireplace</li></ul></li><li><p><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a></p><ul><li>Drop KaTeX dependency by inlining TeXMath lib</li></ul></li><li><p><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></p><ul><li>Add <code>:responses</code> key with raw responses</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li>Documentation improvements</li><li>Fix wrong typehint</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li><code>not=</code> is now a function</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li><a href="https://github.com/babashka/cli/issues/122">#122</a>: introduce new <code>:repeated-opts</code> option to enforce repeating the option for accepting multiple values (e.g. <code>--foo 1 --foo 2</code> rather than <code>--foo 1 2</code>)</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Fixed Java download program that respects <code>CLJ_JVM_OPTS</code> for downloading tools jar.</li><li>Released several versions catching up with the clojure CLI</li></ul></li><li><p><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</p><ul><li>Pod protocol fix: don&apos;t send done with async messages</li><li>Robustness improvements</li><li>Bump fsnotify</li></ul></li><li><p><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</p><ul><li>Send current working directory in describe message (for tools like clojure-mcp)</li><li>Add <code>&quot;session-closed&quot;</code> to close op reply</li></ul></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p><ul><li>JSON1 support</li></ul></li><li><p><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</p><ul><li>0.1.15</li><li><a href="https://github.com/babashka/http-server/issues/22">#22</a>: fix off-by-one error in range requests (<a href="https://github.com/jyn514">@jyn514</a>)</li><li>0.1.14</li><li><a href="https://github.com/babashka/http-server/issues/21">#21</a>: Add <code>:not-found</code> option for handling unfound files. The option is a function of the request and should return a map with <code>:status</code> and <code>:body</code>.</li><li><a href="https://github.com/babashka/http-server/issues/19">#19</a>: Add text/html MIME types for asp and aspx file extensions (<a href="https://github.com/respatialized">@respatialized</a>)</li><li>0.1.13</li><li><a href="https://github.com/babashka/http-server/issues/16">#16</a>: support range requests (<a href="https://github.com/jmglov">jmglov</a>)</li><li><a href="https://github.com/babashka/http-server/issues/13">#13</a>: add an ending slash to the dir link, and don&apos;t encode the slashes (<a href="https://github.com/KDr2">@KDr2</a>)</li><li><a href="https://github.com/babashka/http-server/issues/12">#12</a>: Add headers to index page (rather than just file responses)</li></ul></li></ul><p>Contributions to third party projects:</p><ul><li><p><a href="https://github.com/redplanetlabs/specter">specter</a>: Clojure(Script)&apos;s missing piece</p><ul><li>Fix babashka support by removing optimizations that only worked due to SCI bug</li></ul></li><li><p><a href="https://github.com/jank-lang/clojure-test-suite">clojure-test-suite</a>: Dialect-independent tests for clojure.core, and others, focused on characterizing how Clojure JVM behaves so that other dialects to reach parity.</p><ul><li>Added babashka to the test suite</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one comman</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/speculative">speculative</a></li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-may-jun-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-may-jun-2025.html"/>
    <title>OSS updates May and June 2025</title>
    <updated>2025-07-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during May and June 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details><!--

- ls -lat ~/dev
- babashka sub dir checken

--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months, 19 in total!</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Bump edamame (support old-style <code>#^</code> metadata)</li><li>Bump SCI: fix <code>satisfies?</code> for protocol extended to <code>nil</code></li><li>Bump rewrite-clj to <code>1.2.50</code></li><li><strong>1.12.204 (2025-06-24)</strong></li><li>Compatibility with <a href="https://github.com/nextjournal/clerk">clerk</a>&apos;s main branch</li><li><a href="https://github.com/babashka/babashka/issues/1834">#1834</a>: make <code>taoensso/trove</code> work in bb by exposing another <code>timbre</code> var</li><li>Bump <code>timbre</code> to <code>6.7.1</code></li><li>Protocol method should have <code>:protocol</code> meta</li><li>Add <code>print-simple</code></li><li>Make bash install script work on Windows for GHA</li><li>Upgrade Jsoup to <code>1.21.1</code></li><li><strong>1.12.203 (2025-06-18)</strong></li><li>Support <code>with-redefs</code> + <code>intern</code> (see SCI issue <a href="https://github.com/babashka/sci/issues/973">#973</a></li><li><a href="https://github.com/babashka/babashka/issues/1832">#1832</a>: support <code>clojure.lang.Var/intern</code></li><li>Re-allow <code>init</code> as task name</li><li><strong>1.12.202 (2025-06-15)</strong></li><li>Support <code>clojure.lang.Var/{get,clone,reset}ThreadBindingFrame</code> for JVM Clojure compatibility</li><li><a href="https://github.com/babashka/babashka/issues/1741">#1741</a>: fix <code>taoensso.timbre/spy</code> and include test</li><li>Add <code>taoensso.timbre/set-ns-min-level!</code> and <code>taoensso.timbre/set-ns-min-level</code></li><li><strong>1.12.201 (2025-06-12)</strong></li><li><a href="https://github.com/babashka/babashka/issues/1825">#1825</a>: Add <a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a> as built-in Markdown library</li><li>Promesa compatibility (pending PR <a href="https://github.com/funcool/promesa/pull/160">here</a>)</li><li>Upgrade clojure to <code>1.12.1</code></li><li><a href="https://github.com/babashka/babashka/issues/1818">#1818</a>: wrong argument order in <code>clojure.java.io/resource</code> implementation</li><li>Add <code>java.text.BreakIterator</code></li><li>Add classes for compatibility with <a href="https://github.com/funcool/promesa">promesa</a>:<ul><li><code>java.lang.Thread$Builder$OfPlatform</code></li><li><code>java.util.concurrent.ForkJoinPool</code></li><li><code>java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory</code></li><li><code>java.util.concurrent.ForkJoinWorkerThread</code></li><li><code>java.util.concurrent.SynchronousQueue</code></li></ul></li><li>Add <code>taoensso.timbre/set-min-level!</code></li><li>Add <code>taoensso.timbre/set-config!</code></li><li>Bump <code>fs</code> to <code>0.5.26</code></li><li>Bump <code>jsoup</code> to <code>1.20.1</code></li><li>Bump <code>edamame</code> to <code>1.4.30</code></li><li>Bump <code>taoensso.timbre</code> to <code>6.7.0</code></li><li>Bump <code>pods</code>: more graceful error handling when pod quits unexpectedly</li><li><a href="https://github.com/babashka/babashka/issues/1815">#1815</a>: Make install-script wget-compatible (<a href="https://github.com/eval">@eval</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1822">#1822</a>: <code>type</code> should prioritize <code>:type</code> metadata</li><li><code>ns-name</code> should work on symbols</li><li><code>:clojure.core/eval-file</code> should affect <code>*file*</code> during eval</li><li><a href="https://github.com/babashka/babashka/issues/1179">#1179</a>: run <code>:init</code> in tasks only once</li><li><a href="https://github.com/babashka/babashka/issues/1823">#1823</a>: run <code>:init</code> in tasks before task specific requires</li><li>Fix <code>resolve</code> when <code>*ns*</code> is bound to symbol</li><li>Bump <code>deps.clj</code> to <code>1.12.1.1550</code></li><li>Bump <code>http-client</code> to <code>0.4.23</code></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li><strong>0.10.47 (2025-06-27)</strong></li><li>Security issue: function recursion can be forced by returning internal keyword as return value</li><li>Fix <a href="https://github.com/babashka/sci/issues/975">#975</a>: Protocol method should have :protocol var on metadata</li><li>Fix <a href="https://github.com/babashka/sci/issues/971">#971</a>: fix <code>satisfies?</code> for protocol that is extended to <code>nil</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/977">#977</a>: Can&apos;t analyze sci.impl.analyzer with splint</li><li><strong>0.10.46 (2025-06-18)</strong></li><li>Fix <a href="https://github.com/babashka/sci/issues/957">#957</a>: <code>sci.async/eval-string+</code> should return promise with <code>:val nil</code> for ns form rather than <code>:val &lt;Promise&gt;</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/959">#959</a>: Java interop improvement: instance method invocation now leverages type hints</li><li>Bump edamame to <code>1.4.30</code></li><li>Give metadata <code>:type</code> key priority in <code>type</code> implementation</li><li>Fix <a href="https://github.com/babashka/sci/issues/967">#967</a>: <code>ns-name</code> should work on symbols</li><li>Fix <a href="https://github.com/babashka/sci/issues/969">#969</a>: <code>^:clojure.core/eval-file</code> metadata should affect binding of <code>*file*</code> during evaluation</li><li>Sync <code>sci.impl.Reflector</code> with changes in <code>clojure.lang.Reflector</code> in clojure 1.12.1</li><li>Fix <code>:static-methods</code> option for class with different name in host</li><li>Fix <a href="https://github.com/babashka/sci/issues/973">#973</a>: support <code>with-redefs</code> on core vars, e.g. <code>intern</code>. The fix for this issue entailed quite a big refactor of internals which removes &quot;magic&quot; injection of ctx in core vars that need it.</li><li>Add <code>unchecked-set</code> and <code>unchecked-get</code> for CLJS compatibility</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Make clerk compatible with babashka</li></ul></li><li><p><a href="https://github.com/borkdude/quickblog">quickblog</a>: light-weight static blog engine for Clojure and babashka</p><ul><li><strong>0.4.7 (2025-06-12)</strong></li><li>Switch to <a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a> for markdown rendering The minimum babashka version to be used with quickblog is now v1.12.201 since it comes with Nextjournal Markdown built-in.</li><li>Link to previous and next posts; see &quot;Linking to previous and next posts&quot; in the README (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Fix flaky caching tests (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Fix argument passing in test runner (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Add <code>--date</code> to api/new. (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Support Selmer template for new posts in api/new</li><li>Add &apos;language-xxx&apos; to pre/code blocks</li><li>Fix README.md with working version in quickstart example</li><li>Fix <a href="https://github.com/borkdude/quickblog/issues/104">#104</a>: fix caching with respect to previews</li><li>Fix <a href="https://github.com/borkdude/quickblog/issues/104">#104</a>: document <code>:preview</code> option</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: configurable EDN and Clojure parser with location metadata and more</p><ul><li><strong>1.4.31 (2025-06-25)</strong></li><li>Fix <a href="https://github.com/borkdude/edamame/issues/124">#124</a>: add <code>:imports</code> to <code>parse-ns-form</code></li><li>Fix <a href="https://github.com/borkdude/edamame/issues/125">#125</a>: Support <code>#^:foo</code> deprecated metadata reader macro (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li>Fix <a href="https://github.com/borkdude/edamame/issues/127">#127</a>: expose <code>continue</code> value that indicates continue-ing parsing (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li>Fix <a href="https://github.com/borkdude/edamame/issues/122">#122</a>: let <code>:auto-resolve-ns</code> affect syntax-quote</li><li><strong>1.4.30</strong></li><li><a href="https://github.com/borkdude/edamame/issues/120">#120</a>: fix <code>:auto-resolve-ns</code> failing case</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li><a href="https://github.com/squint-cljs/squint/issues/678">#678</a>: Implement <code>random-uuid</code> (<a href="https://github.com/rafaeldelboni">@rafaeldelboni</a>)</li><li><strong>v0.8.149 (2025-06-19)</strong></li><li><a href="https://github.com/squint-cljs/squint/issues/671">#671</a>: Implement <code>trampoline</code> (<a href="https://github.com/rafaeldelboni">@rafaeldelboni</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/673">#673</a>: remove experimental atom as promise option since it causes unexpected behavior</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/672">#672</a>: alias may contain dots</li><li><strong>v0.8.148 (2025-05-25)</strong></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/669">#669</a>: munge refer-ed + renamed var</li><li><strong>v0.8.147 (2025-05-09)</strong></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/661">#661</a>: support <code>throw</code> in expression position</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/662">#662</a>: Fix extending protocol from other namespace to <code>nil</code></li><li>Better solution for multiple expressions in return context in combination with pragmas</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2560">#2560</a>: NEW linter: <code>:locking-suspicious-lock</code>: report when locking is used on a single arg, interned value or local object</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2555">#2555</a>: false positive with <code>clojure.string/replace</code> and <code>partial</code> as replacement fn</li><li><strong>2025.06.05</strong></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2541">#2541</a>: NEW linter: <code>:discouraged-java-method</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2522">#2522</a>: support <code>:config-in-ns</code> on <code>:missing-protocol-method</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2524">#2524</a>: support <code>:redundant-ignore</code> on <code>:missing-protocol-method</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2536">#2536</a>: false positive with <code>format</code> and whitespace flag after percent</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2535">#2535</a>: false positive <code>:missing-protocol-method</code> when using alias in method</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2534">#2534</a>: make <code>:redundant-ignore</code> aware of <code>.cljc</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2527">#2527</a>: add test for using ns-group + config-in-ns for <code>:missing-protocol-method</code> linter</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2218">#2218</a>: use <code>ReentrantLock</code> to coordinate writes to cache directory within same process</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2533">#2533</a>: report inline def under fn and defmethod</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2521">#2521</a>: support <code>:langs</code> option in <code>:discouraged-var</code> to narrow to specific language</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2529">#2529</a>: add <code>:ns</code> to <code>&amp;env</code> in <code>:macroexpand-hook</code> macros when executing in CLJS</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2547">#2547</a>: make redundant-fn-wrapper report only for all cljc branches</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2531">#2531</a>: add <code>:name</code> data to <code>:unresolved-namespace</code> finding for clojure-lsp</li></ul></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p><ul><li>A configuration for <a href="https://github.com/cjohansen/replicant/">replicant</a> was added</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li><strong>v0.7.23 (2025-06-18)</strong></li><li><a href="https://github.com/babashka/scittle/issues/107">#107</a>: add <code>replicant</code> plugin (<a href="https://github.com/jeroenvandijk">@jeroenvandijk</a>)</li><li><a href="https://github.com/babashka/scittle/issues/102">#102</a>: add <code>applied-science/js-interop</code> plugin (<a href="https://github.com/chr15m">@chr15m</a>)</li><li><a href="https://github.com/babashka/scittle/issues/105">#105</a>: add <code>goog.string/htmlEscape</code> (<a href="https://github.com/ikappaki">@ikappaki</a> )</li><li><a href="https://github.com/babashka/scittle/issues/113">#113</a>: add <code>unchecked-set</code> and <code>unchecked-get</code></li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li><strong>1.3.204 (2025-05-15)</strong></li><li><a href="https://github.com/babashka/nbb/issues/389">#389</a>: fix regression caused by <a href="https://github.com/babashka/nbb/issues/387">#387</a></li><li><strong>1.3.203 (2025-05-13)</strong></li><li><a href="https://github.com/babashka/nbb/issues/387">#387</a>: bump <code>import-meta-resolve</code> to fix deprecation warnings on Node 22+</li><li><strong>1.3.202 (2025-05-12)</strong></li><li>Fix nbb nrepl server for Deno</li><li><strong>1.3.201 (2025-05-08)</strong></li><li>Deno improvements for loading <code>jsr:</code> and <code>npm:</code> deps, including react in combination with reagent</li><li><a href="https://github.com/babashka/nbb/issues/382">#382</a>: prefix all node imports with <code>node:</code></li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li><strong>v0.2.5 (2025-05-01)</strong></li><li>Fix <a href="https://github.com/borkdude/quickdoc/issues/32">#32</a>: fix anchor links to take into account var names that differ only by case</li><li><strong>v0.2.4 (2025-05-01)</strong></li><li>Revert source link in var title and move back to <code>&lt;sub&gt;</code></li><li>Specify clojure 1.11 as the minimal Clojure version in <code>deps.edn</code></li><li>Fix macro information</li><li>Fix <a href="https://github.com/borkdude/quickdoc/issues/39">#39</a>: fix link when var is named multiple times in docstring</li><li>Upgrade clj-kondo to <code>2025.04.07</code></li><li>Add explicit <code>org.babashka/cli</code> dependency</li></ul></li><li><p><a href="https://github.com/nextjournal/markdown">Nextjournal Markdown</a></p><ul><li><strong>0.7.186</strong></li><li>Make library more GraalVM <code>native-image</code> friendly</li><li><strong>0.7.184</strong></li><li>Consolidate utils in <code>nextjournal.markdown.utils</code></li><li><strong>0.7.181</strong></li><li>Hiccup JVM compatibility for fragments (see <a href="https://github.com/nextjournal/markdown/issues/34">#34</a>)</li><li>Support HTML blocks (<code>:html-block</code>) and inline HTML (<code>:html-inline</code>) (see <a href="https://github.com/nextjournal/markdown/issues/7">#7</a>)</li><li>Bump commonmark to 0.24.0</li><li>Bump markdown-it to 14.1.0</li><li>Render <code>:code</code> according to spec into <code>&lt;pre&gt;</code> and <code>&lt;code&gt;</code> block with language class (see <a href="https://github.com/nextjournal/markdown/issues/39">#39</a>)</li><li>No longer depend on <code>applied-science/js-interop</code></li><li>Accept parsed result in <code>-&gt;hiccup</code> function</li><li>Expose <code>nextjournal.markdown.transform</code> through main <code>nextjournal.markdown</code> namespace</li><li>Stabilize API and no longer mark library alpha</li></ul></li><li><p><a href="https://github.com/babashka/nrepl-client">babashka.nrepl-client</a></p><ul><li>Add <code>:responses</code> key with raw responses</li></ul></li><li><p><a href="https://github.com/borkdude/speculative">speculative</a></p><ul><li>Add spec for <code>even?</code></li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</p><ul><li><strong>0.4.23 (2025-06-06)</strong></li><li><a href="https://github.com/babashka/http-client/issues/75">#75</a>: override existing content type header in multipart request</li><li>Accept <code>:request-method</code> in addition to <code>:request</code> to align more with other clients</li><li>Accept <code>:url</code> in addition to <code>:uri</code> to align more with other clients</li></ul></li><li><p><a href="https://github.com/borkdude/unused-deps">unused-deps</a>: Find unused deps in a clojure project</p><ul><li>This is a brand new project!</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li><a href="https://github.com/babashka/fs/issues/147">#147</a>: <code>fs/unzip</code> should allow selective extraction of files (<a href="https://github.com/sogaiu">@sogaiu</a>)</li><li><a href="https://github.com/babashka/fs/issues/145">#145</a>: <code>fs/modified-since</code> works only with ms precision but should support the precision of the filesystem</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Fix <code>cherry.embed</code> which is used by malli</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Released several versions catching up with the clojure CLI</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one comman</li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-mar-apr-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-mar-apr-2025.html"/>
    <title>OSS updates March and April 2025</title>
    <updated>2025-05-02T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during March and April 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without you the below projects would not be as mature or wouldn&apos;t exist or be maintained at all! So a sincere thank you to everyone who contributes to the sustainability of these projects.</p><img alt="gratitude" src="https://emoji.slack-edge.com/T03RZGPFR/gratitude/f8716bb6fb7e5249.png" width="50px" text-align="center"><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

babashka sub dir checken
--><h2 id="blog-posts">Blog posts</h2><p>I blogged about an important improvement in babashka regarding type hints <a href="https://blog.michielborkent.nl/babashka-java-reflection-type-hints.html">here</a>.</p><h2 id="interviews">Interviews</h2><p>Also I did an interview with Jiri from Clojure Corner by Flexiana, viewable <a href="https://www.youtube.com/watch?v=H7ZlwEDxzRs">here</a>.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/H7ZlwEDxzRs?si=HQuZFsQXloxGkF9B" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Improve Java reflection based on provided type hints (read blog post <a href="https://blog.michielborkent.nl/babashka-java-reflection-type-hints.html">here</a>)</li><li>Add compatibility with the <a href="https://github.com/potetm/fusebox">fusebox</a> library</li><li>Fix virtual <code>ThreadBuilder</code> interop</li><li>Add <code>java.util.concurrent.ThreadLocalRandom</code></li><li>Add <code>java.util.concurrent.locks.ReentrantLock</code></li><li>Add classes:<ul><li><code>java.time.chrono.ChronoLocalDate</code></li><li><code>java.time.temporal.TemporalUnit</code></li><li><code>java.time.chrono.ChronoLocalDateTime</code></li><li><code>java.time.chrono.ChronoZonedDateTime</code></li><li><code>java.time.chrono.Chronology</code></li></ul></li><li><a href="https://github.com/babashka/babashka/issues/1806">#1806</a>: Add <code>cheshire.factory</code> namespace (<a href="https://github.com/lread">@lread</a>)</li><li>Bump GraalVM to <code>24</code></li><li>Bump SCI to <code>0.9.45</code></li><li>Bump edamame to <code>1.4.28</code></li><li><a href="https://github.com/babashka/babashka/issues/1801">#1801</a>: Add <code>java.util.regex.PatternSyntaxException</code></li><li>Bump core.async to <code>1.8.735</code></li><li>Bump cheshire to <code>6.0.0</code></li><li>Bump babashka.cli to <code>0.8.65</code></li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Replace tools.analyzer with a more light-weight analyzer which also adds support for Clojure 1.12</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li><a href="https://github.com/squint-cljs/squint/issues/653">#653</a>: respect <code>:context expr</code> in <code>compile-string</code></li><li><a href="https://github.com/squint-cljs/squint/issues/657">#657</a>: respect <code>:context expr</code> in <code>set!</code> expression</li><li><a href="https://github.com/squint-cljs/squint/issues/659">#659</a>: fix invalid code produced for REPL mode with respect to <code>return</code></li><li><a href="https://github.com/squint-cljs/squint/issues/651">#651</a> Support <code>:require</code> + <code>:rename</code> + allow renamed value to be used in other :require clause</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/649">#649</a>: reset ns when compiling file and fix initial global object</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/647">#647</a>: emit explicit <code>null</code> when written in else branch of <code>if</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/640">#640</a>: don&apos;t emit anonymous function if it is a statement (<a href="https://github.com/jonasseglare">@jonasseglare</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/643">#643</a>: Support lexicographic compare of arrays (<a href="https://github.com/jonasseglare">@jonasseglare</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/602">#602</a>: support hiccup-style shorthand for id and class attributes in <code>#jsx</code> and <code>#html</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/635">#635</a>: <code>range</code> fixes</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/636">#636</a>: add <code>run!</code></li><li><code>defclass</code>: elide constructor when not provided</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/603">#603</a>: don&apos;t emit multiple returns</li><li>Drop constructor requirement for <code>defclass</code></li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2522">#2522</a>: support <code>:config-in-ns</code> on <code>:missing-protocol-method</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2524">#2524</a>: support <code>:redundant-ignore</code> on <code>:missing-protocol-method</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1292">#1292</a>: NEW linter: <code>:missing-protocol-method</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2512">#2512</a>: support vars ending with <code>.</code>, e.g. <code>py.</code> according to clojure analyzer</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2516">#2516</a>: add new <code>--repro</code> flag to ignore home configuration</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2493">#2493</a>: reduce image size of native image</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2496">#2496</a>: Malformed <code>deftype</code> form results in <code>NPE</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2499">#2499</a>: Fix <code>(alias)</code> bug (<a href="https://github.com/Noahtheduke">@Noahtheduke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2492">#2492</a>: Report unsupported escape characters in strings</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2502">#2502</a>: add end locations to invalid symbol</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2511">#2511</a>: fix multiple parse errors caused by incomplete forms</li><li>document var-usages location info edge cases (<a href="https://github.com/sheluchin">@sheluchin</a>)</li><li>Upgrade to GraalVM 24</li><li>Bump datalog parser</li><li>Bump built-in cache</li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Fix <a href="https://github.com/babashka/sci/issues/957">#957</a>: <code>sci.async/eval-string+</code> should return promise with <code>:val nil</code> for ns form rather than <code>:val &lt;Promise&gt;</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/959">#959</a>: Java interop improvement: instance method invocation now leverages type hints</li><li>Fix <a href="https://github.com/babashka/sci/issues/942">#942</a>: improve error location of invalid destructuring</li><li>Add <code>volatile?</code> to core vars</li><li>Fix <a href="https://github.com/babashka/sci/issues/950">#950</a>: interop on local in CLJS</li><li>Bump edamame to <code>1.4.28</code></li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li>Fix <a href="https://github.com/borkdude/quickdoc/issues/32">#32</a>: fix anchor links to take into account var names that differ only by case</li><li>Revert source link in var title and move back to <code>&lt;sub&gt;</code></li><li>Specify clojure 1.11 as the minimal Clojure version in <code>deps.edn</code></li><li>Fix macro information</li><li>Fix <a href="https://github.com/borkdude/quickdoc/issues/39">#39</a>: fix link when var is named multiple times in docstring</li><li>Upgrade clj-kondo to <code>2025.04.07</code></li><li>Add explicit <code>org.babashka/cli</code> dependency</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li><a href="https://github.com/babashka/cli/issues/119">#119</a>: <code>format-table</code> now formats multiline cells appropriately (<a href="https://github.com/lread">@lread</a>)</li><li>Remove <code>pom.xml</code> and <code>project.clj</code> for cljdoc</li><li><a href="https://github.com/babashka/cli/issues/116">#116</a>: Un-deprecate <code>:collect</code> option to support custom transformation of arguments to collections (<a href="https://github.com/lread">@lread</a>)</li><li>Support <code>:collect</code> in <code>:spec</code></li></ul></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p><ul><li><a href="https://github.com/babashka/process/issues/163">#163</a>, <a href="https://github.com/babashka/process/issues/164">#164</a>: Program resolution strategy for <code>exec</code> and Windows now matches macOS/Linux/PowerShell (<a href="https://github.com/lread">@lread</a>)</li><li>Fix memory leak by executing shutdown hook when process finishes earlier than VM exit (<a href="https://github.com/maxweber">@maxweber</a>)</li></ul></li><li><p><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</p><ul><li>Fix <a href="https://github.com/borkdude/html/issues/3">#3</a>: allow dynamic attribute value: <code>(html [:a {:a (+ 1 2 3)}])</code></li><li>Fix <a href="https://github.com/borkdude/html/issues/9">#9</a>: shortcuts for id and classes</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Add <code>cljs.pprint/pprint</code></li><li>Add <code>add-tap</code></li><li>Bump squint compiler common which brings in new <code>#html</code> id and class shortcuts + additional features and optimizations, such as an optimization for <code>aset</code></li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Add better Deno + <code>jsr:</code> dependency support, stay tuned.</li></ul></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</p><ul><li>Several improvements which makes babashka compatible with <a href="https://github.com/gfredericks/test.chuck">test.chuck</a>. See <a href="https://files.mastodon.social/media_attachments/files/114/437/768/756/996/338/original/b8ebcb333f287e5c.png">this screenshot</a>!</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p><ul><li><a href="https://github.com/borkdude/edamame/issues/117">#117</a>: throw on triple colon keyword</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li><a href="https://github.com/babashka/fs/issues/141">#141</a>: <code>fs/match</code> doesn&apos;t match when root dir contains glob or regex characters in path</li><li><a href="https://github.com/babashka/fs/issues/138">#138</a>: Fix <code>fs/update-file</code> to support paths (<a href="https://github.com/rfhayashi">@rfhayashi</a>)</li></ul></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p><ul><li>Upgrade to GraalVM 23, fixes encoding issue with Korean characters</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one comman</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>Added a configuration for <code>cljs.spec.alpha</code> and related namespaces</li></ul></li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-java-reflection-type-hints.html</id>
    <link href="https://blog.michielborkent.nl/babashka-java-reflection-type-hints.html"/>
    <title>Babashka Java interop, reflection and type hints</title>
    <updated>2025-04-26T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Consider the following Clojure code:</p><pre><code class="language-clojure">(def thread-pool (java.util.concurrent.Executors/newCachedThreadPool))
(def fut (.submit thread-pool (fn [] 3)))
@fut ;;=&gt; ?
</code></pre><p>I didn&apos;t use any type hints, but the names of the vars should give you an idea what&apos;s happening:</p><ul><li>a thread pool is created</li><li>a piece of work in the form of a function is submitted</li><li>the thread pool returns a future which we can dereference to do a blocking wait and get the result.</li></ul><p>What result would you expect this program to give? My initial guess would be <code>3</code>.</p><p>However, in <a href="https://github.com/babashka/babashka">babashka</a> the result would sometimes be <code>nil</code> (version <code>1.12.199</code> on macOS Apple silicon does for example). I&apos;ve seen this happen in JVM Clojure too in CI (given no type hints, and thus relying on Clojure reflection). I discovered this problem when trying to make bb run the <a href="https://github.com/potetm/fusebox">fusebox</a> library and executing its test suite in CI using babashka.</p><p>What&apos;s the mechanism behind this flakiness? The <code>.submit</code> method in the snippet above is overloaded. When Clojure is doing reflection, it finds the most suitable method for <code>.submit</code> given the instance object and the arguments. In this case the type of the instance object (the <code>thread-pool</code> value) is of type <code>java.util.concurrent.ThreadPoolExecutor</code>, which has three overloads (inherited from <code>java.util.concurrent.AbstractExecutorService</code>):</p><ul><li><code>public Future&lt;?&gt; submit(Runnable task)</code></li><li><code>public &lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result)</code></li><li><code>public &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task)</code></li></ul><p>Only two of those match the number of arguments we used in the snippet, so we are left with:</p><ul><li><code>public Future&lt;?&gt; submit(Runnable task)</code></li><li><code>public &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task)</code></li></ul><p>Clojure&apos;s reflector will try to see if the argument type to <code>.submit</code> matches any of these methods. Since we called it with a function, in this case it matches both. If multiple methods match, it will try to pick the most specific method using <code>clojure.lang.Compiler/subsumes</code>. Since <code>Runnable</code> and <code>Callable</code> are two distinct types (one doesn&apos;t inherit from the other), Clojure&apos;s reflector just returns the first method it deemed most suitable. So it could be either method. The java documentation mentions the <code>submit</code> method with the <code>Runnable</code> argument first, but this isn&apos;t necessarily the order in which Java reflection will list those methods. I have found out that the order may even be indeterministic over multiple CI runs and JVM implementations or versions. What the exact cause of this indeterminism is, I don&apos;t know, but I found out the hard way that it exists 😅.</p><p>So when does the above snippet return <code>nil</code>? When the <code>Runnable</code> overload is chosen, since <code>Runnable</code> is an interface with <code>run</code> method that returns <code>void</code> (which is <code>nil</code> in Clojure). Let me show this using a snippet that uses JVM Clojure type hinting, where we don&apos;t rely on reflection:</p><pre><code class="language-clojure">(set! *warn-on-reflection* true)

(def ^java.util.concurrent.ThreadPoolExecutor thread-pool
  (java.util.concurrent.Executors/newCachedThreadPool))
(def fut (.submit thread-pool ^Runnable (fn [] 3)))
@fut  ;; =&gt; nil
</code></pre><p>Now let&apos;s do the same with <code>Callable</code>:</p><pre><code class="language-clojure">(set! *warn-on-reflection* true)

(def ^java.util.concurrent.ThreadPoolExecutor thread-pool
  (java.util.concurrent.Executors/newCachedThreadPool))
(def fut (.submit thread-pool ^Callable (fn [] 3)))
@fut ;; =&gt; 3
</code></pre><p>So we see the issue: depending on the overload of <code>.submit</code> we get a different value when we dereference the future, either <code>nil</code> or the value returned from the function.</p><p>So far, babashka has relied exclusively on runtime reflection to implement Java interop. So we do get into a problem with the above snippet, unless we add type hints. But so far babashka, or more specifically, <a href="https://github.com/babashka/sci">SCI</a> hasn&apos;t made use of type hints to determine the most suitable method. The Clojure <em>compiler</em> does this, but as you know, SCI interprets code and doesn&apos;t make use of the clojure Compiler. It does use a forked version of <code>clojure.lang.Reflector</code>, clojure&apos;s runtime reflection code, aptly renamed to <code>sci.impl.Reflector</code>. So far, pretty much the only change to that code was making some methods public that were used internally by <a href="https://github.com/babashka/sci">SCI</a>. To fix the above problem, SCI now actually makes use of type hints and passes these to <code>sci.impl.Reflector</code>. So in the newly published version of babashka, this code:</p><pre><code class="language-clojure">(def thread-pool (java.util.concurrent.Executors/newCachedThreadPool))
(def fut (.submit thread-pool ^Callable (fn [] 3)))
@fut ;;=&gt; 3
</code></pre><p>will consistently return <code>3</code> and when changing <code>Callable</code> to <code>Runnable</code>, you&apos;ll get <code>nil</code>. Note that the above snippet will still have the ambiguous behavior in JVM Clojure, since it doesn&apos;t have enough type hints to figure out the right method at compile time and <code>clojure.lang.Reflector</code> does nothing with type hints. Once the Clojure compiler finds out that you&apos;re calling <code>.submit</code> on a <code>java.util.concurrent.ExecutorService</code> though, the code will run with the expected method.</p><p>Can you think of more methods in the Java standard library which have this ambiguity when relying solely on Clojure reflection? I&apos;d love to hear about those to see if they work reliably in babashka given some extra help through type hints.</p><p>Thanks to <a href="https://github.com/potetm">Tim Pote</a> for thinking along when fixing the issues in babashka and reading a preview of this blog post.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jan-feb-2025.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jan-feb-2025.html"/>
    <title>OSS updates January and February 2025</title>
    <updated>2025-02-28T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during January and February 2025.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

drwxr-xr-x  489 borkdude  staff  15648 28 feb 13:47 squint
drwxr-xr-x@ 315 borkdude  staff  10080 28 feb 12:21 homebrew-brew
drwxr-xr-x@  79 borkdude  staff   2528 28 feb 11:02 babashka

--><h2 id="updates">Updates</h2><p>As I&apos;m writing this I&apos;m still recovering from a flu that has kept me bedridden for a good few days, but I&apos;m starting to feel better now.</p><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months.</p><ul><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2493">#2493</a>: reduce image size of native image</li><li>2025.02.20:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2473">#2473</a>: New linter: <code>:unknown-ns-options</code> will warn on malformed <code>(ns)</code> calls. The linter is <code>{:level :warning}</code> by default. (<a href="https://github.com/Noahtheduke">@Noahtheduke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2475">#2475</a>: add <code>:do-template</code> linter to check args &amp; values counts (<a href="https://github.com/imrekoszo">@imrekoszo</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2465">#2465</a>: fix <code>:discouraged-var</code> linter for fixed arities</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2277">#2277</a>: prefer an array class symbol over <code>(Class/forName ...)</code> in <code>defprotocol</code> and <code>extend-type</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2466">#2466</a>: fix false positive with tagged literal in macroexpand hook</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2463">#2463</a>: using <code>:min-clj-kondo-version</code> results in incorrect warning (<a href="https://github.com/imrekoszo">@imrekoszo</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2464">#2464</a>: <code>:min-clj-kondo-version</code> warning/error should have a location in <code>config.edn</code> (<a href="https://github.com/imrekoszo">@imrekoszo</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2472">#2472</a> hooks <code>api/resolve</code> should return <code>nil</code> for unresolved symbols and locals</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2472">#2472</a>: add <code>api/env</code> to determine if symbol is local</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2482">#2482</a>: Upgrade to Oracle GraalVM 23</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2483">#2483</a>: add <code>api/quote-node</code> and <code>api/quote-node?</code> to hooks API (<a href="https://github.com/camsaul">@camsaul</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2490">#2490</a>: restore unofficial support for ignore hints via metadata</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Fix <a href="https://github.com/squint-cljs/squint/issues/609">#609</a>: make <code>remove</code> return a transducer when no collection is provided</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/611">#611</a>: Implement the <code>set?</code> function (<a href="https://github.com/jonasseglare">@jonasseglare</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/613">#613</a>: Optimize <code>aset</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/XXX">#626</a>: Implement <code>take-last</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/615">#615</a>: <code>(zero? &quot;0&quot;)</code> should return <code>false</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/617">#617</a>: <code>deftype</code> field name munging problem</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/618">#618</a>: Named multi-arity <code>fn</code> args don&apos;t get munged (<a href="https://github.com/grayrest">@grayrest</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/622">#622</a>: operator precendence issue with <code>|</code> and <code>if</code></li><li>Add <code>clojure.string</code> functions <code>lower-case</code>, <code>upper-case</code>, <code>capitalize</code> (<a href="https://github.com/plexus">@plexus</a>)</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/605">#605</a>: merge command line <code>--paths</code> with <code>squint.edn</code> config properly</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/607">#607</a>: make <code>mapcat</code> return a transducer if no collections are provided (<a href="https://github.com/jonasseglare">@jonasseglare</a>)</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Experimenting upgrading to new beta core.async, work in is a branch ready to be merged</li><li><a href="https://github.com/babashka/babashka/issues/1785">#1785</a>: Allow subclasses of <code>Throwable</code> to have instance methods invoked (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1791">#1791</a>: interop problem on Jsoup form element</li><li><a href="https://github.com/babashka/babashka/issues/1793">#1793</a>: Bump <code>rewrite-clj</code> to <code>1.1.49</code> (fixes parsing of <code>foo//</code> among other things)</li><li>Bump <code>deps.clj</code></li><li>Bump <code>fs</code></li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li>v0.5.24 (2025-01-09)</li><li><a href="https://github.com/babashka/fs/issues/135">#135</a>: additional fix for preserving protocol when calling <code>fs/path</code> on multiple arguments (<a href="https://github.com/Sohalt">@Sohalt</a>)</li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting</p><ul><li>Records should have keys present and set to <code>nil</code></li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Catch up with several new versions of clojure CLI</li><li>Fix <a href="https://github.com/borkdude/deps.clj/issues/132">#132</a>: copy install tools.edn to config dir when install version is newer, similar to clojure CLI bash script</li><li>Adds support for <code>XDG_DATA_HOME</code> environment variable according to <a href="https://specifications.freedesktop.org/basedir-spec/latest/">XDG Base Directory Specification</a></li></ul></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p><ul><li>Add support for DuckDB (<a href="https://github.com/paintparty">@avelino</a>)</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p><ul><li>Fix #115: add location to exception for invalid keyword</li></ul></li><li><p><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</p><ul><li><a href="https://github.com/borkdude/rewrite-edn/issues/40">#40</a>: <code>assoc</code>/<code>update</code> now handles map keys that have no indent at all (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/borkdude/rewrite-edn/issues/43">#43</a>: bump rewrite-clj to 1.1.49 (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/borkdude/rewrite-edn/issues/40">#40</a>: <code>assoc</code>/<code>update</code> now handles map keys that have no indent at all (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/borkdude/rewrite-edn/issues/40">#40</a>: <code>assoc</code>/<code>update</code> now aligns indent to comment if that&apos;s all that is in the map (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/borkdude/rewrite-edn/issues/40">#40</a>: <code>update</code> now indents new entries in same way as <code>assoc</code> (<a href="https://github.com/lread">@lread</a>)</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one comman</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>Added a configuration for <code>cljs.spec.alpha</code> and related namespaces</li></ul></li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure<ul><li>Add support for <code>:require-cljs</code> which allows you to use <code>.cljs</code> files for render functions</li><li>Add support for nREPL for developing render functions</li></ul></li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes<ul><li>Work has started to support prepending output (in support for babashka parallel tasks). Stay tuned.</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-nov-dec-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-nov-dec-2024.html"/>
    <title>OSS updates November and December 2024</title>
    <updated>2024-12-31T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during November and December 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

- write something about Heart of Clojure and bbslideshow?

--><h2 id="updates">Updates</h2><p>Clojurists Together announced that I&apos;m among the 5 developers who were voted to receive the Long Term Funding in 2025. You can see the announcement <a href="https://www.clojuriststogether.org/news/clojurists-together-2025-long-term-funding-announcement/">here</a>. Thanks so much!</p><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months.</p><ul><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li><a href="https://github.com/babashka/babashka/issues/1771">#1771</a>: <code>*e*</code> in REPL should contain exception thrown by user, not a wrapped one</li><li><a href="https://github.com/babashka/babashka/issues/1777">#1777</a> Add <code>java.nio.file.attribute.UserDefinedFileAttributeView</code></li><li><a href="https://github.com/babashka/babashka/issues/1776">#1776</a> <code>Add java.nio.file.attribute.PosixFileAttributes</code></li><li><a href="https://github.com/babashka/babashka/issues/1761">#1761</a> Support calling <code>clojure.lang.RT/iter</code></li><li><a href="https://github.com/babashka/babashka/issues/1760">#1760</a> For compatibility with <a href="https://github.com/paintparty/fireworks">Fireworks v0.10.3</a>, added the following to <code>:instance-checks</code> entry in <code>babashka.impl.classes/classes</code>(<a href="https://github.com/paintparty">@paintparty</a>)<ul><li><code>clojure.lang.PersistentArrayMap$TransientArrayMap</code></li><li><code>clojure.lang.PersistentHashMap$TransientHashMap</code></li><li><code>clojure.lang.PersistentVector$TransientVector</code></li><li><code>java.lang.NoSuchFieldException</code></li><li><code>java.util.AbstractMap</code></li><li><code>java.util.AbstractSet</code></li><li><code>java.util.AbstractList</code></li></ul></li><li><a href="https://github.com/babashka/babashka/issues/1760">#1760</a> For compatibility with <a href="https://github.com/paintparty/fireworks">Fireworks v0.10.3</a>, added <code>volatile?</code> entry to <code>babashka.impl.clojure.core/core-extras</code>(<a href="https://github.com/paintparty">@paintparty</a>)</li><li>Bump <code>babashka.cli</code> to <code>0.8.61</code></li><li>Bump <code>clj-yaml</code> to <code>1.0.29</code></li><li><a href="https://github.com/babashka/babashka/issues/1768">#1768</a>: Add <code>taoensso.timbre</code> <code>color-str</code> function</li><li>Add classes:<ul><li><code>javax.crypto.KeyAgreement</code></li><li><code>java.security.KeyPairGenerator</code></li><li><code>java.security.KeyPair</code></li><li><code>java.security.spec.ECGenParameterSpec</code></li><li><code>java.security.spec.PKCS8EncodedKeySpec</code></li><li><code>java.security.spec.X509EncodedKeySpec</code></li><li><code>java.security.Signature</code></li></ul></li><li>Add <code>java.util.concurrent.CompletionStage</code></li><li>Bump <code>core.async</code> to <code>1.7.701</code></li><li>Bump <code>org.babashka/cli</code> to <code>0.8.162</code></li><li>Include <a href="https://jsoup.org/">jsoup</a> for HTML parsing. This makes bb compatible with the <a href="https://github.com/clj-commons/hickory">hickory</a> library (and possibly other libraries?).</li><li><a href="https://github.com/babashka/babashka/issues/1752">#1752</a>: include <code>java.lang.SecurityException</code> for <code>java.net.http.HttpClient</code> support (<a href="https://github.com/grzm">@grzm</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1748">#1748</a>: add <code>clojure.core/ensure</code></li><li>Upgrade <code>taoensso/timbre</code>to <code>v6.6.0</code></li><li>Upgrade <code>babashka.http-client</code> to <code>v0.4.22</code></li><li>Add <code>:git/sha</code> from build to <code>bb describe</code> output (<a href="https://github.com/lispyclouds">@lispyclouds</a>)</li><li>Fix NPE with determining if executing from self-contained executable</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Fix <a href="https://github.com/squint-cljs/squint/issues/255">#255</a>: fn literal with rest args</li><li><a href="https://github.com/squint-cljs/squint/issues/596">#596</a>: fix unary division to produce reciprocal</li><li><a href="https://github.com/squint-cljs/squint/issues/592">#592</a>: fix <code>clj-&gt;js</code> to not process custom classes</li><li><a href="https://github.com/squint-cljs/squint/issues/585">#585</a>: fix <code>clj-&gt;js</code> to realize lazy seqs into arrays</li><li><a href="https://github.com/squint-cljs/squint/issues/586">#586</a>: support extending protocol to <code>nil</code></li><li><a href="https://github.com/squint-cljs/squint/issues/581">#581</a>: support docstring in <code>defprotocol</code></li><li><a href="https://github.com/squint-cljs/squint/issues/582">#582</a>: add <code>extend-protocol</code></li><li>Add <code>delay</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/575">#575</a>: <code>map?</code> should not return <code>true</code> for array</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/577">#577</a>: support <code>$default</code> + <code>:refer</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/572">#572</a>: prevent vite page reload</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li>Fix <a href="https://github.com/babashka/cli/issues/109">#109</a>: allow options to start with a number</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p><ul><li><a href="https://github.com/babashka/babashka/issues/99">#99</a>: make <code>js/import</code> work</li><li><a href="https://github.com/babashka/babashka/issues/55">#55</a>: create gh-pages dir before using.</li><li><a href="https://github.com/babashka/babashka/issues/89">#89</a>: allow <code>evaluate_script_tags</code> to specify individual scripts.</li><li><a href="https://github.com/babashka/scittle/issues/87">#87</a>: prod build on fresh checkout fails</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2451">#2272</a>: Lint for nil return from if-like forms</li><li>Add <code>printf</code> to vars linted by <code>analyze-format</code>. (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2272">#2272</a>: Report var usage in <code>if-let</code> etc condition as always truthy</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2272">#2272</a>: Report var usage in <code>if-not</code> condition as always truthy</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2433">#2433</a>: false positive redundant ignore with hook</li><li>Document <code>:cljc</code> config option. (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2439">#2439</a>: uneval may apply to nnext form if reader conditional doesn&apos;t yield a form (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2431">#2431</a>: only apply redundant-nested-call linter for nested exprs</li><li>Relax <code>:redundant-nested-call</code> for <code>comp</code>, <code>concat</code>, <code>every-pred</code> and <code>some-fn</code> since it may affect performance</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2446">#2446</a>: false positive <code>:redundant-ignore</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2448">#2448</a>: redundant nested call in hook gen&apos;ed code</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2424">#2424</a>: fix combination of :config-in-ns and :discouraged-namespace</li><li>2024.11.14</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2212">#2212</a>: NEW linter: <code>:redundant-nested-call</code> (<a href="https://github.com/tomdl89">@tomdl89</a>), set to level <code>:info</code> by default</li><li>Bump <code>:redundant-ignore</code>, <code>:redundant-str-call</code> linters to level <code>:info</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1784">#1784</a>: detect <code>:redundant-do</code> in <code>catch</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2410">#2410</a>: add <code>--report-level</code> flag</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2416">#2416</a>: detect empty <code>require</code> and <code>:require</code> forms (<a href="https://github.com/NoahTheDuke">@NoahTheDuke</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1786">#1786</a>: Support <code>gen-interface</code> (by suppressing unresolved symbols)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2407">#2407</a>: support ignore hint on called symbol</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2420">#2420</a>: Detect uneven number of clauses in <code>cond-&gt;</code> and <code>cond-&gt;&gt;</code> (<a href="https://github.com/tomdl89">@tomdl89</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2415">#2415</a>: false positive type checking issue with <code>str/replace</code> and <code>^String</code> annotation</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>1.3.196 (2024-11-25)</li><li>Add <code>locking</code> macro for compatibility with CLJS</li><li>1.3.195 (2024-11-07)</li><li><a href="https://github.com/babashka/nbb/issues/343">#343</a>: support <code>:reload</code> for reloading CLJS namespaces and JS code</li></ul></li><li><p><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</p><ul><li>Fix parsing of <code>b//</code> symbol</li></ul></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p><ul><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3/issues/19">#19</a>: Restore mac intel support (this time for real)</li></ul></li><li><p><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</p><ul><li>Fix <a href="https://github.com/babashka/tools-deps-native/issues/30">#30</a>: pod won&apos;t run on newer versions of macOS</li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></p><ul><li><a href="https://github.com/babashka/http-client/issues/71">#73</a>: Allow implicit ports when specifying the URL as a map (<a href="https://github.com/lvh">@lvh</a>)</li><li><a href="https://github.com/babashka/http-client/issues/71">#71</a>: Link back to sources in release artifact (<a href="https://github.com/lread">@lread</a>)</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scr- <a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compil- <a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one comman</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>Added a configuration for <code>cljs.spec.alpha</code> and related namespaces</li></ul></li><li><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure<ul><li>Add support for <code>:require-cljs</code> which allows you to use <code>.cljs</code> files for render functions</li><li>Add support for nREPL for developing render functions</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Upgrade/sync with clojure CLI v1.12.0.1479</li></ul></li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes<ul><li>Work has started to support prepending output (in support for babashka parallel tasks). Stay tuned.</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/thanksgiving-2024.html</id>
    <link href="https://blog.michielborkent.nl/thanksgiving-2024.html"/>
    <title>Thanks for giving!</title>
    <updated>2024-11-27T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Dear sponsors,</p><p>It&apos;s almost Thanksgiving again. We don&apos;t have this tradition here in The Netherlands, but I do think it&apos;s a good to have a special day to count our blessings. I feel very blessed because of your ongoing support. My Clojure projects wouldn&apos;t be as well maintained and fully featured if I didn&apos;t have the sponsoring that I have currently.</p><p>You can read about the past year of OSS updates (and further back) <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>. Main projects are still clj-kondo, babashka, SCI, scittle, squint.</p><p>You can read about my plans for the next year <a href="https://www.clojuriststogether.org/news/vote-on-2025-long-term-funding-applications/#michiel-borkent">here</a> (a vote would be appreciated as well if you happen to be a CT sponsor!).</p><p>Feel free to reach out if you want to contact me about anything. Here, on Clojurians Slack, e-mail (<a href="mailto:michielborkent@gmail.com">michielborkent@gmail.com</a>) or otherwise. I&apos;d love to chat and catch up with you about how you are using (some of) my projects.</p><p>Here&apos;s to another year of Clojure OSS! Thanks for your support!</p><p>With gratitude,</p><p>Michiel Borkent / @borkdude</p><img src="https://files.mastodon.social/media_attachments/files/113/554/454/795/737/364/original/71cc0eaf53606ff3.png"><p>PS: if you aren&apos;t sponsoring, but are interested, here are the main ways to do so:</p><details>
<summary>Sponsor info</summary><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-sep-oct-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-sep-oct-2024.html"/>
    <title>OSS updates September and October 2024</title>
    <updated>2024-11-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during September and October 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>Soon Clojurists Together will be opening their application for long term funding. If you are a member, don&apos;t forget to vote!</p><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

- write something about Heart of Clojure and bbslideshow?

--><h2 id="updates">Updates</h2><p>In September I visited <a href="https://2024.heartofclojure.eu/">Heart of Clojure</a> where Christian, Teodor and I did a workshop on babashka. The first workshop was soon fully booked so we even did a second one and had a lot of fun doing so. It was so good to see familiar Clojure faces in real life again. Thanks Arne and Gaiwan team for organizing this amazing conference.</p><p>Although I didn&apos;t make it to the USA for the Clojure conj in October, Alex Miller did invite me to appear towards the end of his closing talk when he mentioned that 90% of survey respondents used babashka.</p><p><img src="https://files.mastodon.social/media_attachments/files/113/369/966/507/536/059/original/4707ab0b7fcb6f11.png" width="80%"></img></p><p><img src="https://pbs.twimg.com/media/GazP9WmbUAAACIr?format=jpg&name=4096x4096" width="80%"></img></p><p>If you are interested in a full stack web framework with babashka and squint, check out <a href="https://github.com/m3tti/borkweb">borkweb</a>.</p><p>Here are updates about the projects/libraries I&apos;ve worked on in the last two months.</p><ul><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1784">#1784</a>: detect <code>:redundant-do</code> in <code>catch</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2410">#2410</a>: add <code>--report-level</code> flag</li><li>2024.09.27</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2404">#2404</a>: fix regression with metadata on node in hook caused by <code>:redundant-ignore</code> linter</li><li>2024.09.26</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2366">#2366</a>: new linter: <code>:redundant-ignore</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2386">#2386</a>: fix regression introduced in <a href="https://github.com/clj-kondo/clj-kondo/issues/2364">#2364</a> in <code>letfn</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2389">#2389</a>: add new <code>hooks-api/callstack</code> function</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2392">#2392</a>: don&apos;t skip jars that were analyzed with <code>--skip-lint</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2395">#2395</a>: enum constant call warnings</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2400">#2400</a>: <code>deftype</code> and <code>defrecord</code> constructors can be used with <code>Type/new</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2394">#2394</a>: add <code>:sort</code> option to <code>:unsorted-required-namespaces</code> linter to enable case-sensitive sort to match other tools</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2384">#2384</a>: recognize <code>gen/fmap</code> var in <code>cljs.spec.gen.alpha</code></li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li><a href="https://github.com/babashka/babashka/issues/1752">#1752</a>: include <code>java.lang.SecurityException</code> for <code>java.net.http.HttpClient</code> support</li><li><a href="https://github.com/babashka/babashka/issues/1748">#1748</a>: add <code>clojure.core/ensure</code></li><li>Upgrade to <code>taoensso/timbre</code> <code>v6.6.0</code></li><li>Upgrade to GraalVM 23</li><li><a href="https://github.com/babashka/babashka/issues/1743">#1743</a>: fix new fully qualified instance method in call position with GraalVM 23</li><li>Clojure 1.12 interop: method thunks, FI coercion, array notation (see below)</li><li>Upgrade SCI reflector based on clojure 1.12 and remove specific workaround for <code>Thread/sleep</code> interop</li><li>Add <code>tools.reader.edn/read</code></li><li>Fix <a href="https://github.com/babashka/babashka/issues/1741">#1741</a>: <code>(taoensso.timbre/spy)</code> now relies on macros from <code>taoensso.encore</code> previously not available in bb</li><li>Upgrade Clojure to <code>1.12.0</code></li><li><a href="https://github.com/babashka/babashka/issues/1722">#1722</a>: add new clojure 1.12 vars</li><li><a href="https://github.com/babashka/babashka/issues/1720">#1720</a>: include new clojure 1.12&apos;s <code>clojure.java.process</code></li><li><a href="https://github.com/babashka/babashka/issues/1719">#1719</a>: add new clojure 1.12 <code>clojure.repl.deps</code> namespace. Only calls with explicit versions are supported.</li><li><a href="https://github.com/babashka/babashka/issues/1598">#1598</a>: use Rosetta on CircleCI to build x64 images</li><li><a href="https://github.com/babashka/babashka/issues/1716">#1716</a>: expose <code>babashka.http-client.interceptors</code> namespace</li><li><a href="https://github.com/babashka/babashka/issues/1707">#1707</a>: support <code>aset</code> on primitive array</li><li><a href="https://github.com/babashka/babashka/issues/1676">#1676</a>: restore compatibility with newest <a href="https://github.com/overtone/at-at/">at-at</a> version (1.3.58)</li><li>Bump SCI</li><li>Bump <code>fs</code></li><li>Bump <code>process</code></li><li>Bump <code>deps.clj</code></li><li>Bump <code>http-client</code></li><li>Bump <code>clj-yaml</code></li><li>Bump <code>edamame</code></li><li>Bump <code>rewrite-clj</code></li><li>Add <code>java.io.LineNumberReader</code></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><ul><li>Fix <a href="https://github.com/babashka/sci/issues/942">#942</a>: improve error location of invalid destructuring</li><li>Fix <a href="https://github.com/babashka/sci/issues/917">#917</a>: support new Clojure 1.12 Java interop: <code>String/new</code>, <code>String/.length</code> and <code>Integer/parseInt</code> as fns</li><li>Fix <a href="https://github.com/babashka/sci/issues/925">#925</a>: support new Clojure 1.12 array notation: <code>String/1</code>, <code>byte/2</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/926">#926</a>: Support <code>add-watch</code> on vars in CLJS</li><li>Support <code>aset</code> on primitive array using reflection</li><li>Fix <a href="https://github.com/babashka/sci/issues/928">#928</a>: record constructor supports optional meta + ext map</li><li>Fix <a href="https://github.com/babashka/sci/issues/934">#934</a>: <code>:allow</code> may contain namespaced symbols</li><li>Fix <a href="https://github.com/babashka/sci/issues/937">#937</a>: throw when copying non-existent namespace</li><li>Update <code>sci.impl.Reflector</code> (used for implementing JVM interop) to match Clojure 1.12</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Fix watcher and compiler not overriding <code>squint.edn</code> configurations with command line options.</li><li>Allow passing <code>--extension</code> and <code>--paths</code> via CLI</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/563">#563</a>: prioritize refer over core built-in</li><li>Update <code>chokidar</code> to v4 which reduces the number of dependencies</li><li>BREAKING: Dynamic CSS in <code>#html</code> must now be explicitly passed as map literal: <code>(let [m {:color :green}] #html [:div {:style {:&amp; m}}])</code>. Fixes issue when using <code>lit-html</code> in combination with <code>classMap</code>. See <a href="https://squint-cljs.github.io/squint/?src=KG5zIG15bGl0CiAgKDpyZXF1aXJlIFtzcXVpbnQuY29yZSA6cmVmZXIgW2RlZmNsYXNzIGpzLXRlbXBsYXRlXV0KICAgWyJodHRwczovL2VzbS5zaC9saXRAMy4wLjAiIDphcyBsaXRdCiAgIFsiaHR0cHM6Ly9lc20uc2gvbGl0QDMuMC4wL2RpcmVjdGl2ZXMvY2xhc3MtbWFwLmpzIiA6cmVmZXIgW2NsYXNzTWFwXV0pKQoKKGRlZmNsYXNzIE15RWxlbWVudAogIChleHRlbmRzIGxpdC9MaXRFbGVtZW50KQogICheOnN0YXRpYyBmaWVsZCBwcm9wZXJ0aWVzIHs6Y291bnQge319KQoKICAoY29uc3RydWN0b3IgW3RoaXNdCiAgICAoc3VwZXIpCiAgICAoc2V0ISB0aGlzLmNvdW50IDApCiAgICAoc2V0ISB0aGlzLm5hbWUgIkhlbGxvIikpCgogIE9iamVjdAogIChyZW5kZXIgW3RoaXNdCiAgICAjaHRtbCBebGl0L2h0bWwKICAgIFs6ZGl2CiAgICAgWzpoMSB7OmNsYXNzIChjbGFzc01hcCB7OmVuYWJsZWQgdHJ1ZX0pfQogICAgICB0aGlzLm5hbWVdCiAgICAgWzpidXR0b24geyJAY2xpY2siIHRoaXMub25DbGljawogICAgICAgICAgICAgICA6cGFydCAiYnV0dG9uIn0KICAgICAgIkNsaWNrIGNvdW50ICIgdGhpcy5jb3VudF1dKQoKICAob25DbGljayBbdGhpc10KICAgIChzZXQhIHRoaXMuY291bnQgKGluYyB0aGlzLmNvdW50KSkpKQoKKGRlZm9uY2UgZm9vCiAgKGRvCiAgICAoanMvd2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSAibXktZWxlbWVudCIgTXlFbGVtZW50KQogICAgdHJ1ZSkpCgooZGVmIGFwcCAob3IgKGpzL2RvY3VtZW50LnF1ZXJ5U2VsZWN0b3IgIiNhcHAiKQogICAgICAgICAgIChkb3RvIChqcy9kb2N1bWVudC5jcmVhdGVFbGVtZW50ICJkaXYiKQogICAgICAgICAgICAgKHNldCEgLWlkICJhcHAiKQogICAgICAgICAgICAgKGpzL2RvY3VtZW50LmJvZHkucHJlcGVuZCkpKSkKCihzZXQhICguLWlubmVySFRNTCBhcHApICNodG1sIFs6ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbOm15LWVsZW1lbnRdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjX1s6bXktZWxlbWVudF1dKQ%3D%3D">demo</a></li><li><a href="https://github.com/squint-cljs/squint/issues/556">#556</a>: fix referring to var in other namespace via global object in REPL mode</li><li>Pass <code>--repl</code> opts to <code>watch</code> subcommand in CLI</li><li><a href="https://github.com/squint-cljs/squint/issues/552">#552</a>: fix REPL output with hyphen in ns name</li><li>Ongoing work on browser REPL. Stay tuned.</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Fix referring to vars in other namespaces globally</li><li>Allow <code>defclass</code> to be referenced through other macros, e.g. as <code>cherry.core/defclass</code></li><li>Fix emitting keyword in HTML</li><li><a href="https://github.com/squint-cljs/cherry/issues/138">#138</a>: Support <code>#html</code> literals, ported from squint</li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></p><ul><li><a href="https://github.com/babashka/http-client/issues/68">#68</a> Fix accidental URI path decoding in uri-with-query (<a href="https://github.com/hxtmdev">@hxtmdev</a>)</li><li><a href="https://github.com/babashka/http-client/issues/71">#71</a>: Link back to sources in release artifact (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/http-client/issues/71">#73</a>: Allow implicit ports when specifying the URL as a map (<a href="https://github.com/lvh">@lvh</a>)</li></ul></li><li><p><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</p><ul><li><a href="https://github.com/babashka/http-server/issues/16">#16</a>: support range requests (<a href="https://github.com/jmglov">jmglov</a>)</li><li><a href="https://github.com/babashka/http-server/issues/13">#13</a>: add an ending slash to the dir link, and don&apos;t encode the slashes (<a href="https://github.com/KDr2">@KDr2</a>)</li><li><a href="https://github.com/babashka/http-server/issues/12">#12</a>: Add headers to index page (rather than just file responses)</li></ul></li><li><p><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command<br></p><ul><li>Fix #88: bbin ls with 0-length files doesn&apos;t crash</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p></li><li><p>Add <code>cljs.pprint/code-dispatch</code> and <code>cljs.pprint/with-pprint-dispatch</code></p></li><li><p><a href="https://github.com/clojure/clojurescript">clojurescript</a></p><ul><li><a href="https://github.com/clojure/clojurescript/commit/f1fc819da94147411e353ecb17c751af6a18ce2e">Throw when calling ana-api/ns-publics on non-existing ns</a></li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></p><ul><li><a href="https://github.com/babashka/neil/issues/241">#241</a>: ignore missing deps file (instead of throwing) in <code>neil new</code> (<a href="https://github.com/bobisageek">@bobisageek</a>)</li></ul></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p><ul><li>Added a configuration for <code>cljs.spec.alpha</code> and related namespaces</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Include <code>cljs.spec.alpha</code>, <code>cljs.spec.gen.alpha</code>, <code>cljs.spec.test.alpha</code></li></ul></li><li><p><a href="https://github.com/borkdude/qualify-methods">qualify-methods</a></p><ul><li>Initial release of experimental tool to rewrite instance calls to use fully qualified methods (Clojure 1.12 only0</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Add support for <code>:require-cljs</code> which allows you to use <code>.cljs</code> files for render functions</li><li>Add support for nREPL for developing render functions</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Upgrade/sync with clojure CLI v1.12.0.1479</li></ul></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p><ul><li>Work has started to support prepending output (in support for babashka parallel tasks). Stay tuned.</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<br></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</li><li><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</li><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jul-aug-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jul-aug-2024.html"/>
    <title>OSS updates July and August 2024</title>
    <updated>2024-08-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during July and August 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

drwxr-xr-x@  79 borkdude  staff   2528 Apr 28 16:32 babashka
--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Unreleased:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2386">#2386</a>: fix regression introduced in <a href="https://github.com/clj-kondo/clj-kondo/issues/2364">#2364</a> in <code>letfn</code> (unreleased)</li><li>v2024.08.29:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2303">#2303</a>: Support array class notation of Clojure 1.12 (<code>byte/1</code>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/916">#916</a>: New linter: <code>:destructured-or-binding-of-same-map</code> which warns about <code>:or</code> defaults referring to bindings of same map, which is undefined and may result in broken behavior</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2362">#2362</a>: turn min-version warning into lint warning</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1603">#1603</a>: Support Java classes in <code>:analyze-call</code> hook</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2369">#2369</a>: false positive unused value in quoted list</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2374">#2374</a>: Detect misplaced return Schemas (<a href="https://github.com/frenchy64">@frenchy64</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2364">#2364</a>: performance: code that analyzed fn arity is ran twice</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2355">#2355</a>: support <code>:as-alias</code> with current namespace without warning about self-requiring namespace</li><li>v2024.08.01:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2359">#2359</a>: <code>@x</code> should warn with type error about <code>x</code> not being an IDeref, e.g. with <code>@inc</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2345">#2345</a>: Fix SARIF output and some enhancements (<a href="https://github.com/nxvipin">@nxvipin</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2335">#2335</a>: read causes side effect, thus not an unused value</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2336">#2336</a>: <code>do</code> and <code>doto</code> type checking (<a href="https://github.com/yuhan0">@yuhan0</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2322">#2322</a>: report locations for more reader errors (<a href="https://github.com/yuhan0">@yuhan0</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2342">#2342</a>: report unused maps, vectors, sets, regexes, functions as <code>:unused-value</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2352">#2352</a>: type mismatch error for <code>or</code> without arguments</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2344">#2344</a>: copying configs and linting dependencies can now be done in one go with <code>--dependencies --copy-configs</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2357">#2357</a>: <code>:discouraged-namespace</code> can have <code>:level</code> per namespace</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Mostly bumped library dependencies and improvements in SCI</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p><ul><li>Support new Clojure 1.12 array notation</li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><ul><li>Fix <a href="https://github.com/babashka/sci/issues/923">#923</a>: check for duplicate keys in dynamic set or map literals</li><li>Fix <a href="https://github.com/babashka/sci/issues/926">#926</a>: Support <code>add-watch</code> on vars in CLJS</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li><a href="https://github.com/squint-cljs/cherry/issues/135">#135</a>: Fix UMD build</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Bump org.babashka/cli</li><li>Bump SCI</li></ul></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p><ul><li>Fix <a href="https://github.com/borkdude/quickdoc/issues/39">#39</a>: fix link when var is named multiple times in docstring</li></ul></li><li><p><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</p><ul><li><a href="https://github.com/babashka/http-server/issues/13">#13</a>: add an ending slash to the dir link, and don&apos;t encode the slashes (<a href="https://github.com/KDr2">@KDr2</a>)</li><li><a href="https://github.com/babashka/http-server/issues/16">#16</a>: support range requests</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<br></p><ul><li>Fix <a href="https://github.com/babashka/cli/issues/102">#102</a>: <code>format-table</code> correctly pads cells containing ANSI escape codes</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Upgrade/sync with clojure CLI v1.11.4.1474</li><li>deps.clj is now available as <code>clojure.exe</code> via the <a href="https://github.com/casselc/clj-msi">clj-msi</a> installer and the official installation method on plain Windows!</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li><a href="https://github.com/babashka/fs/issues/132">#132</a>: add <code>read-link</code> to resolve symbolic link, without target of link needing to exist</li></ul></li><li><p><a href="https://github.com/borkdude/tools">tools</a>: a set of <a href="https://github.com/babashka/bbin/">bbin</a> installable scripts</p><ul><li>Updated antq</li><li>Added <code>--minimize</code> option to the ddiff script</li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></p><ul><li>Ensure that http-client works with Clojure 1.10 as the minimum supported Clojure version</li></ul></li><li><p><a href="https://github.com/babashka/sci.nrepl">sci.nrepl</a>: nREPL server for SCI projects that run in the browser</p><ul><li>Mostly changes to accomodate running sci.nrepl with <a href="https://github.com/nextjournal/clerk">clerk</a> viewer functions</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a>: Moldable Live Programming for Clojure</p><ul><li>Mostly worked on making viewer functions available from <code>.cljs</code> files and allow working on them via a nREPL session</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li>Nikita Prokopov made the <a href="https://github.com/squint-cljs/squint/blob/main/logo/logo.svg">squint logo</a>!</li><li><a href="https://github.com/squint-cljs/squint/issues/542">#542</a>: fix <code>run</code> on Windows</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br></li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command<br></li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-may-jun-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-may-jun-2024.html"/>
    <title>OSS updates May and June 2024</title>
    <updated>2024-06-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during May and June 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

drwxr-xr-x@  79 borkdude  staff   2528 Apr 28 16:32 babashka
--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://github.com/borkdude/html">html</a>: Html generation library inspired by squint&apos;s html tag</p><ul><li>A <strong>NEW</strong> library for html generation that is both safe, performant, generates easy to understand code and works the same across CLJ and CLJS.</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting. Released v1.3.191 with the following changes:<br></p><ul><li>Fix <a href="https://github.com/babashka/babashka/issues/1688">#1688</a>: <code>use-fixtures</code> should add metadata to <code>*ns*</code></li><li>Fix <a href="https://github.com/babashka/babashka/issues/1692">#1692</a>: Add support for <code>ITransientSet</code> and <code>org.flatland/ordered-set</code></li><li>Bump org.flatland/ordered to <code>1.15.12</code>.</li><li>Partially Fix <a href="https://github.com/babashka/babashka/issues/1695">#1695</a>: <code>--repl</code> arg handling should consume only one arg (itself) (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li>Partially Fix <a href="https://github.com/babashka/babashka/issues/1695">#1695</a>: make <code>*command-line-args*</code> value available in the REPL (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li>Fix <a href="https://github.com/babashka/babashka/issues/1686">#1686</a>: do not fetch dependencies/invoke java for <code>version</code>, <code>help</code>, and <code>describe</code> options (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1696">#1696</a>: add <code>clojure.lang.DynamicClassLoader</code> constructors (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1696">#1696</a>: add <code>clojure.core/*source-path*</code> (points to the same sci var as <code>*file*</code>) (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1696">#1696</a>: add <code>clojure.main/with-read-known</code> (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1696">#1696</a>: add <code>clojure.core.server/repl-read</code> (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1696">#1696</a>: make the <code>cognitect-labs/transcriptor</code> library work (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li><a href="https://github.com/babashka/babashka/issues/1700">#1700</a>: catch exceptions from resolving symbolic links during <code>bb.edn</code> lookup (<a href="https://github.com/bobisageek">@bobisageek</a>)</li><li>Support <code>java.nio.channels.ByteChannel</code> + several other related interop</li><li>Bump <code>nrepl/bencode</code> to <code>1.2.0</code></li><li>Bump <code>babashka/fs</code></li><li>Bump <code>org.babashka/http-client</code> to <code>0.4.18</code></li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br></p><ul><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2335">#2335</a>: read causes side effect, thus not an unused value</li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2336">#2336</a>: <code>do</code> and <code>doto</code> type checking (<a href="https://github.com/yuhan0">@yuhan0</a>)</li><li>Fix <a href="https://github.com/clj-kondo/clj-kondo/issues/2322">#2322</a>: report locations for more reader errors (<a href="https://github.com/yuhan0">@yuhan0</a>)</li><li>Imports were copied to <code>.clj-kondo/imports</code> but weren&apos;t pick up correctly. Thanks <a href="https://github.com/frenchy64">@frenchy64</a> for reporting the bug.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2333">#2333</a>: Add location to invalid literal syntax errors</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2323">#2323</a>: New linter <code>:redundant-str-call</code> which detects unnecessary <code>str</code> calls. Off by default.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2302">#2302</a>: New linter: <code>:equals-expected-position</code> to enforce expected value to be in first (or last) position. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1035">#1035</a>: Support SARIF output with <code>--config {:output {:format :sarif}}</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2307">#2307</a>: import configs to intermediate dir</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2309">#2309</a>: Report unused <code>for</code> expression</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2315">#2315</a>: Fix regression with unused JavaScript namespace</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2304">#2304</a>: Report unused value in <code>defn</code> body</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2227">#2227</a>: Allow <code>:flds</code> to be used in keys destructuring for ClojureDart</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2316">#2316</a>: Handle ignore hint on protocol method</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2322">#2322</a>: Add location to warning about invalid unicode character</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2319">#2319</a>: Support <code>:discouraged-var</code> on global JS values, like <code>js/fetch</code></li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li><a href="https://github.com/squint-cljs/squint/issues/536">#536</a>: HTML is not escaped in dynamic expression</li><li><a href="https://github.com/squint-cljs/squint/issues/537">#537</a>: Fix <code>not</code>: wrap argument in parens</li><li>Return interop expression in function body</li><li>Prefer value from props map over explicit value</li><li><code>#html</code> improvements, support <code>:&amp;</code> for spreading props</li><li><a href="https://github.com/squint-cljs/squint/issues/492">#492</a>: defclass static methods and fields</li><li><a href="https://github.com/squint-cljs/squint/issues/526">#526</a>: Fix export of class name with dashes</li><li><a href="https://github.com/squint-cljs/squint/issues/517">#517</a>: Preserve state over REPL evals</li><li><a href="https://github.com/squint-cljs/squint/issues/513">#513</a>: Fix <code>shuffle</code> core function random distribution and performances</li><li><a href="https://github.com/squint-cljs/squint/issues/517">#517</a>: Fix re-definition of class with <code>defclass</code> in REPL</li><li><a href="https://github.com/squint-cljs/squint/issues/522">#522</a>: fix <code>nil</code> <code>#html</code> rendering issue</li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br> Released version 0.3.65 with the following changes:</p><ul><li><a href="https://github.com/babashka/neil/issues/209">#209</a>: add newlines between dependencies</li><li><a href="https://github.com/babashka/neil/issues/185">#185</a>: throw on non-existing library</li><li>Bump <code>babashka.cli</code></li><li>Fetch latest stable <code>slipset/deps-deploy</code>, instead of hard-coding (<a href="https://github.com/vedang">@vedang</a>)</li><li>Several emacs package improvements (<a href="https://github.com/agzam">@agzam</a>)</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Fix <a href="https://github.com/squint-cljs/cherry/issues/130">#130</a>: fix predefined <code>:aliases</code> for cherry.embed</li><li>Support <code>IDeref</code>, <code>ISwap</code>, <code>IReset</code> in <code>deftype</code></li></ul></li><li><p><a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a>: Clojure/Script mode for CodeMirror 6.</p><ul><li>Fix <a href="https://github.com/nextjournal/clojure-mode/issues/54">#54</a>: support slurping from within string literal</li></ul></li><li><p><a href="https://github.com/brightin/pottery">pottery</a>: A clojure library to interact with gettext and PO/POT files</p><ul><li>Contributed a few improvements to dealing with reader conditionals</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Fix <code>cljs.pprint/print-table</code> + <code>with-out-str</code></li><li>Fixed <code>cljs.test/testing</code> macro to display strings correctly on test failure (<a href="https://github.com/jaidetree">@jaidetree</a>)</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<br></p><ul><li>Fix <a href="https://github.com/babashka/cli/issues/98">#98</a>: internal options should not interfere with :restrict</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Upgrade/sync with clojure CLI v1.11.3.1463</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br></li><li><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command<br></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-mar-apr-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-mar-apr-2024.html"/>
    <title>OSS updates March and April 2024</title>
    <updated>2024-04-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during March and April 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

drwxr-xr-x@  79 borkdude  staff   2528 Apr 28 16:32 babashka
--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li><a href="https://github.com/squint-cljs/squint/issues/509">#509</a>: Optimization: use arrow fn for implicit IIFE when possible</li><li>Optimization: emit <code>const</code> in let expressions, which esbuild optimizes better</li><li>Don&apos;t wrap arrow function in parens, see <a href="https://github.com/squint-cljs/vite-plugin-squint/pull/12">this issue</a></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/499">#499</a>: add support for emitting arrow functions with <code>^:=&gt;</code> metadata</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/505">#505</a>: Support <code>:rename</code> in <code>:require</code></li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/490">#490</a>: render css maps in html mode</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/502">#502</a>: allow method names in <code>defclass</code> to override squint built-ins</li><li>Fix <a href="https://github.com/squint-cljs/squint/issues/496">#496</a>: don&apos;t wrap strings in another set of quotes</li><li>Fix rendering of attribute expressions in HTML (should be wrapped in quotes)</li><li>Compile destructured function args to JS destructuring when annotated with <code>^:js</code>. This benefits working with vitest and playwright.</li><li><a href="https://github.com/squint-cljs/squint/issues/481">#481</a>: BREAKING, squint no longer automatically copies all non-compiled files to the <code>:output-dir</code>. This behavior is now explicit with <code>:copy-resources</code>, see docs.</li><li>Add new <code>#html</code> reader for producing HTML literals using hiccup. See <a href="https://github.com/squint-cljs/squint?tab=readme-ov-file#html">docs</a> and <a href="https://squint-cljs.github.io/squint/?src=KG5zIG15ZWxlbWVudAogICg6cmVxdWlyZSBbc3F1aW50LmNvcmUgOnJlZmVyIFtkZWZjbGFzcyBqcy10ZW1wbGF0ZV1dCiAgIFsiaHR0cHM6Ly9lc20uc2gvbGl0IiA6YXMgbGl0XSkpCgooZGVmY2xhc3MgTXlFbGVtZW50CiAgKGV4dGVuZHMgbGl0L0xpdEVsZW1lbnQpCiAgKGZpZWxkIG5hbWUgIldvcmxkIikKICAoZmllbGQgY291bnQgMCkKCiAgKGNvbnN0cnVjdG9yIFtfXQogICAgKHN1cGVyKSkKCiAgT2JqZWN0CiAgKHJlbmRlciBbdGhpc10KICAgICNodG1sIF5saXQvaHRtbAogICAgWzpkaXYKICAgICBbOmgxIG5hbWVdCiAgICAgWzpidXR0b24geyJAY2xpY2siICguLW9uQ2xpY2sgdGhpcykKICAgICAgICAgICAgICAgOnBhcnQgImJ1dHRvbiJ9CiAgICAgICJDbGljayBjb3VudCAiIGNvdW50XV0pCgogIChvbkNsaWNrIFt0aGlzXQogICAgKHNldCEgY291bnQgKGluYyBjb3VudCkpCiAgICAoLmRpc3BhdGNoRXZlbnQgdGhpcyAobmV3IGpzL0N1c3RvbUV2ZW50ICJjb3VudC1jaGFuZ2VkIikpKSkKCihzZXQhICguLXByb3BlcnRpZXMgTXlFbGVtZW50KSAjanMgeyJjb3VudCIgI2pzIHt9fSkKCihqcy93aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lICJteS1lbGVtZW50IiBNeUVsZW1lbnQpCgooZGVmIGFwcCAob3IgKGpzL2RvY3VtZW50LnF1ZXJ5U2VsZWN0b3IgIiNhcHAiKQogICAgICAgICAgIChkb3RvIChqcy9kb2N1bWVudC5jcmVhdGVFbGVtZW50ICJkaXYiKQogICAgICAgICAgICAgKHNldCEgLWlkICJhcHAiKQogICAgICAgICAgICAgKGpzL2RvY3VtZW50LmJvZHkucHJlcGVuZCkpKSkKCihzZXQhICguLWlubmVySFRNTCBhcHApICNodG1sIFs6bXktZWxlbWVudF0p">playground example</a>.</li><li><a href="https://github.com/squint-cljs/squint/issues/483">#483</a>: Fix operator precedence problem</li></ul></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects.<br> Released version 0.3.65 with the following changes:</p><ul><li><a href="https://github.com/babashka/neil/issues/209">#209</a>: add newlines between dependencies</li><li><a href="https://github.com/babashka/neil/issues/185">#185</a>: throw on non-existing library</li><li>Bump <code>babashka.cli</code></li><li>Fetch latest stable <code>slipset/deps-deploy</code>, instead of hard-coding (<a href="https://github.com/vedang">@vedang</a>)</li><li>Several emacs package improvements (<a href="https://github.com/agzam">@agzam</a>)</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<br> Released 2024.03.13</p><ul><li>Fix memory usage regression introduced in 2024.03.05</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2299">#2299</a>: Add documentation for <code>:java-static-field-call</code>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1732">#1732</a>: new linter: <code>:shadowed-fn-param</code> which warns on using the same parameter name twice, as in <code>(fn [x x])</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2276">#2276</a>: New Clojure 1.12 array notation (<code>String*</code>) may occur outside of metadata</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2278">#2278</a>: <code>bigint</code> in CLJS is a known symbol in <code>extend-type</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2288">#2288</a>: fix static method analysis and suppressing <code>:java-static-field-call</code> locally</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2293">#2293</a>: fix false positive static field call for <code>(Thread/interrupted)</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2296">#2296</a>: publish multi-arch Docker images (including linux aarch64)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2295">#2295</a>: lint case test symbols in list <br>Unreleased changed:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1035">#1035</a>: Support SARIF output with <code>--config {:output {:format :sarif}}</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2309">#2309</a>: report unused for expression</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2135">#2135</a>: fix regression with unused JavaScript namespace</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2302">#2302</a>: New linter: <code>:equals-expected-position</code> to enforce expected value to be in first (or last) position. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2304">#2304</a>: Report unused value in <code>defn</code> body</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<br> Released version 0.8.58-59</p><ul><li>Fix <a href="https://github.com/babashka/cli/issues/96">#96</a>: prevent false defaults from being removed/ignored</li><li>Fix <a href="https://github.com/babashka/cli/issues/91">#91</a>: keyword options and hyphen options should not mix</li><li>Fix <a href="https://github.com/babashka/cli/issues/89">#89</a>: long option never represents alias</li></ul></li><li><p><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments<br> Released 0.4.8 with the following update:</p><ul><li>Add newline after adding new element to top level map with <code>assoc-in</code></li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>nbb bundle JS output will ignore <code>nbb.edn</code></li><li><a href="https://github.com/babashka/nbb/issues/351">#351</a>: Update bun docs/example.</li><li>Add <code>cljs.core/exists?</code></li></ul></li><li><p><a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a>: Clojure/Script mode for CodeMirror 6.</p><ul><li>Fix <a href="https://github.com/nextjournal/clojure-mode/issues/49">#49</a>: bug with hitting backspace after line comment Test it in the <a href="https://squint-cljs.github.io/squint/?repl=true&amp;src=I18oKyAxIDIgMyk%3D">squint playground</a>.</li></ul></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Use instaparse from babashka</p><ul><li>Serialize regexes in parse results</li></ul></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI<br> Released v0.6.17</p><ul><li><a href="https://github.com/babashka/babashka/issues/77">#77</a>: make dependency on browser (<code>js/document</code>) optional so scittle can run in webworkers, Node.js, etc.</li><li><a href="https://github.com/babashka/babashka/issues/69">#69</a>: executing script tag with src + whitespace doesn&apos;t work</li><li><a href="https://github.com/babashka/babashka/issues/72">#72</a>: add clojure 1.11 functions like <code>update-vals</code></li><li><a href="https://github.com/babashka/babashka/issues/75">#75</a>: Support reader conditionals in source code</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li><a href="https://github.com/squint-cljs/cherry/issues/127">#127</a>: fix duplicate <code>cherry-cljs</code> property in <code>package.json</code> which caused issues with some bundlers</li><li>Bump squint common compiler code</li></ul></li><li><p><a href="https://github.com/nextjournal/clerk">clerk</a></p><ul><li><a href="https://github.com/nextjournal/clerk/issues/646">#646</a> Fix parsing + location issue which fixes compatibility with honey.sql</li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<br> Released 0.4.17-19</p><ul><li><a href="https://github.com/babashka/http-client/issues/55">#55</a>: allow <code>:body</code> be <code>java.net.http.HttpRequest$BodyPublisher</code></li><li>Support a Clojure function as <code>:client</code> option, mostly useful for testing</li><li><a href="https://github.com/babashka/http-client/issues/49">#49</a>: add <code>::oauth-token</code> interceptor</li><li><a href="https://github.com/babashka/http-client/issues/52">#52</a>: document <code>:throw</code> option</li></ul></li><li><p><a href="https://github.com/babashka/bbin">bbin</a>: Install any Babashka script or project with one command<br> These fixes have been made by <a href="https://github.com/rads">@rads</a>:</p><ul><li><a href="https://github.com/babashka/bbin/issues/62">Fix #62: bbin ls is unnecessarily slow</a></li><li><a href="https://github.com/babashka/bbin/issues/72">Fix #72: bbin install [LOCAL-FILE] should not be restricted to files with the <code>.clj</code> extension</a></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><ul><li>Fix <a href="https://github.com/babashka/sci/issues/626">#626</a>: add <code>cljs.core/exists?</code></li><li>Fix <a href="https://github.com/babashka/sci/issues/919">#919</a>: :js-libs + refer + rename clashes with core var</li><li>Fix <a href="https://github.com/babashka/sci/issues/906">#906</a>: <code>merge-opts</code> loses <code>:features</code> or previous context</li></ul></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p><ul><li>Fix Windows issue related to relative paths (which took me all day, argh!)</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p><ul><li><a href="https://github.com/babashka/fs/issues/122">#122</a>: <code>fs/copy-tree</code>: fix copying read-only directories with children (<a href="https://github.com/sohalt">@sohalt</a>)</li><li><a href="https://github.com/babashka/fs/issues/127">#127</a>: Inconsistent documentation for the <code>:posix-file-permissions</code> options (<a href="https://github.com/teodorlu">@teodorlu</a>)</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Fix <a href="https://github.com/babashka/babashka/issues/1679">#1679</a>: bump timbre and fix wrapping <code>timbre/log!</code></li><li>Add <code>java.util.concurrent.CountDownLatch</code></li><li>Add <code>java.lang.ThreadLocal</code></li><li>Bump versions of included libraries</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</li><li><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jan-feb-2024.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jan-feb-2024.html"/>
    <title>OSS updates January and February 2024</title>
    <updated>2024-02-29T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during January and February 2024.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Like you can read on <a href="https://metaredux.com/posts/2024/02/15/cider-community-impact.html">Bozhidar
Batsov</a>&apos;s blog these aren&apos;t the easiest times for Open Source sponsored software. I have no reason to complain, but I did see a similar drop in sponsoring in the last year. I&apos;m thankful for those who sponsored my projects in the past and even more for those who keep doing so!</p><p>Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Current top tier sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://nubank.com.br">Nubank</a></li></ul><p>Open the details section for more info about sponsoring.</p><details>
<summary>Sponsor info</summary><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy. Released 2024.02.12</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2276">#2276</a>: New Clojure 1.12 array notation (<code>String*</code>) may occur outside of metadata</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2278">#2278</a>: <code>bigint</code> in CLJS is a known symbol in <code>extend-type</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2288">#2288</a>: fix static method analysis and suppressing <code>:java-static-field-call</code> locally</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2293">#2293</a>: fix false positive static field call for <code>(Thread/interrupted)</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2093">#2093</a>: publish multi-arch Docker images (including linux aarch64)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2274">#2274</a>: Support clojure 1.12 new type hint notations</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2260">#2260</a>: calling static <em>field</em> as function should warn, e.g. <code>(System/err)</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1917">#1917</a>: detect string being called as function</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1923">#1923</a>: Lint invalid fn name</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2256">#2256</a>: enable <code>assert</code> in hooks</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2253">#2253</a>: add support for <code>datomic-type-extensions</code> to datalog syntax checking</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2255">#2255</a>: support <code>:exclude-files</code> in combination with linting from stdin + provided <code>--filename</code> argument</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2246">#2246</a>: preserve metadata on symbol when going through <code>:macroexpand</code> hook</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2254">#2254</a>: lint files in absence of config dir</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2251">#2251</a>: support suppressing <code>:unused-value</code> using <code>:config-in-call</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2266">#2266</a>: suppress <code>:not-a-function</code> linter in reader tag</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2259">#2259</a>: <code>ns-map</code> unmaps var defined prior in namespace</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2272">#2272</a>: Report var usage in <code>if</code>/<code>when</code> condition as always truthy, e.g. <code>(when #&apos;some-var 1)</code></li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</p><ul><li><a href="https://github.com/squint-cljs/squint/issues/472">#472</a>: Use consistent alias</li><li><a href="https://github.com/squint-cljs/squint/issues/474">#474</a>: fix JSX fragment</li><li><a href="https://github.com/squint-cljs/squint/issues/475">#475</a>: don&apos;t crash watcher on deleting file</li><li>Add <code>simple-benchmark</code></li><li><a href="https://github.com/squint-cljs/squint/issues/468">#468</a>: Keywords in JSX should render with hyphens</li><li><a href="https://github.com/squint-cljs/squint/issues/466">#466</a>: Fix <code>doseq</code> expression with <code>set!</code> in function return position</li><li><a href="https://github.com/squint-cljs/squint/issues/462">#462</a>: Add <code>&quot;exports&quot;</code> field to <code>package.json</code></li><li><a href="https://github.com/squint-cljs/squint/issues/460">#460</a>: escape <code>&lt;</code> and <code>&gt;</code> in JSX strings</li><li><a href="https://github.com/squint-cljs/squint/issues/458">#458</a>: don&apos;t emit <code>null</code> in statement position</li><li><a href="https://github.com/squint-cljs/squint/issues/455">#455</a>: don&apos;t export non-public vars</li><li>Fix infix operator in return position</li><li>Allow playground to use JSX in non-REPL mode</li><li>Add transducer arity to all existing core functions</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting. Two releases in the past two months with the following changes:</p><ul><li><a href="https://github.com/babashka/babashka/issues/1660">#1660</a>: add <code>:deps-root</code> as part of hash to avoid caching issue with <code>deps.clj</code></li><li><a href="https://github.com/babashka/babashka/issues/1632">#1632</a>: fix <code>(.readPassword (System/console))</code> by upgrading GraalVM to <code>21.0.2</code></li><li><a href="https://github.com/babashka/babashka/issues/1661">#1661</a>: follow symlink when reading adjacent bb.edn</li><li><a href="https://github.com/babashka/babashka/issues/1665">#1665</a>: <code>read-string</code> should use non-indexing reader for compatibilty with Clojure</li><li>Bump edamame to 1.4.24</li><li>Bump http-client to 0.4.16</li><li>Bump babashka.cli to 0.8.57</li><li>Uberjar task: support reader conditional in .cljc file</li><li>Support reader conditional in .cljc file when creating uberjar</li><li>Add more <code>javax.net.ssl</code> classes</li><li><a href="https://github.com/babashka/babashka/issues/1675">#1675</a>: add <code>hash-unordered-coll</code></li><li><a href="https://github.com/babashka/babashka/issues/1658">#1658</a>: fix command line parsing for scripts that parse <code>--version</code> or <code>version</code> etc</li><li>Add <code>clojure.reflect/reflect</code></li><li>Add <code>java.util.ScheduledFuture</code>, <code>java.time.temporal.WeekFields</code></li><li>Support <code>Runnable</code> to be used without import</li><li>Allow <code>catch</code> to be used as var name</li><li><a href="https://github.com/babashka/babashka/issues/1646">#1646</a>: command-line-args are dropped when file exists with same name</li><li><a href="https://github.com/babashka/babashka/issues/1645">#1645</a>: Support for <code>clojure.lang.LongRange</code></li><li><a href="https://github.com/babashka/babashka/issues/1652">#1652</a>: allow <code>bb.edn</code> to be empty</li><li><a href="https://github.com/babashka/babashka/issues/1586">#1586</a>: warn when config file doesn&apos;t exist and <code>--debug</code> is enabled</li><li><a href="https://github.com/babashka/babashka/issues/1410">#1410</a>: better error message when exec fn doesn&apos;t exist</li><li>Bump <code>babashka.cli</code> to <code>0.8.55</code> which contains subcommand improvements</li><li>Bump <code>deps.clj</code> to <code>1.11.1.1435</code></li><li>Bump <code>babashka.fs</code> to <code>0.5.20</code></li><li>Compatibility with <code>plumbing.core</code></li><li>Compatibility with <code>shadow.css</code> by improving <code>tools.reader</code> compatibility</li><li><a href="https://github.com/babashka/babashka/issues/1647">#1647</a>: Allow capturing env vars at build time (only relevant for building bb)</li></ul></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p><ul><li><a href="https://github.com/babashka/process/issues/123">#123</a>: <code>exec</code> now converts <code>:env</code> and <code>:extra-env</code> keywords (<a href="https://github.com/lread">@lread</a>)</li><li><a href="https://github.com/babashka/process/issues/140">#140</a>: accept <code>java.nio.file.Path</code> as <code>:dir</code> argument</li><li><a href="https://github.com/babashka/process/issues/148">#148</a>: accept <code>Path</code> in <code>:out</code>, <code>:err</code> and <code>:in</code></li><li>Support <code>:out :bytes</code> (<a href="https://github.com/hansbugge">@hansbugge</a>)</li></ul></li><li><p><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</p><ul><li>Released version 0.1.6 which fixes <code>:key-fn</code> + <code>read</code> behavior for cheshire</li></ul></li><li><p><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</p><ul><li>Upgraded the underlying tools.build version to the latest version used in tools.build (the very latest wasn&apos;t compatible with tools.build!)</li></ul></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p><ul><li>Support new <code>^[String]</code> metadata notation which desugars into <code>^{:param-tags [String]}</code></li><li>Add <code>:map</code> and <code>:set</code> options to coerce map/set literals into customizable data structures, for example, an ordered collections to preserve key order.</li></ul></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p><ul><li>Add <code>cljs.test/run-test</code> macro</li><li>Add cljs.core/Atom</li><li>Add promesa <code>promesify</code></li></ul></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</p><ul><li><a href="https://github.com/babashka/http-client/issues/45">#45</a>: query param values are double encoded</li></ul></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li>Fix <a href="https://github.com/babashka/cli/issues/82">#82</a>: prefer alias over composite option</li><li>Add <code>:opts</code> to <code>:error-fn</code> input</li><li>Fix command line args for test runner <code>--dirs</code>, <code>--only</code>, etc</li><li>Fix <code>--no-option</code> (<code>--no</code> prefix) in combination with subcommands</li><li>Prioritize <code>:exec-args</code> over spec <code>:default</code>s</li><li><code>dispatch</code> improvements (<a href="https://github.com/Sohalt">@Sohalt</a>, <a href="https://github.com/borkdude">@borkdude</a>):<ul><li>The <code>:cmds</code> order of entries in the table doesn&apos;t matter</li><li>Support parsing intermediate options: <code>foo --opt1=never bar --opt2=always</code></li></ul></li></ul></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><ul><li>Bump edamame</li><li>Add <code>hash-ordered-coll</code></li><li><code>read-string</code> should use non-indexing reader</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><p><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</p></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</p></li><li><p><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</p></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p></li><li><p><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</p></li><li><p><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</p></li><li><p><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</p></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p></li><li><p><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</p></li><li><p><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</p></li><li><p><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</p></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p></li><li><p><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</p></li><li><p><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</p></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p></li><li><p><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</p></li><li><p><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</p></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></p></li><li><p><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</p></li><li><p><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</p></li><li><p><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</p></li><li><p><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</p></li><li><p><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</p></li><li><p><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</p></li><li><p><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</p></li><li><p><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</p></li><li><p><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</p></li><li><p><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</p></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-dec-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-dec-2023.html"/>
    <title>OSS updates December 2023</title>
    <updated>2023-12-31T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during December 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="happy-new-year!">Happy new year!</h2><p>First all, as this is the last day of 2023, I wish you all a happy new year. Hopefully many goods things may happen in the Clojure ecosystem. I&apos;m grateful many of you have sponsored my work in 2023!</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible. Without <em>you</em>, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all. Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://github.com/pitch-io">Pitch</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy. Released 2023.12.15</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1990">#1990</a>: Specify <code>:min-clj-kondo-version</code> in config.edn and warn when current version is too low (<a href="https://github.com/snasphysicist">@snasphysicist</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1753">#1753</a>: New linter <code>:underscore-in-namespace</code> (<a href="https://github.com/cosineblast">@cosineblast</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2207">#2207</a>: New <code>:condition-always-true</code> linter, see <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2235">#2235</a>: New <code>:multiple-async-in-deftest</code> linter: warn on multiple async blocks in <code>cljs.test/deftest</code>, since only the first will run.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2013">#2013</a>: Fix NPE and similar errors when linting an import with an illegal token (<a href="https://github.com/cosineblast">@cosineblast</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2215">#2215</a>: Passthrough hook should not affect linting</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2232">#2232</a>: Bump analysis for clojure 1.12 (partitionv, etc)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2223">#2223</a>: Do not consider classes created with <code>deftype</code> a var that is referred with <code>:refer :all</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2236">#2236</a>: <code>:line-length</code> warnings cannot be <code>:clj-kondo/ignore</code>d</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2224">#2224</a>: Give <code>#&apos;foo/foo</code> and <code>(var foo/foo)</code> the same treatment with respect to private calls</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2239">#2239</a>: Fix printing of unresolved var when going through <code>:macroexpand</code> hook</li></ul></li><li><p><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka v0.3.3 - v0.3.6 released</p><ul><li>Fix caching in watch mode</li><li><a href="https://github.com/borkdude/quickblog/issues/86">#86</a>: group archive page by year</li><li><a href="https://github.com/borkdude/quickblog/issues/85">#85</a>: don&apos;t render discuss links when <code>:discuss-link</code> isn&apos;t set</li><li><a href="https://github.com/borkdude/quickblog/issues/84">#84</a>: sort tags by post count</li><li><a href="https://github.com/borkdude/quickblog/issues/80">#80</a>: Generate an <code>about.html</code> when a template exists (<a href="https://github.com/elken">@elken</a>)</li><li><a href="https://github.com/borkdude/quickblog/issues/78">#78</a>: Allow configurable :page-suffix to omit <code>.html</code> from page links (<a href="https://github.com/anderseknert">@anderseknert</a>)</li><li><a href="https://github.com/borkdude/quickblog/pull/76">#76</a>: Remove livejs script tag on render. (<a href="https://github.com/jmglov">@jmglov</a>)</li><li><a href="https://github.com/borkdude/quickblog/pull/75">#75</a>: Omit preview posts from index. (<a href="https://github.com/jmglov">@jmglov</a>)</li><li>Support capitalization of tags</li><li><a href="https://github.com/borkdude/quickblog/issues/66">#66</a>: Unambigous ordering of posts, sorting by date (descending), post title, and then file name.  (<a href="https://github.com/UnwarySage">@UnwarySage</a>)</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler <br>Lots of stuff happened in December with squint! Too many to mention here, just check the <a href="https://github.com/squint-cljs/squint/blob/main/CHANGELOG.md">CHANGELOG.md</a></p></li><li><p><a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a>: Clojure/Script mode for CodeMirror 6.</p><ul><li>Improved the eval-region extension: when you evaluate <code>#_(+ 1 2 3)|</code> the expression <code>(+ 1 2 3)</code> is evaluated Test it in the <a href="https://squint-cljs.github.io/squint/?repl=true&amp;src=I18oKyAxIDIgMyk%3D">squint playground</a>.</li></ul></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure Released 0.5.20:</p><ul><li><a href="https://github.com/babashka/fs/issues/119">#119</a>: <code>fs/delete-tree</code>: add <code>:force</code> flag to delete read-only directories/files. Set the flag to true in  <code>fs/with-temp-dir</code> (<a href="https://github.com/jlesquembre">@jlesquembre</a>)</li><li><a href="https://github.com/babashka/fs/issues/102">#102</a>: add <code>gzip</code> and <code>gunzip</code> functions</li><li><a href="https://github.com/babashka/fs/issues/113">#113</a>: <code>fs/glob</code>: enable <code>:hidden</code> (when not already set) when <code>pattern</code> starts with dot (<a href="https://github.com/eval">@eval</a>).</li><li><a href="https://github.com/babashka/fs/issues/117">#117</a>: fix <code>fs/match</code> and <code>fs/glob</code> not finding files in root-folder (<a href="https://github.com/eval">@eval</a>).</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Released version 0.1.16 which catches up with the latest compiler improvements in squint and also adds the <code>clojure.set</code> namespace</li></ul></li><li><p><a href="https://github.com/babashka/http-server">http-server</a>: serve static assets</p><ul><li>Released 0.1.12 with several new features</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.</p><ul><li>Working towards a new release, planned for next month.</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</p></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p></li><li><p><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</p></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p></li><li><p><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</p></li><li><p><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</p></li><li><p><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</p></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</p></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p></li><li><p><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</p></li><li><p><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</p></li><li><p><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</p></li><li><p><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</p></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p></li><li><p><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</p></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p></li><li><p><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</p></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p></li><li><p><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</p></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p></li><li><p><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</p></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></p></li><li><p><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</p></li><li><p><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</p></li><li><p><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</p></li><li><p><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</p></li><li><p><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</p></li><li><p><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</p></li><li><p><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</p></li><li><p><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</p></li><li><p><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</p></li><li><p><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</p></li><li><p><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</p></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-nov-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-nov-2023.html"/>
    <title>OSS updates November 2023</title>
    <updated>2023-12-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during November 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Without you, the below projects would not be as mature or wouldn&apos;t exist or be maintained at all.</p><p>Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://github.com/pitch-io">Pitch</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="advent-of-code">Advent of Code</h2><p>It is Advent of Code time of year again. You can solve puzzles in an online <a href="https://github.com/squint-cljs/squint">squint</a> or <a href="https://github.com/squint-cljs/cherry">cherry</a> playground <a href="https://squint-cljs.github.io/squint/?src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMiAxKSkKICAgICAgICAgICAgICNfc3B5CiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMKICAgICAgICAgICAgIChtYXB2IHBhcnNlLWxvbmcpKSkKCihkZWZuIHBhcnQtMQogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChhcHBseSBtYXgpKSkKCihkZWZuIHBhcnQtMgogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChzb3J0LWJ5IC0pCiAgICAodGFrZSAzKQogICAgKGFwcGx5ICspKSkKCih0aW1lIChwYXJ0LTEpKQojXyh0aW1lIChwYXJ0LTIpKQ%3D%3D&amp;boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&amp;repl=true">here</a>.</p><p>Change the <code>/squint/</code> part of the url to <code>/cherry/</code> to switch ClojureScript dialect versions.</p><p>You can read more about the playground <a href="https://blog.michielborkent.nl/squint-advent-of-code.html">here</a>.</p><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><p><a href="https://blog.michielborkent.nl/archive.html">blog</a> I&apos;ve written two blog posts this month:</p><ul><li><a href="https://blog.michielborkent.nl/squint-cloudflare-bun.html">Writing a Cloudflare worker with squint and bun</a></li><li><a href="https://blog.michielborkent.nl/squint-advent-of-code.html">Playing Advent of Code with Squint</a>.</li></ul></li><li><p><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler <br>Lots of stuff happened in November with squint! You could say that I&apos;ve grown a little addicted to improving this project currently, driven by how users use it and also while developing the <a href="https://squint-cljs.github.io/squint/?src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMiAxKSkKICAgICAgICAgICAgICNfc3B5CiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMKICAgICAgICAgICAgIChtYXB2IHBhcnNlLWxvbmcpKSkKCihkZWZuIHBhcnQtMQogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChhcHBseSBtYXgpKSkKCihkZWZuIHBhcnQtMgogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChzb3J0LWJ5IC0pCiAgICAodGFrZSAzKQogICAgKGFwcGx5ICspKSkKCih0aW1lIChwYXJ0LTEpKQojXyh0aW1lIChwYXJ0LTIpKQ%3D%3D&amp;boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&amp;repl=true">playground</a>, a lot of potential improvements emerged..</p><details>
- Restore backward compatibility with code that is compiled with older versions of squint
- Optimize various outputs for smaller size
- Add `js-in`
- Support `into` + `xform`
- Support `sort` on strings
- [#386](https://github.com/squint-cljs/squint/issues/386): allow expression in value position in map literal
- Improvements with respect to laziness in `mapcat` and `concat`
- Do not array mutate argument in `reverse`
- Escape JSX attribute vector value (and more)
- `map` + `transduce` support
- Fix `for` in REPL mode
 - Throw when object is not iterable in `for`
- Make next lazy when input is lazy
- Fix playground shim (fixes issue in older versions of Safari)
- Add `js-mod` and `quot`
- [#380](https://github.com/squint-cljs/squint/issues/380): Don't emit space in between `#jsx` tags
- Add `re-find`
- Add `condp` macro
- Use `compare` as default compare function in `sort` (which fixes numerical sorting)
- Allow `assoc!` to be called on arbitrary classes (regression)
- Improve `get` to call `get` method when present.
- Allow keywords and collections to be used as functions in HOFs
- Make filter, etc aware of truthiness
- Reduce code size for truthiness checks
- Add `str/split-lines`
- Add `partition-by`
- Add `parse-long`
- Add `sort-by`
- Fix top level await
- Support multiple dimensions in `aset`
- Add `coercive-=` as alias for `==`
- Add `js-delete`
- Fix `min-key` and `max-key` and improve tests
- Add `min-key` and `max-key`
- Fix `defonce` in REPL-mode
- Fix `doseq` and `for` when binding name clashes with core var
- Several REPL improvements
- Improve [https://squint-cljs.github.io/squint/](https://squint-cljs.github.io/squint/)
- Allow alias name to be used as object in REPL mode
- Copy resources when using `squint compile` or `squint watch`
- Return map when `select-keys` is called with `nil`
- nREPL server: print values through `cljs.pprint` ([@PEZ](https://github.com/PEZ))
- Initial (incomplete!) nREPL server on Node.js: `npx squint nrepl-server :port 1888`
- Update/refactor [threejs](https://github.com/squint-cljs/squint/tree/main/examples/threejs) example
- [#360](https://github.com/squint-cljs/squint/issues/360): `assoc-in!` should not mutate objects in the middle if they already exist
- Evaluate `lazy-seq` body just once
- Avoid stackoverflow with `min` and `max`
- [#360](https://github.com/squint-cljs/squint/issues/360): fix assoc-in! with immutable objects in the middle
- Add `mod`, `object?`
- Optimize `get`
- Add [threejs](https://github.com/squint-cljs/squint/tree/main/examples/threejs) example
- [#357](https://github.com/squint-cljs/squint/issues/357): fix version in help text
- Fix iterating over objects
- Add `clojure.string`'s `triml`, `trimr`, `replace`
- Fix `examples/vite-react` by adding `public/index.html`
- Add `find`, `bounded-count`, `boolean?`, `merge-with`, `meta`, `with-meta`, `int?`, `ex-message`, `ex-cause`, `ex-info`
- Fix munging of reserved symbols in function arguments</li><li><p><a href="https://jsfiddle.net/xbgj6v1q/1/">scittle-hoplon</a>: a custom scittle distribution with Hoplon. I helped developing the SCI configuration for Hoplon.</p></li><li><p><a href="https://github.com/squint-cljs/squint/tree/main/examples/threejs">gespensterfelder</a>: a demo that Jack Rusher wrote using Three.js ported to squint.</p></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects Version 0.2.63 released which adds mvn search and some bugfixes</p></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p><ul><li>Small bugfix around priority of <code>:exec-args</code> and <code>default</code></li></ul></li><li><p><a href="https://github.com/borkdude/aoc-proxy">aoc-proxy</a>: a Cloudflare worker that can be used to fetch Advent of Code puzzle input from the browser (see <a href="https://squint-cljs.github.io/squint/?src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMiAxKSkKICAgICAgICAgICAgICNfc3B5CiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMKICAgICAgICAgICAgIChtYXB2IHBhcnNlLWxvbmcpKSkKCihkZWZuIHBhcnQtMQogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChhcHBseSBtYXgpKSkKCihkZWZuIHBhcnQtMgogIFtdCiAgKC0%2BPiBpbnB1dAogICAgKHBhcnRpdGlvbi1ieSBuaWw%2FKQogICAgKHRha2UtbnRoIDIpCiAgICAobWFwICMoYXBwbHkgKyAlKSkKICAgIChzb3J0LWJ5IC0pCiAgICAodGFrZSAzKQogICAgKGFwcGx5ICspKSkKCih0aW1lIChwYXJ0LTEpKQojXyh0aW1lIChwYXJ0LTIpKQ%3D%3D&amp;boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&amp;repl=true">Advent of Code playground</a>)</p></li><li><p><a href="https://github.com/squint-cljs/squint-macros">squint-macros</a>: a couple of macros that stand-in for <a href="https://github.com/applied-science/js-interop">applied-science/js-interop</a> and <a href="https://github.com/funcool/promesa">promesa</a> to make CLJS projects compatible with squint and/or cherry.</p></li><li><p><a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a>: Clojure/Script mode for CodeMirror 6.</p><ul><li>Ported the eval-region extension to squint so you can use it straight from JS. This is used in the <a href="https://squint-cljs.github.io/squint/?repl=true">squint playground</a> when you press Cmd-Enter after an expression.</li></ul></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p><ul><li>A helper macro was improved such that you can define macros that are usable in SCI</li><li>The re-frame configuration now has support for <code>re-frame.alpha</code>. See <a href="https://babashka.org/sci.configs/">playground</a>.</li></ul></li><li><p><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting. A new release: 1.3.186!</p><details>
- [Support self-contained binaries as uberjars!](https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar)
- Add `java.security.KeyFactory`, `java.security.spec.PKCS8EncodedKeySpec`, `java.net.URISyntaxException`, `javax.crypto.spec.IvParameterSpec`
- Fix babashka.process/exec wrt `babashka.process/*defaults*`
- [#1632](https://github.com/babashka/babashka/issues/1632): Partial fix for `(.readPassword (System/console))`
- Enable producing self-contained binaries using [uberjars](https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar)
- Bump httpkit to `2.8.0-beta3` (fixes GraalVM issue with virtual threads)
- Bump `deps.clj` and `fs`
- Expose `taoensso.timbre.appenders.core`
- nREPL: implement `ns-list` op
- SCI: optimize `swap!`, `deref` and `reset!` for normal atoms (rather than user-created `IAtom`s)
- Add test for [#1639](https://github.com/babashka/babashka/issues/1639)
- Upgrade to GraalVM 21.0.1
<br>Still unreleased:
- Add `java.util.ScheduledFuture`
- Support `Runnable` to be used without import
- Allow `catch` to be used as var name</li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs <br>Released version 0.8.41<details></p><ul><li>Bump edamame to 1.3.23</li><li><a href="https://github.com/babashka/sci/issues/889">#889</a>: allow <code>(def foo/foo 1)</code> when inside namespace <code>foo</code></li><li><a href="https://github.com/babashka/sci/issues/891">#891</a>: reset file metadata on var when it&apos;s re-evaluated from other file</li><li><a href="https://github.com/babashka/sci/issues/893">#893</a>: expose <code>sci.async/eval-form</code> and <code>sci.async/eval-form+</code></li><li>Improve <code>sci.async/eval-string</code>, respect top-level <code>do</code> forms</li><li>Add experimental new <code>:static-methods</code> option to override how static methods get evaluated.</li><li>Expose <code>destructure</code></li><li>Macroexpand <code>(.foo bar)</code> form</li><li>Optimize <code>deref</code>, <code>swap!</code>, <code>reset!</code> for host values</li><li>Add <code>time</code> macro to core namespace</li><li><a href="https://github.com/babashka/sci/issues/896">#896</a>: allow <code>catch</code> to be used as var name</li></ul></li><li><p><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</p><ul><li>Released version 0.1.10 which catches up with the latest compiler improvements in squint</li></ul></li><li><p><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.</p><ul><li>New <code>:condition-always-true</code> and <code>:underscore-in-namespace</code> linters + couple of bugfixes. Release expected in December.</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><p><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</p></li><li><p><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</p></li><li><p><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.</p></li><li><p><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client</p></li><li><p><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</p></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p></li><li><p><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</p></li><li><p><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs</p></li><li><p><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</p></li><li><p><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</p></li><li><p><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</p></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p></li><li><p><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</p></li><li><p><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</p></li><li><p><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</p></li><li><p><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</p></li><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p></li><li><p><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</p></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p></li><li><p><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</p></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></p></li><li><p><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</p></li><li><p><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</p></li><li><p><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</p></li><li><p><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</p></li><li><p><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</p></li><li><p><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</p></li><li><p><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</p></li><li><p><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</p></li><li><p><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</p></li><li><p><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</p></li><li><p><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</p></li><li><p><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</p></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/squint-advent-of-code.html</id>
    <link href="https://blog.michielborkent.nl/squint-advent-of-code.html"/>
    <title>Playing Advent of Code with Squint</title>
    <updated>2023-11-24T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In the <a href="https://blog.michielborkent.nl/squint-cloudflare-bun.html">previous
post</a> I described how I built a Cloudflare worker with <a href="https://github.com/squint-cljs/squint">squint</a>.  This worker is part of my attempt to build a playground for squint in which you can play <a href="https://adventofcode.com/">Advent of
Code</a>. Advent of Code is a series of programming puzzles published each day through December 1-25. By exercising puzzles solutions on squint, I&apos;m able to detect missing or incompatible features compared to ClojureScript.</p><h2 id="playground">Playground</h2><p>The Advent of Code playground can be loaded <a href="https://squint-cljs.github.io/squint/examples/aoc/index.html">here</a>.</p><p>This link redirects you to the most recent version and I&apos;ll be updating the redirected-to link if necessary.</p><h2 id="puzzle-input">Puzzle input</h2><p>To play Advent of Code, you need to download your puzzle input:</p><pre><code class="language-clojure">(def input (str/trim (js-await (fetch-input 2017 1))))
</code></pre><p>The <code>fetch-input</code> function is pre-defined in this <a href="https://gist.github.com/borkdude/cf94b492d948f7f418aa81ba54f428ff">boilerplate</a> gist and is loaded via the <code>boilerplate</code> query parameter.  Advent of Code input is personalized and based on your Advent of Code account. This is why you are asked to fill in your Advent of Code token in the top of the UI. You can obtain this token by visiting <a href="https://adventofcode.com/">Advent of Code</a>, registering + logging in and then find the <code>session</code> cookie in the developer console. Copy paste this value into the UI and hit <code>Save!</code>. After doing so, the session token is saved in local storage for next puzzles you might want to solve. The session token is only saved in your browser. The Cloudflare worker doesn&apos;t store anything and only serves as a proxy.</p><h2 id="repl-mode">REPL-mode</h2><p>The playground has two ways of compiling Squint Clojurescript to JS: the normal ES6 mode and REPL-mode. In REPL-mode you&apos;re able to incrementally evaluate squint snippets. This works by compiling vars in keys of global objects, much like CLJS does it. E.g.:</p><pre><code class="language-clojure">(defn foo [])
</code></pre><p>is compiled to</p><pre><code class="language-clojure">var squint_core = await import(&apos;squint-cljs/core.js&apos;);
globalThis.user = globalThis.user || {};
globalThis.user.foo = (function () {
return null;
});
var foo = globalThis.user.foo;
</code></pre><p>in REPL-mode. This output certainly isn&apos;t optimal for JS bundlers like <code>esbuild</code> so it&apos;s only intended for development.</p><p>By hitting &quot;Compile&quot; the whole editor is compiled + evaluated. The compiled JavaScript is visible in the right output pane.  When in REPL-mode, hitting Cmd-Enter (or Windows-Enter) with the cursor after a form will compile only that expression.  Use the <code>comment</code> form to evaluate sub-expressions while working towards a complete solution.</p><p>While working on your puzzle, the state of the editor is saved to local storage, so if you accidentally close the browser, the input re-appear next time you visit the playground.</p><p>Let me know if you&apos;re enjoying this and feel free to post issues in the <code>#squint</code> channel on Clojurians Slack!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/squint-cloudflare-bun.html</id>
    <link href="https://blog.michielborkent.nl/squint-cloudflare-bun.html"/>
    <title>Writing a Cloudflare worker with squint and bun</title>
    <updated>2023-11-19T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll describe how to write a Cloudflare worker with squint and bun.</p><h2 id="introduction">Introduction</h2><p>As I tried to build an <a href="https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fe613dbceac5b04c2b71b032a75f13881bccd72c5%2Faoc_ui.cljs&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmIGlucHV0ICgtPj4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIyIDEpKQogICAgICAgICAgICAgI19zcHkKICAgICAgICAgICAgIHN0ci9zcGxpdC1saW5lcwogICAgICAgICAgICAgKG1hcHYgcGFyc2UtbG9uZykpKQoKKGRlZm4gcGFydC0xCiAgW10KICAoLT4%2BIGlucHV0CiAgICAocGFydGl0aW9uLWJ5IG5pbD8pCiAgICAodGFrZS1udGggMikKICAgIChtYXAgIyhhcHBseSArICUpKQogICAgKGFwcGx5IG1heCkKICAgIGFwcGVuZCkpCgooZGVmbiBwYXJ0LTIKICBbXQogICgtPj4gaW5wdXQKICAgIChwYXJ0aXRpb24tYnkgbmlsPykKICAgICh0YWtlLW50aCAyKQogICAgKG1hcCAjKGFwcGx5ICsgJSkpCiAgICAoc29ydC1ieSAtKQogICAgKHRha2UgMykKICAgIChhcHBseSArKQogICAgYXBwZW5kKSkKCih0aW1lIChwYXJ0LTEpKQoodGltZSAocGFydC0yKSk%3D">Advent of Code
playground</a> for squint, I wanted to support downloading puzzle input from <a href="https://adventofcode.com">adventofcode.com</a>. Doing this directly from the playground resulted in CORS issues. Mario Trost in the #adventofcode channel on Clojurians Slack suggested that this could be solved using a Cloudflare worker and indeed it could. Thanks Mario!</p><p>A <a href="https://workers.cloudflare.com/">Cloudflare worker</a> is tiny &quot;serverless&quot; application that scales automatically. The first 100k requests a day are free. A worker can be written in JavaScript, among other languages. Workers written in JavaScript can use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch
  API</a> which comprises of <code>fetch</code>, <code>Request</code>, <code>Response</code> and more standardized stuff, available as global objects in browsers, Node.js, deno, bun and other browser-inspired JavaScript runtimes. These APIs are basically all you need to build a worker.</p><p><a href="https://github.com/squint-cljs/squint">Squint</a> is a ClojureScript dialect designed for easier JS interop and smaller bundle output. As such, it seems like a good fit for Cloudflare workers. The smaller the code, the better the (cold) startup time.</p><p><a href="https://bun.sh/">Bun</a> is a fast all-in-one JavaScript runtime / bundler / toolkit. Bun seems a good tool to use for developing Cloudflare workers since with little boilerplate you can get something running quickly. Bun supports hot reloading of worker code too.</p><h2 id="hello-world">Hello world</h2><p>To produce a &quot;hello world&quot; worker only the following is necessary:</p><p><code>squint.edn</code>:</p><pre><code class="language-clojure">{:paths [&quot;src&quot;]
 :extension &quot;js&quot;
 :output-dir &quot;out&quot;}
</code></pre><p>The Squint CLJS files are going into <code>src</code> and compiled <code>.js</code> files will be written to <code>out</code>.</p><p>The only source file:</p><p><code>src/index.cljs</code>:</p><pre><code class="language-clojure">(ns index)

(defn ^:async handler [{:keys [method] :as req} _env _ctx]
  (js/Response. &quot;hello world&quot;))

(def default
  {:fetch handler})
</code></pre><p>Beware that your handler isn&apos;t going to be called <code>fetch</code> since this will conflict with <code>js/fetch</code>, something that tripped me up. So I just called it <code>handler</code>.  Calling a var <code>default</code> in squint will make it the default export, which is something Cloudflare workers use.</p><p>Now run <code>bun install squint-cljs</code> and then <code>bun squint watch</code>.  In parallel, run <code>bun --hot out/index.js</code>. This will spin up a server. You can make change to the code and new requests will see the changes. This is very convenient for local development and testing.</p><p>To bundle everything to a single file, run:</p><pre><code class="language-shell">bun build --minify --outdir=dist/out/index.js
</code></pre><p>Then you can run <code>bun dist/index.js</code> to prove to yourself that the standalone JS works.</p><p>The standalone JavaScript file is somewhere around 2 kilobytes. Seriously: 2kb, that&apos;s it :)!</p><p>To deploy to Cloudflare, I&apos;m using <a href="https://developers.cloudflare.com/workers/wrangler/">wrangler</a>.  It needs a small config file, called <code>wrangler.toml</code> which describes the name of the application and the location of the main JS file:</p><pre><code class="language-clojure">name = &quot;hello-world&quot;
main = &quot;dist/index.js&quot;
compatibility_date = &quot;2023-09-04&quot;
</code></pre><p>After writing the config file, you can run <code>bun wrangler deploy</code>. You will be asked to log in to the Cloudflare dashboard, etc. Eventually your application will be running at <code>https://hellow-world.&lt;your-user&gt;.workers.dev</code>.</p><h2 id="proxy">Proxy</h2><p>The final worker code can be seen below. The handler looks at an incoming request, and decides whether it&apos;s a <code>GET</code> or <code>OPTION</code> request. In the handling of the <code>GET</code> request, the URL params <code>day</code>, <code>year</code> and <code>aoc-token</code> are pulled out. While developing I noticed that the <code>URLSearchParams</code> object implements a <code>Map</code>-like ad-hoc interface, but squint&apos;s <code>get</code> function wasn&apos;t aware of this, so initially I couldn&apos;t use destructuring like this:</p><pre><code class="language-clojure">(let [{:keys [foo]} (-&gt; (js/URL. &quot;https://foo.com?foo=1&quot;) :searchParams)] foo)
</code></pre><p>to get <code>foo</code> out of this object. Similarly for the <code>Headers</code> object from <code>Response</code>. Both have a <code>get</code> method. I decided to make the squint <code>get</code> function work with any JS datastructure that has a <code>get</code> method. I&apos;m not entirely sure if that is a good idea though since arbitrary methods called <code>get</code> may perform side effects... Let me know in the comments!  But after doing so, destructuring worked on the search params.</p><p>Then a request is made to <code>https://adventofcode.com</code> to retrieve the input. When doing this from a non-browser, you don&apos;t get into any CORS issues. Note that we can nicely use <code>js-await</code> for waiting for promise results. The text that <code>adventofcode.com</code> returned is passed back along with <code>&quot;Access-Control-Allow-Origin&quot; &quot;*</code> headers to satisfy all the CORS ... stuff.</p><p>I also noticed the browser playground was doing an <code>OPTION</code> request so I also need to handle those, returning the most permissive headers to satisfy the CORS gods.</p><p><code>src/index.cljs</code></p><pre><code class="language-clojure">(ns index)

(defn ^:async handler [{:keys [method] :as req} _env _ctx]
  (if (= :GET method)
    (let [params (-&gt; req :url (js/URL.) :searchParams)
          {:keys [aoc-token day year]} params]
      (if (and aoc-token day year)
        (let [resp (js-await (js/fetch (str &quot;https://adventofcode.com/&quot; year &quot;/day/&quot; day &quot;/input&quot;)
                                       {:headers {:cookie (str &quot;session=&quot; aoc-token)}}))
              body (js-await (.text resp))
              resp (js/Response. body {:headers {&quot;Access-Control-Allow-Origin&quot; &quot;*&quot;}})]
          resp)
        (js/Response. &quot;Set &apos;aoc-token, &apos;day&apos; and &apos;year&apos; as a URL query parameter&quot; {:status 400
                                                                                   :headers {&quot;Access-Control-Allow-Origin&quot; &quot;*&quot;}})))
    ;; response for :OPTION
    (js/Response. nil {:status 200
                       :headers {&quot;Access-Control-Allow-Origin&quot; &quot;*&quot;
                                 &quot;Access-Control-Allow-Methods&quot; &quot;GET,HEAD,POST,OPTIONS&quot;
                                 &quot;Access-Control-Allow-Headers&quot; &quot;*&quot;}})))

(def default
  {:fetch handler})
</code></pre><p>The final production JS is still around 2-3kb.  After another <code>bun wrangler deploy</code> this browser playground for Advent of Code started working:</p><p><a href="https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fe613dbceac5b04c2b71b032a75f13881bccd72c5%2Faoc_ui.cljs&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmIGlucHV0ICgtPj4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIyIDEpKQogICAgICAgICAgICAgI19zcHkKICAgICAgICAgICAgIHN0ci9zcGxpdC1saW5lcwogICAgICAgICAgICAgKG1hcHYgcGFyc2UtbG9uZykpKQoKKGRlZm4gcGFydC0xCiAgW10KICAoLT4%2BIGlucHV0CiAgICAocGFydGl0aW9uLWJ5IG5pbD8pCiAgICAodGFrZS1udGggMikKICAgIChtYXAgIyhhcHBseSArICUpKQogICAgKGFwcGx5IG1heCkKICAgIGFwcGVuZCkpCgooZGVmbiBwYXJ0LTIKICBbXQogICgtPj4gaW5wdXQKICAgIChwYXJ0aXRpb24tYnkgbmlsPykKICAgICh0YWtlLW50aCAyKQogICAgKG1hcCAjKGFwcGx5ICsgJSkpCiAgICAoc29ydC1ieSAtKQogICAgKHRha2UgMykKICAgIChhcHBseSArKQogICAgYXBwZW5kKSkKCih0aW1lIChwYXJ0LTEpKQoodGltZSAocGFydC0yKSk%3D">Advent of Code
playground</a></p><p>You need to insert your Advent of Code session token in the input box, run <code>Compile</code> and after that it&apos;s stored in local storage, for other puzzles you might want to solve this year!  Give it a spin and let me know what you think.</p><p>The source code for the worker is available <a href="https://github.com/borkdude/aoc-proxy">here</a>.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-oct-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-oct-2023.html"/>
    <title>OSS updates October 2023</title>
    <updated>2023-11-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during October 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://github.com/pitch-io">Pitch</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.<ul><li><a href="https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar">Support self-contained binaries as uberjars!</a></li><li>Add <code>java.security.KeyFactory</code>, <code>java.security.spec.PKCS8EncodedKeySpec</code>, <code>java.net.URISyntaxException</code></li><li>Fix babashka.process/exec wrt <code>babashka.process/*defaults*</code></li><li><a href="https://github.com/babashka/babashka/issues/1632">#1632</a>: Partial fix for <code>(.readPassword (System/console))</code></li><li>Enable producing self-contained binaries using <a href="https://github.com/babashka/babashka/wiki/Self-contained-executable#uberjar">uberjars</a></li><li>Bump httpkit to <code>2.8.0-beta3</code> (fixes GraalVM issue with virtual threads)</li><li>Bump <code>deps.clj</code> and <code>fs</code></li><li>Expose <code>taoensso.timbre.appenders.core</code></li><li>nREPL: implement <code>ns-list</code> op</li><li>SCI: optimize <code>swap!</code>, <code>deref</code> and <code>reset!</code> for normal atoms (rather than user-created <code>IAtom</code>s)</li></ul></li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>A configuration for <a href="https://github.com/hoplon/hoplon">hoplon</a> and <a href="https://github.com/hoplon/javelin">javelin</a> was added. You can play around with hoplon in a SCI-enabled environment <a href="https://babashka.org/sci.configs/?gist=e83da19df3d2739861334171779f79d5">here</a></li></ul></li><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2207">#2207</a>: New <code>:condition-always-true</code> linter, see <a href="https://github.com/clj-kondo/clj-kondo/tree/master/doc/linters.md">docs</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2013">#2013</a>: Fix NPE and similar errors when linting an import with an illegal token <br>Published a new version (2023.10.20) with these changes:</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1804">#1804</a>: new linter <code>:self-requiring-namespace</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2065">#2065</a>: new linter <code>:equals-false</code>, counterpart of <code>:equals-true</code> (<a href="https://github.com/svdo">@svdo</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2199">#2199</a>: add <code>:syntax</code> check for var names starting or ending with dot (reserved by Clojure)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2179">#2179</a>: consider alias-as-object usage in CLJS for :unused-alias linter</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2183">#2183</a>: respect <code>:level</code> in <code>:discouraged-var</code> config</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2184">#2184</a>: Add missing documentation for <code>:single-logical-operand</code> linter (<a href="https://github.com/wtfleming">@wtfleming</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2187">#2187</a>: Fix type annotation of argument of <code>clojure.core/parse-uuid</code> from <code>nilable/string</code> to string (<a href="https://github.com/dbunin">@dbunin</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2192">#2192</a>: Support <code>:end-row</code> and <code>:end-col</code> in <code>:pattern</code> output format (<a href="https://github.com/joshgelbard">@joshgelbard</a>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2182">#2182</a>: Namespace local configuration does not silence <code>:missing-else-branch</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2186">#2186</a>: Improve warning when <code>--copy-configs</code> is enabled but no config dir exists</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2190">#2190</a>: false positive with <code>:unused-alias</code> and namespaced map</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2200">#2200</a>: include optional <code>:callstack</code> in analysis</li></ul></li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler <br>Lots of stuff happened in October with squint!<ul><li><a href="https://github.com/squint-cljs/squint/issues/350">#350</a>: <code>js*</code> should default to <code>:context :expr</code></li><li><a href="https://github.com/squint-cljs/squint/issues/352">#352</a>: fix <code>zero?</code> in return position</li><li>Add <code>NaN?</code> (<a href="https://github.com/sher">@sher</a>)</li><li><a href="https://github.com/squint-cljs/squint/issues/347">#347</a>: Add <code>:pre</code> and <code>:post</code> support in <code>fn</code></li><li>Add <code>number?</code></li><li>Support <code>docstring</code> in <code>def</code></li><li>Handle multipe source <code>:paths</code> in a more robust fashion</li><li><a href="https://github.com/squint-cljs/squint/issues/344">#344</a>: macros can&apos;t be used via aliases</li><li>Add <code>squint.edn</code> support, see <a href="https://github.com/squint-cljs/squint/tree/main/README.md#squintedn">docs</a></li><li>Add <code>watch</code> subcommand to watch <code>:paths</code> from <code>squint.edn</code></li><li>Make generated <code>let</code> variable names in JS more deterministic, which helps hot reloading in React</li><li>Added a <a href="https://github.com/squint-cljs/squint/blob/main/examples/vite-react">vite + react example project</a>.</li><li>Resolve symbolic namespaces <code>(:require [foo.bar])</code> from <code>:paths</code></li><li>Add <code>bit-and</code> and <code>bit-or</code></li><li>Include <code>lib/squint.core.umd.js</code> which defines a global <code>squint.core</code> object (easy to use in browsers, see <a href="https://github.com/squint-cljs/squint/blob/main/README.md#compile-on-a-server-use-in-a-browser">docs</a>)</li><li>Add <code>subs</code>, <code>fn?</code>, <code>re-seq</code></li><li>Add <code>squint.edn</code> with <code>:paths</code> to resolve macros from (via <code>:require-macros</code>)</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects Version 0.2.62 released<ul><li>Fix NPE during <code>neil dep upgrade</code></li></ul></li><li><a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a><ul><li>Porting this CLJS project such that it can run with <a href="https://github.com/squint-cljs/squint">squint</a> also. You can now use this library directly from NPM as a JS library. See <a href="https://squint-cljs.github.io/squint/">this page</a> for a demo on how to use it directly from a CDN! This work is funded by <a href="https://nextjournal.com/">Nextjournal</a>.</li></ul></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler<ul><li>Released version 0.1.9</li></ul></li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes<ul><li>Fix self-requiring namespace (which clj-kondo now also catches via optional linter!)</li></ul></li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo<ul><li>Bumped clj-kondo version</li></ul></li><li><a href="https://github.com/http-kit/http-kit">http-kit</a>: Simple, high-performance event-driven HTTP client+server for Clojure.<ul><li><a href="https://github.com/http-kit/http-kit/issues/543">#543</a> Migrate away from <code>SimpleDateFormat</code> to <code>java.time</code>, fixes native-image issue and virtual threads</li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<ul><li>A number of small bugfixes and additions</li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Expose <code>destructure</code> to scripts</li><li>Macroexpand <code>(.foo bar)</code> form in <code>macroexpand-1</code></li><li>Optimize <code>deref</code>, <code>swap!</code>, <code>reset!</code> for host values</li><li>Add <code>time</code> macro</li></ul></li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI<ul><li><code>sci.core</code> itself was exposed to nbb users</li></ul></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure<ul><li>Minor fixes in <code>glob</code> by <a href="https://github.com/eval">@eval</a>, thanks!</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Get home directory via environment variable rather than system property by <a href="https://github.com/DerGuteMoritz">@DerGuteMoritz</a>, thanks!</li></ul></li><li><a href="https://github.com/babashka/babashka.nrepl">babashka.nrepl</a>: The nREPL server from babashka as a library, so it can be used from other SCI-based CLIs<ul><li>Fix <code>classpath</code> op</li><li>Implement <code>ns-list</code> op</li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/porting-cljs-project-to-squint.html</id>
    <link href="https://blog.michielborkent.nl/porting-cljs-project-to-squint.html"/>
    <title>Porting a ClojureScript project to Squint</title>
    <updated>2023-11-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="squint">Squint</h2><p><a href="https://github.com/squint-cljs/squint">Squint</a> is a ClojureScript syntax to JS compiler. I deliberately don&apos;t call it a CLJS compiler, since it has some differences with CLJS: all data structures in squint are just JS objects, arrays and iterators/generators. The standard library mimics ClojureScript in that it never mutates if CLJS doesn&apos;t mutate, e.g. <code>assoc</code> returns a new object and doesn&apos;t mutate the object argument.  This approach has a few benefits and of course a few drawbacks. Some of the benefits are that JS interop becomes considerably easier, the bundle size becomes way smaller, in some cases performance is better (but as always, this is very contextual) and sharing a library to NPM to be consumed by other JavaScript projects becomes easier as well. A few drawbacks of this approach are that we lose structural sharing of CLJS data structures (the squint lib mostly uses copy-on-write like how CLJS once started) and you lose the fast equality checks you can get from structural sharing.  Note that there is also squint&apos;s sister project, <a href="https://github.com/squint-cljs/cherry">cherry</a> which does use CLJS&apos;s immutable data structures, but you get a minimum of 350kb project size due to CLJS&apos;s standard library being bundled with it and not being optimizable by ES6 bundlers. Perhaps the extra bundle size offsets the drawbacks of squint&apos;s direct JS interop approach for you. But let&apos;s just see how far we can get with just squint in porting a ClojureScript project!</p><h2 id="clojure-mode">Clojure-mode</h2><p>As a case study in this blog, we&apos;re going to look at <a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a>, a project by Nextjournal which offers a Clojure mode for <a href="https://codemirror.net/">CodeMirror</a> 6. A request was made some time ago to make this library usable directly from JavaScript as an NPM library. Since most of the code in this project is JS interop (using the excellent <a href="https://github.com/applied-science/js-interop">js-interop</a> library) it seemed like a good candidate for a squint port. In Martin Kavalar of Nextjournal&apos;s own words:</p><blockquote><p>I feel that codemirror and prosemirror extensions are especially well suited for squint as they are interop heavy and the libraries takes care of state using their own re-frame/redux like architecture</p></blockquote><p>Martin asked me if I could do this in a way such that the library would still be usable from ClojureScript as well. One of the ways to accomplish this is to use <code>.cljc</code> files.</p><h2 id="reader-conditionals">Reader conditionals</h2><p>When porting the project, I added features and fixed bugs in squint to accommodate targeting both CLJS and squint. So almost every <code>.cljs</code> file was renamed to a <code>.cljc</code> file and CLJS-specific code like <code>goog-define</code> was re-implemented using a squint override:</p><pre><code class="language-clojure">#?(:squint (def node-js? (some? js/globalThis.process))
   :cljs (goog-define node-js? false))
</code></pre><p>The above expression checks whether we are inside NodeJS, which arguably could have been done without <code>goog-define</code> but my goal was to leave the original code as is.</p><h2 id="watcher">Watcher</h2><p>To ease developing, I added a watcher to the squint compiler, which reads the <code>squint.edn</code> file in your project and then automatically compiles all <code>.cljs</code> and <code>.cljc</code> files in your project to a corresponding <code>.mjs</code> file in an <code>:output-dir</code> (the extension is configurable):</p><p><code>squint.edn</code>:</p><pre><code class="language-clojure">{:paths [&quot;src-shared&quot; &quot;src-squint&quot; &quot;test&quot;]
 :output-dir &quot;dist&quot;}
</code></pre><p>The watcher can be started with <code>npx squint watch</code> (or <code>yarn squint watch</code> or <code>bun squint watch</code>).  In <code>src-shared</code> I put the files which are ported from the <code>src</code> directory, while <code>src-squint</code> has extra files that are specific for the squint port. The <code>src</code> directory contains CLJS-specific files that are not in scope for test.</p><p>When running <code>npx squint compile</code> all the files in <code>:paths</code> are re-compiled, which is handy when you want to distribute the project to NPM.</p><h2 id="symbolic-namespaces">Symbolic namespaces</h2><p>Before doing this port, other JS files had to be referenced using the JS library notation in the <code>ns</code> form:</p><pre><code class="language-clojure">(:require [&quot;./my_other_ns.mjs&quot;])
</code></pre><p>To increase sharing of code, I supported loading namespaces from <code>squint.edn</code>&apos;s <code>:paths</code> using the notation we&apos;re using to from Clojure(Script):</p><pre><code class="language-clojure">(:require [nextjournal.my-other-ns])
</code></pre><h2 id="stub-macros">Stub macros</h2><p>In a lot of places the <code>js-interop</code> library was used to create literals, functions with JS object destructuring, etc, most of which squint already does out of the box.  To accommodate this, I wrote a bunch of macros which basically did nothing and replaces the <code>j</code> alias with a namespace which mocks the <code>js-interop</code> library:</p><pre><code class="language-clojure">(ns nextjournal.clojure-mode
  (:require ...
            #?@(:squint []
                :cljs [[applied-science.js-interop :as j]])
            ...)
  #?(:squint (:require-macros [applied-science.js-interop :as j])))
</code></pre><p>In squint, macros are (currently) loaded via the <code>:require-macros</code> section in a <code>ns</code> form. The squint compiler looks for a <code>.cljc</code> file within <code>:paths</code>, then loads this file using <a href="https://github.com/babashka/sci">SCI</a>, makes the transformation and the resumes compilation of the transformed form. The reason SCI is used is that squint doesn&apos;t know Clojure&apos;s data structures at run-time, but you can still use them at compile time. This model is pretty similar how CLJS executes macros on the JVM.</p><p>The stub macros for <code>js-interop</code> look like this:</p><pre><code class="language-clojure">(ns applied-science.js-interop
  (:refer-clojure :exclude [defn get get-in fn let select-keys assoc!]))

(defmacro lit [x] x)

(defmacro defn [&amp; body]
  `(clojure.core/defn ~@body))

(defmacro get-in [&amp; body]
  `(clojure.core/get-in ~@body))

(defmacro fn [&amp; body]
  `(clojure.core/fn ~@body))

(defmacro let [&amp; body]
  `(clojure.core/let ~@body))

(defmacro call-in [obj path &amp; fs]
  `(.. ~obj ~@(map #(symbol (str &quot;-&quot; %)) path) ~@(map list fs)))

...
</code></pre><p>As you can see, most of the macros just defer to squint&apos;s default behavior. But a macro like <code>call-in</code>, which isn&apos;t part of squint, transforms to just raw JS interop.</p><h2 id="tests">Tests</h2><p>Luckily the clojure-mode project has a lot of tests. They generally have this shape:</p><pre><code class="language-clojure">(deftest enter-and-indent
  (are [input expected]
      (= (apply-cmd commands/enter-and-indent input) expected)

    &quot;(|)&quot; &quot;(\n |)&quot;
    &quot;((|))&quot; &quot;((\n  |))&quot;
    &quot;(()|)&quot; &quot;(()\n |)&quot;
    &quot;(a |b)&quot; &quot;(a\n  |b)&quot;
    &quot;(a b|c)&quot; &quot;(a b\n  |c)&quot;))
</code></pre><p>Squint does not have a testing framework. Currently my thinking is that users should just use Node&apos;s built-in testing framework when writing squint projects or whatever else people use for front-end testing. Initially I started porting the tests to top level <code>doseq</code> forms, like:</p><pre><code class="language-clojure">(doseq [[input expected]
        (partition 2
                   [&quot;(|)&quot; &quot;(\n |)&quot;
                    &quot;((|))&quot; &quot;((\n  |))&quot;
                    &quot;(()|)&quot; &quot;(()\n |)&quot;
                    &quot;(a |b)&quot; &quot;(a\n  |b)&quot;
                    &quot;(a b|c)&quot; &quot;(a b\n  |c)&quot;])]
  (assert.equal (apply-cmd commands/enter-and-indent input) expected))
</code></pre><p>but this got old really fast since I needed to duplicate 17 tests with dozens of test cases each. So I wrote a really hacky macro which took the <code>deftest</code> + <code>are</code> forms and rewrote them to the <code>doseq</code> forms I initially wrote manually, yielding the following <code>ns</code> form in the test namespace:</p><pre><code class="language-clojure">(ns nextjournal.clojure-mode-tests
  (:require #?@(:squint []
                :cljs [[cljs.test :refer [are testing deftest]]])
            ...
            #?(:squint [&quot;assert&quot; :as assert]))
  #?(:squint (:require-macros [nextjournal.clojure-mode-tests.macros :refer [deftest are testing]])))
</code></pre><p>Note that instead of <code>(is (= ...))</code> I&apos;m using Node&apos;s <code>assert.equal</code> which performs deep equality and gives nice error messages about non-equal cases. Running the squint tests in CI is now just a matter of running:</p><pre><code class="language-shell">$ node dist/nextjournal/clojure_mode_tests.mjs
</code></pre><h2 id="truthiness">Truthiness</h2><p>Once I got the tests running, I discovered some interesting bugs. Before doing the port, squint just used JS&apos;s own truthiness. This causes unexpected bugs with code like <code>(or (foo) 1)</code> when <code>foo</code> was a function that could return <code>0</code>. In JavaScript, <code>0</code> is falsey. This was by far the most important cause of bugs in the squint port. After experiencing this pain, I decided to adopt CLJS truthiness in squint, such that <code>(or 0 1)</code> returns <code>0</code>.</p><h2 id="data-structures-as-functions">Data structures as functions</h2><p>Another source of bugs was code like:</p><pre><code class="language-clojure">({:foo :bar} :foo)
</code></pre><p>In Squint, <code>{:foo :bar}</code> is just a JavaScript object and those cannot be called as functions as of now. Squint could be clever and just support literal collections in function position by emitting <code>(get {:foo :bar} :foo)</code> but this would break down when the user would push the data literal to a local or var (unless you add some kind of inference). I chose to just rewrite those expressions to use <code>get</code> or <code>contains?</code> instead, which works both in CLJS and squint:</p><pre><code class="language-clojure">(get {:foo :bar} :foo)
</code></pre><h2 id="miscellaneous">Miscellaneous</h2><p>Several other things were missing in squint, like:</p><ul><li>Support for <code>:pre</code> and <code>:post</code> in <code>fn</code></li><li>Macro usages via an alias instead of <code>:refer</code></li><li>Several core functions like <code>bit-and</code>, <code>bit-or</code>, <code>re-seq</code>, <code>fn?</code>, <code>subs</code>, <code>max</code>, <code>min</code>, <code>every-pred</code> , etc. All of those got added while doing the port.</li></ul><h2 id="development">Development</h2><p>Aside from running tests I used <a href="https://vitejs.dev/">vite</a> which is very easy to set up. Just create an <code>index.html</code> page, load your <code>.mjs</code> file from there using:</p><pre><code class="language-html">&lt;script src=&quot;js/demo.mjs&quot; type=&quot;module&quot;&gt;&lt;/script&gt;
</code></pre><p>and run:</p><pre><code class="language-clojure">$ npx vite --config vite.config.js public
</code></pre><p>where <code>public</code> is the directory that contains the <code>index.html</code> page.</p><p>The most basic vite config:</p><pre><code class="language-javascript">export default {
  base: &apos;./&apos;,
};
</code></pre><p>This spins up a development server and automatically hot-reloads all compiled JavaScript.</p><h2 id="publishing-to-npm">Publishing to NPM</h2><p>Since the <code>.mjs</code> files are written to <code>dist</code> (as configured in <code>squint.edn</code>), publishing the project to NPM can be done by adding <code>&quot;files&quot;: &quot;dist&quot;</code> to <code>package.json</code> To make the <code>dist/nextjournal/clojure_mode.mjs</code> file available when writing</p><pre><code class="language-javascript">import { default_extensions, complete_keymap } from &apos;@nextjournal/clojure-mode&apos;;
</code></pre><p>I had to add</p><pre><code class="language-clojure">&quot;exports&quot;: {&quot;.&quot;: &quot;dist/nextjournal/clojure_mode.mjs&quot;}
</code></pre><p>to <code>package.json</code>.</p><p>After that it was just a matter adding a package name and version and hitting <code>npm publish</code> (the first time you&apos;re doing this, you need to add <code>--access public</code> when you want to publish the package publically).</p><p>The package now lives on <a href="https://npmjs.com/package/@nextjournal/clojure-mode">NPM</a>!</p><h2 id="use-directly-from-cdn">Use directly from CDN</h2><p>Having the package on NPM also lets you directly use it from an HTML page using a CDN.  The <a href="https://jspm.org/">jspm</a> tool can convert a <code>package.json</code> into an <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"><code>importmap</code></a>. I did this for the <a href="https://squint-cljs.github.io/squint/">squint demo
page</a>. There you can see clojure-mode compiled with squint in action, without having to use any build tooling, since everything is loaded directly from a CDN!</p><h2 id="conclusion">Conclusion</h2><p>It seems squint hits the sweet spot for a project like <a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a> where most of the code is JavaScript interop. In this blog I demonstrated how to target both CLJS and squint with an existing library. CLJS or squint? Why not both!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-sep-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-sep-2023.html"/>
    <title>OSS updates September 2023</title>
    <updated>2023-09-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during September 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://github.com/pitch-io">Pitch</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>Last week I delivered my babashka talk at <a href="https://www.thestrangeloop.com/2023/babashka-a-meta-circular-clojure-interpreter-for-the-command-line.html">Strange
loop</a> talk and much of my attention went to the preparation of that (slides <a href="https://speakerdeck.com/borkdude/babashka-a-meta-circular-clojure-interpreter-for-the-command-line-at-strange-loop-2023">here</a>). Hopefully the talk will be online soon. Keep an eye on the <a href="https://www.youtube.com/playlist?list=PLcGKfGEEONaBNsY_bOj8IhbCPvj6OAdWo">Strange Loop Youtube
channel</a>.</p><p>EDIT: the talk is now available <a href="https://www.youtube.com/watch?v=DHtRfO3Bp90">here</a>.</p><p>I did manage to get some coding done as well, despite testing positive for COVID when I arrived back home...</p><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy. Published a new version (2023.09.07) with these changes:<ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1332">#1332</a>: New linter <code>:unused-alias</code>. See <a href="https://github.com/clj-kondo/clj-kondo/tree/master/doc/linters.md">docs</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2143">#2143</a>: false positive type warning for <code>clojure.set/project</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2145">#2145</a>: support ignore hint on multi-arity branch of function definition</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2147">#2147</a>: use alternative solution as workaround for <a href="https://github.com/cognitect/transit-clj/issues/43">https://github.com/cognitect/transit-clj/issues/43</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2152">#2152</a>: Fix false positive with used-underscored-binding with core.match</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2150">#2150</a>: allow command line options = as in --fail-level=error</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2149">#2149</a>: <code>:lint-as clojure.core/defmacro</code> should suppress <code>&amp;env</code> as unresolved symbol</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2161">#2161</a>: Fix type annotation for <code>clojure.core/zero?</code> to number -&gt; boolean</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2165">#2165</a>: Fix error when serializing type data to cache</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2167">#2167</a>: Don&apos;t crash when <code>:unresolved-symbol</code> linter config contains unqualified symbol</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2170">#2170</a>: <code>:keyword-binding</code> linter should ignore auto-resolved keywords</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2172">#2172</a>: detect invalid amount of args and invalid argument type for <code>throw</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2164">#2164</a>: deftest inside let triggers :unused-value</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2154">#2154</a>: add <code>:exclude</code> option to <code>:deprecated-namespace</code> linter</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2134">#2134</a>: don&apos;t warn on usage of private var in <code>data_readers.clj(c)</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2148">#2148</a>: warn on configuration error in <code>:unused-refeferred-var</code> linter</li><li>Expose more vars in <code>clj-kondo.hooks-api</code> interpreter namespace</li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting. Version 1.3.185 released!<ul><li><a href="https://github.com/babashka/babashka/pull/1624">#1624</a>: Use Oracle GraalVM 21 (<a href="https://github.com/lispyclouds">@lispyclouds</a>)</li><li>Use PGO to speed up loops (now 2-3x faster for <code>(time (loop [val 0 cnt 10000000] (if (pos? cnt) (recur (inc val) (dec cnt)) val)))</code>!)</li><li>Bump babashka.http-client to v0.4.15</li><li>Bump rewrite-clj to v0.1.1.47</li><li><a href="https://github.com/babashka/babashka/issues/1619">#1619</a>: Fix reflection issue with <code>Thread/sleep</code> in <code>core.async/timeout</code></li><li>Support interop on <code>java.util.stream.IntStream</code></li><li><a href="https://github.com/babashka/babashka/issues/1513">#1513</a>: Fix interop on <code>Thread/sleep</code> with numbers that aren&apos;t already longs</li><li>Bump babashka.cli to 0.7.53</li><li>Fix <a href="https://github.com/babashka/babashka.nrepl/issues/66">#babashka.nrepl/66</a></li><li>Various nREPL server improvements (classpath op, file lookup information for <code>cider-find-var</code>)</li><li>Bump cheshire to 5.12.0</li></ul></li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler A lot of happened in squint this month:<ul><li>Many core var implementations got added: <code>reduce-kv</code>, <code>max</code>, <code>min</code>, <code>every-pred</code>, <code>into-array</code>, <code>some-fn</code>, <code>keep-indexed</code>, <code>iterate</code>, <code>juxt</code>, <code>compare</code>, <code>to-array</code>, <code>fn?</code></li><li>Bun compatibility</li><li>Lots of bug fixes</li><li>REPL improvements</li><li>Adopt CLJS truth semantics: <code>0</code> and <code>&quot;&quot;</code> are no longer considered falsey</li><li>Lots more coming next month!</li></ul></li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects Version 0.2.61 released<ul><li><a href="https://github.com/babashka/neil/issues/181">#181</a>: fix <code>neil --version</code></li><li>fix tests by referring to latest hiccup (<a href="https://github.com/teodorlu">@teodorlu</a>)</li><li><a href="https://github.com/babashka/neil/issues/180">#180</a>: <code>neil dep upgrade</code>: allow upgrading from an unstable version to the latest unstable version (<a href="https://github.com/teodorlu">@teodorlu</a>)</li><li><a href="https://github.com/babashka/neil/issues/180">#180</a>: <code>neil dep upgrade</code>: with <code>--unstable</code>, opt-into unstable library updates (<a href="https://github.com/teodorlu">@teodorlu</a>)</li><li><a href="https://github.com/babashka/neil/issues/183">#183</a>: Don&apos;t drop <code>:exclusions</code> when running <code>neil dep add</code> or <code>neil dep upgrade</code> ([@borkdude] and [@teodorlu])</li></ul></li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<ul><li>Small release with the option to add your own header on top of <code>format-opts</code>, thanks to <a href="https://github.com/Sohalt">@Sohalt</a></li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<ul><li>A number of small bugfixes and additions</li></ul></li><li>A number of experiments around <a href="https://github.com/squint-cljs/squint">squint</a>:<ul><li><a href="https://github.com/borkdude/bun-squint-loader">bun-squint-loader</a>: a demo of how to implement a loader for <a href="https://github.com/oven-sh/bun">bun</a> which lets you directly load <code>.cljs</code> files which are then compiled using</li><li>squint <a href="https://github.com/borkdude/squint-bun-cloudflare">cloudflare worker</a></li></ul></li><li><a href="https://github.com/borkdude/rewrite-edn">rewrite-edn</a>: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments<ul><li>Fixed a round-tripping issue by bumping rewrite-clj</li></ul></li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: use tools.deps directly from babashka<ul><li>aarch64 binary (thanks @TimoKramer for contributing)</li><li>update upstream projects</li></ul></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler<ul><li>Bump shared compiler code with squint and publish new version</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Bumped tools jar and fixed a bug concerning SHA comparison</li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Add experimental <code>:static-methods</code> override to control how a static method is invoked. This allowed a fix in babashka for <code>Thread/sleep</code> on non-longs and for <code>Class/forName</code> which works arond a bug in Oracle GraalVM 21.</li></ul></li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li><a href="https://github.com/holyjak">@holyjak</a> made a configuration for <a href="https://github.com/fulcrologic/fulcro">Fulcro</a> which can be seen live in action <a href="https://blog.jakubholy.net/2023/interactive-code-snippets-fulcro/">here</a></li></ul></li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-aug-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-aug-2023.html"/>
    <title>OSS updates August 2023</title>
    <updated>2023-08-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during August 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://github.com/pitch-io">Pitch</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>Currently my attention is mostly directed at the upcoming <a href="https://www.thestrangeloop.com/2023/babashka-a-meta-circular-clojure-interpreter-for-the-command-line.html">Strange loop</a> talk. I&apos;m very excited to be part of the last iteration of this conference. It will also be my first time flying to the USA!</p><p>Rahul De and Anupriya Johari will be giving a workshop at JavaZone on Tuesday the 5th of September. Check the details <a href="https://2023.javazone.no/program/19a5cab3-7afd-4dc1-b60a-bea8562d3186">here</a>.</p><p>Here are updates about the projects/libraries I&apos;ve worked on last month.</p><ul><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure<ul><li>Release version <code>0.7.27</code> (see <a href="https://github.com/borkdude/jet/blob/master/CHANGELOG.md#0727-2023-08-02">changelogs</a>) with missing 1.11 functions and options for easier kebab/camel/etc. casing.</li></ul></li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure<ul><li>No update in quickdoc, but happy to see that Github have resolved a bug on their side with local anchors in HTML, which quickdoc relies on</li><li>Require clojure 1.11 as the minimal clojure version</li></ul></li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>Worked together with <a href="https://github.com/niwinz">@niwinz</a> to make sci.configs upgradable to promesa 10 and 11. Many thanks to Andrey for making promesa backward-compatible again, since sci.configs relies on Clojure libraries to be always upgradable without breaking changes.</li></ul></li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI<ul><li>Bumped sci.configs and promesa</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>The tools jar relocated to Github releases so deps.clj was updated to this new location, with backward compatibility</li><li>Per my request, Alex added a <code>.sha256</code> file to Github releases so the downloaded jar file could be verified against corruption</li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Clojure compatibility: allow <code>(def foo/foo 1)</code> in namespace <code>foo</code></li><li>Clojure compatibility: reset file metadata on var when it&apos;s re-evaluated from other file</li><li>Add <code>sci.async/eval-form</code> and <code>sci.async/eval-form+</code></li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.<ul><li>expose <code>sci.core</code> in babashka</li><li>Asahi linux support (linux on Apple m1/m2)</li><li>Several other library upgrades and Clojure compatibility fixes</li><li>Compatibility with the newest integrant version</li></ul></li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3<ul><li>Upgrade sqlite version so it supports json fields</li></ul></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a><ul><li>Add <a href="https://github.com/squint-cljs/squint/blob/main/doc/defclass.md"><code>defclass</code></a> to cherry (similar to squint)</li><li>Expose <code>clojure.string</code> and <code>clojure.walk</code> namespaces</li><li>Fix overriding core vars</li></ul></li><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li>working towards a new release with a large number of small bug fixes, see upcoming <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">changelog</a></li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: babashka&apos;s http-client<ul><li>A number of small bugfixes and additions</li></ul></li></ul><!-- ## Contributions to other projects --><!-- - [clojurescript](https://github.com/clojure/clojurescript): --><!--   - [PR 202](https://github.com/clojure/clojurescript/pull/202): a `macroexpand` fix --><!--   - [PR 203](https://github.com/clojure/clojurescript/pull/203): a symbol optimization fix --><!-- - [malli](https://github.com/metosin/malli/commit/cf918db28ff71a2f735f465f30f0bc1028ecd7d9): cherry integration --><!-- - [clerk](https://github.com/nextjournal/clerk/commit/cb079b14213185d27c5a2d1cc1e80943521a4fb5): cherry integration --><!-- - [clojure-lsp](https://github.com/clojure-lsp/clojure-lsp/commit/60d67cca59f0747e8b68802157afbe7f61440c7f): integrated a new clj-kondo feature: showing the languages in a CLJC context --><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo</li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler and <a href="https://github.com/squint-cljs/cherry">cherry</a> Experimental ClojureScript to ES6 module compi</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a></li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jul-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jul-2023.html"/>
    <title>OSS updates July 2023</title>
    <updated>2023-08-02T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during July 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><ul><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li>A big fat new release: 2023.07.23. Several new linting rules and lots of fixes. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20230713">changelogs</a> here.</li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: Babashka&apos;s http-client<ul><li>Added a websocket API, a fix for the <code>:ssl-context {:insecure true}</code> option and more. See <a href="https://github.com/babashka/http-client/blob/main/CHANGELOG.md">CHANGELOG</a>.</li></ul></li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod<ul><li>The events emitted from the file watcher are now automatically deduplicated.</li><li>An aarch64 binary for Mac is now available Thanks to @fjsousa and @lispyclouds.</li></ul></li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata<ul><li>A small bugfix release around reading malformed reader conditional expressions</li></ul></li><li><a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a>: a leiningen plugin for clj-kondo<ul><li>This plugin now follows the version number of clj-kondo</li></ul></li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler and <a href="https://github.com/squint-cljs/cherry">cherry</a> Experimental ClojureScript to ES6 module compiler<ul><li>Add <a href="https://github.com/squint-cljs/squint/blob/main/doc/defclass.md"><code>defclass</code></a> in squint, inspired by shadow-cljs</li><li>More work on getting squint and cherry to work in one build</li><li>Provide UMD build which works better in Firefox Webworkers</li><li>cherry can now be used in a playground at <a href="https://dev.livecodes.io/?template=clojurescript">livecodes.io</a></li><li>Fix <code>doseq</code> and add <code>doall</code> and <code>dorun</code> in squint</li></ul></li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter<ul><li>Allow anonymous function literals in <code>project.clj</code></li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.<ul><li>Version <code>1.3.182</code> released, mostly library bumps and small bugfixes. See changelogs <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#13182-2023-07-20">here</a>.</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>More robust handling of downloading and unzipping tools jar</li></ul></li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI<ul><li>Fixed a small bug with evaluating tags: when there would be whitespace + a <code>&quot;src&quot;</code> attribute, the whitespace would be executed and the attribute was ignored.</li></ul></li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a> and <a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a><ul><li>This EXPERIMENTAL combo allows you to use tools.build from babashka. In this release a reflection issue was addressed.</li></ul></li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI<ul><li>Add missing function to promesa</li></ul></li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure<ul><li>Release version <code>0.7.27</code> (see <a href="https://github.com/borkdude/jet/blob/master/CHANGELOG.md#0727-2023-08-02">changelogs</a>) with missing 1.11 functions and options for easier kebab/camel/etc. casing.</li></ul></li></ul><!-- ## Contributions to other projects --><!-- - [clojurescript](https://github.com/clojure/clojurescript): --><!--   - [PR 202](https://github.com/clojure/clojurescript/pull/202): a `macroexpand` fix --><!--   - [PR 203](https://github.com/clojure/clojurescript/pull/203): a symbol optimization fix --><!-- - [malli](https://github.com/metosin/malli/commit/cf918db28ff71a2f735f465f30f0bc1028ecd7d9): cherry integration --><!-- - [clerk](https://github.com/nextjournal/clerk/commit/cb079b14213185d27c5a2d1cc1e80943521a4fb5): cherry integration --><!-- - [clojure-lsp](https://github.com/clojure-lsp/clojure-lsp/commit/60d67cca59f0747e8b68802157afbe7f61440c7f): integrated a new clj-kondo feature: showing the languages in a CLJC context --><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><p><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</p></li><li><p><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</p></li><li><p><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</p></li><li><p><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</p></li><li><p><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><ul><li>Support <code>:require-macros</code></li><li>Introduce <code>eval-string+</code> which received an optional initial <code>:ns</code> key and also returns the last active <code>:ns</code> so you can preserve the namespace state over multiple evaluations.</li><li>Released v0.8.40</li></ul></li><li><p><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</p><ul><li>Implement <code>:out :bytes</code> to receive output as bytes (thanks Hans Bugge Grathwohl)</li><li>Make <code>:dir</code> option accept <code>java.nio.file.Path</code></li></ul></li><li><p><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</p></li><li><p><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</p></li><li><p><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</p></li><li><p><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></p></li><li><p><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</p></li><li><p><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</p></li><li><p><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</p></li><li><p><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</p></li><li><p><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</p></li><li><p><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</p></li><li><p><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</p></li><li><p><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</p></li><li><p><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</p></li><li><p><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</p></li><li><p><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</p></li><li><p><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</p></li><li><p><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</p></li><li><p><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</p></li><li><p><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</p></li></ul></details></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-june-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-june-2023.html"/>
    <title>OSS updates June 2023</title>
    <updated>2023-06-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during June 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>First a few updates of what I&apos;ve been up to outside of sitting behind a screen. This month was packed with two trips and a vacation so there aren&apos;t as many updates as usual.</p><ul><li><a href="https://babashka.org/conf/">Babashka-conf</a> happened June 10th in Berlin. It was more than I could have hoped for: a professionally organized event with the creative, positive, welcoming spirit we&apos;re used to from other Clojure conferences. Thanks everybody for coming out, especially to the speakers, organization and Malcolm + staff for recording the videos. You can view all the talks <a href="https://www.youtube.com/playlist?list=PLaN-rC-CjQqDu1AVhGdGOoEqsSAhd2W6t">here</a>. To see photos, comments, etc you can look for the #babashka_conf hash-tag on social media.</li><li>I&apos;ve had the pleasure to visit the JUXT 10th year anniversary this month in London. Check out <a href="https://www.youtube.com/watch?v=fT28NeZtaAg">this wonderful talk</a> by Alexander Davis on the state of frontend, with some nice comments about squint at the end.</li><li>End of June and beginning of July I&apos;m away on a <a href="https://twitter.com/borkdude/status/1674401271372042240">vacation</a> to Switzerland to recover a bit from all of this fun. I hope to take it easy on the coding and just relax a bit and recharge for what is to come next.</li><li>Babashka and SCI will be featured at the last iteration of <a href="https://www.thestrangeloop.com/">Strange Loop</a>!</li></ul><p>The following projects had updates in the last month. Note that only highlights are mentioned and not a full overview of all changes. See the project&apos;s changelogs for all changes.</p><ul><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler and <a href="https://github.com/squint-cljs/cherry">cherry</a> Experimental ClojureScript to ES6 module compiler<ul><li>Both projects can now be used simultaneously in one build. The use case for this is when you have projects like <a href="https://github.com/nextjournal/clerk">clerk</a> that ship with multiple options for evaluating CLJS at runtime and you want to offer both squint and cherry as options.</li></ul></li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases<ul><li>Version 0.1.2 was released which contains upgrades of database drivers and next.jdbc library. Also a bug was fixed around mssql.</li></ul></li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<ul><li>Implemented an alternative to <code>shutdown-agents</code> which does not kill threads when using an exec function, e.g. when spinning up a web server. Also see <a href="https://clojure.atlassian.net/browse/TDEPS-198">TDEPS-198</a>.</li></ul></li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI<ul><li>Namespace state is now preserved over multiple blocks</li></ul></li><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li>Actively working towards a <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#unreleased">new release</a>, probably next month.</li></ul></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure<ul><li>Add <code>gzip</code> and <code>gunzip</code> functions (thanks to Lauri Oherd)</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Tried to improve the situation where the downloaded tools jar may be corrupt and causes trouble when calculating the classpath, using a crc32 check. See babashka <a href="https://github.com/babashka/babashka/issues/1576">issue</a>.</li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Support <code>:require-macros</code></li><li>Introduce <code>eval-string+</code> which received an optional initial <code>:ns</code> key and also returns the last active <code>:ns</code> so you can preserve the namespace state over multiple evaluations.</li><li>Released v0.8.40</li></ul></li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes<ul><li>Implement <code>:out :bytes</code> to receive output as bytes (thanks Hans Bugge Grathwohl)</li><li>Make <code>:dir</code> option accept <code>java.nio.file.Path</code></li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.<ul><li>1575: fix command line parsing problem with -e + <code>*command-line-args*</code></li><li>1576: make downloading/unzipping of deps.clj tools .zip file more robust (see deps.clj)</li><li>released version 1.3.181</li><li>1581: bb <code>print-deps</code>: sort dependencies (thanks to Teodor Heggelund)</li><li>1579: add <code>clojure.tools.reader/resolve-symbol</code> built-in</li></ul></li></ul><!-- ## Contributions to other projects --><!-- - [clojurescript](https://github.com/clojure/clojurescript): --><!--   - [PR 202](https://github.com/clojure/clojurescript/pull/202): a `macroexpand` fix --><!--   - [PR 203](https://github.com/clojure/clojurescript/pull/203): a symbol optimization fix --><!-- - [malli](https://github.com/metosin/malli/commit/cf918db28ff71a2f735f465f30f0bc1028ecd7d9): cherry integration --><!-- - [clerk](https://github.com/nextjournal/clerk/commit/cb079b14213185d27c5a2d1cc1e80943521a4fb5): cherry integration --><!-- - [clojure-lsp](https://github.com/clojure-lsp/clojure-lsp/commit/60d67cca59f0747e8b68802157afbe7f61440c7f): integrated a new clj-kondo feature: showing the languages in a CLJC context --><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/http-client">http-client</a>: Babashka&apos;s http-client</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual</li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI</li></ul></details><!-- - [tools-deps-native](https://github.com/babashka/tools-deps-native): Run tools.deps as a native binary--><!-- - [tools.bbuild](https://github.com/babashka/tools.bbuild): Library of functions for building Clojure projects--></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-may-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-may-2023.html"/>
    <title>OSS updates May 2023</title>
    <updated>2023-05-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during May 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="babashka-conf"><a href="https://babashka.org/conf/">Babashka-conf</a></h2><p>Babashka-conf is happening June 10th in Berlin. Only a few tickets left!</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Open the details section for more info.</p><details>
<summary>Sponsor info</summary>
Top sponsors:<ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p></details><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="updates">Updates</h2><p>The following projects had updates in the last month. Note that only highlights are mentioned and not a full overview of all changes. See the project&apos;s changelogs for all changes.</p><ul><li>Preparations for <a href="https://github.com/babashka/conf">babashka conf</a> are in full swing and I&apos;m preparing a talk with the title &apos;Growing an ecosystem&apos;.</li><li>This month I&apos;ve had the honor to visit the JUXT 10 year anniversary in London and met a lot of fellow Clojurians over there.</li><li>Babashka and SCI will be featured at the last iteration of <a href="https://www.thestrangeloop.com/">Strange Loop</a>!</li><li>My OSS work is funded by Clojurists Together in <a href="https://www.clojuriststogether.org/news/q2-2023-funding-announcement/">Q2</a></li><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li>Version 2023.05.18 - 2023.05.26 were released. Full changelogs <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">here</a>. Highlights:</li><li>Linter <code>:uninitialized-var</code> moved from default <code>:level :off</code> to <code>:warning</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2065">#2065</a>: new linter <code>:equals-true</code>: suggest using <code>(true? x)</code> over <code>(= true x)</code> (defaults to <code>:level :off</code>).</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2066">#2066</a>: new linters <code>:plus-one</code> and <code>:minus-one</code>: suggest using <code>(inc x)</code> over <code>(+ x 1)</code> (and similarly for <code>dec</code> and <code>-</code>, defaults to <code>:level :off</code>)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2058">#2058</a>: warn about <code>#()</code> and <code>#&quot;&quot;</code> in <code>.edn</code> files</li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting.<ul><li>Released 1.3.180, mostly a maintenance release</li><li>See the complete <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">CHANGELOG</a></li></ul></li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI<ul><li><a href="https://github.com/babashka/scittle/issues/58">#58</a>: build system for creating scittle distribution with custom libraries. See <a href="https://github.com/babashka/scittle/tree/main/plugins/demo">plugins/demo</a>.</li><li>Use <code>window.location.hostname</code> for WebSocket connection instead of hardcoding <code>&quot;localhost&quot;</code> (<a href="https://github.com/pyrmont">@pyrmont</a>)</li><li>Upgrade <code>sci.configs</code> to <code>&quot;33bd51e53700b224b4cb5bda59eb21b62f962745&quot;</code></li><li>Update nREPL implementation: implement <code>eldoc</code> (<code>info</code>, <code>lookup</code>) (<a href="https://github.com/benjamin-asdf">@benjamin-asdf</a>)</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Introduce all new programmatic <a href="https://github.com/borkdude/deps.clj/blob/master/API.md">API</a></li><li>Automatically use file when exceeding Windows argument length</li></ul></li><li><a href="https://github.com/borkdude/deps.add-lib">deps.add-lib</a>: Clojure 1.12&apos;s add-lib feature for leiningen and/or other environments without a specific version of the clojure CLI<ul><li>First clojars release</li></ul></li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI<ul><li>Nbb is now compatible with <a href="https://bun.sh/">bun</a>. To run nbb in a bun project, use <code>bunx --bun nbb</code>.</li></ul></li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler<ul><li>Fix import with <code>$default</code></li></ul></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a> Experimental ClojureScript to ES6 module compiler<ul><li>Support <code>with-out-str</code></li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: Babashka&apos;s http-client<ul><li>Add <code>:authenticator</code> option</li></ul></li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs.<ul><li>This project now has a configuration for datascript, for anyone who wants to use SCI together with datascript. See <a href="https://github.com/babashka/sci.configs/commit/33bd51e53700b224b4cb5bda59eb21b62f962745">this</a> commit.</li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Support <code>:require-macros</code></li></ul></li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes<ul><li>Support <code>:pre-start-fn</code> in <code>exec</code></li><li>Allow passing <code>:cmd</code> in map argument</li><li>Better testing for <code>exec</code> by <a href="https://github.com/lread">@lread</a></li></ul></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure<ul><li><code>:paths</code> argument for <code>fs/which</code> by <a href="https://github.com/lread">@lread</a></li><li>Support inputstream in <code>fs/copy</code></li><li>Add <code>fs/owner</code> to return owner of file</li></ul></li></ul><!-- ## Contributions to other projects --><!-- - [clojurescript](https://github.com/clojure/clojurescript): --><!--   - [PR 202](https://github.com/clojure/clojurescript/pull/202): a `macroexpand` fix --><!--   - [PR 203](https://github.com/clojure/clojurescript/pull/203): a symbol optimization fix --><!-- - [malli](https://github.com/metosin/malli/commit/cf918db28ff71a2f735f465f30f0bc1028ecd7d9): cherry integration --><!-- - [clerk](https://github.com/nextjournal/clerk/commit/cb079b14213185d27c5a2d1cc1e80943521a4fb5): cherry integration --><!-- - [clojure-lsp](https://github.com/clojure-lsp/clojure-lsp/commit/60d67cca59f0747e8b68802157afbe7f61440c7f): integrated a new clj-kondo feature: showing the languages in a CLJC context --><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><details>
<summary>Click for more details</summary><ul><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata<ul><li>Improvements for reading namespaced maps</li></ul></li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual<ul><li>Several corrections</li><li>Dynamic <code>:exec-args</code></li><li>Script-adjacent <code>bb.edn</code> docs</li></ul></li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<ul><li>Support <code>--no-option</code> and parse as <code>{:option false}</code></li><li>Support grouped aliase like <code>-ome</code> as <code>{:o true, :m true, :e true}</code></li></ul></li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3<ul><li>Better error message when connection is not a string</li></ul></li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a><ul><li>Add transform function</li></ul></li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure<ul><li>Add option to elide commas</li></ul></li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li></ul></details><!-- - [tools-deps-native](https://github.com/babashka/tools-deps-native): Run tools.deps as a native binary--><!-- - [tools.bbuild](https://github.com/babashka/tools.bbuild): Library of functions for building Clojure projects--></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-apr-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-apr-2023.html"/>
    <title>OSS updates April 2023</title>
    <updated>2023-04-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during April 2023.</p><p>To see previous OSS updates, go <a href="https://blog.michielborkent.nl/tags/oss-updates.html">here</a>.</p><h2 id="babashka-conf"><a href="https://babashka.org/conf/">Babashka-conf</a></h2><p>Babashka-conf is happening June 10th in Berlin. Save the date and/or submit your babashka/clojure-related talk or workshop in the CfP!</p><h2 id="sponsors">Sponsors</h2><p>I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="projects">Projects</h2><p>The following projects had updates in the last month. Note that only highlights are mentioned and not a full overview of all changes. See the project&apos;s changelogs for all changes.</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a>: static analyzer and linter for Clojure code that sparks joy.<ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1196">#1196</a>: show language context in <code>.cljc</code> files with <code>:output {:langs true}</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#show-language-context-in-cljc-files">docs</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2030">#2030</a>: Add a new <code>:discouraged-tag</code> linter for discouraged tag literals. See the <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#discouraged-tag">docs</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2058">#2058</a>: warn about <code>#()</code> and <code>#&quot;&quot;</code> in `.edn files</li></ul></li><li><a href="https://github.com/babashka/babashka">babashka</a>: native, fast starting Clojure interpreter for scripting<ul><li>Released 1.3.177 - 1.3.179</li><li><a href="https://github.com/babashka/babashka/issues/1541">#1541</a>: respect <code>bb.edn</code> adjacent to invoked file. This eases writing system-global scripts from projects without using bbin. See <a href="https://book.babashka.org/#_script_adjacent_bb_edn">docs</a>.</li><li>See the complete <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">CHANGELOG</a>.</li></ul></li><li><a href="https://github.com/squint-cljs/cherry">cherry</a> Experimental ClojureScript to ES6 module compiler<ul><li>Improve <code>cherry.embed</code></li></ul></li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs<ul><li>Better error message when trying to <code>recur</code> across <code>try</code></li><li>Improvement for error locations in multiple threads</li></ul></li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata<ul><li>Improvements for reading namespaced maps</li></ul></li><li><a href="https://github.com/babashka/book">babashka.book</a>: Babashka manual<ul><li>Several corrections</li><li>Dynamic <code>:exec-args</code></li><li>Script-adjacent <code>bb.edn</code> docs</li></ul></li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!<ul><li>Support <code>--no-option</code> and parse as <code>{:option false}</code></li><li>Support grouped aliase like <code>-ome</code> as <code>{:o true, :m true, :e true}</code></li></ul></li><li><a href="https://github.com/babashka/http-client">http-client</a>: Babashka&apos;s http-client<ul><li>Support <code>java.net.URI</code> directly in <code>:uri</code> option</li><li>Better <code>:ssl-config</code> option support</li><li>Better <code>:proxy</code> option support</li></ul></li><li><a href="https://github.com/babashka/pod-babashka-go-sqlite3">pod-babashka-go-sqlite3</a>: A babashka pod for interacting with sqlite3<ul><li>Better error message when connection is not a string</li></ul></li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI<ul><li>Fix <code>:local/root</code> deps in <code>nbb.edn</code> when not invoking from current working directory</li><li>Fix regression, <code>cljs.core/PersistentQueue.EMPTY</code> no longer working</li></ul></li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a><ul><li>Add transform function</li></ul></li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure<ul><li>Add option to elide commas</li></ul></li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure<ul><li>Catch up with clojure CLI changes</li></ul></li></ul><h2 id="contributions-to-other-projects">Contributions to other projects</h2><ul><li><a href="https://github.com/clojure/clojurescript">clojurescript</a>:<ul><li><a href="https://github.com/clojure/clojurescript/pull/202">PR 202</a>: a <code>macroexpand</code> fix</li><li><a href="https://github.com/clojure/clojurescript/pull/203">PR 203</a>: a symbol optimization fix</li></ul></li><li><a href="https://github.com/metosin/malli/commit/cf918db28ff71a2f735f465f30f0bc1028ecd7d9">malli</a>: cherry integration</li><li><a href="https://github.com/nextjournal/clerk/commit/cb079b14213185d27c5a2d1cc1e80943521a4fb5">clerk</a>: cherry integration</li><li><a href="https://github.com/clojure-lsp/clojure-lsp/commit/60d67cca59f0747e8b68802157afbe7f61440c7f">clojure-lsp</a>: integrated a new clj-kondo feature: showing the languages in a CLJC context</li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><ul><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a>: babashka filewatcher pod</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://borkdude.github.io/clj2el/">clj2el</a>: transpile Clojure to elisp</li><li><a href="https://github.com/borkdude/deflet">deflet</a>: make let-expressions REPL-friendly!</li><li><a href="https://github.com/babashka/json">babashka.json</a>: babashka JSON library/adapter</li></ul><!-- - [tools-deps-native](https://github.com/babashka/tools-deps-native): Run tools.deps as a native binary--><!-- - [tools.bbuild](https://github.com/babashka/tools.bbuild): Library of functions for building Clojure projects--></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-news-feb-mar-2023.html</id>
    <link href="https://blog.michielborkent.nl/babashka-news-feb-mar-2023.html"/>
    <title>Babashka news of February and March 2023</title>
    <updated>2023-04-07T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>If you want to help me keep track of babashka-related news, please contribute to <a href="https://github.com/babashka/babashka/blob/master/doc/news.md">news.md</a> or use the <code>#babashka</code> hashtag on <a href="https://twitter.com/search?q=%28%23babashka%20OR%20babashka%28&amp;src=typed_query&amp;f=live">Twitter</a> or <a href="https://mastodon.social/tags/babashka">Mastodon</a>.</p><h2 id="2023-03">2023-03</h2><h3 id="releases">Releases</h3><p>1.3.176, 1.3.175, 1.2.174:</p><p>Biggest highlight: Switch to GraalVM 19 and enable virtual threads!</p><h3 id="videos">Videos</h3><ul><li><a href="https://pitch.com/public/03fa9c7e-2b0e-45fb-8a22-d4a4d4d79d24">Blambda! The sound of babashka and AWS colliding</a>, by Josh Glover from Pitch!</li></ul><h3 id="projects">Projects</h3><ul><li><a href="https://github.com/babashka/json">babashka.json</a>: JSON abstraction library</li><li><a href="https://github.com/oliyh/martian">martian</a> is now babashka compatible!</li><li><a href="https://github.com/keychera/panas.reload">panas.reload</a>: a hot reload for babashka serving html+css (or htmx)</li><li><a href="https://git.sr.ht/~rwv/cljs-exif-reader">cljs-exif-reader</a>: Extract information from TIFF and JPEG images (works in babashka, despite the name)</li></ul><h3 id="jobs">Jobs</h3><ul><li>Write babashka at <a href="https://twitter.com/RobStuttaford/status/1641694501793038336">Cognician</a>!</li></ul><h2 id="2023-02">2023-02</h2><h2 id="releases-2">Releases</h2><p>1.1.173: mostly bugfixes</p><h3 id="articles">Articles</h3><ul><li><a href="https://github.com/whacked/cow/blob/main/a%20technique%20for%20live%20coding%20simple%20web%20pages.md">A technique for live coding simple web pages</a> with babashka</li></ul><h3 id="videos-2">Videos</h3><ul><li><a href="https://www.youtube.com/watch?v=NfgYon96dsE">Stockholm Clojure Meetup Feb 23: Blambda! The sound of Babashka and Lambda colliding</a></li></ul><h3 id="projects-2">Projects</h3><ul><li><a href="https://github.com/philoskim/debux">debux</a> is now babaskha-compatible</li><li><a href="https://github.com/matthewdowney/linesofcode-bb">lines-of-code-bb</a>: Babashka script to count lines of Clojure code, docs, comments, and more</li><li><a href="https://github.com/eval/deps-try">deps-try</a>: a babashka-script to try out Clojure libraries in rebel-readline</li><li><a href="https://github.com/pixelated-noise/bb-dialog">bb-dialog</a> adds support for <code>--treeview</code></li><li><a href="https://mastodon.me.uk/@choffee/109845697304457129">A duckduck go CLI with babashka and (bbl)gum</a></li><li><a href="https://github.com/babashka/http-client">babashka http-client</a> now supports multipart uploads</li><li><a href="https://github.com/oakmac/sublime-pretty-edn">sublime-pretty-edn</a>: Format, Validate, Minify EDN files in Sublime Text</li><li><a href="https://twitter.com/borkdude/status/1628473136969576449">Play console tetris in babashka!</a></li><li><a href="https://github.com/lambdaisland/kaocha">kaocha test runner</a> became babashka compatible!</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-mar-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-mar-2023.html"/>
    <title>OSS updates March 2023</title>
    <updated>2023-04-07T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during March 2023.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><p>On to the projects that I&apos;ve been working on!</p><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="cherry"><a href="https://github.com/squint-cljs/cherry">cherry</a></h2><p>Experimental ClojureScript to ES6 module compiler</p><p>This month I&apos;ve been preparing cherry as a compiler that you can embed in your existing CLJS / shadow-cljs applications. This makes cherry an additional alternative to <a href="https://github.com/babashka/sci">SCI</a> and self-hosted CLJS.</p><p>Read about embedding cherry into your application <a href="https://github.com/squint-cljs/cherry/blob/main/doc/embed.md">here</a>.</p><p>I&apos;ve been working on several PRs to include cherry as an additional evaluator in:</p><ul><li><a href="https://github.com/nextjournal/clerk/pull/446">clerk</a></li><li><a href="https://github.com/metosin/malli/pull/888">malli</a></li><li>One project that is still unpublished but will be coming soon!</li></ul><h2 id="scimacs"><a href="https://github.com/jackrusher/scimacs">scimacs</a></h2><p>The Small Clojure Interpreter (SCI) integrated with emacs as a loadable module.</p><p>This is a new project by Jack Rusher and I&apos;ve helped him with the SCI integration.</p><h2 id="clj2el"><a href="https://borkdude.github.io/clj2el/">clj2el</a></h2><p>Transpile clojure to elisp. A brand new project to transpile Clojure to Elisp. It might be of value for those who know Clojure better than Elisp and want to have something to get started. It&apos;s far from complete. Try it in the playground <a href="https://borkdude.github.io/clj2el/">here</a>.</p><h2 id="deflet"><a href="https://github.com/borkdude/deflet">deflet</a></h2><p>Make let-expressions REPL-friendly!</p><p>The <code>deflet</code> macro lets your write inline-def expressions, while expanding those to regular let expressions, giving you the benefits of REPL-driven development without polluting production code with top level vars.</p><h2 id="babashka"><a href="https://github.com/babashka/babashka">babashka</a></h2><p>Native, fast starting Clojure interpreter for scripting</p><p>New release: 1.3.175 (2023-03-18)), 1.3.176 (2023-03-18)</p><p>Highlights:</p><p>The <code>clojure.core.async/go</code> macro now uses virtual threads.</p><p>Many small fixes and upgrades.</p><p>See the complete <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">CHANGELOG</a>.</p><h3 id="babashka.json"><a href="https://github.com/babashka/json">babashka.json</a></h3><p>This is a JSON abstraction library that you can include in babashka and JVM projects while also including your own favorite JSON implementation. The idea is that babashka libraries can include this, while JVM projects don&apos;t have to switch their JSON implementation to cheshire.core.</p><h3 id="babashka-compatibility-in-external-libs">Babashka compatibility in external libs</h3><p>I worked together with the maintainers of the following libraries to make them compatible with babashka:</p><ul><li><a href="https://github.com/oliyh/martian/commit/f0f7679364f58eb4ef558e9ad2340274b9742542">martian</a>: HTTP abstraction library for Clojure/script, supporting OpenAPI, Swagger, Schema, re-frame and more</li></ul><h2 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a></h2><p>Static analyzer and linter for Clojure code that sparks joy</p><p>New release: 2023.03.17</p><p>Some highlights:</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2010">#2010</a>: Support inline macro configuration. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#inline-macro-configuration">docs</a></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2010">#2010</a>: Short syntax to disable linters: <code>{:ignore [:unresolved-symbol]}</code> or <code>{:ignore true}</code>, valid in ns-metadata, <code>:config-in-ns</code>, <code>:config-in-call</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2009">#2009</a>: new <code>:var-same-name-except-case</code> linter: warn when vars have names that differ only in case (important for AOT compilation and case-insensitive filesystems)</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1269">#1269</a>: warn on <code>:jvm-opts</code> in top level of <code>deps.edn</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/2003">#2003</a>: detect invalid arity call for function passed to <code>update</code>, <code>update-in</code>, <code>swap!</code>, <code>swap-vals!</code>, <code>send</code>, <code>send-off</code>, and <code>send-via</code></li></ul><p><a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Check the
changelog</a> for details.</p><h2 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h2><p>Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><p>New release: 0.7.39 (2023-03-07)</p><ul><li><a href="https://github.com/babashka/sci/issues/874">#874</a>: Keyword arguments as map support for CLJS</li></ul><p>See <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">changelog</a> for more.</p><h2 id="contributions-to-other-projects">Contributions to other projects</h2><ul><li><a href="https://github.com/clojure/clojurescript">clojurescript</a>:<ul><li><a href="https://github.com/clojure/clojurescript/pull/202">PR 202</a>: a <code>macroexpand</code> fix</li><li><a href="https://github.com/clojure/clojurescript/pull/203">PR 203</a>: a symbol optimization fix</li></ul></li><li><a href="https://github.com/clojure-lsp/clojure-lsp/commit/b7111ef6b5f9c1d93b2272683ff4b6eb58b240c9">clojure-lsp</a>: fix reflection issue on JDK 19</li><li><a href="https://github.com/http-kit/http-kit/commit/e2d71039ea2617e789a08606a0c404c41367dca8">http-kit</a>: add native-image tests</li><li><a href="https://github.com/funcool/promesa/commit/18fea52fd99b24a65927907eff6879b970c71dfd">promesa</a>: fix GraalVM native-image compilation</li><li><a href="https://github.com/clj-commons/etaoin/commit/706f342216af69d23de671803ac67c3e1f515941">etaoin</a>: JDK 19 + babashka issue</li></ul><h2 id="brief-mentions">Brief mentions</h2><p>The following projects also got updates, mostly in the form of maintenance and performance improvements. This post would get too long if I had to go into detail about them, so I&apos;ll briefly mention them in random order:</p><ul><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/borkdude/gh-release-artifact">gh-release-artifact</a>: Upload artifacts to Github releases idempotently</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/babashka/nbb">Nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/http-client">http-client</a>: Babashka&apos;s http-client</li></ul><h2 id="other-projects">Other projects</h2><p>These are (some of the) other projects I&apos;m involved with but little to no activity happened in the past month.</p><ul><li><a href="https://github.com/borkdude/cljs-showcase">cljs-showcase</a>: Showcase CLJS libs using SCI</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/pod-babashka-lanterna">pod-babashka-lanterna</a>: Interact with clojure-lanterna from babashka</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li></ul><!-- - [tools-deps-native](https://github.com/babashka/tools-deps-native): Run tools.deps as a native binary--><!-- - [tools.bbuild](https://github.com/babashka/tools.bbuild): Library of functions for building Clojure projects--></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/cherry-embed.html</id>
    <link href="https://blog.michielborkent.nl/cherry-embed.html"/>
    <title>Embedding cherry for runtime CLJS compilation</title>
    <updated>2023-03-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><a href="https://github.com/squint-cljs/cherry">Cherry</a> is a new, experimental ClojureScript compiler.  One of the main ideas behind cherry is to reduce friction between ClojureScript and JS tooling. It can be used as a standalone compiler directly as an NPM package without a JVM.</p><p>Since v0.0.1, cherry can be embedded into an existing vanilla CLJS or shadow-cljs project. To facilitate this, cherry exposes the <code>cherry.embed</code> namespace. It contains the following:</p><ul><li><code>preserve-ns</code>: a macro to define a CLJS namespace as globals, so cherry output can access functions after advanced compilation.</li><li><code>eval-form</code>, <code>eval-string</code>, <code>compile-form</code> and <code>compile-string</code> functions to evaluate or compile an s-expr or string</li></ul><p>An example shadow-cljs project:</p><p><code>deps.edn</code>:</p><pre><code class="language-clojure">{:aliases {:cherry {:extra-deps {io.github.squint-cljs/cherry
                                 {:git/sha &quot;4e948708cb20ab0a1a892c30fe87842a2efcc380&quot;}}}
           :shadow {:extra-deps {thheller/shadow-cljs {:mvn/version &quot;2.22.9&quot;}}
                    :main-opts [&quot;-m&quot; &quot;shadow.cljs.devtools.cli&quot;]}}}
</code></pre><p><code>package.json</code>:</p><pre><code class="language-json">{&quot;type&quot;: &quot;module&quot;}
</code></pre><p><code>shadow-cljs.edn</code></p><pre><code class="language-clojure">{:deps true
 :builds
 {:cli
  {:target :esm
   :runtime :node
   :output-dir &quot;out&quot;
   :modules {:eval {:init-fn my.cherry/init}}
   :build-hooks [(shadow.cljs.build-report/hook
                  {:output-to &quot;report.html&quot;})]}}}

</code></pre><p><code>src/my/cherry.cljs</code>:</p><pre><code class="language-clojure">(ns my.cherry
  (:require [cherry.embed :as cherry]))

(cherry/preserve-ns &apos;cljs.core)
(cherry/preserve-ns &apos;clojure.string)

(defn init []
  (let [[_ expr] (.slice js/process.argv 2)]
    (cherry/eval-string expr)))
</code></pre><p>Note that when you don&apos;t want to &quot;preserve&quot; an entire namespace, you can just <code>(defn ^:export foo [])</code> a function or value in your CLJS namespace.</p><p>When compiling this with <code>clojure -M:cherry:shadow release cli</code>, we get a single <code>out/eval.js</code> file of about 550kb of which roughly 330kb comes from preserving the <code>cljs.core</code> namespace.</p><p>We can invoke it with:</p><pre><code class="language-shell">$ node out/eval.js -e &apos;(do (prn :hello) (js/console.log (clojure.string/join , [1 2 3])))&apos;
:hello
123
</code></pre><p>Note that you can enable <code>eval</code> in your CLJS/shadow app with:</p><pre><code class="language-clojure">(set! *eval* cherry/eval-form)
</code></pre><p>Full example:</p><pre><code class="language-clojure">(ns my-shadow.app
  (:require [cherry.embed :as cherry]))

(cherry/preserve-ns &apos;cljs.core)

(set! *eval* cherry/eval-form)

(def x (eval &apos;(+ 1 2 3)))
</code></pre><p>Since cherry is a compiler, the code generally runs faster than with <a href="https://github.com/babashka/sci">SCI</a> which is an interpreter. For many cases SCI is fast enough, but numerical computations in a hot loop isn&apos;t one of its strenghts:</p><pre><code class="language-shell">$ npx nbb@latest -e &apos;(time (print (loop [i 0 j 10000000] (if (zero? j) i (recur (inc i) (dec j))))))&apos;
10000000
&quot;Elapsed time: 566.194958 msecs&quot;
</code></pre><p>With cherry:</p><pre><code class="language-shell">$ node out/eval.js -e &apos;(time (print (loop [i 0 j 10000000] (if (zero? j) i (recur (inc i) (dec j))))))&apos;
10000000
&quot;Elapsed time: 8.812375 msecs&quot;
</code></pre><p>The execution time is similar to self-hosted ClojureScript:</p><pre><code class="language-shell">$ plk -e &apos;(time (print (loop [i 0 j 10000000] (if (zero? j) i (recur (inc i) (dec j))))))&apos;
10000000&quot;Elapsed time: 9.894542 msecs&quot;
</code></pre><p>Cherry is still experimental and looking for feedback. Please try it out and join the Clojurians Slack channel for discussion.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-feb-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-feb-2023.html"/>
    <title>OSS updates February 2023</title>
    <updated>2023-03-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during February 2023.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.patreon.com/borkdude">Patreon</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><blockquote><p><strong>Attention</strong> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/260px-Warning.svg.png" width="20px"></p></blockquote><blockquote><p>If you are using Github Sponsors and are making payments via Paypal, please update to a creditcard since Github Sponsors won&apos;t support Paypal from February 23rd 2023. Read their statement <a href="https://github.blog/changelog/2023-01-23-github-sponsors-will-stop-supporting-paypal/">here</a>. If you are not able to pay via a creditcard, you can still sponsor me via one of the ways mentioned above.</p></blockquote><p>On to the projects that I&apos;ve been working on!</p><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

--><h2 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h2><p>Native, fast starting Clojure interpreter for scripting</p><p>New release: 1.2.174</p><p>Highlights:</p><ul><li>Use GraalVM 22.3.1 on JDK 19.0.2. This adds virtual thread support. See <a href="https://twitter.com/borkdude/status/1572222344684531717">demo</a>.</li><li>Add more <code>java.time</code> and related classes with the goal of supporting <a href="https://github.com/juxt/tick">juxt.tick</a> (<a href="https://github.com/juxt/tick/issues/86">issue</a>)</li></ul><p>See the complete <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">CHANGELOG</a>.</p><h3 id="babashka-compatibility-in-external-libs">Babashka compatibility in external libs</h3><p>I worked together with the maintainers of the following libraries to make them compatible with babashka:</p><ul><li><a href="https://github.com/lambdaisland/kaocha">kaocha</a>: test runner</li><li><a href="https://github.com/greglook/clj-multiformats">multiformats</a>: Clojure(Script) implementations of the self-describing multiformat specs</li></ul><h2 id="http-client:-babashka&apos;s-http-client"><a href="https://github.com/babashka/http-client">Http-client</a>: Babashka&apos;s http-client</h2><p>The <code>babashka.http-client</code> namespace mostly replaces <a href="https://github.com/babashka/babashka.curl">babashka.curl</a>.</p><p>This month support for <code>:multipart</code> uploads was added, mostly based on and inspired by <a href="https://github.com/gnarroway/hato">hato</a>&apos;s implementation.</p><h2 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h2><p>Static analyzer and linter for Clojure code that sparks joy</p><p>New release: 2023.02.17</p><p>Some highlights:</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1976">#1976</a>: warn about using multiple bindings after varargs (<code>&amp;</code>) symbol in fn syntax</li><li>Add arity checks for core <code>def</code></li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1954">#1954</a>: new <code>:uninitialized-var</code> linter. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#uninitialized-var">docs</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1996">#1996</a>: expose <code>hooks-api/resolve</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/hooks.md#api">docs</a>.</li></ul><p><a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Check the
changelog</a> for details.</p><h2 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h2><p>Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</p><p>This month:</p><ul><li>Adding JS libraries to a SCI context. See <a href="https://github.com/babashka/sci#javascript-libraries">docs</a></li><li>Keyword arguments as map support for CLJS</li><li>Making loading of libraries thread-safe in JVM</li><li>Several fixes with respect to <code>deftype</code> and <code>toString</code> + <code>equals</code></li></ul><h2 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h2><p>File system utility library for Clojure</p><p>Highlights:</p><ul><li>several <code>xdg-*-home</code> helper functions, contributed by <a href="https://github.com/eval">@eval</a></li><li><code>babashka.fs/zip</code>  now takes a <code>:root</code> option to elide a parent folder or folders. E.g. <code>(fs/zip &quot;src&quot; {:root &quot;src&quot;})</code> will zip <code>src/foo.clj</code> into the zip file under <code>foo.clj</code>.</li></ul><p>See <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#changelog">changelog</a> for more details.</p><h2 id="process"><a href="https://github.com/babashka/process">Process</a></h2><p>Clojure library for shelling out / spawning sub-processes</p><p>This month I looked into wrapping output of processes with a prefix so when ran in parallel, you can easily distuingish them. A preliminary solution is in <a href="https://github.com/babashka/process/discussions/102#discussioncomment-4903758">this thread</a>.</p><h2 id="pod-babashka-lanterna"><a href="https://github.com/babashka/pod-babashka-lanterna">Pod-babashka-lanterna</a></h2><p>Interact with clojure-lanterna from babashka</p><p>A very experimental 0.0.1 release was published.</p><p>You can try it out by playing tetris in the console with babashka:</p><pre><code class="language-clojure">bb -Sdeps &apos;{:deps {io.github.borkdude/console-tetris {:git/sha &quot;2d3bee34ea93c84608c7cc5994ae70480b2df54c&quot;}}}&apos; -m tetris.core
</code></pre><h2 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h2><p>Scripting in Clojure on Node.js using SCI</p><p>Finally nbb has gotten support for passing maps to keyword argument functions:</p><pre><code class="language-clojure">(defn foo [&amp; {:keys [a b c]}])
(foo :a 1 :b 2 :c 3)
(foo {:a 1 :b 2 :c 3})
</code></pre><p>Several other improvements have been made in the area of macros and resolving JS library references and resolving dependencies in an <code>nbb.edn</code> file, relative to an invoked script which is not in the current directory.</p><p>See changelogs <a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">here</a>.</p><h2 id="joyride"><a href="https://github.com/BetterThanTomorrow/joyride">Joyride</a></h2><p>VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</p><p>This month I contributed a built-in version of <a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a> to joyride, so joyriders can rewrite their code from within VSCode.</p><h2 id="cljs-showcase"><a href="https://github.com/borkdude/cljs-showcase">Cljs-showcase</a></h2><p>Showcase CLJS libs using SCI</p><p>A little project to show how you can use SCI to showcare your CLJS library in an interactive way.</p><h2 id="brief-mentions">Brief mentions</h2><p>The following projects also got updates, mostly in the form of maintenance and performance improvements. This post would get too long if I had to go into detail about them, so I&apos;ll briefly mention them in random order:</p><ul><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/borkdude/quickdoc">quickdoc</a>: Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>: Rewrite Clojure code and edn</li><li><a href="https://github.com/babashka/babashka-sql-pods">sql pods</a>: babashka pods for SQL databases</li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</li></ul><h2 id="other-projects">Other projects</h2><p>These are some of the other projects I&apos;m involved with but little to no activity happened in the past month.</p><ul><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</li><li><a href="https://github.com/borkdude/edamame">edamame</a>: Configurable EDN/Clojure parser with location metadata</li><li><a href="https://github.com/squint-cljs/cherry">cherry</a>: Experimental ClojureScript to ES6 module compiler</li><li><a href="https://github.com/borkdude/grasp">grasp</a>: Grep Clojure code using clojure.spec regexes</li><li><a href="https://github.com/borkdude/jet">jet</a>: CLI to transform between JSON, EDN, YAML and Transit using Clojure</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: leiningen to deps.edn converter</li><li><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a> - Pure CLJS version of 4clojure, meant to run forever!</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a></li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li></ul><!-- - [tools-deps-native](https://github.com/babashka/tools-deps-native): Run tools.deps as a native binary--><!-- - [tools.bbuild](https://github.com/babashka/tools.bbuild): Library of functions for building Clojure projects--></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-news-jan-2023.html</id>
    <link href="https://blog.michielborkent.nl/babashka-news-jan-2023.html"/>
    <title>Babashka news of January 2023</title>
    <updated>2023-02-05T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>If you want to help me keep track of babashka-related news, please contribute to <a href="https://github.com/babashka/babashka/blob/master/doc/news.md">news.md</a> or use the <code>#babashka</code> hashtag on <a href="https://twitter.com/search?q=%28%23babashka%20OR%20babashka%28&amp;src=typed_query&amp;f=live">Twitter</a> or <a href="https://mastodon.social/tags/babashka">Mastodon</a>.</p><h3 id="releases">Releases</h3><p>New releases in the past month: 1.0.170 - 1.1.173 Release highlights:</p><ul><li>Support for <code>data_readers.clj(c)</code></li><li>Include <a href="https://github.com/babashka/http-client">http-client</a> as built-in library</li><li>Compatibility with <a href="https://github.com/clojure/tools.namespace">clojure.tools.namespace.repl/refresh</a></li><li>Compatibility with <a href="https://github.com/clojure/java.classpath">clojure.java.classpath</a> (and other libraries which rely on <code>java.class.path</code> and <code>RT/baseLoader</code>)</li><li>Compatibility with <a href="https://github.com/weavejester/eftest">eftest</a> test runner (see demo)</li><li>Compatibility with <a href="https://github.com/weavejester/cljfmt">cljfmt</a></li><li>Support for <code>*loaded-libs*</code> and <code>(loaded-libs)</code></li><li>Support <code>add-watch</code> on vars (which adds compatibility with <code>potemkin.namespaces</code>)</li><li>BREAKING: make printing of script results explicit with <code>--prn</code></li></ul><h3 id="events">Events</h3><ul><li><a href="https://clojure.stream/workshops/babashka">Babashka Workshop</a> at ClojureStream with Rahul De</li><li><a href="https://www.meetup.com/sthlm-clj/events/291204199/?utm_medium=referral&amp;utm_campaign=share-btn_savedevents_share_modal&amp;utm_source=twitter">Blambda! The sound of Babashka and Lambda colliding</a>: sthlm.clj (Stockholm, Sweden)</li></ul><h3 id="articles">Articles</h3><p>One new book this month:</p><ul><li><a href="https://www.braveclojure.com/quests/babooka/">Babooka: write command line Clojure</a> by Daniel Higginbotham</li></ul><p>and several blog posts:</p><ul><li><a href="https://jmglov.net/blog/2023-01-04-blambda-analyses-sites.html">Blambda analyses sites</a> by Josh Glover</li><li><a href="https://logico-jp.io/2023/01/07/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure/">Babashka: How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure</a> in Japanese</li><li><a href="https://www.gethop.dev/post/the-wizard-of-hop-how-we-built-the-web-based-hop-cli-settings-editor-using-babashka-and-scittle">The wizard of HOP - How we built the web based HOP CLI Settings Editor using Babashka and Scittle</a> by Bingen Galartza</li><li><a href="https://rattlin.blog/bbgum.html">Simple TUIs with Babashka and Gum</a> by Rattlin.blog</li><li><a href="https://www.pixelated-noise.com/blog/2023/01/20/bb-dialog-announcement/index.html">Babashka And Dialog Part Ii: Announcing The Bb-Dialog Library</a> by A.C. Danvers</li><li><a href="https://tech.toryanderson.com/2023/01/14/re-writing-a-globalprotect-openconnect-vpn-connect-script-in-babashka/">Re-Writing a GlobalProtect OpenConnect VPN Connect script in Babashka</a> by Tory Anderson</li></ul><h3 id="projects">Projects</h3><p>Projects that were new, had updates or were made compatible with babashka:</p><ul><li><a href="https://github.com/pitch-io/asdf-babashka">asdf-babashka</a>: babashka plugin for the asdf version manager</li><li><a href="https://github.com/prestancedesign/babashka-htmx-todoapp">babashka-htmx-todoapp</a>: Quick example of a todo list SPA using Babashka and HTMX</li><li><a href="https://github.com/lispyclouds/bblgum">bblgum</a>: An extremely tiny and simple wrapper around charmbracelet/gum</li><li><a href="https://github.com/pixelated-noise/bb-dialog">bb-dialog</a>: A simple wrapper library for working with dialog from Babashka</li><li><a href="https://github.com/borkdude/carve">carve</a>: Remove unused Clojure vars</li><li><a href="https://github.com/ThaddeusJiang/chr">chr</a>: native commands history report for the default terminal users</li><li><a href="https://github.com/clj-kondo/clj-kondo-bb">clj-kondo-bb</a>: Invoke clj-kondo from babashka scripts!</li><li><a href="https://github.com/weavejester/cljfmt">cljfmt</a>: A tool for formatting Clojure code</li><li><a href="https://github.com/claytn/drepl">drepl</a>: Node JS dependency-repl. The node repl you already know with easy library installations</li><li><a href="https://github.com/babashka/instaparse-bb">instaparse-bb</a>: Wrapper library aroud pod-babashka-instaparse</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: Lein project.clj to deps.edn converter</li><li><a href="https://github.com/babashka/neil">neil</a>: A CLI to add common aliases and features to deps.edn-based projects</li><li><a href="https://github.com/filipesilva/obsidian-babashka">obsidian-babashka</a>: Run Obsidian Clojure(Script) codeblocks in Babashka</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure)</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/adam-james-v/solenoid">solenoid</a>: A small clojure tool for making little control UIs while using the REPL!</li><li><a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: babashka version of tools.build</li><li><a href="https://gist.github.com/yogthos/f86e63b856e1413180b2262024ece977">weather</a>: command line util for grabbing current weather for a city using OpenWeather API</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jan-2023.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jan-2023.html"/>
    <title>OSS updates of January 2023</title>
    <updated>2023-02-05T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during January 2023.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li>The <a href="https://opencollective.com/babashka">Babaska</a> or <a href="https://opencollective.com/clj-kondo">Clj-kondo</a> OpenCollective</li><li><a href="https://ko-fi.com/borkdude">Ko-fi</a></li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><p>If you&apos;re used to sponsoring through some other means which isn&apos;t listed above, please get in touch.</p><blockquote><p><strong>Attention</strong> <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/260px-Warning.svg.png" width="20px"></p></blockquote><blockquote><p>If you are using Github Sponsors and are making payments via Paypal, please update to a creditcard since Github Sponsors won&apos;t support Paypal from February 23rd 2023. Read their statement <a href="https://github.blog/changelog/2023-01-23-github-sponsors-will-stop-supporting-paypal/">here</a>. If you are not able to pay via a creditcard, you can still sponsor me via one of the ways mentioned above.</p></blockquote><h2 id="projects">Projects</h2><!--

sources: https://github.com/borkdude
local ~/dev and ~/dev/babashka dir (since github doesn't show all repos)

- quickblog*
- babashka *
- babashka/pod-babashka-instaparse 31 commits *
- instaparse.bb *
- nbb *
- http-client *
- neil *
- clj-kondo / clj-kondo-bb / lein clj-kondo *
- edamame *
- https://github.com/borkdude/jna-native-image-sci *
- carve *
- jet *
- deps.clj *
- 4ever-clojure *
- joyride *
- squint / cherry *
- tools-deps-native / tools.bbuild *
- scittle *
- lein2deps *
- pod-babashka-buddy *
- edamame *
- nbb *
- babashka.cli *
- fs *
- process *
- deps.clj *
- sci *

--><h3 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h3><p>Native, fast starting Clojure interpreter for scripting.</p><p>New releases in the past month: 1.0.170 - 1.1.173 Highlights:</p><ul><li>Support for <code>data_readers.clj(c)</code></li><li>Include <a href="https://github.com/babashka/http-client">http-client</a> as built-in library</li><li>Compatibility with <a href="https://github.com/clojure/tools.namespace">clojure.tools.namespace.repl/refresh</a></li><li>Compatibility with <a href="https://github.com/clojure/java.classpath">clojure.java.classpath</a> (and other libraries which rely on <code>java.class.path</code> and <code>RT/baseLoader</code>)</li><li>Compatibility with <a href="https://github.com/weavejester/eftest">eftest</a> test runner (see demo)</li><li>Compatibility with <a href="https://github.com/weavejester/cljfmt">cljfmt</a></li><li>Support for <code>*loaded-libs*</code> and <code>(loaded-libs)</code></li><li>Support <code>add-watch</code> on vars (which adds compatibility with <code>potemkin.namespaces</code>)</li><li>BREAKING: make printing of script results explicit with <code>--prn</code></li></ul><h4 id="babashka-compatibility-in-external-libs">Babashka compatibility in external libs</h4><p>I contributed changes to the following libraries to make them compatible with babashka:</p><ul><li><a href="https://github.com/weavejester/cljfmt">cljfmt</a> - A tool for formatting Clojure code</li><li><a href="https://github.com/borkdude/carve">carve</a> - Remove unused Clojure vars</li><li><a href="https://github.com/philoskim/debux">debux</a> - A trace-based debugging library for Clojure and ClojureScript</li></ul><p>Check the <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">changelog</a> for all the changes!</p><h3 id="http-client"><a href="https://github.com/babashka/http-client">Http-client</a></h3><p>The new babashka http-client project mostly replaces <a href="https://github.com/babashka/babashka.curl">babashka.curl</a>.</p><p>This month the default client was improved to accept <code>gzip</code> and <code>deflate</code> as encodings by default, reflecting what <code>babashka.curl</code> did.</p><p>Also <code>babashka.http-client</code> is now available as a built-in namespace in <code>babashka</code> v1.1.171 and higher.</p><h3 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h3><p>Static analyzer and linter for Clojure code that sparks joy</p><p>Three new releases with many fixes and improvements in the last month. <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Check the
changelog</a> for details.</p><p>Some highlights:</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1742">#1742</a>: new linter <code>:aliased-namespace-var-usage</code>: warn on var usage from namespaces that were used with <code>:as-alias</code>. See <a href="https://twitter.com/borkdude/status/1613524896625340417/photo/1">demo</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1926">#1926</a>: Add keyword analysis for EDN files. This means you can find references for keywords throughout your project with clojure-lsp, now including in EDN files.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1902">#1902</a>: provide <code>:symbols</code> analysis for navigation to symbols in quoted forms or EDN files. See <a href="https://twitter.com/borkdude/status/1612773780589355008">demo</a>.</li></ul><p>The symbol analysis is used from clojure-lsp for which I provided a patch <a href="https://github.com/borkdude/clojure-lsp/commit/f662adab1b17d5dbc3648d6d8208334dc920aa0e">here</a>.</p><p>A new project around clj-kondo is <a href="https://github.com/clj-kondo/clj-kondo-bb">clj-kondo-bb</a> which enables you to use clj-kondo from babashka scripts.</p><p>Also <a href="https://github.com/clj-kondo/lein-clj-kondo">lein-clj-kondo</a> got an update.</p><h3 id="instaparse-bb"><a href="https://github.com/babashka/instaparse-bb">Instaparse-bb</a></h3><p>This is a new project and gives you access to a subset of <a href="https://github.com/Engelberg/instaparse">instaparse</a> via a <a href="https://github.com/babashka/pod-babashka-instaparse">pod</a>.</p><p>Instaparse was request a few times to have as a library in babashka and instaparse-bb is a good first step, without making a decision on that yet. See the relevant discussion <a href="https://github.com/babashka/babashka/discussions/1335">here</a>.</p><h3 id="carve"><a href="https://github.com/borkdude/carve">Carve</a></h3><p>Remove unused Clojure vars</p><p>In the <a href="https://github.com/borkdude/carve/blob/master/CHANGELOG.md#035">0.3.5</a> version, Carve got the following updates:</p><ul><li>Upgrade clj-kondo version</li><li>Make babashka compatible by using the <a href="https://github.com/clj-kondo/clj-kondo-bb">clj-kondo-bb</a> library</li><li>Discontinue the <code>carve</code> binary in favor of invocation with babashka. Instead you can now install carve with <a href="https://github.com/babashka/bbin">bbin</a>:<pre><code>bbin install io.github.borkdude/carve
</code></pre></li><li>Implement <a href="https://github.com/babashka/cli">babashka.cli</a> integration</li><li>Implement <code>--help</code></li></ul><h3 id="jet"><a href="https://github.com/borkdude/jet">Jet</a></h3><p>CLI to transform between JSON, EDN, YAML and Transit using Clojure</p><p>Version <code>0.4.23</code>:</p><ul><li><a href="https://github.com/borkdude/jet/issues/123">#123</a>: Add <code>base64/encode</code> and <code>base64/decode</code></li><li>Add <code>jet/paths</code> and <code>jet/when-pred</code></li><li>Deprecate interactive mode</li><li>Deprecate <code>--query</code> in favor of <code>--thread-last</code>, <code>--thread-first</code> or <code>--func</code></li></ul><h3 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h3><p>File system utility library for Clojure.</p><p>Fs has gotten a few new functions:</p><ul><li><code>unifixy</code>, to turn a Windows path into a path with Unix-style path separators. Note that that style is supported by the JVM and this offers a more reliable way to e.g. match filenames via regexes.</li><li>several <code>xdg-*-home</code> helper functions, contributed by <a href="https://github.com/eval">@eval</a></li></ul><p>See <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#changelog">changelog</a> for more details.</p><h3 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h3><p>A CLI to add common aliases and features to <code>deps.edn</code>-based projects.</p><p>This month there were several small fixes, one of them being to always pick stable versions when adding or upgrading libraries. See full <a href="https://github.com/babashka/neil/blob/main/CHANGELOG.md">changelog</a> for details.</p><h3 id="quickblog"><a href="https://github.com/borkdude/quickblog">Quickblog</a></h3><p>Light-weight static blog engine for Clojure and babashka.</p><p>The blog you&apos;re currently reading is made with quickblog.</p><p>Version <a href="https://github.com/borkdude/quickblog/blob/main/CHANGELOG.md#023-2023-01-30">0.2.3</a> was released with contributions from several people, mostly enabling you to tweak your own blog even more, while having good defaults.</p><p>Instances of quickblog can be seen here:</p><ul><li><a href="https://blog.michielborkent.nl">Michiel Borkent&apos;s blog</a></li><li><a href="https://jmglov.net/blog">Josh Glover&apos;s blog</a></li><li><a href="https://jdt.me/strange-reflections.html">Jeremy Taylor&apos;s blog</a></li><li><a href="https://blog.cofx.nl/">Luc Engelen&apos;s blog</a> (<a href="https://github.com/cofx22/blog">source</a>)</li><li><a href="https://rattlin.blog/">Rattlin.blog</a></li></ul><p>If you are also using quickblog, please let me know!</p><p>A collection of ready to be used SCI configs for e.g. Reagent, Promesa, Re-frame and other projects that are used in nbb, joyride, scittle, etc.  See recent <a href="https://github.com/babashka/sci.configs/commits/main">commits</a> for what&apos;s been improved.</p><h3 id="edamame"><a href="https://github.com/borkdude/edamame">Edamame</a></h3><p>Edamame got a new function: <code>parse-next+string</code> which returns the original string along with the parsed s-expression.</p><h3 id="lein2deps"><a href="https://github.com/borkdude/lein2deps">lein2deps</a></h3><p>Lein to deps.edn converter</p><p>This tool can convert a <code>project.edn</code> file to a <code>deps.edn</code> file. It even supports Java compilation and evaluation of code within <code>project.clj</code>. There is now a lein plugin which enables you to sync your <code>project.clj</code> with your <code>deps.edn</code> every time you start <code>lein</code>. Several other minor enhancements were made.  See <a href="https://github.com/borkdude/lein2deps/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="4ever-clojure"><a href="https://github.com/oxalorg/4ever-clojure">4ever-clojure</a></h3><p>I added the ability to build and deploy 4ever-clojure to Github Actions. Every time a commit is merged, the site is automatically updated.</p><h3 id="brief-mentions">Brief mentions</h3><p>The following projects also got updates, mostly in the form of maintenance and performance improvements. This post would get too long if I had to go into detail about them, so I&apos;ll briefly mention them in random order:</p><ul><li><a href="https://github.com/borkdude/jna-native-image-sci">jna-native-image-sci</a>: Compile a program that uses JNA to native-image and allow dynamic evaluation using <a href="https://github.com/babashka/sci">SCI</a>!</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a>: A faithful port of the clojure CLI bash script to Clojure</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>: VSCode CLJS scripting and REPL (via <a href="https://github.com/babashka/sci">SCI</a>)</li><li><a href="https://github.com/squint-cljs/squint">squint</a>: CLJS <em>syntax</em> to JS compiler</li><li><a href="https://github.com/babashka/tools-deps-native">tools-deps-native</a>: Run tools.deps as a native binary</li><li><a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>: Library of functions for building Clojure projects</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/pod-babashka-buddy">pod-babashka-buddy</a>: A pod around buddy core (Cryptographic Api for Clojure).</li><li><a href="https://github.com/babashka/nbb">nbb</a>: Scripting in Clojure on Node.js using SCI</li><li><a href="https://github.com/babashka/cli">CLI</a>: Turn Clojure functions into CLIs!</li><li><a href="https://github.com/babashka/process">process</a>: Clojure library for shelling out / spawning sub-processes</li><li><a href="https://github.com/babashka/sci">SCI</a>: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs</li><li><a href="https://github.com/babashka/scittle">scittle</a>: Execute Clojure(Script) directly from browser script tags via SCI</li><li><a href="https://github.com/babashka/sci.configs">sci.configs</a>: A collection of ready to be used SCI configs</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-news-2022.html</id>
    <link href="https://blog.michielborkent.nl/babashka-news-2022.html"/>
    <title>Babashka news in 2022</title>
    <updated>2023-01-06T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>This is an overview of all the news collected about babashka in 2022! It is a collection of links to scripts, libraries, blog posts, talks and tweets about babashka. If you want to help me keep track of babashka-related news, please contribute to <a href="https://github.com/babashka/babashka/blob/master/doc/news.md">news.md</a>.</p><h2 id="2022-12"><a href="https://twitter.com/search?q=%28%23babashka%20OR%20babashka%29%20until%3A2023-01-01%20since%3A2022-12-01&amp;src=typed_query&amp;f=live">2022-12</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">1.0.168</a>.</li><li><a href="https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746">How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure</a></li><li><a href="https://github.com/babashka/http-client">http-client</a>: a new HTTP client library for babashka</li><li><a href="https://presumably.de/how-to-do-things-with-babashka.html">How to Do Things With Babashka</a> by Paulus Esterhazy (2022-12)</li><li><a href="https://www.karimarttila.fi/clojure/2022/12/04/using-babashka-to-get-electricity-prices">Using Babashka to Get Electricity Prices</a> by Kari Marttila</li><li><a href="https://www.pixelated-noise.com/blog/2022/12/09/dialog-and-babashka/index.html">Adding prompts to your babashka scripts with dialog</a> by A.C. Danvers</li><li><a href="https://blog.exupero.org/scraping-an-html-dictionary-with-babashka-and-bootleg/">Scraping an HTML dictionary with Babashka and Bootleg</a> by exupero</li><li><a href="https://github.com/borkdude/quickblog">quickblog</a> v0.1.0: Light-weight static blog engine for Clojure and babashka</li><li><a href="https://github.com/kbosompem/bb-excel">bb-excel</a>: Read Excel Files in babashka scripts</li><li><a href="https://gist.github.com/MrGung/29d0547fe45316c3438032fd164d42c6">Get paginated list of issues from gitlab with clojure/babashka</a> by Steffen Glückselig</li><li>Install development builds: <code>bash &lt;(curl https://raw.githubusercontent.com/babashka/babashka/master/install) --dev-build --dir /tmp</code></li><li><a href="https://twitter.com/borkdude/status/1606280110692352001">JVM interop improvements in bb</a></li><li><a href="https://twitter.com/borkdude/status/1599067149187764224">A little trick to have conditional code for babashka in a .clj file without resorting to .cljc reader conditionals</a></li><li><a href="https://gist.github.com/jeeger/6e39fea94ce49e33d1fa43f40cc36630">Get Advent of Code input in babashka</a> by Jan Seeger</li><li><a href="https://gist.github.com/yogthos/f86e63b856e1413180b2262024ece977">Grabbing current weather for a city using OpenWeather API</a> by Dmitri Sotnikov</li></ul><h2 id="2022-11"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-12-01%20since%3A2022-11-01&amp;src=typed_query&amp;f=live">2022-11</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">1.0.165 - 1.0.167</a>.</li><li>Registration for a <a href="https://clojure.stream/workshops/babashka">Babashka workshop</a> with Rahul De at ClojureStream is now open!</li><li><a href="https://github.com/eerohele/Tutkain">Tutkain, a Sublime plugin for clojure based on socket REPL now with support for babashka</a></li><li><a href="https://blaster.ai/blog/posts/manage-git-hooks-w-babashka.html">Manage git hooks in babashka</a> by Mykhaylo Bilyanskyy</li><li>[Messing around with babashka](Messing around with Babashka) by Ian Muge</li><li><a href="https://twitter.com/borkdude/status/1597505695800516609">A babashka one liner to inspect data in portal</a></li><li><a href="https://yogthos.net/posts/2022-11-26-nREPL-system-interaction.html">Using nREPL as a system interface</a> by Dmitri Sotnikov</li><li><a href="https://github.com/lambdaisland/deep-diff2">deep-diff2</a> is now babashka-compatible!</li><li><a href="https://github.com/babashka/babashka/blob/master/examples/normalize-keywords.clj">A script to normalize auto-resolved keywords</a></li><li><a href="https://gist.github.com/jeeger/d13159fefaee33c771be979639900ebc">Sum up page counts of books from Calibre library with babashka</a> by Jan Seeger</li><li><a href="https://gist.github.com/CarnunMP/c592cd3b6e711d56ddd4ca7832b9b251">Tiny babashka script that returns a random clojure doc</a> by Carnun Marcus-Page</li></ul><h2 id="2022-10"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-11-01%20since%3A2022-10-01&amp;src=typed_query&amp;f=live">2022-10</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">1.0.164</a>.</li><li><a href="https://github.com/justone/bb-pod-racer">bb-pod-racer</a>: Speed up development of Babashka pods by Nate Jones</li><li><a href="https://marketplace.visualstudio.com/items?itemName=fbeyer.babashka-tasks">Babashka tasks VSCode plugin</a> by Ferdinand Beyer</li><li>A <a href="https://github.com/nextjournal/clerk/pull/232">PR</a> to get Clerk working in babashka</li><li><a href="https://github.com/borkdude/lein2deps">lein2deps</a>: lein to deps.edn converter</li><li><a href="https://github.com/grzm/awyeah-api">awyeah-api</a> by Michael Glaesemann v0.8.41 is now available! aws-api for Babashka. Aw yeah!</li><li><a href="https://github.com/epiccastle/bbssh/releases/tag/v0.2.0">bbssh</a> by Crispin Wellington, v0.2.0 released</li><li><a href="https://gist.github.com/stelcodes/ddc8ff53de2192dca7d3fee1081ddb77">safely use rsync --archive --delete to backup a directory</a> by Stel Abrego</li></ul><h2 id="2022-09"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-10-01%20since%3A2022-09-01&amp;src=typed_query&amp;f=live">2022-09</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.9.162 - 0.10.163</a>.</li><li>Introducing <a href="https://radsmith.com/bbin">bbin</a>: a tool to install babashka scripts on your system by Radford Smith</li><li><a href="https://github.com/epiccastle/bbssh">bbssh</a>: Babashka pod for SSH support by <a href="https://github.com/epiccastle">Epic Castle</a></li><li><a href="https://twitter.com/borkdude/status/1572222344684531717">Loom virtual threads are coming to babashka</a></li><li><a href="https://gist.github.com/stelcodes/7d9136a5839b645b6cd5bc829a9fe541">Tiny script to cycle through pulseaudio outputs (aka sinks)</a> by Stel Abrego</li><li><a href="https://twitter.com/borkdude/status/1569351199404576770">Tetris in the console via pod-babashka-lantera</a></li><li><a href="https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=764642f55b7a9821acbabcfa1e2d354afab99be7">org-mode gets support for babashka</a></li><li><a href="https://github.com/babashka/process#promesa">docs for combining babashka process with promesa</a> <a href="https://github.com/exoscale/interceptor">exoscale/interceptor</a> became babashka-compatible!</li><li><a href="https://twitter.com/borkdude/status/1568315151404924933">Tutkain, socket REPL Sublime plugin, gets better support for babashka</a></li><li><a href="https://github.com/davclark/babashka-tweepy">babashka tweepy</a>: kicking the tires on using the tweepy library from a babashka task by Dav Clark</li><li><a href="https://github.com/jjcomer/aoc-helper">aoc helper</a> by Josh Comer</li><li><a href="https://jmglov.net/blog/2022-09-02-dogfooding-blambda-logs.html">Dogfooding blambda part 5</a> by Josh Glover</li></ul><h2 id="2022-08"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-09-01%20since%3A2022-08-01&amp;src=typed_query&amp;f=live">2022-08</a></h2><ul><li>It&apos;s babashka&apos;s third birthday on August 9th 2022!</li><li><a href="https://github.com/clj-commons/etaoin">etaoin</a>, Pure Clojure Webdriver protocol implementation, is now babashka-compatible!</li><li><a href="https://github.com/cgrand/xforms">xforms</a> is now babashka-compatible!</li><li><a href="https://github.com/squint-cljs/squint">squint</a> and <a href="https://github.com/squint-cljs/cherry">cherry</a> are CLJS-compilers that work with babashka!</li></ul><h2 id="2022-07"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-08-01%20since%3A2022-07-01&amp;src=typed_query&amp;f=live">2022-07</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.8.157 - 0.9.161</a>.</li><li><a href="https://play.teod.eu/document-transform-pandoc-clojure/">Recursive document transformations with Pandoc and Clojure</a> by Teodor Heggelund</li><li><a href="https://babashka.org/toolbox/">Babashka toolbox</a>: A categorised directory of libraries and tools for Babashka</li><li><a href="https://github.com/borkdude/quickblog">Quickblog</a>: Light-weight static blog engine for Clojure and babashka</li><li>Win a babashka t-shirt by participating in <a href="https://twitter.com/borkdude/status/1547847843381030912">this</a> contest!</li><li><a href="https://www.juxt.pro/blog/nbb-lambda">AWS Lambda, now with first class parentheses</a> by Ray McDermott (about nbb)</li><li><a href="https://github.com/brandonstubbs/bb-github-app">bb-github-app</a>: An example Babashka Script authenticating as a Github App and interacting with the Checks API</li><li><a href="https://github.com/askonomm/ruuter#setting-up-with-babashka">Ruuter</a> is a routing library which works very well with bb</li><li><a href="https://jmglov.net/blog/2022-07-03-blambda.html">Blambda!</a> by Josh Glover</li><li>Files with the <code>.bb</code> extension are now correctly highlighted as Clojure code on Github! See <a href="https://twitter.com/borkdude/status/1543937735429431298">this</a> tweet.</li><li>Encode and decode files as kroki url diagrams, a <a href="https://gist.github.com/henryw374/070845dbd8cfb4672a3c0d06cf8b00e4">gist</a> by Henry Widd</li><li>Customized bb builds with clj-nix: <a href="https://twitter.com/jlesquembre/status/1543686641461694470">tweet</a></li><li>Expose Clojure functions in the CLI with babashka and nix: <a href="https://twitter.com/jlesquembre/status/1546777332471455745">tweet</a></li><li><a href="https://github.com/noprompt/meander">Meander</a> is now compatible with bb: <a href="https://twitter.com/borkdude/status/1542881167338250242">tweet</a></li><li><a href="https://javahippie.net/clojure/2022/07/23/deleting-aws-glacier-vaults-with-babashka.html">Deleting AWS Glacier vaults with babashka</a> by Tim Zöller</li></ul><h2 id="2022-06"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-07-01%20since%3A2022-06-01&amp;src=typed_query&amp;f=live">2022-06</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.8.156</a>.</li><li><a href="https://github.com/babashka/babashka/wiki/AWS">AWS wiki page</a></li><li><a href="https://github.com/jmglov/blambda">blambda</a>: Blambda! is a custom runtime for AWS Lambda that lets you write functions using Babashka</li><li><a href="https://blog.michielborkent.nl/babashka-cli.html">Babashka CLI</a>: turn Clojure functions into CLIs!</li><li><a href="https://github.com/babashka/http-server#babashka">Http-server</a>: Serve static assets</li><li><a href="https://github.com/MrGung/deps-bundler">Deps-bundler</a>: Bundle dependencies on a computer that has access to maven and clojars (PC-A) and bring these over to a computer with limited access (PC-L).</li><li><a href="https://github.com/plumatic/schema/blob/master/CHANGELOG.md#130-2022-06-10">Prismatic/schema</a> and babashka are now compatible</li><li><a href="https://github.com/logseq/bb-tasks">Logseq bb tasks</a>: Reusable babashka tasks used by logseq team</li><li>[Breakneck Babashka on K8s](Breakneck Babashka on K8s) by Heow Goodman</li></ul><h2 id="2022-05"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-06-01%20since%3A2022-05-01&amp;src=typed_query&amp;f=live">2022-05</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.8.2</a>.</li><li><a href="https://github.com/clj-commons/etaoin">Etaoin</a> moved to clj-commons and now works with babashka as well.</li><li><a href="https://github.com/babashka/babashka/blob/master/doc/nix.md">Nix docs for babashka</a></li><li><a href="https://github.com/babashka/babashka/tree/master/doc/fly_io">Fly.io docs for babashka</a></li><li><a href="https://blog.michielborkent.nl/babashka-survey-q1-2022.html">Babashka survey results</a></li><li><a href="https://github.com/borkdude/quickdoc">Quickdoc</a>: (Quick and minimal API doc generation for Clojure</li><li><a href="https://github.com/grzm/awyeah-api">Awyeah-api</a> - Cognitect&apos;s aws-api for babashka</li></ul><h2 id="2022-04"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-05-01%20since%3A2022-04-01&amp;src=typed_query&amp;f=live">2022-04</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.8.0 - 0.8.1</a>.</li><li><a href="https://youtu.be/ZvOs5Ele6VE">Babashka and Clojure</a> by Rahul Dé at North Virginia Linux Users Group</li><li><a href="https://github.com/DeLaGuardo/setup-clojure/releases/tag/5.0">Setup-Clojure</a> Github action is now able to install babashka!</li><li>Control Chrome via devtools using <a href="https://github.com/tatut/clj-chrome-devtools/blob/master/bb.clj">clj-chrome-devtools</a> which runs with bb!</li><li>Use pods directly in <code>bb.edn</code>: <a href="https://twitter.com/borkdude/status/1510995356229767172">tweet</a></li></ul><h2 id="2022-03"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-04-01%20since%3A2022-03-01&amp;src=typed_query&amp;f=live">2022-03</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.7.7 - 0.7.8</a>.</li><li><a href="https://youtu.be/jm0RXmyjRJ8">Create a password manager with Clojure using Babashka, sqlite, honeysql and stash</a> by Daniel Amber</li><li><a href="https://www.youtube.com/watch?v=bf8KLKkCH2g">Detecting inconsistent aliases in a clojure codebase</a> by Oxalorg</li><li><a href="https://github.com/oxalorg/clj-konmari/">Clj-konmari</a> by Oxalorg</li><li><a href="https://github.com/cldwalker/logseq-query">Logseq-query</a> by Gabriel Horner <a href="https://twitter.com/cldwalker/status/1506991213030871041">(announcement tweet with video)</a></li><li>The <a href="https://github.com/aysylu/loom">loom</a> library is now compatible <a href="https://twitter.com/borkdude/status/1502237220811550723">(tweet)</a></li><li>The <a href="https://github.com/overtone/at-at">at-at</a> library is now compatible</li></ul><h2 id="2022-02"><a href="https://twitter.com/search?q=%28%23babashka%29%20until%3A2022-03-01%20since%3A2022-02-01&amp;src=typed_query&amp;f=live">2022-02</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.7.5 - 0.7.6</a>.</li><li><a href="https://twitter.com/epic_castle/status/1496784352256008194">Spire is available as a babashka pod</a></li><li>Babashka Clojure template on <a href="https://replit.com/@eccentric-j/Babashka-Clojure-Template?v=1#replit.nix">Repl.it</a> by Eccentric J</li><li>Create a self-contained executable with <a href="https://github.com/babashka/babashka/wiki/Self-contained-executable">caxa</a></li><li>Cli-matic is now compatible due to this <a href="https://github.com/l3nz/cli-matic/pull/145">PR</a></li><li><a href="https://dawranliou.com/blog/i-too-wrote-myself-a-static-site-generator/">I, too, Wrote Myself a Static Site Generator</a> by Daw-Ran Liou</li><li><a href="https://github.com/escherize/staplegun">Staplegun</a>: Single file clipboard-manager</li><li><a href="https://github.com/nikvdp/bbb">Bbb</a>: make executable CLI tools from bb scripts</li><li><a href="https://github.com/redstarssystems/apptemplate">Apptemplate</a>: Application project template for Clojure featuring bb tasks</li></ul><h2 id="2022-01"><a href="https://twitter.com/search?f=live&amp;q=%28%23babashka%29%20until%3A2022-02-01%20since%3A2022-01-01&amp;src=typed_query">2022-01</a></h2><ul><li>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">0.7.4</a>.</li><li><a href="https://github.com/babashka/babashka-dev-builds">Babashka dev builds</a></li><li><a href="https://www.loop-code-recur.io/live-clojure-cookbooks/">Writing Clojure-living-cookbooks</a> by Cyprien Pannier</li><li><a href="https://github.com/prestancedesign/babashka-htmx-todoapp">HTMX Todo App</a></li><li><a href="https://twitter.com/borkdude/status/1484100071134220291">Better linting for <code>bb.edn</code></a></li><li><a href="https://github.com/mknoszlig/unwordle">Unwordle</a>: solver for wordle puzzles</li><li><a href="https://blog.michielborkent.nl/using-babashka-with-php.html">Using babashka with PHP</a> by Michiel Borkent</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-nov-dec-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-nov-dec-2022.html"/>
    <title>OSS updates of November - December 2022</title>
    <updated>2023-01-06T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during November and December 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work via the following organizations. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="projects">Projects</h2><h3 id="http-client"><a href="https://github.com/babashka/http-client">http-client</a></h3><p>The new babashka http-client aims to become default HTTP client solution in babashka.</p><p>Babashka has several built-in options for making HTTP requests, including:</p><ul><li><a href="https://github.com/babashka/babashka.curl">babashka.curl</a></li><li><a href="https://github.com/http-kit/http-kit">http-kit</a></li><li><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.net.http/java/net/http/package-summary.html">java.net.http</a></li></ul><p>In addition, it allows to use several libraries to be used as a dependency:</p><ul><li><a href="https://github.com/schmee/java-http-clj">java-http-clj</a></li><li><a href="https://github.com/gnarroway/hato">hato</a></li><li><a href="https://github.com/clj-commons/clj-http-lite">clj-http-lite</a></li></ul><p>The built-in clients come with their own trade-offs. E.g. babashka.curl shells out to <code>curl</code> which on Windows requires your local <code>curl</code> to be updated. Http-kit buffers the entire response in memory. Using <code>java.net.http</code> directly can be a bit verbose.</p><p>Babashka&apos;s http-client aims to be a good default for most scripting use cases and is built on top of <code>java.net.http</code> and can be used as a dependency-free JVM library as well. The API is mostly compatible with babashka.curl so it can be used as a drop-in replacement. The other built-in solutions will not be removed any time soon.</p><h3 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h3><p>Native, fast starting Clojure interpreter for scripting.</p><p>I had the honor to write a guest blog post for the GraalVM blog about babashka. You can read it <a href="https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746">here</a>.</p><p>Daniel Higginbotham from Brave Clojure wrote <a href="https://www.braveclojure.com/quests/babooka/">Babashka
Babooka</a> which I helped reviewing.</p><p>I also wrote a blog on how to <a href="https://blog.michielborkent.nl/babashka-test-runner.html">test babashka scripts</a>.</p><p>Versions 1.0.165 - 1.0.169 were released. Visit the <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">changelog</a> for details. Highlights:</p><ul><li>Compatibility with Cognitest <a href="https://github.com/cognitect-labs/test-runner">test-runner</a> and <a href="https://github.com/clojure/tools.namespace">tools.namespace</a></li><li><a href="https://github.com/babashka/babashka/issues/1433">#1433</a>: spec source as built-in fallback. When not including the <a href="https://github.com/babashka/spec.alpha">clojure.spec.alpha</a> fork as a library, babashka loads a bundled version, when <code>clojure.spec.alpha</code> is required.</li><li>Many performance improvements (via SCI)</li><li>Several non-special forms are now regular macros rather than treated special (via SCI)</li><li>Update to babashka process to v0.4.13: support <code>(process opts? &amp; args)</code> syntax everywhere</li></ul><h3 id="squint-and-cherry"><a href="https://github.com/squint-cljs/squint">Squint</a> and <a href="https://github.com/squint-cljs/cherry">Cherry</a></h3><p>Squint and cherry are two flavors of the same CLJS compiler.</p><p>Squint is a CLJS <em>syntax</em> to JS compiler for use case where you want to write JS, but do it using CLJS syntax and tooling instead.  Cherry comes with the CLJS standard library and is as such much closer to the normal ClojureScript, but the minimal amount of JS is a little bigger.</p><p>The <a href="https://www.youtube.com/watch?v=oCd74TQ-gf4">video</a> of the talk I did on ClojureDays 2022 came online!</p><p>In the past two months, I&apos;ve been restructuring code between squint and cherry: a bit boring but necessary to keep going forward. Along with some minor bugfixes and features, one new JSX feature landed: you can pass a props map using a new notation inspired by <a href="https://github.com/lilactown/helix">helix</a>.</p><p>You can read details in the <a href="https://github.com/squint-cljs/squint/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h3><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>This is the workhorse that powers babashka, nbb, Joyride, and many other projects.</p><p>Many improvements have happened over the last two months, both in Clojure compatibility and performance. JS and JVM interop has become up to 5x faster. All of these changes benefit babashka, nbb, joyride, etc.</p><p>See <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">changelog</a> for more details.</p><h3 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h3><p>Static analyzer and linter for Clojure code that sparks joy</p><p>Two new releases with many fixes and improvements. <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Check the
changelog</a> for details.</p><p>Some highlights:</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/issues/609">#609</a>: typecheck var usage, e.g. <code>(def x :foo) (inc x)</code> will now give a warning</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1846">#1846</a>: new linters: <code>:earmuffed-var-not-dymamic</code> and <code>:dynamic-var-not-earmuffed</code>. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#dynamic-vars">docs</a>.</li><li><a href="https://github.com/clj-kondo/clj-kondo/issues/1875">#1875</a>: add <code>:duplicate-field-name</code> linter for deftype and defrecord definitions.</li></ul><h3 id="scittle"><a href="https://github.com/babashka/scittle">Scittle</a></h3><p>Execute Clojure(Script) directly from browser script tags via SCI. See it in <a href="https://babashka.org/scittle/">action</a>.</p><p>Version 0.4.11 introduced the <a href="https://github.com/day8/re-frame">re-frame</a> plugin.  You can play around with it in the playground <a href="https://babashka.org/scittle/codemirror.html">here</a>.  Several other releases were made. Details in the <a href="https://github.com/babashka/scittle/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="process"><a href="https://github.com/babashka/process">Process</a></h3><p>Clojure library for shelling out / spawning subprocesses</p><p>This library traditionally had the syntax: <code>(process [ &amp; cmd-args ] ?opts)</code> but in practice, it turned out that having the syntax <code>(process ?opts &amp; cmd-args)</code> is more convenient, since you can use it with <code>apply</code> and <code>*command-line-args*</code>. All functions in <code>babashka.process</code> have been rewritten to support this syntax.</p><p>See <a href="https://github.com/babashka/process/blob/master/CHANGELOG.md">changelog</a> for details.</p><h3 id="quickdoc"><a href="https://github.com/borkdude/quickdoc">Quickdoc</a></h3><p>Quickdoc is a tool to generate documentation from namespace/var analysis done by clj-kondo. It&apos;s fast and spits out an <code>API.md</code> file in the root of your project, so you can immediately view it on Github. Minor fixes and improvements were made.</p><h3 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h3><p>File system utility library for Clojure.</p><p>Fs has gotten one new function: <code>update-file</code>, that alters the contents of a (text) file using a function. The function is reminiscent of <code>swap!</code>.</p><p>See <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#changelog">changelog</a> for more details.</p><h3 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h3><p>A CLI to add common aliases and features to <code>deps.edn</code>-based projects.</p><p>A <code>NEIL_GITHUB_TOKEN</code> can now be configured to avoid hitting the rate limit of the Github API, thanks to Russ Matney.</p><h3 id="quickblog"><a href="https://github.com/borkdude/quickblog">Quickblog</a></h3><p>Light-weight static blog engine for Clojure and babashka.</p><p>The blog you&apos;re currently reading is made with quickblog.</p><p>Version <a href="https://github.com/borkdude/quickblog/blob/main/CHANGELOG.md#010-2022-12-11">0.1.0</a> was finally released with much thanks to Josh Glover. See <a href="https://github.com/borkdude/quickblog/blob/main/CHANGELOG.md#changelog">changelog</a> for more details.</p><h3 id="rewrite-edn"><a href="https://github.com/borkdude/rewrite-edn">Rewrite-edn</a></h3><p>Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments.</p><p>Minor fixes and enhancements. Several functions have been added like <code>fnil</code> and <code>conj</code>. See <a href="https://github.com/borkdude/rewrite-edn/blob/master/CHANGELOG.md">changelog</a>.</p><h3 id="sci.configs"><a href="https://github.com/babashka/sci.configs">Sci.configs</a></h3><p>A collection of ready to be used SCI configs for e.g. Reagent, Promesa, Re-frame and other projects that are used in nbb, joyride, scittle, etc.  See recent <a href="https://github.com/babashka/sci.configs/commits/main">commits</a> for what&apos;s been improved.</p><h3 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h3><p>Scripting in Clojure on Node.js using SCI</p><p>Because it&apos;s so easy to deploy to npm, I usually publish a new version for each issue that is resolved.</p><p>No big changes, but many small bugfixes and improvements in the last two months. See <a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="edamame"><a href="https://github.com/borkdude/edamame">Edamame</a></h3><p>Configurable EDN/Clojure parser with location metadata. It has been stable for a while and reached version 1.0.0. The API is exposed now in <a href="https://github.com/babashka/babashka">babashka</a> and <a href="https://github.com/babashka/nbb">nbb</a> as well.</p><p><a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md">Changelog</a></p><h3 id="lein2deps"><a href="https://github.com/borkdude/lein2deps">lein2deps</a></h3><p>Lein to deps.edn converter</p><p>This tool can convert a <code>project.edn</code> file to a <code>deps.edn</code> file. It even supports Java compilation and evaluation of code within <code>project.clj</code>. Several minor enhancements were made. See <a href="https://github.com/borkdude/lein2deps/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="joyride"><a href="https://github.com/BetterThanTomorrow/joyride">Joyride</a></h3><p>Modify VSCode by executing ClojureScript (SCI) code in your REPL and/or run scripts via keyboard shortcuts.</p><p>I&apos;m working on this project together with Peter Strömberg (known for his work on Calva) and I&apos;m mostly reviewing Peter&apos;s PR instead of writing code.</p><p>Read the changelog <a href="https://github.com/BetterThanTomorrow/joyride/blob/master/CHANGELOG.md">here</a>.</p><h3 id="deps.clj"><a href="https://github.com/borkdude/deps.clj">Deps.clj</a></h3><p>Regular maintainance, keeping up with the official Clojure CLI and tools jar!</p><h3 id="clj-kondo-configs"><a href="https://github.com/clj-kondo/configs">Clj-kondo configs</a></h3><p>Library configurations as dependencies for clj-kondo.</p><p>The claypoole configuration was improved.</p><h3 id="babashka-cli"><a href="https://github.com/babashka/cli">Babashka CLI</a></h3><p>Turn Clojure functions into CLIs!</p><p>Minor fixes. See <a href="https://github.com/babashka/cli/blob/main/CHANGELOG.md">changelog</a>.</p><h3 id="babashka-pods">Babashka pods</h3><p>The <a href="https://github.com/babashka/pods">pods</a> library contains the code that supports using pods in babashka and the JVM. A critical error was fixed that would hang babashka and a new JVM release was pushed to Clojars (v0.1.0).</p><h3 id="babashka-compatibility-in-external-libs">Babashka compatibility in external libs</h3><p>I contributed to <a href="https://github.com/hyperfiddle/rcf">RCF</a>, <a href="https://github.com/lambdaisland/deep-diff2">deep-diff2</a> and <a href="https://github.com/lambdaisland/clj-diff">clj-diff</a> to make these libraries babashka compatible.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/graalvm-babashka.html</id>
    <link href="https://blog.michielborkent.nl/graalvm-babashka.html"/>
    <title>Babashka: How GraalVM Helped Create a Fast-Starting Scripting Environment for Clojure</title>
    <updated>2022-12-08T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>I&apos;m happy to announce a blog post written by me about babashka that was published on the GraalVM medium blog. You can read the full article <a href="https://medium.com/graalvm/babashka-how-graalvm-helped-create-a-fast-starting-scripting-environment-for-clojure-b0fcc38b0746">here</a>.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-test-runner.html</id>
    <link href="https://blog.michielborkent.nl/babashka-test-runner.html"/>
    <title>Testing babashka scripts</title>
    <updated>2022-11-24T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>For testing babashka scripts, you can write your own test runner from scratch, which is easy enough:</p><pre><code class="language-clojure">(ns my-test.runner
  (:require
   [clojure.test :as t]))

(def test-namespaces &apos;[my-test])

(defn -main [&amp; _]
  (doseq [test-ns test-namespaces] (require test-ns))
  (let [{:keys [fail error]}
        (apply t/run-tests test-namespaces)]
    (when (and fail error (pos? (+ fail error)))
      (System/exit 1))))
</code></pre><p>and then run it with <code>bb -m my-test.runner</code>.</p><p>Not too bad, but still, it&apos;s work and boilerplate and even more so when you want to make a runner with CLI argument parsing to support running a subset of your tests. Since a year or so, you can use the <a href="https://github.com/cognitect-labs/test-runner">cognitect-labs/test-runner</a> with babashka. But this required a <a href="https://github.com/babashka/tools.namespace">fork of tools
namespace</a> to be on your babashka classpath (using <code>:deps</code> in your <code>bb.edn</code> file).</p><p>No more! Since babashka version 1.0.166 you can use <a href="https://github.com/clojure/tools.namespace">org.clojure/tools-namespace</a> unmodified. The fix for this was to add the <code>clojure.tools.reader</code> namespace with the <code>read</code> function in babashka as a built-in. Babashka doesn&apos;t support the whole <code>clojure.tools.reader</code> namespace yet, but this is a good start to make it compatible with tools.namespace and now also the cognitect test runner.</p><p>To use it with babashka, add the following to your <code>bb.edn</code>.</p><pre><code class="language-clojure">{:tasks
 {test:bb {:extra-paths [&quot;test&quot;]
           :extra-deps {io.github.cognitect-labs/test-runner
                        {:git/tag &quot;v0.5.1&quot; :git/sha &quot;dfb30dd&quot;}}
           :task (exec &apos;cognitect.test-runner.api/test)
           :exec-args {:dirs [&quot;test&quot;]}
           :org.babashka/cli {:coerce {:nses [:symbol]
                                       :vars [:symbol]}}}}}
</code></pre><p>The <code>exec</code> function call, <code>:exec-args</code> and <code>:org.babashka/cli</code> coercion is there so we can call a Clojure function from the command line.  See <a href="https://blog.michielborkent.nl/babashka-tasks-meets-babashka-cli.html">Babashka tasks meets
babashka
CLI</a> for more details.</p><p>Now create a test file in <code>test/my_test.clj</code>:</p><pre><code class="language-clojure">(ns my-test
  (:require [clojure.test :refer [deftest is testing]]))

(deftest my-first-test
  (testing &quot;equality works&quot;
    (is (= 1 1))))

(deftest my-second-test
  (testing &quot;equality still works&quot;
    (is (= 2 2))))
</code></pre><p>And run the tests:</p><pre><code class="language-shell">$ bb test:bb

Running tests in #{&quot;test&quot;}

Testing my-test

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
</code></pre><p>To run a single test you can specify the name of a var:</p><pre><code class="language-shell">$ bb test:bb --vars my-test/my-second-test

Running tests in #{&quot;test&quot;}

Testing my-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

$ bb test:bb --vars my-test/my-first-test my-test/my-second-test

Running tests in #{&quot;test&quot;}

Testing my-test

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
</code></pre><p>Perhaps this will come in handy for <a href="https://adventofcode.com/2022">Advent of Code 2022</a>!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-sep-oct-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-sep-oct-2022.html"/>
    <title>OSS updates of September - October 2022</title>
    <updated>2022-10-31T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during September and October 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors:</p><ul><li><a href="https://clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://roamresearch.com/">Roam Research</a></li><li><a href="https://nextjournal.com/">Nextjournal</a></li><li><a href="https://toyokumo.co.jp/">Toyokumo</a></li><li><a href="https://www.cognitect.com/">Cognitect</a></li><li><a href="https://kepler16.com/">Kepler16</a></li><li><a href="https://www.adgoji.com/">Adgoji</a></li></ul><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work via the following organizations. Thank you!</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="projects">Projects</h2><!-- September: https://github.com/borkdude?tab=overview&from=2022-09-01&to=2022-09-31 --><!-- October: https://github.com/borkdude?tab=overview&from=2022-10-01&to=2022-10-31 --><h3 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h3><p>Native, fast starting Clojure interpreter for scripting.</p><ul><li>The first <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#10164-2022-10-17">1.0
release</a> was released!</li><li>Optimizations for <code>let</code> (in SCI) which is now up to 8x faster.</li><li>Many small improvements. See the <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">changelogs</a>.</li></ul><h3 id="squint-and-cherry"><a href="https://github.com/squint-cljs/squint">Squint</a> and <a href="https://github.com/squint-cljs/cherry">Cherry</a></h3><p>Squint and cherry are two flavors of the same CLJS compiler.</p><p>Squint is a CLJS <em>syntax</em> to JS compiler for use case where you want to write JS, but do it using CLJS syntax and tooling instead. Squint comes with a standard library that resembles CLJS but is built on bare JS ingredients. As such, squint comes with the usual JS caveats, but we can still have our parens and enjoy a slim bundle size.</p><p>Cherry comes with the CLJS standard library and is as such much closer to the normal ClojureScript, but the minimal amount of JS is a little bigger.</p><p>I&apos;ve working on unifying the compiler code of cherry and squint into one code base, which is still in progress. I&apos;ve also worked on REPL code.</p><p>I&apos;ve also given a <a href="https://twitter.com/borkdude/status/1586662315805450240">presentation on squint and
cherry</a> at the <a href="https://clojuredays.org/">Dutch
Clojure Days</a>. The video will appear online in the future!</p><h3 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h3><p>Static analyzer and linter for Clojure code that sparks joy</p><p>Two new releases with many fixes and improvements. <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Check the
changelogs</a> for details.</p><p>Among several new linters, there is a new <code>:unused-value</code> linter which detects unused values, which is particularly helpful for detecting unused transient operation results which can lead to bugs.</p><h3 id="clj-kondo-configs"><a href="https://github.com/clj-kondo/configs">Clj-kondo configs</a></h3><p>Library configurations as dependencies for clj-kondo.</p><p>The idea of this repository is that you can add configuration for libraries as a dependency to your <code>deps.edn</code> or <code>project.clj</code>.  If you invoke the right command or if you are using Clojure LSP, then the configuration is written into your <code>.clj-kondo</code> directory and clj-kondo will understand custom constructs in your library.  Normally you can provide these configurations as part of your library, but this is not always an option, so the remaining configurations can live over here.</p><h3 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h3><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>This is the workhorse that powers babashka, nbb, Joyride, and many other projects.</p><p>Several bugfixes and enhancements were made in the last two months in two new releases. Performance of <code>let</code> bindings are now up to 8x faster, as already mentioned in the babashka entry of this post.</p><p>See <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">changelogs</a> for more details.</p><h3 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h3><p>Scripting in Clojure on Node.js using SCI</p><p>The first 1.0 version was released.</p><p>Many small bugfixes and improvements in the last two months. See <a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">changelogs</a>.</p><h3 id="clj-yaml"><a href="https://github.com/clj-commons/clj-yaml">Clj-yaml</a></h3><p>In the past two month, I became one of the maintainers, together with <a href="https://github.com/lread">@lread</a>, of <a href="https://github.com/clj-commons/clj-yaml">clj-yaml</a>. Clj-yaml is a built-in library of babashka.</p><h3 id="deps.clj"><a href="https://github.com/borkdude/deps.clj">Deps.clj</a></h3><p>A faithful port of the clojure CLI bash script to Clojure</p><p>A lot of Windows improvements in the last two months. Deps.clj is now also available as part of an <a href="https://github.com/casselc/clj-msi/releases">MSI installer</a> that installs <code>deps.exe</code> as <code>clj.exe</code>. This installer might form the basis for an official Clojure MSI installer.</p><h3 id="gh-release-artifact"><a href="https://github.com/borkdude/gh-release-artifact">Gh-release-artifact</a></h3><p>Upload artifacts to Github releases idempotently</p><p>This tool has been in use within babashka, clj-kondo and other projects to automate uploading release artifacts from various CI systems to Github releases, idempotently. It is now open source and ready to be used by others.</p><h3 id="jet"><a href="https://github.com/borkdude/jet">Jet</a></h3><p>CLI to transform between JSON, EDN, YAML and Transit, powered with a minimal query language.</p><p>The latest release adds support for YAML (by using clj-yaml), thanks to <a href="https://github.com/qdzo">@qdzo</a>.</p><h3 id="babashka-cli"><a href="https://github.com/babashka/cli">Babashka CLI</a></h3><p>Turn Clojure functions into CLIs!</p><p>See <a href="https://github.com/babashka/cli/blob/main/CHANGELOG.md">changelogs</a>.</p><h3 id="process"><a href="https://github.com/babashka/process">Process</a></h3><p>Clojure library for shelling out / spawning subprocesses</p><p>Minor updates and fixes. See <a href="https://github.com/babashka/process/blob/master/CHANGELOG.md">changelogs</a>.</p><h3 id="quickdoc"><a href="https://github.com/borkdude/quickdoc">Quickdoc</a></h3><p>Quickdoc is a tool to generate documentation from namespace/var analysis done by clj-kondo. It&apos;s fast and spits out an <code>API.md</code> file in the root of your project, so you can immediately view it on Github. It has undergone significant improvements in the last two months. I&apos;m using quickdoc myself in several projects. In the last two months, there have been improvements in the table of contents linking and linking to source code.</p><h3 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h3><p>File system utility library for Clojure.</p><p>Minor updates and fixes. See <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#changelog">changelogs</a>.</p><h3 id="carve"><a href="https://github.com/borkdude/carve">Carve</a></h3><p>Carve out the essentials of your Clojure app by removing unused vars</p><p>Version 0.2.0 was released, after a long hiatus, with an updated version of clj-kondo and some minor fixes.</p><h3 id="grasp"><a href="https://github.com/borkdude/grasp">Grasp</a></h3><p>Grep Clojure code using clojure.spec regexes.</p><p>I use this tool to analyze code patterns to make informed choices for e.g. SCI and clj-kondo. E.g. see <a href="https://github.com/borkdude/grasp/blob/master/examples/let_bindings.clj">this</a> example that shows how many let bindings are typically used. See the example in action <a href="https://twitter.com/borkdude/status/1582320503049826304">here</a>.</p><p>A new version was released with minor fixes.</p><h3 id="rewrite-edn"><a href="https://github.com/borkdude/rewrite-edn">Rewrite-edn</a></h3><p>Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments.</p><p>Minor fixes and enhancements. Repeated usage of <code>assoc</code> is now a safe operation. Thanks to <a href="https://github.com/lread">@lread</a> for the improvements.</p><h3 id="lein2deps"><a href="https://github.com/borkdude/lein2deps">lein2deps</a></h3><p>Lein to deps.edn converter</p><p>This new little tool can convert a <code>project.edn</code> file to a <code>deps.edn</code> file. It even supports Java compilation and evaluation of code within <code>project.clj</code>.</p><h3 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h3><p>A CLI to add common aliases and features to <code>deps.edn</code>-based projects.</p><p>Neil now comes with a <code>dep upgrade</code> command, thanks to <a href="https://github.com/teodorlu">@teodorlu</a> and <a href="https://github.com/russmatney">@russmatney</a>, together with other improvements.</p><h3 id="respeced"><a href="https://github.com/borkdude/respeced">Respeced</a></h3><p>Finally, after 4 years, a new release of respeced, a testing library for clojure.spec fdefs.</p><h3 id="quickblog"><a href="https://github.com/borkdude/quickblog">Quickblog</a></h3><p>Light-weight static blog engine for Clojure and babashka</p><p>Small improvements. See <a href="https://github.com/borkdude/quickblog/blob/main/CHANGELOG.md#changelog">changelog</a>. The blog you&apos;re currently reading is made with quickblog.</p><h3 id="sci.configs"><a href="https://github.com/babashka/sci.configs">Sci.configs</a></h3><p>A collection of ready to be used SCI configs</p><p>Added a <code>doseq</code> macro in <a href="https://github.com/funcool/promesa">promesa</a> which also is available via this configuration. Sci.configs is used in <a href="https://github.com/nextjournal/clerk">Clerk</a>, <a href="https://github.com/babashka/nbb">nbb</a>, <a href="https://github.com/BetterThanTomorrow/joyride/">Joyride</a> and other SCI-based CLJS projects.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/deploy-clojure-neil.html</id>
    <link href="https://blog.michielborkent.nl/deploy-clojure-neil.html"/>
    <title>Deploying a Clojure project with neil and tools.build</title>
    <updated>2022-10-22T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In a <a href="https://blog.michielborkent.nl/new-clojure-project-quickstart.html">previous blog
post</a>, I described how you can kick off a Clojure project with <a href="https://github.com/babashka/neil">neil</a>.</p><p>Today I want to show you how easy it is how to deploy a Clojure project to Clojars with neil.</p><p>Assuming you already have a <code>deps.edn</code>, but you don&apos;t yet have a <code>build.clj</code>, you can run:</p><pre><code class="language-shell">$ neil add build
</code></pre><p>This creates a <a href="https://github.com/clojure/tools.build">tools.build</a> <code>build.clj</code> file with functions you typically need for building and deploying a Clojure project.</p><p>The <code>build.clj</code> looks for the project name and version in your <code>deps.edn</code> under <code>[:aliases :neil :project]</code>.</p><p>You can set the project name and version like this:</p><pre><code class="language-clojure">{:deps {}
 :paths [&quot;resources&quot;]
 :aliases
 {:neil {:project {:name io.github.clj-kondo/config-rum-rum
                   :version &quot;1.0.0&quot;}}
  :build ;; added by neil
  {:deps {io.github.clojure/tools.build {:git/tag &quot;v0.8.3&quot; :git/sha &quot;0d20256&quot;}
          slipset/deps-deploy {:mvn/version &quot;0.2.0&quot;}}
   :ns-default build}}}
</code></pre><p>Now all you have to do to deploy your project is run <code>clojure -T:build deploy</code>. This runs the <code>deploy</code> function in <code>build.clj</code> which uses <a href="https://github.com/slipset/deps-deploy">deps-deploy</a>.</p><p>Whenever you want to bump your patch version, you can run:</p><pre><code class="language-shell">$ neil version patch
</code></pre><p>or set the version manually using:</p><pre><code class="language-shell">$ neil version set 1.0.1
</code></pre><p>and then deploy again.</p><p>The <code>neil version</code> command is similar to NPM&apos;s <code>version</code> command.</p><p>For a full project that uses this setup, check out <a href="https://github.com/clj-kondo/configs/tree/main/configs/rum/rum">this
one</a> that I just created today in a couple of keystrokes.</p><p>Happy deploying!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jul-aug-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jul-aug-2022.html"/>
    <title>OSS updates of July - August 2022</title>
    <updated>2022-09-01T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during July and August 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors: <a href="https://clojuriststogether.org/">Clojurists
Together</a>, <a href="https://roamresearch.com/">Roam
Research</a>, <a href="https://nextjournal.com/">Nextjournal</a>, <a href="https://www.adgoji.com/">Adgoji</a>, <a href="https://www.cognitect.com/">Cognitect</a>, <a href="https://kepler16.com/">Kepler16</a>, .</p><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work via the following organizations:</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="projects">Projects</h2><!-- https://github.com/borkdude?tab=overview&from=2022-06-01&to=2022-06-30 --><h3 id="clavascript"><a href="https://github.com/clavascript/clavascript">ClavaScript</a></h3><p>This is a new project: a CLJS syntax to JS compiler for the niche use case where you want to write JS, but do it using CLJS syntax and tooling instead. ClavaScript comes with a standard library that resembles CLJS but is built on bare JS ingredients. As such, Clava comes with the usual JS caveats, but we can still have our parens and enjoy a slim bundle size!</p><h3 id="cherry"><a href="https://github.com/clavascript/cherry">Cherry</a></h3><p>Cherry is similar to ClavaScript, but it does emit CLJS-compatible code (with the persistent data structures, etc). The compiler code is almost identical to Clava&apos;s, but with a few tweaks here and there. E.g. <code>{:a 1}</code> in Clava means: a JS object with a <code>&quot;a&quot;</code> key and <code>1</code> value, but in cherry, <code>{:a 1}</code> means the same as in CLJS. The goal of both Clava and Cherry are to reduce friction between CLJS and JS tooling. Both projects should be considered experimental for now. Challenges in both Clava and Cherry is the REPL, since both projects compile to ES6 modules and ES6 module imports are immutable.</p><p>On <a href="https://clojuredays.org/">ClojureDays 2022</a> I will give a talk titled &quot;ClojureScript reimagined&quot; which will shed more light on both projects.</p><h3 id="scittle"><a href="https://github.com/babashka/scittle">Scittle</a></h3><p>Execute Clojure(Script) directly from browser script tags via SCI. See it in <a href="https://babashka.org/scittle/">action</a>.</p><p>Scittle received two new plugins: one for <code>promesa.core</code> and one for <code>cljs.pprint</code>. Also error messages were improved.</p><h3 id="babashka-toolbox"><a href="https://babashka.org/toolbox/">Babashka toolbox</a></h3><p>Babashka toolbox is a port of <a href="https://www.clojure-toolbox.com/">Clojure
toolbox</a> and gives an overview of bb-compatible libraries and projects.</p><h3 id="babashka-cli"><a href="https://github.com/babashka/cli">Babashka CLI</a></h3><p>Turn Clojure functions into CLIs!</p><p>Several new options have been added: <code>:validate</code>, <code>:require</code>, <code>:restrict</code>. Also error handling was made more flexible.</p><p>Babashka CLI proper is now part of babashka. Also see my blog posts about it:</p><ul><li><a href="https://blog.michielborkent.nl/babashka-tasks-meets-babashka-cli.html">Babashka tasks meets babashka CLI</a></li><li><a href="https://blog.michielborkent.nl/babashka-cli.html">Babashka CLI: turn Clojure functions into CLIs</a></li></ul><h3 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h3><p>Native, fast starting Clojure interpreter for scripting.</p><ul><li>Compatibility with <a href="https://github.com/metosin/malli#babashka">malli</a></li><li><code>-x</code>: a way to execute functions from the command line using babashka CLI</li><li>Many bugfixes and enhancements</li></ul><h3 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h3><p>Scripting in Clojure on Node.js using SCI</p><ul><li>A new <a href="https://github.com/babashka/nbb/tree/main/doc/bundle#bundle">bundle</a> command to bundle nbb scripts to standalone scripts, which can then be processed further with e.g. <code>esbuild</code> to minify and tree-shake them.</li><li><code>nbb.edn</code>: you can now declare dependencies within this file, e.g. from Clojars and nbb will add them automatically to the classpath, so you can <code>require</code> them.</li><li><a href="https://github.com/metosin/malli">Malli</a> compatibilty</li><li>Many small bugfixes and improvements</li></ul><h3 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h3><p>Static analyzer and linter for Clojure code that sparks joy</p><h3 id="bebo"><a href="https://github.com/borkdude/bebo">Bebo</a></h3><p>Run Clojure scripts on <a href="https://deno.land/">Deno</a> via SCI. I&apos;m not exactly sure how useful this is to the wider Clojure community, but I got curious about deno and decided to give this a go.</p><h3 id="quickblog"><a href="https://github.com/borkdude/quickblog">Quickblog</a></h3><p>Light-weight static blog engine for Clojure and babashka</p><p>A lot has been happening in this project, with the help of Josh Glover. Check out the <a href="https://github.com/borkdude/quickblog/blob/main/CHANGELOG.md#changelog">changelog</a>. The blog you&apos;re currently reading is made with quickblog.</p><h3 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h3><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>This is the workhorse that powers babashka, nbb, bebo, and many other projects.</p><p>Several bugfixes and enhancements were made in the last two months.</p><h3 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h3><p>A CLI to add common aliases and features to deps.edn-based projects.</p><p>Neil now has a <code>new</code> subcommand which defers to <a href="https://github.com/seancorfield/deps-new">deps-new</a>. Also <code>neil test</code> was added to run tests using the Cognitect-labs test runner. Much thanks to <a href="https://github.com/rads">rads</a> who contributed a lot.</p><h3 id="process"><a href="https://github.com/babashka/process">Process</a></h3><p>Clojure library for shelling out / spawning subprocesses</p><p>Minor updates and fixes.</p><h3 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h3><p>File system utility library for Clojure.</p><p>Minor updates and fixes.</p><h3 id="pod-babashka-buddy"><a href="https://github.com/babashka/pod-babashka-buddy">Pod-babashka-buddy</a></h3><p>A babashka pod around buddy core (Cryptographic Api for Clojure).</p><p>The latest release adds wrappers for <code>buddy.sign.jwt</code> and provides an <code>aarch64</code> binary.</p><p>See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20220803">changelogs</a>.</p><h3 id="dynaload"><a href="https://github.com/borkdude/dynaload">Dynaload</a></h3><p>The dynaload logic from clojure.spec.alpha as a library</p><p>This library was made compatible with nbb.</p><h3 id="deps.clj"><a href="https://github.com/borkdude/deps.clj">Deps.clj</a></h3><p>Upgrades and minor fixes.</p><h3 id="sci.configs"><a href="https://github.com/babashka/sci.configs">Sci.configs</a></h3><p>A collection of ready to be used SCI configs</p><p>Moved <code>cljs.pprint</code> config from nbb into this project.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-tasks-meets-babashka-cli.html</id>
    <link href="https://blog.michielborkent.nl/babashka-tasks-meets-babashka-cli.html"/>
    <title>Babashka tasks meets babashka CLI</title>
    <updated>2022-08-02T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In a previous blog post <a href="https://blog.michielborkent.nl/babashka-cli.html">(link)</a> I introduced <a href="https://github.com/babashka/cli">babashka CLI</a>. It offers you similar benefits as <code>clojure -X</code> but with a more Unixy command line interface.</p><p>In version <code>0.9.160</code> of babashka, babashka CLI was integrated.  It is available as a built-in library so you don&apos;t need to declare it anymore in <code>:deps</code> in <code>bb.edn</code> unless you want to use a newer version than the built-in one.</p><h2 id="-x">-x</h2><p>For invoking functions from the command line, you can use the new <code>-x</code> flag (a pun to Clojure&apos;s <code>-X</code> of course!):</p><pre><code class="language-clojure">bb -x clojure.core/identity --hello there
{:hello &quot;there&quot;}
</code></pre><p>What we see in the above snippet is that a map <code>{:hello &quot;there&quot;}</code> is constructed by babashka CLI and then fed to the <code>identity</code> function. After that the result is printed to the console.</p><p>What if we want to influence how things are parsed by babashka CLI and provide some defaults? This can be done using metadata. Let&apos;s create a <code>bb.edn</code> and make a file available on the classpath:</p><p><code>bb.edn</code>:</p><pre><code class="language-clojure">{:paths [&quot;.&quot;]}
</code></pre><p><code>tasks.clj</code>:</p><pre><code class="language-clojure">(ns tasks
  {:org.babashka/cli {:exec-args {:ns-data 1}}})

(defn my-function
  {:org.babashka/cli {:exec-args {:fn-data 1}
                      :coerce {:num [:int]}
                      :alias {:n :num}}}
  [m]
  m)
</code></pre><p>Now let&apos;s invoke:</p><pre><code class="language-clojure">$ bb -x tasks/my-function -n 1 2
{:ns-data 1, :fn-data 1, :num [1 2]}
</code></pre><p>As you can see, the namespace options are merged with the function options. Defaults can be provided with <code>:exec-args</code>, like you&apos;re used to from the clojure CLI.</p><h2 id="tasks">Tasks</h2><p>What about task integration? Let&apos;s adapt our <code>bb.edn</code>:</p><pre><code class="language-clojure">{:paths [&quot;.&quot;]
 :tasks {doit {:task (let [x (exec &apos;tasks/my-function)]
                       (prn :x x))
               :exec-args {:task-data 1234}}
         }}
</code></pre><p>and invoke the task:</p><pre><code class="language-clojure">$ bb doit --cli-option :yeah -n 1 2 3
:x {:ns-data 1, :fn-data 1, :task-data 1234, :cli-option :yeah, :num [1 2 3]}
</code></pre><p>As you can see it works similar to <code>-x</code>, but you can provide another set of defaults on the task level with <code>:exec-args</code>. Executing a function through babashka CLI is done using the <code>babashka.task/exec</code> function, available by default in tasks.</p><!-- A hack to parse command line arguments in babashka and then forward them to Clojure: --><!-- ``` clojure --><!-- {:paths ["."] --><!--  :tasks --><!--  {:requires ([babashka.cli :as cli]) --><!--   doit {:task --><!--         (do --><!--           (defn parse {:org.babashka/cli {:coerce {:number [:int]} --><!--                                           :alias {:n :number}}} --><!--             [m] m) --><!--           (clojure "-X" "clojure.core/prn" --><!--                    (exec parse))) --><!--         :exec-args {:task-data 1234}} --><!--   }} --><!-- ``` --><!-- ``` clojure --><!-- $ bb doit -n 1 2 3 --><!-- {:task-data 1234, :number [1 2 3]} --><!-- ``` --><!-- although you can do the above manually using `(babashka.cli/parse-opts ...)` as --><!-- well or by using babashka CLI directly with the [clojure CLI](https://github.com/babashka/cli#clojure-cli). --><p>Hope you will enjoy this!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/new-clojure-project-quickstart.html</id>
    <link href="https://blog.michielborkent.nl/new-clojure-project-quickstart.html"/>
    <title>New Clojure project quickstart</title>
    <updated>2022-08-02T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Clojure beginners sometimes struggle with setting up a new Clojure <code>deps.edn</code> project compared to setting up a <a href="https://leiningen.org/">lein</a> project. This is one of the reasons I&apos;ve built <a href="https://github.com/babashka/neil">neil</a>. But not only for beginners, I&apos;ve been using <code>neil</code> myself a ton too, to add common features to existing <code>deps.edn</code> projects. You may think that <code>neil</code> is a pun on <code>lein</code>. Of course it is. But the name is also an hommage to <a href="https://en.wikipedia.org/wiki/Neil_Peart">Neil
Peart</a>, one of the greatest progressive rock drummers to have ever lived.</p><p>The intent of this post is to give you a starting point from where you can figure out things further. This post isn&apos;t going to explain any details of how <code>deps.edn</code> and related tooling works. For that I&apos;m going to refer you to <a href="https://clojure.org/guides/deps_and_cli">here</a>.</p><p>Let&apos;s install <code>neil</code> which is available for <a href="https://github.com/babashka/neil#homebrew-linux-and-macos">brew</a>, <a href="https://github.com/babashka/neil#scoop-windows">scoop</a> (Windows), <a href="https://github.com/babashka/neil#nix">nix</a>, <a href="https://github.com/babashka/neil#clojure">Clojure
JVM</a> or can easily be installed <a href="https://github.com/babashka/neil#manual">manually</a>. Unless you use clojure JVM, neil runs with <a href="https://babashka.org/">babashka</a> for fast startup time.</p><p>If you&apos;ve already installed <code>babashka</code> (perhaps indirectly by installing <code>neil</code>) but didn&apos;t yet install the <a href="https://clojure.org/guides/deps_and_cli">clojure
CLI</a> or have problems doing so, then you can run <code>bb clojure</code> instead of <code>clojure</code> for launching Clojure. Instead of <code>clj</code>, on linux/macOS you&apos;ll want to use <code>rlwrap bb clojure</code>. If you are on Windows and struggle with the official <code>clojure</code> Powershell-based installation, <code>bb clojure</code> may come in handy too.</p><h2 id="new">New</h2><p>To start a new Clojure project, run <code>neil new --name myproject</code>. This produces a <code>myproject</code> directory with a very basic project layout based on the <a href="https://github.com/seancorfield/deps-new">deps-new</a> <code>scratch</code> template. Now we are are going to incrementally add some functionality to this project. If you like to skip most of these steps, you can start from the more fully featured <code>app</code> template with <code>neil new app --name myproject</code>.</p><h2 id="adding-library">Adding library</h2><p>Let&apos;s decide that we&apos;re going to need a library to deal with files. Let&apos;s search for one:</p><pre><code class="language-clojure">$ neil dep search &quot;file system&quot;
:lib fs/fs :version 1.3.3 :description &quot;File system utilities for clojure&quot;
:lib me.raynes/fs :version 1.4.6 :description &quot;File system utilities for clojure&quot;
:lib babashka/fs :version 0.1.6 :description &quot;Babashka file system utilities.&quot;
</code></pre><p>Let&apos;s go with the <a href="https://github.com/babashka/fs">babashka/fs</a> library:</p><pre><code>$ neil dep add :lib babashka/fs :version 0.1.6
</code></pre><p>Now the library is added to <code>deps.edn</code> and we can use it in our project:</p><pre><code class="language-clojure">$ clj
Clojure 1.11.0
user=&gt; (require &apos;[babashka.fs :as fs])
nil
</code></pre><h2 id="test">Test</h2><p>Let&apos;s start by adding a test runner. Type: <code>neil add test</code>. After doing this, you will be able to run:</p><pre><code class="language-shell">clojure -M:test
</code></pre><p>We don&apos;t have any tests in this project, so let&apos;s add one by adding a file:</p><p><code>test/myproject/core_test.clj</code></p><pre><code class="language-clojure">(ns myproject.core-test
  (:require [clojure.test :as t :refer [deftest is testing]]))

(deftest failing-test
  (testing &quot;TODO: fix test&quot;
    (is (= 3 4))))
</code></pre><p>Now run <code>clojure -M:test</code> again:</p><pre><code class="language-shell">$ clojure -M:test

Running tests in #{&quot;test&quot;}

Testing myproject.core-test

FAIL in (failing-test) (core_test.clj:6)
TODO: fix test
expected: (= 3 4)
  actual: (not (= 3 4))

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
</code></pre><p>The test runner we added is the Cognitect Labs <a href="https://github.com/cognitect-labs/test-runner">test-runner</a> so check out the README of that project if you need to know more.</p><p>Update 2022-08-06: <code>neil</code> now comes with a new subcommand: <code>test</code>, so you can replace <code>clojure -M:test</code> with <code>neil test</code>. Also when you&apos;ve created a project with <code>neil new</code>, <code>neil add test</code> will generate one default test for you.</p><h2 id="repl">REPL</h2><p>Run:</p><pre><code class="language-shell">neil add nrepl
</code></pre><p>to add a <code>:nrepl</code> alias to your project. Now you can run <code>clj -M:nrepl</code> to get a console REPL, but also a running nREPL server that you can connect to from your editor. Note that many editors also support <code>jack-in</code> and if you prefer to use that, you won&apos;t need this.</p><h2 id="uberjar">Uberjar</h2><p>What&apos;s the equivalent of <code>lein uberjar</code> in the <code>deps.edn</code> world? You&apos;re going to need <a href="https://github.com/clojure/tools.build">tools.build</a>. To create a <code>build.clj</code> file (the program that is going to build your uberjar), run:</p><pre><code class="language-shell">neil add build
</code></pre><p>Since the default <code>build.clj</code> file is going to assume your project is under <code>git</code> version control, let&apos;s initialize a git repo first:</p><pre><code class="language-shell">git init
git add deps.edn src test
git commit -m &quot;initial commit&quot;
</code></pre><p>Before creating the uberjar, we have to add <code>:gen-class</code> to <code>src/scratch.clj</code>:</p><pre><code class="language-clojure">(ns scratch
  (:gen-class))
</code></pre><p>and we add <code>:main &apos;scratch</code> in the call to <code>b/uber</code>:</p><pre><code class="language-clojure">(b/uber {:class-dir class-dir
         :uber-file uber-file
         :basis basis
         :main &apos;scratch})
</code></pre><p>Now let&apos;s compile the uberjar:</p><pre><code class="language-shell">clojure -T:build uber
</code></pre><p>And then let&apos;s run it:</p><pre><code class="language-shell">$ java -jar target/lib1-1.2.1-standalone.jar 1 2 3
-main with (1 2 3)
</code></pre><h2 id="babashka-tasks">Babashka tasks</h2><p>If you have difficulty remembering the above invocations, you can write a <code>bb.edn</code> with some <a href="https://book.babashka.org/#tasks">tasks</a>:</p><p><code>bb.edn</code>:</p><pre><code class="language-clojure">{:tasks
 {:requires ([babashka.fs :as fs])

  test {:doc &quot;Run tests&quot;
        :task (apply clojure &quot;-M:test&quot; *command-line-args*)}

  nrepl {:doc &quot;Start REPL&quot;
         :task (if (fs/windows?)
                 (clojure &quot;-M:nrepl&quot;)
                 (shell &quot;rlwrap bb clojure -M:nrepl&quot;))}

  uber {:doc &quot;Build uberjar&quot;
        :task (clojure &quot;-T:build uber&quot;)}}}
</code></pre><p>The <code>clojure</code> function is built into babashka and is a drop-in replacement for the clojure CLI which does not require any installation. With</p><pre><code class="language-clojure">(apply ... *command-line-args*)
</code></pre><p>we send any args you pass to a task invocation to clojure. So to run a specific test, you can write:</p><pre><code class="language-shell">bb test -v myproject.core-test/failing-test
</code></pre><p>If you prefer to use the installed clojure CLI, you can do this by using:</p><pre><code class="language-clojure">(apply shell &quot;clojure&quot; ... *command-line-args*)
</code></pre><p>Now whenever you forget what to do in the current project, run <code>bb tasks</code>:</p><pre><code class="language-shell">$ bb tasks
The following tasks are available:

test  Run tests
nrepl Start REPL
uber  Build uberjar
</code></pre><p>Hope this helps!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-may-jun-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-may-jun-2022.html"/>
    <title>OSS Updates of May - June 2022</title>
    <updated>2022-06-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during May and June 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible! Top sponsors: <a href="https://clojuriststogether.org/">Clojurists
Together</a>, <a href="https://roamresearch.com/">Roam
Research</a>, <a href="https://www.adgoji.com/">Adgoji</a>, <a href="https://www.cognitect.com/">Cognitect</a>, <a href="https://nextjournal.com/">Nextjournal</a>.</p><p>If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work via the following organizations:</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="projects">Projects</h2><h3 id="babashka-cli"><a href="https://github.com/babashka/cli">Babashka CLI</a></h3><p>Turn Clojure functions into CLIs!</p><p>This is one of my newest projects. It aims to close the gap between good command line UX and calling Clojure functions. It is very much inspired by the clojure CLI, but solves a problem which sometimes causes frustration, especially among Windows users: having to use quotes in a shell. It also offers support for subcommands. One project benefiting from that is <a href="https://github.com/babashka/neil">neil</a>. I blogged about babashka CLI <a href="https://blog.michielborkent.nl/babashka-cli.html">here</a>.</p><h3 id="http-server"><a href="https://github.com/babashka/http-server">Http-server</a></h3><p>Serve static assets.</p><p>Another new project is http-server, which can be used in Clojure JVM and babashka to serve static assets in an http server.</p><h3 id="clj-kondo-workshop"><a href="https://github.com/clj-kondo/hooks-workshop-clojured-2022">Clj-kondo workshop</a></h3><p>In June I had the honor and pleasure to give a workshop about <a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a> at <a href="https://clojured.de/">ClojureD</a>. You can work through the material yourself if you&apos;d like <a href="https://github.com/clj-kondo/hooks-workshop-clojured-2022">here</a>. Feel free to join the clj-kondo channel on Clojurians Slack for questions. Here are some <a href="https://twitter.com/borkdude/status/1542521071588347905">pictures</a> from the event.</p><h3 id="jet"><a href="https://github.com/borkdude/jet">Jet</a></h3><p>CLI to transform between JSON, EDN and Transit, powered with a minimal query language.</p><p><a href="https://github.com/borkdude/jet/blob/master/CHANGELOG.md">Changelog</a></p><p>The <code>jet</code> binary is now available for Apple Silicon and adds <a href="https://github.com/redplanetlabs/specter">specter</a> as part of the standard library for transforming data. Also, the output is colorized and pretty-printed using <a href="https://github.com/greglook/puget">puget</a> now.</p><h3 id="edamame"><a href="https://github.com/borkdude/edamame">Edamame</a></h3><p><a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md">Changelog</a></p><p>Configurable EDN/Clojure parser with location metadata. It has been stable for a while and reached version 1.0.0. The API is exposed now in <a href="https://github.com/babashka/babashka">babashka</a> and <a href="https://github.com/babashka/nbb">nbb</a> as well.</p><h3 id="quickdoc"><a href="https://github.com/borkdude/quickdoc">Quickdoc</a></h3><p>Quickdoc is a tool to generate documentation from namespace/var analysis done by clj-kondo. It&apos;s fast and spits out an <code>API.md</code> file in the root of your project, so you can immediately view it on Github. It has undergone significant improvements in the last two months. I&apos;m using quickdoc myself in several projects.</p><h3 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h3><p>Scripting in Clojure on Node.js using SCI.</p><p><a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">Changelog</a></p><p>Added <code>edamame.core</code>, <code>cljs.math</code>, nREPL improvements and now has significant faster startup due to an improvement in <a href="https://github.com/babashka/sci">SCI</a>.</p><h3 id="clojure-lsp"><a href="https://github.com/clojure-lsp/clojure-lsp">Clojure-lsp</a></h3><p>Clojure/Script Language Server (LSP) implementation.</p><p>This project is driven by the static analysis done by <a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a> and used by many people to get IDE-like features in editors like emacs and VSCode.</p><p>I added support for Apple Silicon using <a href="https://cirrus-ci.org/">Cirrus CI</a>.</p><h3 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h3><p>Native, fast starting Clojure interpreter for scripting.</p><p><a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">Changelog</a></p><p>Two new version of babashka were released:</p><p>0.8.2 and 0.8.156. The last segment of the version number now indicates the release count, so the last release is the 156th release.</p><p>Babashka now also has a new Apple Silicon binary built on <a href="https://cirrus-ci.org/">Cirrus
CI</a>.  What is very exciting is that babashka can now execute <a href="https://github.com/plumatic/schema">schema</a> from source. Compatibility with <a href="https://github.com/metosin/malli/pull/718">malli</a> is underway.</p><h3 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h3><p>A linter for Clojure code that sparks joy.</p><p><a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">Changelog</a></p><p>New linters:</p><ul><li><a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#warn-on-reflection"><code>:warn-on-reflection</code></a></li><li><a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#redundant-call"><code>:redundant-call</code></a></li><li><a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#discouraged-namespace"><code>:discouraged-namespace</code></a></li></ul><p>Clj-kondo now also has a new Apple Silicon binary built on <a href="https://cirrus-ci.org/">Cirrus
CI</a>.</p><h3 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h3><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs. Powering babashka, nbb, joyride and many other projects.</p><p><a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">Changelog</a></p><p>New releases: 0.3.5 - 0.3.32</p><p>Highlights:</p><ul><li>New <code>sci.async</code> namespace for asynchronous loading of code</li><li>Reduce advanced compiled JS output with about 20% (~900kb -&gt; ~740kb)</li><li>Many improvements to <code>defrecord</code></li></ul><h3 id="sci-configs"><a href="https://github.com/babashka/sci.configs">SCI configs</a></h3><p>A collection of ready to be used SCI configurations.</p><p>This project contains configurations for reagent, promesa, etc. and are used in nbb, clerk and other projects.</p><p>A recent addition was a configuration for <code>cljs.test</code> which is now shared by nbb and <a href="https://github.com/BetterThanTomorrow/joyride">joyride</a>.</p><h3 id="process"><a href="https://github.com/babashka/process">Process</a></h3><p><a href="https://github.com/babashka/process/blob/master/CHANGELOG.md">Changelog</a></p><p>New releases: 0.1.2 - 0.1.4</p><p>Highlights:</p><p>Support <code>exec</code> call in GraalVM <code>native-images</code> - this means you can replace the current process with another one.</p><h3 id="scittle"><a href="https://github.com/babashka/scittle">Scittle</a></h3><p>The Small Clojure Interpreter exposed for usage in browser script tags.</p><p>Added support developing CLJS via nREPL. See <a href="https://github.com/babashka/scittle/tree/main/doc/nrepl">docs</a>.</p><h3 id="etaoin"><a href="https://github.com/clj-commons/etaoin">Etaoin</a></h3><p>Pure Clojure Webdriver protocol implementation.</p><p>This project is now compatible with babashka! Most of the work on this project was done by Lee Read. If you appreciate his work on this, or other projects like <a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>, consider <a href="https://github.com/sponsors/lread">sponsoring</a> him.</p><h3 id="misc">Misc</h3><p>Brief mentions of miscellaneous other projects I worked on:</p><ul><li><a href="https://github.com/borkdude/nbb-action-example">nbb-action-example</a> - example of how to build a Github Action with <a href="https://github.com/babashka/nbb">nbb</a>.</li><li><a href="https://github.com/BetterThanTomorrow/joyride">joyride</a> - Making VS Code Hackable since 2022</li><li><a href="https://github.com/borkdude/dynaload">dynaload</a> - The dynaload logic from clojure.spec.alpha as a library</li><li><a href="https://github.com/borkdude/deps.clj">deps.clj</a> - A faithful port of the clojure CLI bash script to Clojure.</li><li><a href="https://github.com/babashka/fs">fs</a> - File system utility library for Clojure</li><li><a href="https://github.com/borkdude/fly_io_clojure">fly-io-clojure</a> - A fly.io example for Clojure. Also see examples for <a href="https://github.com/babashka/babashka/tree/master/doc/fly_io">babashka</a> and <a href="https://github.com/babashka/nbb/tree/main/doc/fly_io">nbb</a>.</li><li><a href="https://github.com/babashka/pod-babashka-etaoin">pod-babashka-etaoin</a> - Babashka pod wrapping Etaoin</li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">pod-babashka-fswatcher</a> - Babashka filewatcher pod</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-cli.html</id>
    <link href="https://blog.michielborkent.nl/babashka-cli.html"/>
    <title>Babashka CLI: turn Clojure functions into CLIs</title>
    <updated>2022-06-24T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><a href="https://github.com/babashka/cli">Babashka CLI</a> is a new library for command line argument parsing. The main ideas:</p><ul><li>Put as little effort as possible into turning a Clojure function into a CLI, similar to <code>-X</code> style invocations. For lazy people like me! If you are not familiar with <code>clj -X</code>, read the docs <a href="https://clojure.org/reference/deps_and_cli#_execute_a_function">here</a>.</li><li>But with a better UX by not having to use quotes on the command line as a result of having to pass EDN directly: <code>:dir foo</code> instead of <code>:dir &apos;&quot;foo&quot;&apos;</code> or who knows how to write the latter in <code>cmd.exe</code> or Powershell.</li><li>Open world assumption: passing extra arguments does not break and arguments can be re-used in multiple contexts.</li><li>Because the line between calling functions from the command line and Clojure itself is blurred, validation of arguments should happen in your Clojure function, using your favorite tools (manually, spec, schema, malli...). As such, the library only focuses on coercion: turning argument strings into data which is then passed to your function.</li></ul><p>Given the function:</p><pre><code class="language-clojure">(defn foo [{:keys [force dir] :as m}]
  (prn m))
</code></pre><p>and with a little bit of <a href="https://github.com/babashka/cli#clojure-cli">config</a> in your <code>deps.edn</code>, you can call the function from the command line using:</p><pre><code class="language-text">clj -M:foo --force --dir=src
</code></pre><p>or:</p><pre><code class="language-text">clj -M:foo --force --dir src
</code></pre><p>which will then print:</p><pre><code class="language-clojure">{:force true, :dir &quot;src&quot;}
</code></pre><p>We did not have to teach babashka CLI anything about the expected arguments.</p><p>Another accepted syntax is:</p><pre><code class="language-text">clj -M:foo :force false :dir src
</code></pre><p>and this is parsed as:</p><pre><code class="language-clojure">{:force false, :dir &quot;src&quot;}
</code></pre><p>Booleans, numbers and keywords are auto-coerced, but if you want to make things strict, you can use metadata. E.g. if we want to accept a keyword for the option <code>mode</code>:</p><pre><code class="language-text">clj -M:foo :force false :dir src :mode overwrite
</code></pre><p>and parse it as:</p><pre><code class="language-clojure">{:force false, :dir &quot;src&quot; :mode :overwrite}
</code></pre><p>you can teach babashka CLI using metadata:</p><pre><code class="language-clojure">(defn foo
  {:org.babashka/cli {:coerce {:mode :keyword}}}
  [{:keys [force dir mode] :as m}]
  (prn m))
</code></pre><p>A leading colon is also accepted (and auto-coerced as keyword):</p><pre><code class="language-clojure">clj -M:foo :force false :dir src :mode :overwrite
</code></pre><p>The metadata format is set up in such a way that libraries need not have a dependency on babashka CLI itself.</p><p>Did you notice that the <code>-M</code> invocation now becomes almost identical to <code>-X</code>, but without quotes?</p><pre><code class="language-text">clj -M:foo :force true :dir src :mode :overwrite
clj -X:foo :force true :dir &apos;&quot;src&quot;&apos; :mode :overwrite
</code></pre><p>Let&apos;s look at a recent project, <a href="https://github.com/babashka/http-server">http-server</a>, where I used babashka CLI to serve both <code>-X</code>, and <code>-M</code> needs.</p><p>The only argument hints defined there right now are:</p><pre><code class="language-clojure">(def ^:private cli-opts {:coerce {:port :long}})
</code></pre><p>although that could have been left out since numbers are auto-coerced.</p><p>The <code>-main</code> function simply defers to the clojure <code>exec</code> API function (intended for <code>-X</code> usage) with the parsed arguments:</p><pre><code class="language-clojure">(defn ^:no-doc -main [&amp; args]
  (exec (cli/parse-opts args cli-opts)))
</code></pre><p>In turn, the <code>exec</code> function adds some light logic making it suitable for command line usage. It prints help when <code>:help</code> is true. Because I&apos;m lazy, I just print the docstring of <code>serve</code>, the function that&apos;s going to be called:</p><pre><code class="language-clojure">(defn exec
  &quot;Exec function, intended for command line usage. Same API as serve but
  blocks until process receives SIGINT.&quot;
  {:org.babashka/cli cli-opts}
  [opts]
  (if (:help opts)
    (println (:doc (meta #&apos;serve)))
    (do (serve opts)
        @(promise))))
</code></pre><p>Also the <code>exec</code> function blocks, preventing the process from immediately exiting.</p><p>Now when I add this function to <code>deps.edn</code> using:</p><pre><code class="language-clojure">:serve {:deps {org.babashka/http-server {:mvn/version &quot;0.1.3&quot;}}
        :main-opts [&quot;-m&quot; &quot;babashka.http-server&quot;]
        :exec-fn babashka.http-server/exec}
</code></pre><p>it can be called both with <code>-M</code> and <code>-X</code>:</p><pre><code class="language-text">$ clj -M:serve --port 1339
</code></pre><p>or:</p><pre><code class="language-text">$ clj -M:serve :port 1339
</code></pre><p>or:</p><pre><code class="language-text">$ clj -X:serve :port 1339
</code></pre><p>And help printing is supported in both styles:</p><pre><code class="language-text">$ clj -M:serve --help
Serves static assets using web server.
Options:
  * `:dir` - directory from which to serve assets
  * `:port` - port
</code></pre><p>or:</p><pre><code class="language-clojure">$ clj -X:serve :help true
</code></pre><p>The <code>-main</code> function can also be used in babashka scripts:</p><pre><code class="language-clojure">#!/usr/bin/env bb

(require &apos;[babashka.deps :as deps])
(deps/add-deps
 &apos;{:deps {org.babashka/http-server {:mvn/version &quot;0.1.3&quot;}}})

(require &apos;[babashka.http-server :as http-server])

(apply http-server/-main *command-line-args*)
</code></pre><pre><code class="language-clojure">$ http-server --help
$ http-server --port 1339
</code></pre><p>I hope you&apos;re convinced that with very little code, babashka CLI can let you support both <code>-M</code>, <code>-X</code> style invocations and babashka scripts, while improving command line UX!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/babashka-survey-q1-2022.html</id>
    <link href="https://blog.michielborkent.nl/babashka-survey-q1-2022.html"/>
    <title>Babashka survey Q1 2022 results!</title>
    <updated>2022-05-12T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In Q1 of 2022 I ran the babashka survey again. I&apos;ve done this once before (in November 2020) to see how people are using babashka and what they think could be improved. This year about 200 people responded. That is double the amount since the previous survey!</p><p>Here follows every question of the survey with a summary of the reactions.</p><h2 id="how-are-you-using-babashka?">How are you using babashka?</h2><ul><li>Shell scripting / bash replacement: 90%</li><li>Makefile replacing using babashka tasks: 43%</li><li>Small or internal web apps: 18%</li><li>Continuous integration: 29%</li></ul><p>The first two options were selected in the majority of answers. Unsurprisingly most people are using babashka as a shell-scripting replacement for bash, exactly how it was intended. <a href="https://book.babashka.org/#tasks">Babashka tasks</a> is catching on: almost half of babashka users are using it to replace their Makefiles.</p><h2 id="are-you-using-babashka-for-personal-projects,-at-work,-or-both?">Are you using babashka for personal projects, at work, or both?</h2><ul><li>Personal projects: 73%</li><li>At work: 74%</li></ul><p>About 50% of people used babashka both for personal projects and work. Only personal and only work was about 25% each. Some people use babashka to sneak in some Clojure at their non-Clojure jobs.</p><h2 id="where-do-you-think-babashka-should-be-improved?">Where do you think babashka should be improved?</h2><p>This question was free format. Some common themes:</p><ul><li>Stacktraces, better error messages</li><li>better nREPL / CIDER-middleware support</li><li>documentation:<ul><li>overview of all available vars + docstrings in babashka</li><li>cookbook</li><li>videos</li></ul></li><li>pods:<ul><li>documentation</li><li>http proxy support</li><li>make it easier to create pods</li></ul></li><li>REPL integration for bb tasks</li><li><a href="https://github.com/babashka/babashka/wiki/Self-contained-executable">Producing standalone binaries</a></li><li>Tasks: sharing/importing tasks from other files/remote hosts</li><li>More compatibility with Clojure: <code>deftype</code></li></ul><h2 id="what-features-/-libraries-/-namespaces-in-babashka-do-you-use-the-most?">What features / libraries / namespaces in babashka do you use the most?</h2><p>This question was also free format. Probably the top 5 most named libraries:</p><ul><li><a href="https://book.babashka.org/#tasks">tasks</a></li><li><a href="https://github.com/babashka/fs">fs</a></li><li><a href="https://github.com/babashka/process">process</a></li><li><a href="https://github.com/babashka/babashka.curl">babashka.curl</a></li><li><a href="https://github.com/dakrone/cheshire">cheshire</a> (json)</li></ul><h2 id="what-features-or-namespaces-in-babashka-are-redundant-and-could-be-left-out?">What features or namespaces in babashka are redundant and could be left out?</h2><p>The majority answer here was: none. People seem to be happy with the current selection of libraries.</p><h2 id="what-features-or-libraries-would-you-like-to-see-in-babashka-in-the-future,-if-any?">What features or libraries would you like to see in babashka in the future, if any?</h2><p>It&apos;s hard to see common patterns here. A random pick:</p><ul><li>clojure.spec.alpha</li><li>html parsing</li><li>time library</li><li>native interop</li><li>ssh support</li><li>malli</li><li>specter</li></ul><p>Note that spec is available in babashka via <a href="https://github.com/babashka/spec.alpha">this
library</a>.  Specter also works from source now since <code>:mvn/version &quot;1.1.4&quot;</code>. Dealing with time is done via <code>java.time</code> and <a href="https://github.com/henryw374/cljc.java-time">cljc.java-time</a> is one of the <code>java.time</code> based libraries that work in babashka.</p><h2 id="are-you-using-babashka.*-libraries-with-clojure-on-the-jvm?">Are you using babashka.* libraries with Clojure on the JVM?</h2><p>In order of mentions:</p><ul><li><a href="https://github.com/babashka/fs">fs</a></li><li><a href="https://github.com/babashka/process">process</a></li><li><a href="https://github.com/babashka/babashka.curl">babashka.curl</a></li></ul><p>It&apos;s great that people are using fs and process on the JVM. I didn&apos;t expect so many people to be using babashka.curl on the JVM too!</p><h2 id="is-the-binary-size-of-babashka-important-to-you?">Is the binary size of babashka important to you?</h2><p>84% of the people didn&apos;t care, 12% cared and 4% had a nuanced answer.</p><p>Note that bigger binary size in babashka is correlated with a longer compilation time and more strain on CI resources. That is the primary reason I&apos;m trying to keep it down.</p><h2 id="what-operating-system-are-you-using-babashka-on?">What operating system are you using babashka on?</h2><ul><li>linux: 76%</li><li>macOS: 58%</li><li>Windows: 17%</li></ul><h2 id="which-babashka-pods-are-you-using,-if-any?">Which babashka pods are you using, if any?</h2><p>The top 7:</p><ul><li><a href="https://github.com/babashka/babashka-sql-pods">postgresql</a></li><li><a href="https://github.com/babashka/pod-babashka-aws">aws-api</a></li><li><a href="https://github.com/babashka/babashka-sql-pods">sqlite</a></li><li><a href="https://github.com/retrogradeorbit/bootleg">bootleg</a></li><li><a href="https://github.com/babashka/pod-babashka-etaoin">etaoin</a></li><li><a href="https://github.com/babashka/pod-babashka-buddy">buddy</a></li><li><a href="https://github.com/babashka/pod-babashka-fswatcher">fswatcher</a></li></ul><p>Note that for AWS we now also have a source-compatible library: <a href="https://github.com/grzm/awyeah-api">awyeah-api</a>.</p><h2 id="when-would-you-use-babashka-instead-of-jvm-clojure?">When would you use babashka instead of JVM Clojure?</h2><p>A pick of the free-formatted answers:</p><ul><li>Everything I can use bb for.</li><li>Where deployment for bb is easier.</li><li>Short lived, small scripts.</li><li>Command line apps.</li><li>When performance isn&apos;t a strict requirement, but resource usage is</li><li>For small websites.</li></ul><h2 id="any-other-feedback-on-babashka-you-would-like-to-give?">Any other feedback on babashka you would like to give?</h2><p>Lots of thank you&apos;s and compliments... <code>*blush*</code></p><h2 id="are-you-a-user-of-other-babashka-related-projects?-please-share!">Are you a user of other babashka-related projects? Please share!</h2><p>Favorite pick:</p><ul><li>My personal website, <a href="https://saltosti.com">saltosti.com</a>, is a scittle app running via a <code>&lt;script&gt;</code> tag.</li></ul><p>Other answers:</p><ul><li><a href="https://github.com/babashka/sci">SCI</a></li><li><a href="https://github.com/borkdude/nbb">nbb</a></li><li><a href="https://babashka.org/scittle/">scittle</a></li><li><a href="https://github.com/babashka/obb">obb</a></li></ul><h2 id="conclusion">Conclusion</h2><p>The majority of answers to this survey were not too surprising, yet a good confirmation that babashka is doing what it&apos;s supposed to be doing. In individual answers there were a few fun discoveries, like learning which big companies are using babashka.</p><p>You can read results from the previous survey <a href="https://github.com/babashka/babashka/blob/master/doc/surveys/2020-11.md">here</a>. In that survey I asked users what they thought was currently missing in babashka. You can find those answers <a href="https://github.com/babashka/babashka/blob/master/doc/surveys/2020-11.md#q4-what-functionality-is-currently-missing-in-babashka">here</a>. I think almost all points were addressed in the meanwhile. The improvements requested in this survey feel mostly as finishing touches: documentation, error messages, nREPL improvements, so it&apos;s probably safe to say that babashka now covers the most important Clojure scripting use cases.</p><p>Hardly anyone mentioned performance as something that should be improved, although that has been an area of focus in the beginning of this year and something I will be looking into in an ongoing basis. Most if not all of that work is happening in SCI, which is also powering <a href="https://github.com/babashka/nbb">nbb</a> and other JS targets.</p><p>If you are interested in the raw (anonimized) data for this survey, then send me a message.</p><h2 id="thanks">Thanks</h2><p>Thanks for taking the survey and being part of the babashka community!  Also, thanks to everyone making babashka possible. <a href="https://github.com/sponsors/borkdude">Sponsors</a>, <a href="https://github.com/babashka/babashka/graphs/contributors">contributors</a> and users.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-mar-apr-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-mar-apr-2022.html"/>
    <title>OSS Updates of March - April 2022</title>
    <updated>2022-04-29T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during March and April 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible. To name a few: <a href="https://clojuriststogether.org/">Clojurists
Together</a>, <a href="https://roamresearch.com/">Roam
Research</a>, <a href="https://www.adgoji.com/">Adgoji</a>, <a href="https://www.cognitect.com/">Cognitect</a>, <a href="https://nextjournal.com/">Nextjournal</a>.</p><p>If you&apos;d like to sponsor this work or see who else is sponsoring, you can do so via the following channels:</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h2><p>A linter for Clojure (code) that sparks joy.</p><p>Published versions: 2022.03.04, 2022.03.08, 2022.03.09, 2022.04.08, 2022.04.23, 2022.04.25</p><p>Read the changelog <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>New linters: <code>:namespace-mismatch</code>, <code>:non-arg-vec-return-type-hint</code>, <code>:keyword-binding</code>, <code>:discouraged-var</code></li><li>More analysis output for Java classes, protocols and multi-methods</li></ul><h2 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h2><p>Native, fast starting Clojure interpreter for scripting.</p><p>Published versions: 0.7.7, 0.7.8, 0.8.0, 0.8.1</p><p>Read the changelog <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Declarative pod configuration in <code>bb.edn</code></li><li>Compatibility with <a href="https://github.com/redplanetlabs/specter">specter</a></li><li>Fixes for <code>reify</code>, calls to interface default methods are now correctly implemented</li></ul><h2 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h2><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>Published versions: 0.3.2, 0.3.3, 0.3.4</p><p>Read the changelog <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">here</a>.</p><p>Summary: many small incremental improvements.</p><h2 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h2><p>Ad-hoc CLJS scripting on Node.js using SCI.</p><p>Published versions: v0.2.1 - v0.3.10.</p><p>Read the changelog <a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li><a href="https://github.com/babashka/nbb/blob/main/doc/dev.md#features">Features</a> mechanism which allows you to re-package nbb with your favorite CLJS libraries.</li><li>Videos: <a href="https://youtu.be/7DQ0ymojfLg">London Clojurians</a>, <a href="https://youtu.be/_-G9EKaAyuI">On the Code Again</a></li><li><code>nbb.core/await</code> REPL helper to &quot;block&quot; on promises and get their results</li><li>nREPL completion improvements</li></ul><h2 id="joyride"><a href="https://github.com/BetterThanTomorrow/joyride">Joyride</a></h2><p>Modify VSCode by executing ClojureScript (SCI) code in your REPL and/or run scripts via keyboard shortcuts.</p><p>Read the changelog <a href="https://github.com/BetterThanTomorrow/joyride/blob/master/CHANGELOG.md">here</a>.</p><p>This is a new project!</p><h2 id="grasp"><a href="https://github.com/borkdude/grasp">Grasp</a></h2><p>Grep Clojure code using clojure.spec regexes.</p><p>Highlights:</p><ul><li>Support <code>:keep-fn</code>, allowing you to keep track of the conformed value in one go</li></ul><h2 id="obb"><a href="https://github.com/babashka/obb">Obb</a></h2><p>Ad-hoc ClojureScript scripting of Mac applications via Apple&apos;s Open Scripting Architecture.</p><p>Published versions: 0.0.3</p><p>Read the changelog <a href="https://github.com/babashka/obb/blob/main/CHANGELOG.md">here</a>.</p><h2 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h2><p>A CLI to add common aliases and features to deps.edn-based projects.</p><p>Highlights:</p><ul><li>List available versions</li><li>Dependency search</li><li>New <code>license</code> subcommand</li></ul><h2 id="rewrite-edn"><a href="https://github.com/borkdude/rewrite-edn">Rewrite-edn</a></h2><p>Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments.</p><p>Read the changelog <a href="https://github.com/borkdude/rewrite-edn/blob/master/CHANGELOG.md">here</a>.</p><h2 id="tools.misc"><a href="https://github.com/clj-easy/tools.misc">Tools.misc</a></h2><p>Tools library similar to clojure.tools.logging but for misc. tools.</p><p>So far this is just an experiment, but join the discussion if you want.</p><h2 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h2><p>File system utility library for Clojure.</p><p>Published versions: 0.1.4.</p><p>Read the changelog <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md">here</a>.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-updates-jan-feb-2022.html</id>
    <link href="https://blog.michielborkent.nl/oss-updates-jan-feb-2022.html"/>
    <title>OSS Updates of January - February 2022</title>
    <updated>2022-02-27T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In this post I&apos;ll give updates about open source I worked on during January and February 2022.</p><h2 id="sponsors">Sponsors</h2><p>But first off, I&apos;d like to thank all the sponsors and contributors that make this work possible. To name a few: <a href="https://clojuriststogether.org/">Clojurists
Together</a>, <a href="https://roamresearch.com/">Roam
Research</a>, <a href="https://www.adgoji.com/">Adgoji</a>, <a href="https://www.cognitect.com/">Cognitect</a>, <a href="https://nextjournal.com/">Nextjournal</a>.</p><p>If you&apos;d like to sponsor this work or see who else is sponsoring, you can do so via the following channels:</p><ul><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li></ul><h2 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h2><p>Native, fast starting Clojure interpreter for scripting.</p><p>Published versions: 0.7.4 - 0.7.6.</p><p>Read the changelog <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Add new namespace from clojure 1.11: <code>clojure.math</code></li><li>Performance improvements (see SCI).</li><li>Compatibility with more Clojure libraries and lots of small bug fixes.</li></ul><p>I also submitted a PR to <a href="https://github.com/l3nz/cli-matic">cli-matic</a> to fix the long standing issue about babashka compatibility.</p><p>Please leave some feedback about babashka in the <a href="https://forms.gle/ko3NjDg2SwXeEoNQ9">Q1 Survey</a>!</p><h2 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h2><p>A linter for Clojure (code) that sparks joy.</p><p>Published versions: 2022.01.13, 2022.01.15, 2022.02.09.</p><p>Read the changelog <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Maybe new linters added: <code>:conflicting-fn-arity</code>, <code>:clj-kondo-config</code>, <code>:reduce-without-init</code>, <code>:redundant-fn-wrapper</code>, linting for <code>bb.edn</code> config files.</li><li>Improvements with regards to type inferences and map results</li><li>Contributed to clj-kondo config in <a href="https://github.com/Engelberg/better-cond/tree/master/resources/clj-kondo.exports/better-cond/better-cond">better-cond</a> so everyone who uses the library gets correct and useful linting feedback.</li></ul><h2 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h2><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>Published versions: v0.2.9 - v0.3.1.</p><p>Read the changelog <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md">here</a>.</p><ul><li>Fix compatibility with Graal.js</li><li>Performance improvements for loops and vararg function calls.</li><li>JS interop fixes / improvements</li></ul><h2 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h2><p>Ad-hoc CLJS scripting on Node.js using SCI.</p><p>Published versions: v0.1.1 - v0.2.0.</p><p>Read the changelog <a href="https://github.com/babashka/nbb/blob/main/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>See SCI improvements.</li><li>Bundled library updates</li></ul><h2 id="scittle-the-small-clojure-interpreter-exposed-for-usage-in-browser-script-tags"><a href="https://github.com/babashka/scittle">Scittle</a> The Small Clojure Interpreter exposed for usage in browser script tags</h2><p>Published versions: v0.1.0 - v0.1.2.</p><p>Read the changelog <a href="https://github.com/babashka/scittle/blob/main/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Upgrade SCI with performance and JS interop improvements</li><li>Expose more Reagent features</li></ul><h2 id="obb"><a href="https://github.com/babashka/obb">Obb</a></h2><p>Ad-hoc ClojureScript scripting of Mac applications via Apple&apos;s Open Scripting Architecture.</p><p>Published versions: 0.0.1 - 0.0.2</p><p>Read the changelog <a href="https://github.com/babashka/obb/blob/main/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>This is a new project!</li></ul><h2 id="fs"><a href="https://github.com/babashka/fs">Fs</a></h2><p>File system utility library for Clojure.</p><p>Published versions: 0.1.3.</p><p>Read the changelog <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>New functions <code>create-temp-file</code> and <code>zip</code></li><li>Compatibility with <code>com.google.cloud/google-cloud-nio</code></li></ul><h2 id="process"><a href="https://github.com/babashka/process">Process</a></h2><p>Clojure wrapper for <code>java.lang.ProcessBuilder</code>.</p><p>Published versions: 0.1.1. Read the changelog <a href="https://github.com/babashka/process/blob/master/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Support appending to files in addition to overwriting them.</li></ul><h2 id="pod-babashka-go-sqlite-3"><a href="https://github.com/babashka/pod-babashka-go-sqlite3">Pod-babashka-go-sqlite-3</a></h2><p>A babashka pod for interacting with sqlite3.</p><p>Released versions: 0.1.0.</p><p>Highlights:</p><ul><li>Bump sqlite version and support single string rather than wrapped in vector.</li></ul><h2 id="pod-babashka-buddy"><a href="https://github.com/babashka/pod-babashka-buddy">Pod-babashka-buddy</a></h2><p>A pod around buddy core (Cryptographic Api for Clojure).</p><p>Released versions: 0.1.0.</p><p>Highlights: expose more namespaces.</p><h2 id="pod-babashka-aws"><a href="https://github.com/babashka/pod-babashka-aws">Pod-babashka-aws</a></h2><p>AWS pod wrapping the Cognitect aws-api library.</p><p>Released versions: 0.1.1-0.1.2.</p><p>Read the changelog <a href="https://github.com/babashka/pod-babashka-aws/blob/main/CHANGELOG.md">here</a>.</p><p>Highlights:</p><ul><li>Provide aarch64 binary.</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/aws-lambda-nbb.html</id>
    <link href="https://blog.michielborkent.nl/aws-lambda-nbb.html"/>
    <title>Creating an AWS Lambda function with nbb</title>
    <updated>2022-01-08T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="nbb">Nbb</h2><p><a href="https://github.com/babashka/nbb">Nbb</a> is a scripting environment, in the tradition of babashka, but for Node.js. Like babashka, nbb doesn&apos;t have a compile cycle, but it just interprets Clojure code using <a href="https://github.com/babashka/sci">SCI</a>. It has a few useful CLJS libraries included, e.g. for JS interop. It can load <em>any</em> JS library from NPM. Check out the repo <a href="https://github.com/babashka/nbb">here</a>. There are several <a href="https://github.com/babashka/nbb/tree/main/examples">examples</a> available as well.</p><h2 id="nbb-on-aws-lambda">Nbb on AWS Lambda</h2><p>While it was already possible to use nbb on AWS Lambda, it needed some boilerplate code. Valtterri Harmainen captured this boilerplate in his <a href="https://github.com/vharmain/nbb-lambda-adapter">nbb-lambda-adapter</a>.</p><p>This week AWS announced that <a href="https://aws.amazon.com/about-aws/whats-new/2022/01/aws-lambda-es-modules-top-level-await-node-js-14/">AWS Lambda now supports ES Modules and Top-Level
Await for Node.js
14</a>. With that in place, the boilerplate code isn&apos;t necessary anymore.</p><h2 id="creating-an-nbb-lambda">Creating an nbb lambda</h2><p>All you need to do to get nbb running on AWS Lambda is the following:</p><p>package.json:</p><pre><code>{&quot;dependencies&quot;: {&quot;nbb&quot;: &quot;0.1.0&quot;}}
</code></pre><p>index.mjs:</p><pre><code class="language-javascript">import { loadFile } from &apos;nbb&apos;;

const { handler } = await loadFile(&apos;./example.cljs&apos;);

export { handler }
</code></pre><p>example.cljs:</p><pre><code class="language-clojure">(ns example)

(defn handler [event _ctx]
  (js/console.log event)
  (js/Promise.resolve #js{:hello &quot;world&quot;}))

#js {:handler handler}
</code></pre><p>Make sure to run <code>npm install</code>.</p><p>Zip the directory: <code>zip -r app.zip .</code></p><p>Go to the AWS Console. <code>Choose Lambda</code> -&gt; <code>Author from Scratch</code> -&gt; <code>Runtime Node.s 14.x + arm64</code>. The default 128 MB should be sufficient for fast response times after cold start, but for fast cold starts, higher memory (which comes with higher CPU) is better.</p><p>Then choose <code>Upload from</code> and choose the zip file.</p><p>You can test the lambda function by creating a test event and invoking it.</p><p>To be able to invoke the function via HTTP, you&apos;ll first have to <code>Publish</code> it.</p><p>The API Gateway response has to be a little different so adjust your handler code like this...</p><p>example.cljs:</p><pre><code class="language-clojure">(ns example)

(defn handler [event _ctx]
      (js/console.log event)
      (js/Promise.resolve
        (clj-&gt;js {:statusCode 200
                  :body       (js/JSON.stringify #js{:hello &quot;world&quot;})})))

#js {:handler handler}
</code></pre><p>After uploading the updated code, under <code>Configuration &gt; Trigger</code> you can add an API Gateway trigger. Create one and choose <code>HTTP API</code> and <code>Security Open</code> (make sure you change this when it becomes a private production lambda rather than just for the sake of trying nbb on lambda!).</p><p>After that you should end up with a public URL like <code>https://9fov8nrv4f.execute-api.eu-central-1.amazonaws.com/default/...</code> which you can then call from <code>curl</code> or via a browser. The response times I got after the cold start were around 100ms.</p><p>As a nice bonus, you can edit the CLJS code directly in the console:</p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">After cold start on a 128MB ARM lambda:<br><br>$ time curl <a href="https://t.co/NGsyrtbKZp">https://t.co/NGsyrtbKZp</a><br>{&quot;hello&quot;:&quot;world&quot;}curl 0.02s user 0.01s system 23% cpu 0.105 total<br><br>And you get to edit the CLJS code in the console :) <a href="https://t.co/4ql2R04R0N">pic.twitter.com/4ql2R04R0N</a></p>&mdash; (λ. borkdude) (@borkdude) <a href="https://twitter.com/borkdude/status/1479786184557617160?ref_src=twsrc%5Etfw">January 8, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><p>Also check out this <a href="https://github.com/vharmain/nbb-serverless-example">nbb serverless
example</a> that Valtteri Harmainen made.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/using-babashka-with-php.html</id>
    <link href="https://blog.michielborkent.nl/using-babashka-with-php.html"/>
    <title>Using babashka with PHP: guestbook example</title>
    <updated>2022-01-07T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>One of the recurring themes in Clojure land is:</p><ul><li>There is a popular widely used platform (JVM, browser, .NET, Node.js, ...).</li><li>We may not like the language that comes with that platform.</li><li>Adding Clojure on top of that platform might make the platform more tolerable and fun to use.</li></ul><p>Enter PHP. PHP isn&apos;t a platform / language I like to use, but it sure is practical and widely adopted. I already have a PHP server running, so I thought, let&apos;s try some Clojure on top of this in the form of <a href="https://babashka.org/">babashka</a>. Babashka already has a built-in http server, but using this approach it isn&apos;t used. We just rely on PHP calling babashka when the PHP script is requested via nginx. The babashka script prints HTML and then exits. PHP sends the HTML to the browser as it would normally do. If you have already paid the operational costs of installing and maintaining PHP, this approach doesn&apos;t add much cost to it. A closely related CGI-based approach, but one that doesn&apos;t use PHP at all, has been explored before by Eccentric-J and you can read his blog post <a href="https://eccentric-j.com/blog/clojure-like-its-php.html">here</a>.</p><p>The example described in this blog post is a guestbook.  You can view the guestbook <a href="https://cgi.michielborkent.nl/guestbook.php">here</a> and the code is on <a href="https://github.com/borkdude/bb-php-guestbook">Github</a>. Below is a brief explanation of the components involved.</p><h2 id="database-table">Database table</h2><p>I created the following database table to store a name, greeting and some metadata:</p><pre><code class="language-sql">CREATE TABLE public.guestbook
(
name text,
message text,
_created timestamp without time zone,
_session text,
CONSTRAINT session_unique UNIQUE (session)
)
</code></pre><h2 id="php-babashka-wrapper">PHP Babashka wrapper</h2><p>This small PHP script forwards some of the request data to babashka:</p><pre><code class="language-php">&lt;?php
session_start();
$post_data=escapeshellarg(json_encode($_POST));
$query_params=escapeshellarg(json_encode($_GET));
$sess_id=session_id();
passthru(&quot;POST_DATA=$post_data QUERY_PARAMS=$query_params SESSION_ID=$sess_id ./bb guestbook.clj&quot;);
?&gt;
</code></pre><p>The <code>passthru</code> command calls a locally installed version of babashka, in the same directory as the PHP script and adds some environment variables. It encodes posted data and query parameters as JSON, which in the babashka script we will decode as JSON:</p><pre><code class="language-clojure">(def post-data (-&gt; (System/getenv &quot;POST_DATA&quot;)
                   (cheshire/parse-string
                    true)))
</code></pre><h2 id="babashka-guestbook-script">Babashka guestbook script</h2><p>In the babashka script, I use the babashka <a href="https://github.com/babashka/babashka-sql-pods">PostgreSQL pod</a> to interact with the database:</p><pre><code class="language-clojure">(require &apos;[babashka.pods :as pods])
(pods/load-pod &quot;./pod-babashka-postgresql&quot;)
(require &apos;[pod.babashka.postgresql :as sql])
</code></pre><p>Note that I also downloaded the pod locally into the directory. I needed to do this because the PHP server runs under a different user which doesn&apos;t have a home directory, so installing from the <a href="https://github.com/babashka/pod-registry">pod
registry</a> didn&apos;t work for that reason.</p><p>Here I check if a user already posted a greeting before, using the session id:</p><pre><code class="language-clojure">(def session-id (System/getenv &quot;SESSION_ID&quot;))

(def db {:dbtype &quot;postgresql&quot;
         :user &quot;guestbook&quot;
         :password &quot;guestbook&quot;
         :database &quot;guestbook&quot;
         :port 5434})

(def posted-before
  (-&gt; (sql/execute-one! db [&quot;select count(*) from guestbook where _session = ?&quot; session-id])
      :count))
</code></pre><p>The script uses hiccup to render HTML. E.g here is the code for the guestbook:</p><pre><code class="language-clojure">(defn render-messages []
  [:table.table
   [:thead
    [:tr
     [:th &quot;Name&quot;]
     [:th &quot;Greeting&quot;]]]
   [:tbody
    (for [{:guestbook/keys [name message]} entries]
      [:tr
       [:td name]
       [:td message]])]])
</code></pre><p>The guestbook form has some fields to protect against spambots: the user is supposed to fill in the outcome of a sum or multiplication. Also it is required to post the data using the same session id that you got when you entered the data. You can see that in the function <code>process-post-data</code> <a href="https://github.com/borkdude/bb-php-guestbook/blob/main/guestbook.clj#L26">here</a>.</p><p>The babashka script can print at any time and the output is rendered via the PHP wrapper as HTML. This is pretty handy for debugging. I wrote the script remotely on a server and just refreshed my browser any time I added some debug information, old school style.</p><p>One downside of this approach is whenever an exception happens you might not see any useful output in the page, so some defensive programming using <code>try/catch</code> is sometimes necessary.</p><p>So here you have it, documented for any PHP + Clojure user who might find it useful.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-highlights-nov-dec-2021.html</id>
    <link href="https://blog.michielborkent.nl/oss-highlights-nov-dec-2021.html"/>
    <title>OSS Highlights of November - December 2021</title>
    <updated>2021-12-31T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Like the previous <a href="oss-highlights-sep-oct-2021.html">OSS highlights</a>, I&apos;ll give an overview of OSS work I did in November and December of 2021. I&apos;d like to emphasize that I can do this work because of sponsoring via:</p><ul><li><a href="https://www.clojuriststogether.org/">Clojurists Together</a></li><li><a href="https://github.com/sponsors/borkdude">Github Sponsors</a></li><li><a href="https://opencollective.com/babashka">OpenCollective</a> (also see the <a href="https://opencollective.com/clj-kondo">clj-kondo</a> one)</li></ul><p>for which I&apos;m very grateful. I love helping peoeple by providing OSS software and this is now my main activity.</p><h2><a name="enterprise-support"><a href="#enterprise-support">Enterprise support</a></a></h2>
<!-- old name -->
<a name="commercial-oss-support"><a href="#commercial-oss-support"></a></a><p>I&apos;d like to add that I&apos;m also offering enterprise support for my OSS projects. It might be good to know there are options beyond sponsoring if your company needs an extra level of support for my OSS libraries. Recurring sponsors are eligible for a discount. Feel free to reach out via Twitter DM, <a href="mailto:michielborkent@gmail.com">e-mail</a> or on Clojurians Slack to discuss options.</p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Do you need help with <a href="https://twitter.com/hashtag/clojure?src=hash&amp;ref_src=twsrc%5Etfw">#clojure</a> <a href="https://twitter.com/hashtag/graalvm?src=hash&amp;ref_src=twsrc%5Etfw">#graalvm</a> compilation, <a href="https://twitter.com/hashtag/clojure?src=hash&amp;ref_src=twsrc%5Etfw">#clojure</a> static analysis/linting tools, or anything related to my <a href="https://twitter.com/hashtag/oss?src=hash&amp;ref_src=twsrc%5Etfw">#oss</a> projects? I&#39;m available for USD 150/hr. I also do custom license/support contracts if <a href="https://twitter.com/github?ref_src=twsrc%5Etfw">@github</a> sponsors doesn&#39;t fit your business.<a href="https://twitter.com/hashtag/cljkondo?src=hash&amp;ref_src=twsrc%5Etfw">#cljkondo</a> <a href="https://twitter.com/hashtag/babashka?src=hash&amp;ref_src=twsrc%5Etfw">#babashka</a> <a href="https://twitter.com/hashtag/sci?src=hash&amp;ref_src=twsrc%5Etfw">#sci</a></p>&mdash; (λ. borkdude) (@borkdude) <a href="https://twitter.com/borkdude/status/1475416703198707718?ref_src=twsrc%5Etfw">December 27, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><h2 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h2><p>Native, fast starting Clojure interpreter for scripting.</p><p>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#073-2021-12-30">0.7.3</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#072-2021-12-29">0.7.2</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#070-2021-12-10">0.7.0</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#068-2021-12-02">0.6.8</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#067-2021-11-29">0.6.7</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#066-2021-11-29">0.6.6</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#065-2021-11-13">0.6.5</a></p><p>Highlights:</p><ul><li>Load tasks and deps from other bb.edn file using <code>--config</code> and <code>--deps-root</code> options <a href="https://github.com/babashka/babashka/issues/1110">#1110</a></li><li>Add compatibility with <code>clojure.spec.alpha</code>. See <a href="https://github.com/babashka/spec.alpha">babashka/spec.alpha</a> and this <a href="https://blog.michielborkent.nl/using-clojure-spec-alpha-with-babashka.html">blog
  post</a>.</li><li>Compatibility with a <a href="https://github.com/babashka/tools.namespace">fork of
  tools.namespace</a>. This allows running the Cognitect <a href="https://github.com/cognitect-labs/test-runner">test-runner</a> (Cognitest) from source.</li><li><a href="https://github.com/babashka/tools.bbuild">tools.bbuild</a>.</li><li>Compatiblity with <a href="https://github.com/yogthos/markdown-clj">markdown-clj</a> (see <a href="https://blog.michielborkent.nl/markdown-clj-babashka-compatible.html">blog</a>)</li></ul><h2 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h2><p>A linter for Clojure (code) that sparks joy.</p><p>Releases: <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20211219">2021.12.19</a> , <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20211216">2021.12.16</a> , <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20211201">2021.12.01</a></p><p>Highlights:</p><ul><li>Automatically load configurations from <code>.clj-kondo/*/*/config.edn</code>. This can be disabled with <code>:auto-load-configs false</code>.  See issue <a href="https://github.com/clj-kondo/clj-kondo/issues/1492">#1492</a>. This makes life easier for those using <a href="https://github.com/clojure-lsp/clojure-lsp">clojure-lsp</a> which already uses the <code>--copy-configs</code> option by default.</li><li>Several new linters: <code>:reduce-without-init</code>, <code>:duplicate-case-test-constant</code>, <code>:unexpected-recur</code>, <code>:used-underscored-binding</code> and a few around docstrings. See the <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md">linters.md</a> docs for details.</li><li><a href="https://github.com/Engelberg/better-cond">better-cond</a> now bundles a clj-kondo config!</li></ul><p>Note that most new linters in clj-kondo are going to default to <code>:level :off</code> unless they detect a compile time error, like <code>:duplicate-case-test-constant</code>.</p><p>Special thanks to new contributor <a href="https://github.com/mknoszlig">@mknoszlig</a> who has been quite active in adding new linters in collaboration with me.</p><h2 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h2><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><p>Releases: <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md#v028">0.2.8</a></p><p>Highlights:</p><ul><li>Add <code>copy-ns</code> macro for copying an entire Clojure or ClojureScript namespace into a SCI context</li><li><code>clojure.core/read</code> improvements</li><li>Lots of little &apos;devil is in the details&apos; correctness improvements</li></ul><h2 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h2><p>Ad-hoc CLJS scripting on Node.js using SCI.</p><p>Releases: v0.0.108 - v0.1.0. See <a href="https://www.npmjs.com/package/nbb">npm</a>.</p><p>Highlights:</p><ul><li>Add <code>nbb.classpath</code> which is also available in the JS API.</li><li>Add <a href="https://github.com/mfikes/cljs-bean">cljs.bean</a> as built-in library.</li><li>Add <code>--help</code> and <code>--main</code> command line options (finally!)</li></ul><h2 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h2><ul><li>Automatically use newest tool.build with <code>add build</code></li></ul><h2 id="edamame"><a href="https://github.com/borkdude/edamame">Edamame</a></h2><p>Configurable EDN/Clojure parser with location metadata</p><p>Releases: <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0013">0.0.13</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0014">0.0.14</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0015">0.0.15</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0016">0.0.16</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0017">0.0.17</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0018">0.0.18</a> , <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0019">0.0.19</a></p><p>Many small improvements. Edamame now supports reading with a reader which is not an indexing reader too, for compatibility with <code>clojure.core/read</code>.</p><h2 id="babashka.fs"><a href="https://github.com/babashka/fs">Babashka.fs</a></h2><p>File system utility library.</p><p>Releases: <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#v012">0.1.2</a> , <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#v011">0.1.1</a></p><p>Highlights: improve <code>fs/which</code> on Windows, add <code>with-temp-dir</code> macro.</p><h2 id="babashka.process"><a href="https://github.com/babashka/process">Babashka.process</a></h2><p>Clojure wrapper for <code>java.lang.ProcessBuilder</code>.</p><p>Releases: <a href="https://github.com/babashka/fs/blob/master/CHANGELOG.md#010">0.1.0</a></p><p>Highlights:</p><ul><li>Resolve binaries on Windows using <code>fs/which</code></li><li>Support <code>deref</code> with timeout <a href="https://github.com/babashka/process/issues/50">#50</a> (<a href="https://github.com/SevereOverfl0w">@SevereOverfl0w</a>)</li></ul><h2 id="tools.namespace"><a href="https://github.com/clojure/tools.namespace">tools.namespace</a></h2><p>In this core library I contributed two ClojureScript fixes:</p><ul><li><a href="https://github.com/clojure/tools.namespace/commit/180c162f1330d5295b8e5d47bc65cbf3ef1e8eb2">TNS-51</a></li><li><a href="https://github.com/clojure/tools.namespace/commit/f40c9e58278acb152c7b8c1c21a6b10795a99e8a">TNS-57</a></li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/using-clojure-spec-alpha-with-babashka.html</id>
    <link href="https://blog.michielborkent.nl/using-clojure-spec-alpha-with-babashka.html"/>
    <title>Using clojure.spec.alpha with babashka</title>
    <updated>2021-12-10T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="tl;dr">Tl;dr</h2><p>If you want to use <code>clojure.spec.alpha</code> with babashka, upgrade to 0.7.0 or newer and use <a href="https://github.com/babashka/spec.alpha">babashka/spec.alpha</a> as a library.</p><h2 id="the-issue">The issue</h2><p><a href="https://github.com/clojure/spec.alpha">Spec</a> is a library for validating and conforming (destructuring) data that comes with Clojure. For over a year there was an <a href="https://github.com/babashka/babashka/issues/558">open issue</a> in the <a href="https://babashka.org/">babashka</a> Github repo about whether to include clojure.spec into babashka, a fast starting native Clojure scripting environment. Clojure.spec is used in many libraries and adding it would add compatibility with more of them. I already knew that from a technical perspective <a href="https://github.com/babashka/sci">SCI</a> (the interpreter used by babashka) and clojure.spec can work together well. I&apos;ve put this into practice in <a href="https://github.com/borkdude/grasp">grasp</a>, a tool to &quot;grep&quot; Clojure source using clojure specs. It provides a binary which includes clojure spec in the same way that babashka would. The question is: should we include clojure.spec.alpha in babashka?</p><h2 id="what-does-built-in-mean?">What does built-in mean?</h2><p>Adding a library as a built-in in babashka means that it is compiled into babashka&apos;s native image. The functions are pre-compiled to native machine code and aren&apos;t run through the SCI interpreter. This is much better for performance, but also for startup time. Loading libraries from source in babashka involved parsing and analyzing code before using it. Adding a library as a built-in means that this work is already done at compile time, by the Clojure compiler instead of SCI.</p><h2 id="alpha">Alpha</h2><p>So far all built-in third party libraries in babashka are well established projects that have been around for years and whose APIs are unlikely to change. Boring in the good sense. Clojure spec, as of now, is alpha. That doesn&apos;t mean that <code>clojure.spec.alpha</code> is unstable, but what does it mean? Will it ever disappear from Clojure once it&apos;s not alpha anymore? In 2019 Alex Miller gave an inspiring <a href="https://youtu.be/KeZNRypKVa4">talk</a> at ClojuTRE in which he announced that spec 2 was soon coming. I&apos;m still hoping it will soon come, but I understand that a lot of good things happened at Cognitect and they had other things to work on. In the open babashka issue I&apos;ve asked for feedback on including <code>clojure.spec.alpha</code> as it is and most people were in favor of waiting for clojure spec 2. I decided to be patient and investigate alternatives. If we aren&apos;t going to include <code>clojure.spec.alpha</code> as a built-in, what alternatives do we have? We could try to run <code>clojure.spec.alpha</code> from source instead of a built-in so people can use it as an optional library.</p><h2 id="test.check">Test.check</h2><p>The <a href="https://github.com/clojure/test.check">test.check</a> library is used by clojure.spec to generate random data from specs. Libraries operating in the same space as spec, like <a href="https://github.com/metosin/malli">Malli</a>, are using this library for the same purpose. I decided to go ahead and add this library in babashka as a preparation for the soon coming spec 2. This was done in <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v028">0.2.8</a>, released in January 2021. Since then you could already use namespaces from test.check in babashka, without using it with spec.</p><h2 id="spartan.spec">Spartan.spec</h2><p>When babashka was only a few months old, it didn&apos;t cover as many clojure features as it does today. Running <code>clojure.spec.alpha</code> from source wasn&apos;t something within reach, mostly because babashka didn&apos;t support protocols. Protocols were introduced in version <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#v011-2020-06-10">0.1.1</a> in June of 2020, but by then I already made a rewrite of clojure.spec.alpha that used plain hashmaps instead of protocols. This version was called <a href="https://github.com/borkdude/spartan.spec">spartan.spec</a>: spartan, because it supported the basic features of spec, but not all. It did not support generators, <code>fdef</code> and instrumentation. Although I could have made that work, just validating and conforming data is what most people were doing with spec in the libraries that I&apos;ve been trying to run with babashka. Upon requiring <code>spartan.spec</code> it would create the namespace <code>clojure.spec.alpha</code> for you, so libraries loaded after that point would think they were using the original. This approach proved out to work pretty well. Even tools like <a href="https://github.com/bhb/expound">expound</a> worked with spartan.spec. But spartan.spec was a rewrite of spec and needed more work if we wanted to cover the other features. An effort that could be spared if babashka could just load the original spec from source.</p><h2 id="clojure.spec.alpha-from-source">Clojure.spec.alpha from source</h2><p>When introducing protocols, I hadn&apos;t thought of revisiting running clojure.spec.alpha from source again. For some reason this only occurred to me in the past few days. I discovered that the remaining incompatibilities were minimal. Here are some things I found and what I did in a fork to solve the compatibility with babashka:</p><ul><li>Spec uses <code>clojure.lang.Compiler/demunge</code> to turn function names into symbols for displaying information about them. This functionality is also provided by <code>clojure.main/demunge</code> and <code>clojure.repl/demunge</code>, and both functions were already in babashka. I didn&apos;t want to expose <code>clojure.lang.Compiler</code> in babashka, since babashka doesn&apos;t have a compiler at all, so I replaced these calls with the <code>clojure.main/demunge</code> function. I raised an issue on <a href="https://ask.clojure.org/index.php/11371/consider-adding-demunge-into-clojure-core">ask.clojure</a> to see if we can get this function into <code>clojure.core</code>.</li><li>Spec uses Java interop on <code>clojure.lang.Var</code> to get the namespace and name symbols from a var. In babashka there is no <code>clojure.lang.Var</code>: SCI has its own var type which works both in the JVM / GraalVM native and in JavaScript. I used the metadata on SCI vars to get this information instead.</li><li>The function <code>clojure.spec.alpha/multi-spec-impl</code> uses Java interop on multimethods, so I had to expose <code>clojure.lang.MultiFn</code> in babashka to make that possible. I noticed this when trying to use <code>multi-spec</code> in babashka when I thought I was already done porting. Surprisingly spec&apos;s tests didn&apos;t catch this, which I had been using to verify if the port worked. I pulled out some examples from the <a href="https://clojure.org/guides/spec">spec guide</a> and turned those into tests for <code>multi-spec</code>. Alex Miller included those tests upstream after I poked him about it. Thanks Alex!  The <code>multi-spec-impl</code> function pulls out the dispatch function from a multimethod with <code>(.dispatchFn mm)</code>. This is not a method call, since <code>dispatchFn</code> is a public field. I needed to improve SCI to support public field lookups in Java classes. The expression could have been written like <code>(.-dispatchFn mm)</code> to make the field lookup explicit and this is what I changed it to, in order to not have to support this ambiguity in SCI. This issue would have been easier to deal with if <code>clojure.core</code> exposed <code>dispatch-fn</code> like ClojureScript does. Vote <a href="https://ask.clojure.org/index.php/10261/please-add-dispatch-fn-to-clojure-core">here</a> to make that happen. Also, <code>get-method</code> is a core function, the <code>.getMethod</code> interop wasn&apos;t really necessary, but perhaps it is there for performance reasons. This is now supported in babashka without changes.</li><li><code>clojure.lang.RT/checkSpecAsserts</code> is not available in babashka. I replaced this with an atom in the <code>clojure.spec.alpha</code> namespace.</li></ul><p>With these minimal changes and some functions I needed to expose in babashka which weren&apos;t there before (<code>inst-ms</code> being one of them), babashka is now able to run clojure.spec. All tests are passing:</p><pre><code>$ bb test

Testing clojure.test-clojure.spec

Testing clojure.test-clojure.instr

Testing clojure.test-clojure.multi-spec

Ran 13 tests containing 168 assertions.
0 failures, 0 errors.
</code></pre><p>In addition to spec&apos;s own tests, I&apos;ve added tests from the following libraries that are using spec to babashka&apos;s CI: <a href="https://github.com/Engelberg/better-cond">better-cond</a>, <a href="https://github.com/exoscale/coax">coax</a>, <a href="https://github.com/jeaye/orchestra">orchestra</a> and <a href="https://github.com/weavejester/integrant">integrant</a>.</p><p>The benefit of maintaining a fork with minimal changes is that I can easily pull in changes from upstream.  The fork is available <a href="https://github.com/babashka/spec.alpha">here</a> and works with the newly released babashka 0.7.0.</p><p>A demo of data generation using spec:</p><pre><code class="language-clojure">(require &apos;[babashka.deps :as deps])

(deps/add-deps &apos;{:deps {org.babashka/spec.alpha {:git/url &quot;https://github.com/babashka/spec.alpha&quot;
                                                 :git/sha &quot;644a7fc216e43d5da87b07471b0f87d874107d1a&quot;}}})

(require &apos;[clojure.spec.alpha :as s]
         &apos;[clojure.spec.gen.alpha :as gen]
         &apos;[clojure.string :as str])

(prn (gen/sample (s/gen int?)))

(s/def ::street (s/and string? (complement str/blank?)))
(s/def ::street-number int?)
(s/def ::address (s/keys :req-un [::street ::street-number]))
(s/def ::name (s/and string? (complement str/blank?)))
(s/def ::contact (s/keys :req-un [::name ::address]))
(prn (gen/sample (s/gen ::contact)))
</code></pre><pre><code class="language-clojure">(0 -1 0 -1 -6 -1 -2 0 9 1)
({:name &quot;r&quot;, :address {:street &quot;Y&quot;, :street-number -1}} {:name &quot;m&quot;, :address {:street &quot;k8&quot;, :street-number -1}} {:name &quot;5&quot;, :address {:street &quot;s1E&quot;, :street-number 0}} {:name &quot;o4H&quot;, :address {:street &quot;4&quot;, :street-number -1}} {:name &quot;nkhf&quot;, :address {:street &quot;4Fh92&quot;, :street-number 1}} {:name &quot;e&quot;, :address {:street &quot;X&quot;, :street-number 4}} {:name &quot;5v76a9B&quot;, :address {:street &quot;bEf7e&quot;, :street-number 23}} {:name &quot;213V&quot;, :address {:street &quot;fNX3wr&quot;, :street-number 5}} {:name &quot;8336lvbb9&quot;, :address {:street &quot;fVP&quot;, :street-number -1}} {:name &quot;x8X&quot;, :address {:street &quot;utPQA&quot;, :street-number -7}})
</code></pre><p>The above example executes in about 120ms on my machine.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/markdown-clj-babashka-compatible.html</id>
    <link href="https://blog.michielborkent.nl/markdown-clj-babashka-compatible.html"/>
    <title>Making markdown-clj babashka-compatible</title>
    <updated>2021-11-17T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Recently I migrated the highlighting of Clojure code in this blog from CLJS to pure <a href="https://babashka.org/">babashka</a> code. See <a href="writing-clojure-highlighter.html">this</a> blog post.</p><p>For rendering markdown files to html files I was using <a href="https://github.com/retrogradeorbit/bootleg">bootleg</a> as a <a href="https://github.com/retrogradeorbit/bootleg#babashka-pod-usage">pod</a>. A pod is a binary which can act as an RPC server for babashka. Learn more about that <a href="https://github.com/babashka/pods">here</a>.</p><p>Today I noticed a <a href="https://github.com/retrogradeorbit/bootleg/pull/76">new PR</a> in bootleg. The user who submitted the PR also used bootleg for markdown compilation in babashka, but bootleg didn&apos;t expose an option that the underlying library, <a href="https://github.com/yogthos/markdown-clj">markdown-clj</a>, supports. The PR fixes that.</p><p>Then I wondered, can babashka run markdown-clj from source, rather than via a pod? Babashka supports a large subset of Clojure and a large subset of classes from the JVM. By now it can run a fair share of Clojure libraries from source, but sometimes minor tweaks are necessary. I looked at the dependencies of markdown-clj. The only dependency it uses is <a href="https://github.com/clj-commons/clj-yaml">clj-commons/clj-yaml</a> which is luckily included in babashka. If it wasn&apos;t, I&apos;m pretty sure that dependency could be made optional for those that do not need any YAML support in their markdown compilation. When looking closer, I learned that this dependency is used in a small corner of markdown-clj to parse front-matters. I stripped those front-matters out when I <a href="migrating-octopress-to-babashka.html">migrated from Octopress to
babashka</a>, but I realize now I could have left those in. Since the rest of markdown-clj is pure Clojure, there&apos;s a reasonable chance it will work with babashka. Let&apos;s try and see.</p><p>I cloned the repo locally and tried this:</p><pre><code class="language-shell">$ git clone git@github.com:yogthos/markdown-clj.git
$ cd markdown-clj
$ bb -cp src/clj:src/cljc -e &quot;(require &apos;[markdown.core :as md])
  (md/md-to-html-string \&quot;# 100\&quot;)&quot;
----- Error --------------------------------------------------------------------
Type:     java.lang.IllegalStateException
Message:  Can&apos;t dynamically bind non-dynamic var #&apos;markdown.common/*substring*
Location: 73:3
</code></pre><p>The issue here is that <a href="https://github.com/babashka/sci">SCI</a>, the interpreter running Clojure code in babashka, doesn&apos;t understand this way of defining dynamic vars yet:</p><pre><code class="language-clojure">(declare ^{:dynamic true} *substring*)
</code></pre><p>Of course this should be fixed, so I filed an issue with SCI <a href="https://github.com/babashka/sci/issues/630">here</a>.</p><p>But changing the code in markdown-clj to:</p><pre><code class="language-clojure">(def ^{:dynamic true} *substring*)
</code></pre><p>doesn&apos;t seem to have any downsides and would make that part compatible with babashka. There was another dynamic var that had the same problem. After fixing that, I got:</p><pre><code class="language-shell">$ bb -cp src/clj:src/cljc -e &quot;(require &apos;[markdown.core :as md])
  (md/md-to-html-string \&quot;# 100\&quot;)&quot;
&quot;&lt;h1&gt;100&lt;/h1&gt;&quot;
</code></pre><p>It worked!</p><p>To be sure all markdown-clj tests pass with babashka, I added a test runner. The Cognitect Labs <a href="https://github.com/cognitect-labs/test-runner">test-runner</a> (Cognitest :-D) works with babashka, provided that you include the babashka compatible <a href="https://github.com/babashka/tools.namespace">tools.namespace</a> fork in your dependencies. The <code>bb.edn</code> so far:</p><pre><code class="language-clojure">{:deps {markdown-clj/markdown-clj {:local/root &quot;.&quot;}}
 :tasks
 {test:bb {:doc &quot;Runs tests with babashka&quot;
           :extra-paths [&quot;test&quot;]
           :extra-deps {io.github.cognitect-labs/test-runner
                        {:git/tag &quot;v0.5.0&quot; :git/sha &quot;b3fd0d2&quot;}
                        org.clojure/tools.namespace
                        {:git/url &quot;https://github.com/babashka/tools.namespace&quot;
                         :git/sha &quot;3625153ee66dfcec2ba600851b5b2cbdab8fae6c&quot;}}
           :requires ([cognitect.test-runner :as tr])
           :task (apply tr/-main &quot;-d&quot; &quot;test&quot; *command-line-args*)}
 ,,,}}
</code></pre><p>After that, you can run <code>bb test:bb</code>:</p><pre><code class="language-shell">Running tests in #{&quot;test&quot;}
----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Could not resolve symbol: org.apache.commons.lang.StringEscapeUtils/unescapeHtml
Location: /private/tmp/markdown-clj/test/markdown/md_test.cljc:331:11
Phase:    analysis
</code></pre><p>Ouch. The class <code>org.apache.commons.lang.StringEscapeUtils</code>, which is used in the tests, isn&apos;t available in babashka. Let&apos;s comment that one out. Luckily, the tests are already in a <code>.cljc</code> file, so using the <code>:bb</code> reader conditional lets us make changes specifically for babashka while leaving it the same for the other targets:</p><pre><code class="language-clojure">#?(:bb nil
   :default
   (is (= &quot;&lt;p&gt;&lt;a href=\&quot;mailto:abc@google.com\&quot;&gt;abc@google.com&lt;/a&gt;&lt;/p&gt;&quot;
          (#?(:clj  org.apache.commons.lang.StringEscapeUtils/unescapeHtml
              :cljs goog.string/unescapeEntities)
           (entry-function &quot;&lt;abc@google.com&gt;&quot;)))))

#?(:bb nil
   :default
   (is (= &quot;&lt;p&gt;&lt;a href=\&quot;mailto:abc_def_ghi@google.com\&quot;&gt;abc_def_ghi@google.com&lt;/a&gt;&lt;/p&gt;&quot;
          (#?(:clj  org.apache.commons.lang.StringEscapeUtils/unescapeHtml
              :cljs goog.string/unescapeEntities)
           (entry-function &quot;&lt;abc_def_ghi@google.com&gt;&quot;)))))
</code></pre><p>Yes, reader conditionals can be nested. You didn&apos;t see that one coming did you? After this change, bingo!</p><pre><code>$ bb test:bb

Running tests in #{&quot;test&quot;}

Testing markdown.md-file-test

Testing markdown.md-test

Ran 84 tests containing 146 assertions.
0 failures, 0 errors.
</code></pre><p>While I was at it, I also added a <code>deps.edn</code> and tasks for running the Clojure and ClojureScript tests.</p><p><code>deps.edn</code>:</p><pre><code class="language-clojure">{:paths [&quot;src/clj&quot; &quot;src/cljs&quot; &quot;src/cljc&quot;]
 :deps {clj-commons/clj-yaml {:mvn/version &quot;0.7.107&quot;}}
 :aliases
 {:test
  {:extra-paths [&quot;test&quot;]
   :extra-deps {io.github.cognitect-labs/test-runner
                {:git/tag &quot;v0.5.0&quot; :git/sha &quot;b3fd0d2&quot;}
                criterium/criterium {:mvn/version &quot;0.4.4&quot;}
                commons-lang/commons-lang {:mvn/version &quot;2.6&quot;}}
   :main-opts [&quot;-m&quot; &quot;cognitect.test-runner&quot;]
   :exec-fn cognitect.test-runner.api/test}
  :cljs-test
  {:extra-paths [&quot;test&quot;]
   :extra-deps {olical/cljs-test-runner {:mvn/version &quot;3.8.0&quot;}
                org.clojure/clojure {:mvn/version &quot;1.10.1&quot;}
                org.clojure/clojurescript {:mvn/version &quot;1.10.520&quot;}}
   :main-opts [&quot;-m&quot; &quot;cljs-test-runner.main&quot;]}}}
</code></pre><p><code>bb.edn</code>:</p><pre><code class="language-clojure">{:deps {markdown-clj/markdown-clj {:local/root &quot;.&quot;}}
 :tasks
 {,,,
  test:clj {:doc &quot;Runs tests with JVM Clojure&quot;
            :task (clojure &quot;-X:test&quot;)}
  test:cljs {:doc &quot;Runs tests with ClojureScript&quot;
             :task (clojure &quot;-M:cljs-test&quot;)}}}
</code></pre><pre><code class="language-shell">$ bb test:clj

Running tests in #{&quot;test&quot;}

Testing markdown.md-file-test

Testing markdown.md-test

Ran 84 tests containing 148 assertions.
0 failures, 0 errors.

$ bb test:cljs

Testing markdown.md-test

Ran 75 tests containing 136 assertions.
0 failures, 0 errors.
</code></pre><p>After that change, I could use <code>markdown-clj</code> directly in the code for rendering this blog. You can see the diff <a href="https://github.com/borkdude/blog/commit/5ab3eeb6601e81fb0166e9449cc8054bc99da46a">here</a>. Previously I also used bootleg for hiccup, but babashka already has hiccup as a built-in dependency so that wasn&apos;t necessary anymore either.  So the blog rendering code is pure babashka now.</p><p>I submitted a <a href="https://github.com/yogthos/markdown-clj/pull/173">PR</a> with these changes to the markdown-clj repository. This PR was merged and a <a href="https://clojars.org/markdown-clj/versions/1.10.7">new
version</a> was published tn Clojars, which is used in the <code>deps.edn</code> of this blog.</p><h2 id="performance-considerations">Performance considerations</h2><p>What about performance? Previous re-rendering all of the blog posts took 4 seconds and now it takes a second longer. Running markdown-clj from source is slower than using the pod since the code in the pod is all pre-compiled and doesn&apos;t run through SCI. Compiling a single blog post isn&apos;t noticeably slower. The difference is small enough to move forward with markdown-clj from source for now. Since it&apos;s easy to move between pure babashka, using the bootleg pod or running JVM Clojure, I keep my options open.</p><p>After writing the last paragraph, I made this blog&apos;s code run with JVM Clojure. Let&apos;s compare the time for recompiling all blog posts (which is triggered by a change to e.g. <code>render.clj</code>):</p><pre><code class="language-shell">$ touch render.clj
$ time bb render
...
bb render   3.51s  user 0.17s system 75% cpu 4.891 total

$ touch render.clj
$ clojure -M -m render
...
clojure -M -m render   21.97s  user 1.21s system 276% cpu 8.386 total
</code></pre><p>Recompiling the entire blog with babashka is still faster, likely because the startup time on the JVM isn&apos;t that good because Clojure has to load more libraries at startup.</p><p>If we AOT those libraries then JVM Clojure becomes faster but still the startup time doesn&apos;t outweigh the performance of the JVM:</p><pre><code class="language-shell">$ mkdir -p classes
$ clojure -M -e &quot;(compile &apos;render)&quot;
$ time clojure -M -m render
...
clojure -M -m render   13.91s  user 1.05s system 259% cpu 5.753 total
</code></pre><p>Most of the time I won&apos;t recompile all my blog posts but just one:</p><pre><code class="language-shell">$ touch posts/markdown-clj-babashka-compatible.md
$ time bb render
Processing markdown for file: posts/markdown-clj-babashka-compatible.md
bb render   0.42s  user 0.12s system 79% cpu 0.682 total

$ touch posts/markdown-clj-babashka-compatible.md
$ time clojure -M -m render
Processing markdown for file: posts/markdown-clj-babashka-compatible.md
clojure -M -m render   5.58s  user 0.60s system 189% cpu 3.266 total
</code></pre><h2 id="nbb">nbb</h2><p>Dmitri Sotnikov, the author of markdown-clj, suggested that markdown-clj could also be made compatible with <a href="https://github.com/babashka/scittle">scittle</a> and <a href="https://github.com/babashka/nbb">nbb</a>. The only change I had to make to the original source was to change <code>cljs.reader</code> into <code>clojure.edn</code> and then it worked:</p><pre><code class="language-shell">$ nbb -cp src/clj:src/cljc:src/cljs -e &quot;(require &apos;[markdown.core :as md])
  (md/md-&gt;html \&quot;# 100\&quot;)&quot;
&quot;&lt;h1&gt;100&lt;/h1&gt;&quot;
</code></pre><p>After adding a runner:</p><pre><code class="language-clojure">(ns nbb-runner
  (:require [clojure.string :as str]
            [clojure.test :refer [run-tests]]
            [nbb.classpath :as cp]))

(cp/add-classpath (str/join &quot;:&quot; [&quot;src/cljs&quot; &quot;src/cljc&quot; &quot;test&quot;]))

(require &apos;[markdown.md-test])

(run-tests &apos;markdown.md-test)
</code></pre><p>and a few minor tweaks to the tests, the library runs with nbb:</p><pre><code>Testing markdown.md-test

Ran 75 tests containing 134 assertions.
0 failures, 0 errors.
</code></pre></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/publishing-nbb-project-to-npm.html</id>
    <link href="https://blog.michielborkent.nl/publishing-nbb-project-to-npm.html"/>
    <title>Publishing an nbb project to npm</title>
    <updated>2021-11-10T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>This post describes how to publish an <a href="https://github.com/babashka/nbb">nbb</a> based project to <a href="https://npmjs.com/">npm</a>. It is extracted from <a href="https://github.com/babashka/nbb/tree/main/doc/publish">this</a> entry from the nbb documentation.</p><p>Nbb is an ad-hoc CLJS scripting environment for Node.js. You could say that it is to CLJS on Node.js what <a href="https://babashka.org/">babashka</a> is to JVM Clojure.</p><p>As an example we will build a CLI, <code>print-cli-args</code> that prints command line arguments.</p><p>First, create a new directory <code>print-cli-args</code> and cd into it. Then create a <code>package.json</code>:</p><pre><code class="language-json">{
  &quot;name&quot;: &quot;print-cli-args&quot;,
  &quot;version&quot;: &quot;0.0.1&quot;,
  &quot;dependencies&quot;: {
    &quot;nbb&quot;: &quot;0.0.109&quot;
  },
  &quot;bin&quot;: {
    &quot;print-cli-args&quot;: &quot;index.mjs&quot;
  }
}
</code></pre><p>The CLI depends on a specific version of nbb and exposes itself as a binary called <code>print-cli-args</code>, which is linked to <code>index.mjs</code> in our project. It is important to use <code>.mjs</code> rather than <code>.js</code> so Node.js recognizes the file as an ES6 module.</p><p>The <code>index.mjs</code> file is a small wrapper that sets up the classpath for nbb to the <code>src</code> directory relative to the wrapper using <code>addClassPath</code>. It also calls the initial CLJS file using <code>loadFile</code>.</p><pre><code class="language-javascript">#!/usr/bin/env node

import { addClassPath, loadFile } from &apos;nbb&apos;;
import { fileURLToPath } from &apos;url&apos;;
import { dirname, resolve } from &apos;path&apos;;

const __dirname = fileURLToPath(dirname(import.meta.url));

addClassPath(resolve(__dirname, &apos;src&apos;));
await loadFile(resolve(__dirname, &apos;src/print_cli_args/core.cljs&apos;));
</code></pre><p>Finally, in <code>src/print_cli_args/core.cljs</code> we write the CLJS code:</p><pre><code class="language-clojure">(ns print-cli-args.core
  (:require [clojure.string :as str]))

(def cmd-line-args (not-empty (js-&gt;clj (.slice js/process.argv 2))))

(println &quot;Your command line arguments:&quot;
         (or (some-&gt;&gt; cmd-line-args (str/join &quot; &quot;))
             &quot;None&quot;))
</code></pre><p>To test the CLI in development, run <code>node index.mjs 1 2 3</code>.</p><p>When you <code>npm install -g</code> from within the project, you can call <code>print-cli-args</code> from anywhere on your system.</p><p>When everything looks good, it&apos;s time to <code>npm publish</code> so everyone can enjoy your new CLI.</p><p>After you have done so, you can run this example from npm using:</p><pre><code class="language-shell">$ npx print-cli-args 1 2 3
Your command line arguments: 1 2 3
</code></pre><p>or:</p><pre><code class="language-shell">$ npm install -g print-cli-args
$ print-cli-args 1 2 3
Your command line arguments: 1 2 3
</code></pre></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/writing-clojure-highlighter.html</id>
    <link href="https://blog.michielborkent.nl/writing-clojure-highlighter.html"/>
    <title>Writing a Clojure highlighter from scratch</title>
    <updated>2021-11-08T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>In the aftermath of my <a href="better-clojure-highlighting.html">previous blog post</a> about using Nextjournal&apos;s <a href="https://github.com/nextjournal/clojure-mode">clojure-mode</a> for better highlighting, I tried optimizing the JS output and got a look at the internals of <a href="https://codemirror.net/6/">CodeMirror 6</a>. I realized that writing a Clojure highlighter from scratch wasn&apos;t that hard if you had the right tools at hand:</p><ul><li>A tool which can break Clojure code into parts, tells you what each part is (symbol, keyword, vector, etc.)  and also provides a way to put the parts together again, with preservation of whitespace. This tool is already available in <a href="https://babashka.org/">babashka</a> and is a library called <a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a>.</li><li>A tool that can provide additional semantic information: is a symbol a local or a var? The static analysis output of <a href="https://github.com/clj-kondo/clj-kondo">clj-kondo</a> provides that information. This part is optional for incrementally better highlighting.</li></ul><p>I spent my Sunday afternoon combining these tools which resulted in a 160 line script called <code>highlighter.clj</code> which is now used to do the highlighting of this blog.</p><p>This blog post is a high level walkthrough of the code. Let&apos;s begin with the first step.</p><h3 id="1.-parse-blocks-of-clojure-code-from-markdown-and-apply-highlighting.">1. Parse blocks of Clojure code from markdown and apply highlighting.</h3><pre><code class="language-clojure">(defn highlight-clojure [markdown]
  (str/replace markdown #&quot;(?m)```\s*clojure\n([\s\S]+?)\n\s*```&quot;
               (fn [[_ code]]
                 (try (-&gt; (str/trim code)
                          (htmlize)
                          (str/replace &quot;[&quot; &quot;&amp;#91;&quot;)
                          (str/replace &quot;]&quot; &quot;&amp;#93;&quot;)
                          (str/replace &quot;*&quot; &quot;&amp;#42;&quot;)
                          (str/replace &quot;_&quot; &quot;&amp;#95;&quot;))
                      (catch Exception e
                        (log &quot;Could not highlight: &quot; (ex-message e) code)
                        markdown)))))
</code></pre><p>Parsing blocks of Clojure code from a markdown post is done using a basic regex. Then we pass the Clojure code to the <code>htmlize</code> function. After that we escape some markdown-specific characters, so the markdown compiler won&apos;t be confused by them.. If the highlighting failed for some reason, we log it and fall back on the unprocessed markdown. During the implementation I found several snippets of Clojure code with unbalanced parens which I had to fix, since rewrite-clj doesn&apos;t accept it. So all examples from this blog should be copy-pastable into your Clojure editor without problems from now on.</p><h3 id="2.-parse-and-analyze-clojure-using-clj-kondo-and-rewrite-clj:">2. Parse and analyze Clojure using clj-kondo and rewrite-clj:</h3><pre><code class="language-clojure">(defn htmlize [code]
  (binding [*analysis*
            (let [ana (analysis code)]
              {:locals (locals ana)
               :var-defs (var-defs ana)})]
    (let [html (-&gt; code p/parse-string-all node-&gt;html)]
      (format &quot;&lt;pre&gt;&lt;code class=\&quot;clojure hljs\&quot;&gt;%s&lt;/code&gt;&lt;/pre&gt;&quot; html))))
</code></pre><p>Clj-kondo provides information about vars, keywords and locals. We will apply special styling to var definitions and locals and their usages.</p><h3 id="3.-clj-kondo-analysis">3. Clj-kondo analysis</h3><pre><code class="language-clojure">(pods/load-pod &apos;clj-kondo/clj-kondo &quot;2021.10.19&quot;)

(require &apos;[pod.borkdude.clj-kondo :as clj-kondo])

(defn analysis [code]
  (let [tmp (doto (fs/file (fs/create-temp-dir) &quot;code.clj&quot;)
              fs/delete-on-exit)]
    (spit tmp code)
    (-&gt; (clj-kondo/run!
         {:lint [(str tmp)]
          :config {:output {:analysis {:locals true}}}})
        :analysis)))
</code></pre><p>To call clj-kondo from babashka, we use the binary from the <a href="https://github.com/babashka/pod-registry">pod
 registry</a> which is automatically downloaded via <code>load-pod</code> if you provide a fully qualified symbol and version. We write the code to a temp file and lint it. We ask for the static <a href="https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md">analysis</a> data. Locals are not included by default, so we set <code>:locals</code> to <code>true</code>. Later on we want to detect if a symbol is a local or a var. We do this by making a set of locations from the analysis data for each group:</p><pre><code class="language-clojure">(defn locals [analysis]
  (-&gt;&gt; analysis
       ((juxt :locals :local-usages))
       (apply concat)
       (map (juxt :row :col)) set))

(defn var-defs [analysis]
  (-&gt;&gt; analysis
       :var-definitions
       (map (juxt :name-row :name-col)) set))
</code></pre><h3 id="4.-rewrite-clj-nodes">4. Rewrite-clj nodes</h3><p>Next, we parse the code to rewrite-clj nodes. Each node has a tag for which we write a multi-method to dispatch on:</p><pre><code class="language-clojure">(defmulti node-&gt;html tag)
</code></pre><p>For each kind of node we will emit a <code>&lt;span&gt;</code> element with an associated <code>class</code>. For instance, <code>:foo</code> will become <code>&lt;span class=&quot;keyword&quot;&gt;:foo&lt;/span&gt;</code> and so on.</p><p>A small helper function:</p><pre><code class="language-clojure">(defn span [class contents]
  (format &quot;&lt;span class=\&quot;%s\&quot;&gt;%s&lt;/span&gt;&quot;
          class contents))
</code></pre><p>Here is the implementation for a map node:</p><pre><code class="language-clojure">(defmethod node-&gt;html :map [node]
  (span &quot;map&quot; (format &quot;{%s}&quot;
                      (str/join (map node-&gt;html (:children node))))))
</code></pre><p>A map node has <code>:children</code> so we just call <code>node-&gt;html</code> for each child and join the strings together.</p><p>I wrote a <code>:default</code> implementation that logs a warning for nodes that I hadn&apos;t implemented yet:</p><pre><code class="language-clojure">(defmethod node-&gt;html :default [node]
  (log &quot;Unhandled tag:&quot; (tag node))
  (span (name (tag node))
        (if (:children node)
          (str/join &quot;&quot; (map node-&gt;html (:children node)))
          (str node))))
</code></pre><p>and added implementations for all of the nodes that occurred in Clojure snippets in all the posts of this blog so far, by working through the list of unhandled tags.</p><p>Rewrite-clj doesn&apos;t give different tags for symbols, strings, numbers and so on: it groups them under the <code>:token</code> tag. So there is some extra work needed to get different highlighting for different types of tokens. I wrote a function that returns a CSS class by looking at the contents of the node or at the type of value of the node. For a symbol node, I want different highlighting for vars and locals. This is where I check in the clj-kondo analysis if the symbol on that location is a local or var and else fall back on the general symbol CSS class.</p><pre><code class="language-clojure">(defn token-class [node]
  (cond (:k node) &quot;keyword&quot;
        (:lines node) &quot;string&quot;
        (contains? node :value)
        (let [v (:value node)]
          (cond (number? v) &quot;number&quot;
                (string? v) &quot;string&quot;
                (boolean? v) &quot;boolean&quot;
                (nil? v) &quot;nil&quot;
                (symbol? v)
                (cond (contains? (:locals *analysis*)
                                 ((juxt :row :col) (meta node)))
                      &quot;local&quot;
                      (contains? (:var-defs *analysis*)
                                 ((juxt :row :col) (meta node)))
                      &quot;def&quot;
                      :else
                      &quot;symbol&quot;)
                :else (name (tag node))))
        ;; fallback, log missing case
        :else (log (tag node) (keys node) (sexpr node) (type (sexpr node)))))

(defmethod node-&gt;html :token [node]
  (span (token-class node)
        (escape (str node))))
</code></pre><h3 id="5.-styling">5. Styling</h3><p>Finally I wrote some styling:</p><pre><code class="language-css">.def { color: #00f; }
.symbol { color: #708; }
.local { color: cadetblue; }
.string { color: #a11; }
.number { color: blue; }
.keyword { color: #219; }
.uneval { filter: opacity(0.5); }
</code></pre><p>For <code>:uneval</code> nodes, which is rewrite-clj&apos;s name for expressions that are ignored using the reader underscore dispatch macro: <code>#_(+ 1 2 3)</code>, I set opacity to <code>0.5</code>. Can you see the difference?</p><pre><code class="language-clojure">(+ 1 2 3)
#_(+ 1 2 3)
</code></pre><p>That&apos;s it really. A Sunday afternoon well spent. The code for the highlighter is <a href="https://github.com/borkdude/blog/blob/main/highlighter.clj">here</a>. In the future I might pull out this code into a library. The renderer could support ANSI escape code sequences for the terminal as well. Let me know what you think.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/better-clojure-highlighting.html</id>
    <link href="https://blog.michielborkent.nl/better-clojure-highlighting.html"/>
    <title>Better Clojure highlighting with nextjournal/clojure-mode</title>
    <updated>2021-11-05T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Almost two weeks ago I <a href="migrating-octopress-to-babashka.html">wrote</a> about how I replaced my Octopress blog with about 200 lines of <a href="https://github.com/babashka/babashka">babashka</a>. I also wrote that I used <a href="https://highlightjs.org/">highlight.js</a> for highlighting. This blog is mostly about Clojure/Script, so improvements in highlighting of Clojure code are welcome. Highlight.js does a good job, but it&apos;s not as good as it can be. E.g. Nextjournal&apos;s <a href="https://nextjournal.github.io/clojure-mode/">clojure-mode</a>, which is a CodeMirror 6 integration for Clojure, covers a lot more detail. So I tried to strip the demo of clojure-mode to the bare mininum for just for highlighting. I ended up with about 320kb (117kb gzipped) of optimized JS based on a CLJS implementation. Trying to squeeze the last bit out by rewriting it to JS and bundling it with <a href="https://rollupjs.org/guide/en/">Rollup.js</a> like the <a href="https://codemirror.net/6/examples/bundle/">CodeMirror docs</a> suggest yielded 600kb at first. But it turned out I needed to enable the terser <a href="https://rollupjs.org/guide/en/#using-output-plugins">output
plugin</a> and this got the bundle size down to 200kb (79kb gzipped).</p><p>In the future it might be possible to get even smaller builds when CodeMirror 6 gets better support for &apos;just highlighting&apos;. There is a discussion about it <a href="https://discuss.codemirror.net/t/only-syntax-highlighting/2635/5">here</a>.</p><p>To automate building the highlighter code when I re-render this blog, I again used <a href="https://book.babashka.org/#tasks">babashka tasks</a>:</p><pre><code class="language-clojure">{:paths [&quot;.&quot;]
 :tasks
 {:requires ([babashka.fs :as fs]
             [tasks-helper :as th])
  ...
  build-highlighter {:doc &quot;Build Clojure highlighter JS&quot;
                     :task
                     (when
                         (seq (fs/modified-since &quot;public/clojure_highlighter.js&quot;
                               [&quot;src&quot;]))
                       (shell &quot;npx rollup -c rollup.config.js&quot;))}
  render {:doc &quot;Render blog&quot;
          :depends [build-highlighter]
          :task (load-file &quot;render.clj&quot;)}
  ...}}
</code></pre><p>If the <code>public/clojure_highlighter.js</code> file is already there and JavaSceipt sources hasn&apos;t changed, the <code>build-higlighter</code> step won&apos;t take any significant time due to the use of <code>fs/modified-since</code> which I blogged about <a href="speeding-up-builds-fs-modified-since.html">here</a>.</p><pre><code class="language-shell">$ bb clean
$ time bb render

src/clojure_highlighter/main.js → public/clojure_highlighter.js...
created public/clojure_highlighter.js in 2.7s
bb render   6.26s  user 0.84s system 155% cpu 4.557 total

$ time bb render
bb render   0.09s  user 0.05s system 81% cpu 0.174 total
</code></pre><p>The above snippet is still highlighted with Highlight.js, but <code>&lt;code class=&quot;clojure&quot;&gt;...&lt;/code&gt;</code> is highlighted with clojure-mode.</p><p>To show off the highlighting, here is the CLJS code for the highlighter, which I ported to JS later on.</p><pre><code class="language-clojure">(ns clojure-highlighter.main
  (:require [&quot;@codemirror/highlight&quot; :as highlight :refer [tags]]
            [&quot;@codemirror/language&quot; :as language]
            [&quot;@codemirror/state&quot; :refer [EditorState]]
            [&quot;@codemirror/view&quot; :as view :refer [EditorView]]
            [&quot;lezer-clojure&quot; :as lezer-clj]
            [clojure.string :as str]
            [goog.object]))

(def theme
  (.theme EditorView
          #js {&quot;.cm-content&quot; #js {:white-space &quot;pre-wrap&quot;
                                  :padding &quot;10px 0&quot;}
               &quot;&amp;.cm-focused&quot; #js {:outline &quot;none&quot;}
               &quot;.cm-line&quot; #js {:padding &quot;0 9px&quot;
                               :line-height &quot;1.6&quot;
                               :font-size &quot;16px&quot;
                               :font-family &quot;var(--code-font)&quot;}
               &quot;.cm-matchingBracket&quot;
               #js {:border-bottom &quot;1px solid var(--teal-color)&quot;
                    :color &quot;inherit&quot;}
               &quot;.cm-gutters&quot; #js {:background &quot;transparent&quot;
                                  :border &quot;none&quot;}
               &quot;.cm-gutterElement&quot; #js {:margin-left &quot;5px&quot;}
               ;; only show cursor when focused
               &quot;.cm-cursor&quot; #js {:visibility &quot;hidden&quot;}
               &quot;&amp;.cm-focused .cm-cursor&quot; #js {:visibility &quot;visible&quot;}}))

(def style-tags
  (doto #js {:DefLike (.-keyword tags)
             &quot;Operator/Symbol&quot; (.-keyword tags)
             &quot;VarName/Symbol&quot; (.definition tags (.-variableName tags))
             :Boolean (.-atom tags)
             &quot;DocString/...&quot; (.-emphasis tags)
             :Discard! (.-comment tags)
             :Number (.-number tags)
             :StringContent (.-string tags)
             :Keyword (.-atom tags)
             :Nil (.-null tags)
             :LineComment (.-lineComment tags)
             :RegExp (.-regexp tags)}
    (goog.object/set &quot;\&quot;\\\&quot;\&quot;&quot; (.-string tags))))

(def parser lezer-clj/parser)

(def the-parser
  (.configure parser
              #js {:props #js [(highlight/styleTags style-tags)]}))

(def syntax
  (.define language/LezerLanguage
           #js {:parser the-parser}
           #js {:languageData
                #js {:commentTokens {:line &quot;;;&quot;}}}))

(defonce extensions #js[theme
                        (.of (.-editable EditorView) false)
                        highlight/defaultHighlightStyle
                        #js[syntax]])

(defn ^:dev/after-load render []
  (let [elts (js/document.querySelectorAll &quot;code.clojure&quot;)]
    (.forEach elts
              (fn [elt]
                (new EditorView
                     #js {:state
                          (.create EditorState
                                   #js{:doc (str/trim (.-innerText elt))
                                       :extensions #js [extensions]})
                          :parent elt})
                (.remove (.-firstChild elt))))))
</code></pre><p>You can find the code for this blog on <a href="https://github.com/borkdude/blog">Github</a>, including the above code.</p><p>Edits:</p><ul><li>2021-11-06: Include Rollup.js <code>terser</code> output plugin in blog post.</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/oss-highlights-sep-oct-2021.html</id>
    <link href="https://blog.michielborkent.nl/oss-highlights-sep-oct-2021.html"/>
    <title>OSS Highlights of September - October 2021</title>
    <updated>2021-11-03T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>This year I&apos;m receiving a long term grant from <a href="https://www.clojuriststogether.org/">Clojurists
Together</a>. CT asked me to do a bimonthly report on my activities or write a blog post and link to that. That&apos;s what I&apos;m doing here. I&apos;ll be going over the releases of existing and new projects and will mention highlights in some of them. Often, the devil is in the details and there aren&apos;t any new user-facing features, but still a lot of work has gone into refining existing features.</p><p>Donations from <a href="https://github.com/sponsors/borkdude">Github Sponsors</a>, OpenCollective and the year long CT grant directly allow me to spend more time on open source. The list you are seeing here is a result of this. I love working on open source so thank you for allowing me to do this. In <a href="https://soundcloud.com/user-959992602/s4-e40-oss-with-michiel-borkent">this</a> <a href="https://clojurescriptpodcast.com/">ClojureScript podcast</a> episode, Jacek Schae interviewed me on my decision to quit my previous job and work more on Clojure OSS. Have a listen if you want to know more about my motivations. If aside from sponsoring, you or your company needs work done on any of these or related projects and want to make a custom arrangement, please do reach out.</p><p>Note that the projects listed below are not exclusively my effort and are worked on by a number or regular contributors. My thanks also goes out to them.</p><h1 id="nbb"><a href="https://github.com/babashka/nbb">Nbb</a></h1><p>Ad-hoc CLJS scripting on Node.js using SCI.</p><p>Many releases on <a href="https://www.npmjs.com/package/nbb">npm</a>.</p><p>Highlights:</p><ul><li>Console REPL. If you have Node.js simply type <code>npx nbb</code> and you will be dropped into a REPL.</li><li>Socket server REPL</li><li>nREPL server for development with Calva</li><li>Add <code>clojure.test</code> so you can now use nbb to develop e.g. browser tests using puppeteer or playwright</li><li>Support for reader conditionals using <code>:org.babashka/nbb</code></li><li>Print nicer stacktrace when error happens (similar to bb)</li><li>Misc. fixes and enhancements.</li><li>Add <code>js-interop</code> module</li><li>Add Javascript API</li></ul><p>Many exciting things are happening around this project in the community. It&apos;s now possible to run nbb on <a href="https://github.com/vharmain/nbb-lambda-adapter">lambda</a>. <a href="https://github.com/babashka/nbb/discussions/91#discussioncomment-1510273">Exercism</a> is using babashka and nbb to run Clojure exercise submissions. <a href="https://github.com/chr15m/sitefox">Sitefox</a> is a CLJS + Node.js web framework that works well with nbb.</p><h1 id="clj-kondo"><a href="https://github.com/clj-kondo/clj-kondo">Clj-kondo</a></h1><p>A linter for Clojure (code) that sparks joy.</p><p>Releases: <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20211019">2021.10.19</a> , <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20210925">2021.09.25</a> , <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20210915">2021.09.15</a> , <a href="https://github.com/clj-kondo/clj-kondo/blob/master/CHANGELOG.md#20210914">2021.09.14</a></p><p>Highlights:</p><ul><li>New linter: warn on missing <code>gen-class</code> when writing <code>-main</code> function. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#main-without-gen-class">docs</a>.</li><li>New <code>loop</code> without <code>recur</code> linter. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#loop-without-recur">docs</a>.</li><li>Several inference improvements, e.g. <code>(def f (fn [])) (f 1 2)</code> will now give an arity warning.</li><li>Return arbitrary metadata in analysis data. See <a href="https://github.com/clj-kondo/clj-kondo/blob/master/analysis/README.md">docs</a>.</li></ul><h1 id="babashka"><a href="https://github.com/babashka/babashka">Babashka</a></h1><p>Native, fast starting Clojure interpreter for scripting.</p><p>Releases: <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#064">0.6.4</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#063">0.6.3</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#062">0.6.2</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#061">0.6.1</a> , <a href="https://github.com/babashka/babashka/blob/master/CHANGELOG.md#060">0.6.0</a></p><p>Highlight:</p><ul><li>Support for java.net HTTP Client (via raw Java interop). This enables running <a href="https://github.com/schmee/java-http-clj">java-http-clj</a> from source.</li></ul><h1 id="api-diff"><a href="https://github.com/borkdude/api-diff">Api-diff</a></h1><p>Print API diffs between library versions.</p><p>This is a new project.</p><h1 id="sci"><a href="https://github.com/babashka/sci">SCI</a></h1><p>Configurable Clojure interpreter suitable for scripting and Clojure DSLs.</p><h2 id="0.2.7">0.2.7</h2><p>Releases: <a href="https://github.com/babashka/sci/blob/master/CHANGELOG.md#v027">0.2.7</a></p><p>Highlights:</p><ul><li>Loads of JS improvements coming from usage in <a href="https://github.com/borkdude/nbb">nbb</a>. Printing in JS targets can now be controlled via <code>*print-fn*</code> like in ClojureScript.</li></ul><h1 id="neil"><a href="https://github.com/babashka/neil">Neil</a></h1><p>A CLI to add common aliases and features to deps.edn-based projects.</p><p>This is a new project.</p><h1 id="edamame"><a href="https://github.com/borkdude/edamame">Edamame</a></h1><p>Configurable EDN/Clojure parser with location metadata</p><p>Releases: <a href="https://github.com/borkdude/edamame/blob/master/CHANGELOG.md#0012">0.0.12</a></p><h1 id="scittle"><a href="https://github.com/babashka/scittle">Scittle</a></h1><p>The Small Clojure Interpreter exposed for usage in browser script tags.</p><p>Releases: <a href="https://github.com/babashka/scittle/blob/main/CHANGELOG.md#v004">0.0.4</a></p><h1 id="babashka.fs"><a href="https://github.com/babashka/fs">Babashka.fs</a></h1><p>File system utility library.</p><p>Releases: <a href="https://github.com/babashka/fs/releases/tag/v0.1.0">0.1.0</a></p><p>Highlight: add <code>fs/zip</code> function.</p><h1 id="deps.clj"><a href="https://github.com/borkdude/deps.clj">Deps.clj</a></h1><p>A faithful port of the clojure CLI bash script to Clojure. Used as native CLI, deps resolver in babashka and getting started REPL in Calva.</p><p>Various <a href="https://github.com/borkdude/deps.clj/releases">releases</a></p><h1 id="graal-build-time"><a href="https://github.com/clj-easy/graal-build-time">Graal-build-time</a></h1><p>Library to initialize Clojure packages at build time with GraalVM native-image.</p><p>This is a new project.</p><h1 id="graal-config"><a href="https://github.com/clj-easy/graal-config">Graal-config</a></h1><p>GraalVM native-image configurations distribution for Clojure libraries.</p><p>This is a new project.</p><h1 id="jet"><a href="https://github.com/borkdude/jet">Jet</a></h1><p>Releases: <a href="https://github.com/borkdude/jet/blob/master/CHANGELOG.md#0016">0.0.16</a></p><p>Highlight: allow keywordize fn to access all available conversion functions from camel-snake-kebab lib. e.g. <code>csk/-&gt;PascalCase</code>.</p><h1 id="digest"><a href="https://github.com/clj-commons/digest">Digest</a></h1><p>Digest algorithms (md5, sha1 ...) for Clojure.</p><p>I took over this library from Miki Tebeka and I&apos;m maintaining it under clj-commons.</p><h1 id="carve"><a href="https://github.com/borkdude/carve">Carve</a></h1><p>Carve out the essentials of your Clojure app.</p><p>Fixed a regression.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/speeding-up-builds-fs-modified-since.html</id>
    <link href="https://blog.michielborkent.nl/speeding-up-builds-fs-modified-since.html"/>
    <title>Speeding up builds with fs/modified-since</title>
    <updated>2021-10-30T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="babashka-tasks">Babashka tasks</h2><p>When designing <a href="https://book.babashka.org/#tasks">babashka tasks</a> I was aiming to create something like <code>make</code>, <code>just</code>, <code>npm run</code>: run tasks with almost no startup time overhead, possibly with dependencies between them, but with a language I like to work with: Clojure. One thing I deliberately left out for now was a mechanism that talks about targets and whether to rebuild those targets or not. Another inspiration for babashka tasks was <a href="https://github.com/juxt/mach">Mach</a> by <a href="https://www.juxt.pro/">JUXT</a> which does have such a mechanism, which leans heavily on one function: <code>(mach.core/modified-since [file dir])</code>.</p><h2 id="babashka.fs">Babashka.fs</h2><p>Instead of deciding on a built-in mechanism for rebuilding targets, I included the <code>modified-since</code> function in <a href="https://github.com/babashka/fs">babashka.fs</a>, which is a library for common file system operations like copying, deleting or moving files, creating symlinks, etc. The <code>babashka.fs</code> library is included in <a href="https://babashka.org/">babashka</a> but can also be used as a library within Clojure JVM programs. Now let&apos;s see what this function does.</p><h2 id="fs/modified-since"><code>fs/modified-since</code></h2><p>Let&apos;s first take a look at the <a href="https://babashka.org/fs/babashka.fs.html#var-modified-since">docstring</a>:</p><blockquote><p><code>(modified-since anchor file-set)</code></p><p>Returns seq of regular files (non-directories, non-symlinks) from file-set that were modified since the anchor path.  The anchor path can be a regular file or directory, in which case the recursive max last modified time stamp is used as the timestamp to compare with.  The file-set may be a regular file, directory or collection of files (e.g. returned by glob). Directories are searched recursively.</p></blockquote><p>In other words:</p><ul><li>The <code>anchor</code> argument can be a file or directory.</li><li>The <code>file-set</code> argument can be a file or directory.</li><li>The returned value is a seq of regular files from <code>file-set</code> that were <em>modified since</em> the maximum of all the modified timestamps in <code>anchor</code>.</li></ul><p>Let&apos;s see it in action.</p><pre><code class="language-shell">$ touch a
$ touch b
$ bb -e &apos;(fs/modified-since &quot;a&quot; &quot;b&quot;)&apos;
(#object[sun.nio.fs.UnixPath 0x108eff48 &quot;b&quot;])
</code></pre><p>We see that the file <code>b</code> was modified since <code>a</code>. This is because we touched <code>b</code> after we touched <code>a</code>.</p><p>Now let&apos;s touch <code>a</code> again:</p><pre><code>$ touch a
$ bb -e &apos;(fs/modified-since &quot;a&quot; &quot;b&quot;)&apos;
()
</code></pre><p>In other words, if <code>a</code> was a build target and <code>b</code> was a source file, then we didn&apos;t have to rebuild <code>a</code> again since it was already up to date.</p><p>What if <code>a</code> doesn&apos;t exist? In real scenarios this would probably mean that we have to build <code>a</code> for the first time or that it was deleted, possibly because of <code>clean</code> task. In that case <code>b</code> is returned as well:</p><pre><code>$ rm a
$ bb -e &apos;(fs/modified-since &quot;a&quot; &quot;b&quot;)&apos;
(#object[sun.nio.fs.UnixPath 0x108eff48 &quot;b&quot;])
</code></pre><p>When the <code>file-set</code> is a directory, you get all of the files that were modified since <code>anchor</code>:</p><pre><code>$ mkdir -p src
$ touch src/a src/b
$ bb -e &apos;(fs/modified-since &quot;a&quot; &quot;src&quot;)&apos;
(#object[sun.nio.fs.UnixPath 0x69351174 &quot;src/a&quot;] #object[sun.nio.fs.UnixPath 0x40a401b4 &quot;src/b&quot;])
$ touch a src/a
$ bb -e &apos;(fs/modified-since &quot;a&quot; &quot;src&quot;)&apos;
(#object[sun.nio.fs.UnixPath 0x778e11d9 &quot;src/a&quot;])
</code></pre><h2 id="real-world-examples">Real world examples</h2><p>Today I used this function to speed up the rendering of this blog (which reminded me to blog about this function):</p><pre><code class="language-clojure">(doseq [{:keys [file title date legacy]} posts]
  (let [cache-file (fs/file &quot;.work&quot; (html-file file))
        markdown-file (fs/file &quot;posts&quot; file)
        stale? (seq (fs/modified-since cache-file markdown-file))
        body (if stale?
               (let [body (markdown-&gt;html markdown-file)]
                 (spit cache-file body)
                 body)
               (slurp cache-file))
        ...]
    ...)
...)
</code></pre><p>Here I used <code>fs/modified-since</code> simply as a predicate to check if the cached HTML output was newer than the markdown input file: if the result is non-empty, we have to rebuild the markdown to HTML and then store it in a <code>.work</code> directory. The rendering of this blog went down from rougly 1 second to 200ms after building it for the first time. There are more places where I could do a similar optimization but for now it&apos;s fast enough.</p><p>I&apos;ve already used this function several times in <code>bb.edn</code> tasks file to speed up Clojure builds. <a href="https://github.com/clj-easy/graal-build-time/blob/130819a1d953f5864b8ef3d273997dfa014860c2/bb.edn#L30">Here</a> is an example of not rebuilding a jar file when it&apos;s already up to date, without starting a JVM:</p><pre><code class="language-clojure">  jar {:doc &quot;Build jar&quot;
       :depends [compile-sources]
       :task (if (seq (fs/modified-since bs/jar-file [bs/class-dir]))
               (clojure &quot;-T:build jar&quot;)
               (println &quot;Jar is already up to date&quot; bs/jar-file))}
</code></pre><p>The technique I used there is to make a <code>build_shared.clj</code> file which is loaded both by <a href="https://github.com/clojure/tools.build">tools.build</a> and babashka. Before launching a JVM, babashka can check if there&apos;s anything to rebuild. If the sources for the jar aren&apos;t modified since the jar itself, then we can skip launching a JVM entirely. But also within the <code>build.clj</code> which runs inside of a JVM the same technique can be used.</p><p>Here is one more example of how I used <code>fs/modified-since</code> to skip a <code>lein uberjar</code> invocation.</p><pre><code class="language-clojure">build-server {:doc &quot;Produces lsp server standalone jar&quot;
              :depends [java1.8 update-project-clj -uberjar]
              :task (when (seq (fs/modified-since -uberjar [&quot;server/project.clj&quot;
                                                            &quot;server/src&quot;]))
                      (shell {:dir &quot;server&quot;}
                        &quot;lein with-profiles -user do clean, uberjar&quot;))}
</code></pre><p>The usage of this function isn&apos;t tied to any specific build system or scenario: it&apos;s just a comparison of some files with another bunch of files, which makes it generally applicable. This form of optimization does come with a trade-off: e.g. when you forget to take into account changes to <code>deps.edn</code> or so, you might get a false positive &apos;nothing to do here&apos;. It might be a good idea to put <code>.cpcache</code> in the fileset in a <code>deps.edn</code> project as a sign that the classpath changed. Soon <a href="https://clojure.atlassian.net/browse/TDEPS-83">TDEPS-83</a> will land in the <a href="https://clojure.org/guides/deps_and_cli">clojure CLI</a> (and soon after that in <code>bb</code> itself via <a href="https://github.com/borkdude/deps.clj">deps.clj</a>) and then even transitive <code>:local/root</code> changes will be picked up in this directory.</p><p>Hope you enjoyed this little write-up about <code>fs/modified-since</code>. Thanks again to JUXT Mach where I got the inspiration from.</p><p>Happy rebuilding!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/migrating-octopress-to-babashka.html</id>
    <link href="https://blog.michielborkent.nl/migrating-octopress-to-babashka.html"/>
    <title>Replacing my Octopress blog with 200 lines of Babashka</title>
    <updated>2021-10-25T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="octopress">Octopress</h2><p>Seven years ago I started writing about my adventures with Clojure. I started using <a href="http://octopress.org/">Octopress</a> back then and was still using it until today. Octopress worked great for my blogging purposes and I&apos;m grateful that it existed. However, in recent years I became frustrated with the experience of using it, which is probably due to a lack of my familiarity with the Ruby ecosystem. On every new system I had to install a version of Ruby that happened to work with Octopress, which wasn&apos;t always the case. When it did work, I started getting deprecation warnings from Ruby while compiling this blog. On top of this, Octopress seemed no longer maintained. The website says &quot;Octopress 3.0 is Coming&quot; but this announcement was from 2015 and the website hasn&apos;t been updated ever since. It felt like time to move on.</p><h2 id="requirements-for-replacement">Requirements for replacement</h2><p>I started thinking of what was essential for me when writing blog posts and came up with this list of requirements / wishes:</p><ul><li>Port the existing blog with as little effort as possible</li><li>Writing blog posts in a convenient format: markdown is good enough, let&apos;s keep it</li><li>Don&apos;t use a framework like Octopress again: it isn&apos;t worth the learning curve for me</li><li>Don&apos;t get stuck in a language I don&apos;t use every day. The deprecation warnings in Ruby scared me and it was time-consuming to install or update the tooling that I didn&apos;t use on a daily basis.</li></ul><p>My blog has the following essential components:</p><ul><li>Archive page with list of all blog posts written so far</li><li>Index page that lists the most recent blog posts</li><li>Each post has its own HTML page</li><li>An <code>atom.xml</code> feed and a bespoke <code>planetclojure.xml</code> feed for <a href="http://planet.clojure.in/">Planet
  Clojure</a></li><li>Highlighting for Clojure code snippets: not super important, but I&apos;d like to at least have this back after a rewrite.</li></ul><p>The primary goal of this blog is to share some of my experiences. Of secondary importance:</p><ul><li>A way for users to directly react. For now I can live with users reacting via Twitter, Clojurians Slack, etc. and I can figure this out later.</li><li>A fancy web design.</li></ul><p>The language I am most fluent in is Clojure. <a href="https://babashka.org/">Babashka</a> is a scripting tool that has similar startup characteristics as Ruby so it would be nice to keep that from my Octopress experience. Let&apos;s see if I can rewrite my blog with a babashka script.</p><h2 id="rewriting-in-babashka">Rewriting in babashka</h2><p>I started with copying each markdown file in <code>source/_posts</code> and moved them to a directory <code>posts</code>.  In Octopress, blog posts start with a section like:</p><pre><code>---
layout: post
title: Figwheel keep Om turning!
date: 2014-09-25 21:00:50 +0200
comments: true
published: true
categories: [clojure, clojurescript, figwheel, om]
---
</code></pre><p>I removed these sections replaced them with maps in a file called <code>posts.edn</code>:</p><pre><code class="language-clojure">{:title &quot;Figwheel keep Om turning!&quot;
 :file &quot;figwheel-keep-om-turning.md&quot;
 :date &quot;2014-09-25&quot;
 :categories #{&quot;clojure&quot; &quot;clojurescript&quot; &quot;figwheel&quot; &quot;om&quot;}
 :legacy true}
</code></pre><p>The maps are top level values so I can easily append new ones programmatically. The <code>:legacy true</code> flag is for blog posts that existed before the rewrite so I can create redirect pages for them. I plan to no longer include the date in the direct blog post URLs, but I don&apos;t want to break the web for older blog posts. I might switch back to including this metadata in the blog posts themselves and parse them out, but so far this worked out well.</p><p>Then I started writing the <code>render.clj</code> script which iterates over every entry in <code>posts.edn</code> and renders markdown files to HTML.</p><p>To do markdown rendering from babashka I&apos;m using <a href="https://github.com/retrogradeorbit/bootleg">bootleg</a> by Crispin Wellington which is available in the <a href="https://github.com/babashka/pod-registry/blob/master/examples/bootleg.clj">pod
registry</a>.</p><p>I had to fix a couple of things to get the rendering back that I had with Octopress. Links without markup: <code>https://foobar.com</code> instead of <code>[foobar](https://foobar.com)</code>, were rendered as an <code>a</code> element before, but bootleg, which uses <a href="https://github.com/yogthos/markdown-clj">markdown-clj</a> doesn&apos;t do this out of the box.</p><p>Another tweak I had to implement is support line breaks in the middle of markdown link syntax, since emacs&apos;s <code>fill-paragraph</code> sometimes causes that to happen:</p><pre><code class="language-markdown">[foo
bar](https://foobar.com)
</code></pre><p>The tweaks:</p><pre><code class="language-clojure">(pods/load-pod &apos;retrogradeorbit/bootleg &quot;0.1.9&quot;)

(require &apos;[pod.retrogradeorbit.bootleg.markdown :as md])

(defn markdown-&gt;html [file]
  (let [markdown (slurp file)
        ;; make links without markup clickable
        markdown (str/replace markdown #&quot;http[A-Za-z0-9/:.=#?_-]+([\s])&quot;
                              (fn [[match ws]]
                                (format &quot;[%s](%s)%s&quot;
                                        (str/trim match)
                                        (str/trim match)
                                        ws)))
        ;; allow links with markup over multiple lines
        markdown (str/replace markdown #&quot;\[[^\]]+\n&quot;
                              (fn [match]
                                (str/replace match &quot;\n&quot; &quot;$RET$&quot;)))
        html (md/markdown markdown :data :html)
        html (str/replace html &quot;$RET$&quot; &quot;\n&quot;)]
    html))
</code></pre><p>Since this is my personal blog solution, I&apos;m not too worried about these hacks and not being able to use <code>$RET</code> in the text of my blogs. If I were to publish this as a framework or library I would have solved it at the root level, but that wasn&apos;t a cost I was ready to pay now. After these workarounds, it was pretty straightforward to support the most essential things my Octopress blog did.</p><h2 id="highlighting">Highlighting</h2><p>Clojure syntax highlighting works pretty well with <a href="https://github.com/highlightjs/highlight.js">highlight.js</a> which I include like this:</p><pre><code class="language-html">&lt;link rel=&quot;stylesheet&quot;
      href=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/default.min.css&quot;&gt;
&lt;script src=&quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.highlightAll();&lt;/script&gt;
</code></pre><p>After that it just pretty much worked. The Clojure syntax highlighting isn&apos;t perfect, but good enough for a blog with the occasional snippet in my opinion.</p><h2 id="feeds">Feeds</h2><p>The generation of <code>atom.xml</code> and <code>planetclojure.xml</code> (which only contains Clojure-related posts) were easy to implement with a bit of <code>clojure.data.xml</code> code:</p><pre><code class="language-clojure">(def blog-root &quot;https://blog.michielborkent.nl/&quot;)

(defn atom-feed
  [posts]
  (-&gt; (xml/sexp-as-element
       [::atom/feed
        {:xmlns &quot;http://www.w3.org/2005/Atom&quot;}
        [::atom/title &quot;REPL adventures&quot;]
        [::atom/link {:href (str blog-root &quot;atom.xml&quot;) :rel &quot;self&quot;}]
        [::atom/link {:href blog-root}]
        [::atom/updated (rfc-3339-now)]
        [::atom/id blog-root]
        [::atom/author
         [::atom/name &quot;Michiel Borkent&quot;]]
        (for [{:keys [title date file]} posts
              :let [html (str/replace file &quot;.md&quot; &quot;.html&quot;)
                    link (str blog-root html)]]
          [::atom/entry
           [::atom/id link]
           [::atom/link link]
           [::atom/title title]
           [::atom/updated (rfc-3339 date)]
           [::atom/content {:type &quot;html&quot;}
            [:-cdata (get @bodies file)]]])])
      xml/indent-str))

(spit (fs/file out-dir &quot;atom.xml&quot;) (atom-feed posts))
(spit (fs/file out-dir &quot;planetclojure.xml&quot;)
      (atom-feed (filter
                  (fn [post]
                    (some (:categories post) [&quot;clojure&quot; &quot;clojurescript&quot;]))
                  posts)))
</code></pre><p>This <a href="https://validator.w3.org/feed/check.cgi">feed validator</a> gave pretty good feedback on what should and should not go into this XML file.</p><h2 id="rake--&gt;-bb-tasks">Rake -&gt; bb tasks</h2><p>Finally I wrote a <code>bb.edn</code> file with <a href="https://book.babashka.org/#tasks">babashka
tasks</a> to create new blog posts. E.g. I created this very blog post using:</p><pre><code class="language-shell">$ bb new :file migrating-octopress-to-babashka.md :title &quot;Migrating this blog from octopress to babashka&quot;
</code></pre><p>All implemented tasks so far:</p><pre><code class="language-shell">$ bb tasks
The following tasks are available:

new     Create new blog article
render  Render blog
watch   Watch posts and templates and call render on file changes
publish Publish to blog.michielborkent.nl
</code></pre><p>This replaces the <code>rake</code> stuff I used to have with Octopress.</p><h2 id="conclusion">Conclusion</h2><p>I&apos;m pretty happy with how far I got with a couple of hours hacking on the babashka scripts and tasks. The meat of the work is in <code>render.clj</code> which is under 170 lines of Clojure. I feel in control over my own blog again. From here on I can look for a plugin which lets users respond to blog posts and perhaps a fancier design. If you have anything useful to share regarding this, please let me know on e.g. <a href="https://twitter.com/borkdude">Twitter</a>.</p><p>The code for this blog is available <a href="https://github.com/borkdude/blog">here</a>.</p><h2 id="aftermath">Aftermath</h2><p>Since writing this blog post, this blog has undergone some progressions which you can read about here:</p><ul><li><a href="https://blog.michielborkent.nl/better-clojure-highlighting.html">I wanted better Clojure highlighting using nextjournal/clojure-mode</a>.</li><li><a href="https://blog.michielborkent.nl/writing-clojure-highlighter.html">But then I realized that Clojure highlighting isn&apos;t that hard can be done using a home-made solution.</a></li><li><a href="https://blog.michielborkent.nl/markdown-clj-babashka-compatible.html">Instead of the pod, the blog is now using markdown-clj from source</a>.</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/remote-wsl2-clojure.html</id>
    <link href="https://blog.michielborkent.nl/remote-wsl2-clojure.html"/>
    <title>Porting a macOS Clojure dev setup to Windows WSL2</title>
    <updated>2020-07-26T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><strong>EDIT 2020-09-16:</strong> this post is now also available as a talk. The slides are available <a href="https://speakerdeck.com/borkdude/porting-a-macos-clojure-dev-setup-to-windows-wsl2">here</a>.</p><iframe width="560" height="315" src="https://www.youtube.com/embed/j5jLPzBRtKI" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>In the last few years I&apos;ve been developing predominantly on Apple MacBooks. Recently I built myself a <a href="https://tweakers.net/pricewatch/bestelkosten/2370528">new</a> <a href="https://twitter.com/borkdude/status/1280852700612177922">PC</a> with a fast processor and lots of memory. I wanted to move some of my development tasks to that machine. I still like the freedom that laptops give me to work from wherever I want. Be it from the couch in my own home or from a random coffee place in the city where I live, I just like to change environment every few hours and not sit behind my desk all day long. I hadn&apos;t used Windows as my primary OS for almost 10 years. But since Windows 10 (still) comes with RDP, which is better than VNC in terms of performance, and with WSL2, which offers a &quot;real&quot; and well integrated linux experience, I was curious if I could create a setup for remotely working on the new machine. It also would give me an environment to debug Windows specific problems on, which should come in handy for my side projects like <a href="https://github.com/borkdude/babashka">babashka</a> and <a href="https://github.com/borkdude/clj-kondo/">clj-kondo</a>. If it didn&apos;t work out, I could always go dual boot with Ubuntu as the primary dev OS and use VNC if I needed to do anything graphical. For what it is worth, here is a report of setup process I went through.</p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">The pristine smell and beauty of a new PC contrasted with the chaotic reality of my home. <a href="https://t.co/3zLIzYg4XB">pic.twitter.com/3zLIzYg4XB</a></p>&mdash; (λ. borkdude) (@borkdude) <a href="https://twitter.com/borkdude/status/1280852700612177922?ref_src=twsrc%5Etfw">July 8, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><p>Because I had no other Windows machines in my home, I tried creating a USB Windows installation drive in macOS based on <a href="https://www.freecodecamp.org/news/how-make-a-windows-10-usb-using-your-mac-build-a-bootable-iso-from-your-macs-terminal/">this</a> blog post. No matter what I tried, at the end of the installation process Windows <a href="https://twitter.com/borkdude/status/1280943718363734016">would complain</a> with</p><blockquote><p>Windows installation encountered an unexpected error. Verify that the installation sources are accessible, and restart the installation.</p></blockquote><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Installing Ubuntu on new PC. The installer is surprisingly smooth, detects my wifi, even nvidia video card apparently. Whereas Windows be like <a href="https://t.co/FQNzeJ6V2X">pic.twitter.com/FQNzeJ6V2X</a></p>&mdash; (λ. borkdude) (@borkdude) <a href="https://twitter.com/borkdude/status/1280943718363734016?ref_src=twsrc%5Etfw">July 8, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><p>A good friend offered help and created an installation drive using <a href="https://rufus.ie/">Rufus</a> on his Windows Home installation, which did work.</p><p>Once Windows was installed, I <a href="https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/remote-desktop-allow-access">enabled RDP</a> and installed <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">WSL2</a>, <a href="https://www.microsoft.com/store/apps/9n6svws3rx71">Ubuntu 20.04</a>, <a href="https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab">Windows Terminal</a> and <a href="https://docs.docker.com/docker-for-windows/wsl/">Docker Desktop for WSL2</a>.</p><p>To be able to run WSL2, I had to enable a virtualization option in my BIOS first.</p><p>I intend to use Ubuntu WSL2 as my primary dev environment on this machine, so it made sense to tweak the <a href="https://superuser.com/questions/1456511/is-there-a-way-to-change-the-default-shell-in-windows-terminal">Terminal configuration</a> to open Ubuntu by default, instead of PowerShell. I found it annoying that Ubuntu in Terminal starts in the Windows home directory (<code>/mnt/c/Users/borkdude</code>), so I set <code>&quot;startingDirectory&quot;: &quot;//wsl$/Ubuntu-20.04/home/borkdude&quot;</code> in my Ubuntu profile.</p><p>I use zsh as my default shell on macOS and wanted that in WSL2 as well so I installed that using <code>sudo apt update &amp;&amp; sudo apt install zsh</code> followed by <code>chsh -s $(which zsh)</code>. I also installed <a href="https://github.com/ohmyzsh/ohmyzsh">ohmyzsh</a> and enabled the only two plugins I use on a daily basis: <code>git</code> and <code>jump</code>.</p><p>Then I started porting the dev setup I use for work on my MacBook, mainly consisting of Docker images, a couple of Clojure projects, knitted together with some bash scripts. I use a couple of shell scripts to set all my development environment variables and aliases for easily setting up ssh tunnels. These worked after only making a few tweaks (for example, the ethernet card is called differently in macOS and Ubuntu in WSL2). Of course I needed to install <code>git</code> to clone my work projects. To run Clojure projects I installed OpenJDK version 8 and 11 via <code>apt</code>. I use <a href="jenv.be">jenv</a> to manage Java versions on a project basis, which worked perfectly:</p><pre><code class="language-sh">sudo apt-get install openjdk-8-jdk
jenv add /usr/lib/jvm/java-1.8.0-openjdk-amd64/
</code></pre><p>Also I installed <a href="https://boot-clj.com/">boot</a>, a Clojure build tool and the <a href="https://clojure.org/guides/deps_and_cli">Clojure CLI</a> which are all well supported in linux.</p><p>Before running my work projects, I wanted to copy over a PostgreSQL database and other data from my MacBook using <code>rsync</code>. Before I could do that, I needed to enable <code>ssh</code> in Ubuntu. I found out I could do this by running <code>sudo service ssh start</code> but I still could not log in from my MacBook. It turns out you also have to forward and open up the port in the Windows Firewall. I found <a href="https://github.com/microsoft/WSL/issues/4150#issuecomment-504209723">this</a> PowerShell script that lets you do that. As the comment suggests, I also created a scheduled task that runs this script upon Windows login. I did the same thing for running the <code>ssh</code> service using <code>wsl -u root sudo service ssh start</code>. Be sure to select <code>Run using the highest privileges</code>. I&apos;m sure there is a better way to do this via <code>systemd</code> in WSL2, but this works for me. So now I could <code>rsync</code> my the data from macOS to WSL2. I started the Docker containers, the Clojure projects and it worked! We have a fairly I/O intensive process as part of our stack, which seems to perform well in WSL2.</p><p>Enabling SSH in WSL also lets me use Emacs from my laptop and edit files on the remote machine using <a href="https://www.emacswiki.org/emacs/TrampMode">tramp mode</a>. I ran into one issue with this. Since I use a non-standard prompt in zsh, emacs tramp could not parse the output from the remote shell. So I added this hack to my <code>~/.zshrc</code>:</p><pre><code class="language-sh">case &quot;$TERM&quot; in
    &quot;dumb&quot;)
        bash
esac
</code></pre><p>Emacs sets <code>TERM</code> to <code>&quot;dumb&quot;</code> when opening files using <code>tramp</code>. When this is the case, I just invoke <code>bash</code> instead of continuing with <code>zsh</code>. There may be a better solution, but this works.</p><p>Of course I also wanted to be able to run Emacs on the machine itself. I first tried to run Emacs in Windows <a href="https://github.com/m-parashar/emax64">natively</a>, but I read somewhere that editing WSL2 files directly from Windows is not recommended. Also you might run into the line ending differences between Windows and linux/macOS. I decided to play it safe and install emacs inside WSL2 using <code>apt</code>. If you do decide to use the Windows-native Emacs and have trouble finding where emacs expects configuration files, you can find this using <code>M-x describe-variable user-init-file</code>. On my machine that was <code>C:\Users\borkdude\AppData\Roaming\.config\emacs\init.el.</code>. To get a graphical UI for the emacs started from WSL2, I needed to install an X-server on Windows. There are plenty of free and open source solutions to choose from, but I chose to buy <a href="https://www.microsoft.com/en-us/p/x410/9nlp712zmn9q?activetab=pivot:overviewtab">X410</a> on sale for <span class="formula">9.99 instead of </span>49.99. It seems to be actively worked on and has <a href="https://x410.dev/cookbook/wsl/using-x410-with-wsl2/">good documentation</a>. To automatically start X410 on Windows startup I followed <a href="https://x410.dev/cookbook/automatically-start-x410-on-login/">these</a> instructions. When started, in the tray there is an X icon where you can modify settings for X410. I have enabled Windowed Apps, Allow Public Access, DPI Scaling (High Quality) and Shared Clipboard. To export the right <code>DISPLAY</code> value for GUI applications in WSL2 I have this in my <code>.zshenv</code>:</p><pre><code class="language-sh">export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk &apos;{print $2; exit;}&apos;):0.0
</code></pre><p>and then run emacs using <code>setsid emacs</code> from a zsh session (I created an alias for this in my <code>.zshenv</code>).</p><p>I&apos;m using the exact same emacs config I use on macOS, which is based on <a href="https://twitter.com/bbatsov">@bbatsov</a>&apos;s <a href="https://github.com/bbatsov/prelude">prelude</a>. It looks and feels the same as on macOS, although now I probably have to learn the &quot;real&quot; emacs keybindings for copying (<code>M-w</code>) and pasting (<code>C-y</code>) instead of using the macOS keybindings, which may be in fact a nice side effect of this experiment.</p><p>Even connecting to an nREPL server with <code>cider-connect</code> works seemlessly from my laptop, provided that I forward and open up the port in Windows Firewall like described above.</p><p>Some closing tips.</p><p>There is a known <a href="https://github.com/microsoft/WSL/issues/4166">issue</a> with memory usage of WSL2. Since linux uses non-allocated memory for filesystem caching, Windows thinks this memory is really used. As time goes by, Windows could end up allocating all your system&apos;s memory to WSL2. To put a limit to this, I use this config in <code>C:\Users\borkdude\.wslconfig</code>:</p><pre><code>[wsl2]

memory=92GB
</code></pre><p>My PC has a whopping 128GB of memory so this still leaves 36GB of memory to Windows.</p><p>As I will mainly use this PC for work, I turn it off at night and during the weekends. To get back where I left, without restarting all my development processes from scratch, I use the <a href="https://support.microsoft.com/en-us/help/920730/how-to-disable-and-re-enable-hibernation-on-a-computer-that-is-running">Hibernate</a> setting.</p><p>I use <a href="https://tailscale.com/">Tailscale</a> to set up a VPN between my laptop and Windows machine so I can connect through RDP, emacs tramp and/or nREPL when I go outside of my home.</p><p>For RDP I use <a href="https://apps.apple.com/nl/app/microsoft-remote-desktop/id1295203466?mt=12">Microsoft Remote Desktop.app</a>. Since I have a Retina screen, I enabled the &quot;optimize for Retina displays&quot; setting which gives a better resolution.</p><p>As a bonus I can re-use some licenses I already owned for apps I am using on macOS: Beyond Compare and Acronis True Image.</p><p>I&apos;m pleasantly surprised with WSL2, the Terminal app and Docker integration. I&apos;ve only been using this setup for week but so far so good.</p><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Pretty good startup time of <a href="https://twitter.com/hashtag/babashka?src=hash&amp;ref_src=twsrc%5Etfw">#babashka</a> in WSL2 on Windows on new machine (Ryzen 3950X): 4ms on average<a href="https://twitter.com/graalvm?ref_src=twsrc%5Etfw">@graalvm</a> <a href="https://t.co/TKPPoeFZlL">pic.twitter.com/TKPPoeFZlL</a></p>&mdash; (λ. borkdude) (@borkdude) <a href="https://twitter.com/borkdude/status/1281689072310919168?ref_src=twsrc%5Etfw">July 10, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/clj-kondo-hooks.html</id>
    <link href="https://blog.michielborkent.nl/clj-kondo-hooks.html"/>
    <title>Clj-kondo hooks</title>
    <updated>2020-06-21T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><a href="https://github.com/borkdude/clj-kondo/">Clj-kondo</a> is a Clojure linter that uses static analysis. This means it only looks at source code, but does not execute it. While the information available to produce good lint warnings is more limited with static analysis, static analyzing is generally more performant, and works independently from a runtime (JVM, nodeJS, browser, etc.). Static analysis does not suffer from causing unwanted side effects when executing code. It often yields good enough results. Where static analysis falls short, clj-kondo offers <a href="https://github.com/borkdude/clj-kondo/blob/master/doc/config.md">configuration</a> options where the user can help clj-kondo understand more of their code.</p><p>One area where static analysis of Clojure code becomes hard is macros. Macros can introduce new syntactical constructs. Often macros are syntactically similar to existing Clojure core macros. This is where you can use clj-kondo&apos;s <code>:lint-as</code> configuration. In places where this isn&apos;t possible, for example because the macro had irregular binding patterns, one could use <code>:unresolved-symbol</code> + <code>:exclude</code> which would simply ignore unresolved symbol errors in an entire s-expression.</p><p>I&apos;ve been asking myself the following question for a while now: can clj-kondo make more sense of custom macros with a little help from the user? Clj-kondo could invent some DSL to express a transformation, but DSLs often cover just 80% of what you want to achieve. To get 20% more power, you&apos;d have to turn the DSL into something like Clojure itself. So why not just use Clojure directly?</p><p>Clj-kondo is distributed in a couple of different ways. A widely used distribution is the binary compiled with GraalVM. One limitation of a GraalVM-compiled binary is that one cannot introduce new classes at runtime. And this is what <code>clojure.core/eval</code> does, so that&apos;s off the table. Since August 2019 I&apos;ve been working on the <a href="https://github.com/borkdude/sci">Small Clojure
Interpreter</a>. It&apos;s not a compiler, like Clojure, but it allows you to interpret Clojure expressions within a GraalVM binary. The interpreter is used in <a href="http://babashka.org/">babashka</a> but it has other uses as well and also works in JavaScript.</p><p>This interpreter can be used in clj-kondo to execute hooks that users can provide to transform custom macro calls into constructs that clj-kondo can understand. And this is what I&apos;ve worked on.</p><p>Clj-kondo uses a vendored version of <a href="https://github.com/xsc/rewrite-clj">rewrite-clj</a> to analyze source code. My first attempt at the hooks API was to transform the rewrite-clj nodes into Clojure s-expressions. Then the user&apos;s hook function would transform these s-expressions in a similar fashion as the macro would, returning new s-expressions. Lastly clj-kondo would then translate these s-expressions back into rewrite-clj nodes and continue analysis. Ostensibly this worked great for several test cases, but ultimately it wasn&apos;t good enough. The main problem is that numbers, strings and keywords cannot carry metadata. Metadata on sexprs was used to keep track of the original locations. When (some of) these locations are lost, clj-kondo cannot accurately position lint warnings anymore. And this is unacceptable in my opinion. You can read more about this problem on ClojureVerse <a href="https://clojureverse.org/t/feedback-wanted-on-new-clj-kondo-macroexpansion-feature/6043">here</a> and in the issue on Github <a href="https://github.com/borkdude/clj-kondo/issues/811">here</a>.</p><p>After more experimentation I decided that the transformation should happen direcly on rewrite-clj nodes in order to preserve location information. This led to the current implementation of the <code>:analyze-call</code> hook, documented <a href="https://github.com/borkdude/clj-kondo/blob/master/doc/hooks.md">here</a>. Additionally, some library specific example config + hook code is provided <a href="https://github.com/borkdude/clj-kondo/tree/master/examples">here</a>, showing how to make clj-kondo understand <a href="https://github.com/tonsky/rum">Rum</a>&apos;s <code>defc</code> macro and <a href="https://github.com/scgilardi/slingshot">slingshot</a>&apos;s <code>try+</code> macro.</p><p>I consider this new feature a powerful feature but not an easy to use one. It does provide a higher degree of linting quality while still enjoying the benefits of static analysis. Luckily we only have to figure out the right code for each library once. I urge library authors and users to contribute their configurations to the clj-kondo <a href="https://github.com/borkdude/clj-kondo/tree/master/examples">repository</a> so we can all benefit.</p><p><a href="https://www.clojuriststogether.org/">Clojurist Together</a> has sponsored this work as part of their <a href="https://www.clojuriststogether.org/news/announcing-summer-of-bugs/">Summer of
Bugs</a> program. Thanks to the people who have made this possible: the Clojurists Together staff and of course the people who donate.</p><p>Hope you enjoy. Happy linting!</p><p>Michiel Borkent (a.k.a. <a href="https://twitter.com/borkdude">@borkdude</a>)</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/transducing-text.html</id>
    <link href="https://blog.michielborkent.nl/transducing-text.html"/>
    <title>Transducing a text file</title>
    <updated>2018-01-17T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>This post highlights of one of the core ideas posted in <a href="https://www.grammarly.com/blog/engineering/building-etl-pipelines-with-clojure-and-transducers/">this
blogpost</a>. If you&apos;ve already read it and you&apos;re intimately familiar with transducers, this post probably won&apos;t have anything new for you. I&apos;ve posted this to <a href="https://stackoverflow.com/a/47354316/6264">Stackoverflow</a> before and saving this to my blog for archival purposes.</p><p>In the pre-transducer era, reading text files was often done like this:</p><pre><code class="language-clojure">(require &apos;[clojure.java.io :as io])
(with-open [rdr (io/reader &quot;/tmp/work.txt&quot;)]
  (-&gt;&gt; (line-seq rdr)
       (mapcat #(str/split % #&quot;;&quot;))
       (map count)
       (doall)))
</code></pre><p>Given input <code>work.txt</code>:</p><pre><code>I;am;a;string
Next;line;please
</code></pre><p>this would return <code>(1 2 1 6 4 4 6)</code>. One caveat with this approach is you have to realize the result inside the <code>with-open</code> macro, else the file would already be closed.</p><p>What if we want to use transducers instead of lazy collection transformations? The ingredient you need is something that allows you to treat the lines as a reducible collection and which closes the reader when you&apos;re done reducing:</p><pre><code class="language-clojure">    (defn lines-reducible
      [^java.io.BufferedReader rdr]
      (reify clojure.lang.IReduceInit
        (reduce [this f init]
          (try
            (loop [state init]
              (if (reduced? state)
                @state
                (if-let [line (.readLine rdr)]
                  (recur (f state line))
                  state)))
            (finally
              (.close rdr))))))
</code></pre><h4 id="count-the-length-of-each-&apos;split&apos;">Count the length of each &apos;split&apos;</h4><pre><code class="language-clojure">    (require &apos;[clojure.string :as str])
    (require &apos;[clojure.java.io :as io])

    (into []
          (comp
           (mapcat #(str/split % #&quot;;&quot;))
           (map count))
          (lines-reducible (io/reader &quot;/tmp/work.txt&quot;)))
    ;;=&gt; [1 2 1 6 4 4 6]
</code></pre><h4 id="sum-the-length-of-all-&apos;splits&apos;">Sum the length of all &apos;splits&apos;</h4><pre><code class="language-clojure">    (transduce
     (comp
      (mapcat #(str/split % #&quot;;&quot;))
      (map count))
     +
     (lines-reducible (io/reader &quot;/tmp/work.txt&quot;)))
    ;;=&gt; 24
</code></pre><h4 id="sum-the-length-of-all-words-until-we-find-a-word-that-is-longer-than-5">Sum the length of all words until we find a word that is longer than 5</h4><pre><code class="language-clojure">    (transduce
     (comp
      (mapcat #(str/split % #&quot;;&quot;))
      (map count))
     (fn
       ([] 0)
       ([sum] sum)
       ([sum l]
        (if (&gt; l 5)
          (reduced sum)
          (+ sum l))))
     (lines-reducible (io/reader &quot;/tmp/work.txt&quot;)))
</code></pre><p>or with <code>take-while</code>:</p><pre><code class="language-clojure">    (transduce
     (comp
      (mapcat #(str/split % #&quot;;&quot;))
      (map count)
      (take-while #(&gt; 5 %)))
     +
     (lines-reducible (io/reader &quot;/tmp/work.txt&quot;)))
</code></pre><p>Read <a href="https://www.grammarly.com/blog/engineering/building-etl-pipelines-with-clojure-and-transducers/">https://www.grammarly.com/blog/engineering/building-etl-pipelines-with-clojure-and-transducers/</a> for more details.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/parsing-a-circuit-with-clojure-spec.html</id>
    <link href="https://blog.michielborkent.nl/parsing-a-circuit-with-clojure-spec.html"/>
    <title>Parsing a circuit with clojure.spec</title>
    <updated>2017-10-10T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p><a href="http://adventofcode.com/">Advent of Code</a> is a collection of self-contained programming problems, one for each day during <a href="https://en.wikipedia.org/wiki/Advent">Advent</a>. My favorite problem of 2015&apos;s edition was <a href="http://adventofcode.com/2015/day/7">Day 7: Some Assembly
Required</a>.  You can read the full description on the site. I&apos;ll explain it briefly. A circuit looks like this:</p><pre><code class="language-abap">123 -&gt; x
456 -&gt; y
x AND y -&gt; d
x OR y -&gt; e
x LSHIFT 2 -&gt; f
y RSHIFT 2 -&gt; g
NOT x -&gt; h
NOT y -&gt; i
</code></pre><p>On the left you have one or more inputs combined by a logical gate which is then wired to the output on the right.</p><p>If you run this circuit, it will produce the following state:</p><pre><code>d: 72
e: 507
f: 492
g: 114
h: 65412
i: 65079
x: 123
y: 456
</code></pre><p>The problem can be subdivided into parsing and processing. When I solved this problem in 2015 I used good old <code>string/split</code> and regexes. But it can also be solved quite elegantly with <a href="https://clojure.org/guides/spec">clojure.spec</a> as we shall see.</p><p>I&apos;ll walk you through the circuit spec in reverse.</p><p>An expression is the left hand side followed by the symbol <code>-&gt;</code> followed by the right hand side.</p><pre><code class="language-clojure">(s/def ::expr (s/cat :lhs ::lhs :arrow #{&apos;-&gt;} :rhs ::rhs))
</code></pre><p>The right hand side is always a variable name.</p><pre><code class="language-clojure">(s/def ::rhs ::varname)
</code></pre><p>The left hand side is a little bit more involved. It is either a simple value (a variable name or concrete value: <code>x</code>, <code>456</code>, <code>1337</code>, <code>ac</code>), a binary expression (<code>x AND y</code>) or something which is negated (<code>NOT x</code>).</p><pre><code class="language-clojure">(s/def ::lhs (s/alt :simple-value ::val
                    :binary-expression
                    ::binary-expression
                    :not ::not))
</code></pre><p>A negated expression is the symbol <code>NOT</code> followed by a value.</p><pre><code class="language-clojure">(s/def ::not (s/cat :not #{&apos;NOT} :operand ::val))
</code></pre><p>A binary expression is a value followed by an operator followed by another value.</p><pre><code class="language-clojure">(s/def ::binary-expression (s/cat
                            :left-operand ::val
                            :operator ::binary-operator
                            :right-operand ::val))
</code></pre><p>A binary operator is one of the symbols in the set.</p><pre><code class="language-clojure">(s/def ::binary-operator #{&apos;LSHIFT &apos;RSHIFT &apos;AND &apos;OR})
</code></pre><p>A value is either a variable name or a non-negative integer.</p><pre><code class="language-clojure">(s/def ::val (s/alt :name ::varname
                    :value nat-int?))
</code></pre><p>Lastly, a variable name is a symbol. I could have specified this in more detail by restricting the allowed characters and the length of the symbol, but this was not needed to succesfully parse my input.</p><pre><code class="language-clojure">(s/def ::varname
  (s/with-gen symbol?
    (fn [] varname-gen)))
</code></pre><p>However, to generate a variable name which looks like my input, for the sake of playing around with spec, I need to provide my own generator. Scanning through my input, I discovered that a variable name&apos;s length is either 1 or 2 and only alphabetic characters may be used.</p><pre><code class="language-clojure">(def varname-gen
  (gen/fmap (fn [chars]
              (symbol
               (str/lower-case
                (apply str chars))))
            (gen/vector (gen/char-alpha)
                        1
                        2)))
</code></pre><p>Running the generator yields for example:</p><pre><code class="language-clojure">(gen/sample varname-gen) ;;=&gt; (g dv de pw hi a c j bz y)
</code></pre><p>We can now generate entire expressions:</p><pre><code class="language-clojure">(gen/sample (s/gen ::expr)) ;;=&gt; ((NOT g -&gt; sw) (NOT 0 -&gt; j) (gl LSHIFT 0 -&gt; q) (NOT 1 -&gt; ly) (NOT 2 -&gt; j) (ug -&gt; o) (p RSHIFT 0 -&gt; p) (NOT oj -&gt; dz) (ih -&gt; m) (NOT 5 -&gt; fc))
</code></pre><p>Looks good.</p><p>To read the lines from the input file I cheated a little bit by using <code>edn/read-string</code> which parses raw strings to a vector of symbols and numbers for me:</p><pre><code class="language-clojure">(defn get-lines []
  (str/split-lines
   (slurp &quot;input-day7.txt&quot;)))

(defn parsed-lines [lines]
  (mapv (fn [l]
          (let [edn (edn/read-string
                     (format &quot;[%s]&quot; l))]
            (s/conform ::expr edn)))
        lines))
</code></pre><p>I could have used <code>line-seq</code> or a <a href="https://stackoverflow.com/a/47354316/6264">text transducer</a> to save some memory, but as Knuth says, if you optimize everything you will always be unhappy.</p><p>Let&apos;s peek at the first conformed expression which corresponds to the line <code>bn RSHIFT 2 -&gt; bo </code>:</p><pre><code class="language-clojure">(first (parsed-lines (get-lines))) ;;=&gt; {:lhs [:binary-expression {:left-operand [:name bn], :operator RSHIFT, :right-operand [:value 2]}], :arrow -&gt;, :rhs bo}
</code></pre><p>Yay! Now we have to write some code that processes these lines and calculates the values for each variable. To do this, we are going to build up a map of symbols to their values:</p><pre><code class="language-clojure">(def context (atom {}))
</code></pre><p>The right hand side of an expression is always a variable name. So we <code>assoc</code> it to the <code>context</code> where the value is a <code>delay</code> of the evaluation of the left hand side.</p><pre><code class="language-clojure">(defn evaluate-expr! [expr]
  (let [rhs (:rhs expr)
        lhs (:lhs expr)]
    (swap! context assoc rhs
           (delay
            (evaluate* lhs)))))
</code></pre><p>The reason we are using a <code>delay</code> for the values of the context map, is twofold: delaying and caching.  Firstly, not all values that the variable depends on are already added to the context, so we have to delay calculation until every expression has been processed. Secondly, once a value of a variable is known, we do not want to recalculate it. My circuit file is 339 lines long and without caching this becomes terribly slow.</p><p>The API we need to get the solution for our Advent of Code puzzle is a function from symbol to integer.</p><pre><code class="language-clojure">(defn value-by-symbol [sym]
  @(get @context sym))
</code></pre><p>The double <code>deref</code> is needed because we&apos;re dealing with an <code>atom</code> and a <code>delay</code>.</p><p>The last bit we need to is evaluate the left hand side of an expression. Here we pattern match on the kind of expression and evaluate accordingly!</p><pre><code class="language-clojure">(defn evaluate* [[kind tree-or-val]]
  (case kind
    :value tree-or-val
    :name (value-by-symbol tree-or-val)
    :simple-value (evaluate* tree-or-val)
    :not (bit-not
          (evaluate*
           (:operand tree-or-val)))
    :binary-expression
    (let [l (evaluate* (:left-operand tree-or-val))
          r (evaluate* (:right-operand tree-or-val))
          operator (case (:operator tree-or-val)
                     AND bit-and
                     OR bit-or
                     LSHIFT bit-shift-left
                     RSHIFT bit-shift-right)]
      (operator l r))))
</code></pre><p>Finally, after evaluating all the lines we can ask for the value of a symbol in the circuit.</p><pre><code class="language-clojure">(value-by-symbol &apos;a) ;;=&gt; 46065
</code></pre><p>which happened to be the correct value for my input!</p><p>Thanks for reading. The full code is available on <a href="https://github.com/borkdude/aoc2015_day7">Github</a>. Constructive feedback and criticisms are welcome.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/inline-def-debugging.html</id>
    <link href="https://blog.michielborkent.nl/inline-def-debugging.html"/>
    <title>Inline def: an effective* debugging technique for Clojure</title>
    <updated>2017-05-25T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Clojure beginners often hear that inline <code>def</code> is bad style. For code you commit that&apos;s mostly true. Example:</p><pre><code class="language-clojure">(defn foo [x]
  (def y (+ x 1))
  y)
</code></pre><p>Here <code>def</code> performs a side effect every time you call <code>foo</code>, by (re)defining a <code>Var</code> <code>y</code> which is global to the current namespace. Instead you should use <code>let</code> to make it a local:</p><pre><code class="language-clojure">(defn foo [x]
  (let [y (+ x 1)]
    y))
</code></pre><p>However, inline <code>defs</code> can serve a useful purpose, namely that of a simple debugger. Debuggers for Clojure exist, e.g. in CIDER, but I mostly forget to use them. After <code>println</code>, inline <code>def</code> is my debugging tool of choice.</p><p>Example:</p><pre><code class="language-clojure">(defn foo [&amp; [{:keys [a b c] :as m}]]
  (+ a b c))
</code></pre><p>How should I call this function? Of course.</p><pre><code class="language-clojure">(foo :a 1 :b 2 :c 3)
;; =&gt; java.lang.NullPointerException
</code></pre><p>Wait, what? Inline <code>def</code> to the rescue.</p><pre><code class="language-clojure">(defn foo [&amp; [{:keys [a b c] :as m}]]
  (def m m) ;; TODO: remove this line before commit
  (+ a b c))
  
(foo :a 1 :b 2 :c 3)
;; =&gt; java.lang.NullPointerException
m ;;=&gt; :a
</code></pre><p>Oh, of course! What happened is that <code>m</code> was bound to the first argument. I get it, I should have called <code>foo</code> like this:</p><pre><code class="language-clojure">(foo {:a 1 :b 2 :c 3}) ;;=&gt; 6
</code></pre><p>Time to remove the inline <code>def</code> and get on with life.</p><p>I regularly use this technique to capture input that is part of some processing chain and I&apos;m not sure what data is flowing through, or when the input is hard to simulate from the REPL, e.g. coming form a large HTTP request body. Recently I was working on some XML parsing. For every XML file this function was called:</p><pre><code class="language-clojure">(defn process-xml [xml-as-str]
  (def xml-as-str xml-as-str) ;; TODO: remove this line before commit
  ;; processing
  )
</code></pre><p>That function was part of larger flow that reads from a directory of zipfiles containing XML files. After processing a few files I would get an exception. Let&apos;s inspect <code>xml-as-str</code>, the last input that triggered the exception.</p><pre><code class="language-clojure">xml-as-str ;;=&gt; &quot;&quot;
</code></pre><p>So the last entry from the zipfile was empty. Turns out the entry was not an XML file, but a directory represented by an empty string. Another example involved some XML file that didn&apos;t have the format I expected. Every time I got a new exception I could quickly see what was going on and retry <code>process-xml</code> with <code>xml-as-str</code> without kicking off the flow from scratch.</p><pre><code class="language-clojure">(process-xml xml-as-str) ;;=&gt; ok, now it works!
</code></pre><p>Next time you have the urge to reach for a debugger, you might want to become friends with inline <code>def</code> first.</p><p>Creating temporary vars with the same name as function arguments has the added benefit of being able to evaluate expressions within your function. This is discussed the blogpost <a href="http://blog.cognitect.com/blog/2017/6/5/repl-debugging-no-stacktrace-required">REPL Debugging: no stacktrace required</a> by <a href="stuarthalloway">Stuart Halloway</a>.</p><p>*) <a href="https://www.reddit.com/r/Clojure/comments/6dcmv2/an_effective_debugging_technique_for_clojure/">And somewhat controversial</a></p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/one-off-clojure-libraries.html</id>
    <link href="https://blog.michielborkent.nl/one-off-clojure-libraries.html"/>
    <title>One off experiments with Clojure and ClojureScript libraries</title>
    <updated>2016-10-19T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Did you ever need to know the date and time 30 hours from now, because that is the time you could check into your plane to EuroClojure 2016 (and you&apos;re too lazy to do this in your head)? Or maybe you just saw an interesting Clojure library on Twitter or Reddit that you wanted to try out?  How convenient would it be if you didn&apos;t have to create a project for such one off experiments.</p><p>There are several good options in Clojure for this. In this post let&apos;s assume we were going to try out <a href="https://github.com/clj-time/clj-time"><code>clj-time</code></a>, an excellent date and time library based on Joda Time. We&apos;ll show how to make a script that gives you almost instantaneous access to this library from the command line using <a href="http://boot-clj.com">Boot</a>. And then we&apos;ll make it even faster using <a href="http://planck-repl.org/">Planck</a>.</p><h2 id="leiningen">Leiningen</h2><p>For <a href="https://leiningen.org">Leiningen</a>, there is <a href="https://github.com/rkneufeld/lein-try">lein try</a>. This is a plugin you can install into <code>~/.lein/profiles.clj</code>. Then from the command line, just type <code>lein try clj-time</code> and we&apos;re good to go:</p><pre><code class="language-clojure">user=&gt; (require &apos;[clj-time.core :as t])
nil
user=&gt; (require &apos;[clj-time.local :as l])
nil
user=&gt; (t/plus (l/local-now) (t/hours 30))
#object[org.joda.time.DateTime 0x3b3c5f5f &quot;2016-10-25T16:53:58.154+02:00&quot;]
</code></pre><h2 id="boot">Boot</h2><p>For <a href="http://boot-clj.com">Boot</a> this story seems even simpler as there is no need to install a plugin. Boot supports an option for including dependencies from the command line. Just type <code>boot -d clj-time repl</code> to get a REPL with the latest <code>clj-time</code> as a dependency:</p><pre><code class="language-clojure">$ boot -d clj-time repl
;;; output omitted
boot.user=&gt; (require &apos;[clj-time.core :as t])
;;; etc.
</code></pre><p>Note that Boot&apos;s <code>repl</code> task also supports the <code>--eval</code> option (<code>-e</code> for short), so we can already put the <code>require</code> on the command line:</p><pre><code>$ boot -d clj-time repl -e &quot;(require &apos;[clj-time.core :as t]))&quot;
Clojure 1.8.0
;;; output omitted
boot.user=&gt; (t/plus (l/local-now) (t/hours 30))
#object[org.joda.time.DateTime 0x3489e3ab &quot;2016-10-25T17:11:18.560+02:00&quot;
```

How convenient this is. This allows us to write it as a script:

``` bash
#!/usr/bin/env bash

echo &quot;Example: (t/plus (l/local-now) (t/hours 30))&quot;
boot -d clj-time repl -e &quot;(do (require &apos;[clj-time.core :as t]) (require &apos;[clj-time.local :as l]))&quot;
</code></pre><p>Great to have handy for EuroClojure 2017!</p><p>Note that Boot allows us to load dependencies dynamically. Suppose you&apos;re experimenting but need another library. No need to restart the REPL. You can just type:</p><pre><code class="language-clojure">boot.user=&gt; (set-env! :dependencies &apos;[[org.clojure/core.async &quot;RELEASE&quot;]])
;;; output omitted
boot.user=&gt; (require &apos;[clojure.core.async :refer [go-loop]])
;;; continue experimenting
</code></pre><h2 id="plank">Plank</h2><p>Wouldn&apos;t it be great if we could also experiment with ClojureScript libraries from a REPL? For example <a href="https://github.com/andrewmcveigh/cljs-time"><code>cljs-time</code></a>? The easiest way to get here is <a href="http://planck-repl.org/">Planck</a>, which as of now runs only on OS X.</p><p>Planck can use jar files from <code>~/.m2</code>, but you have to specify the full classpath. This is easily done with the help of Boot:</p><pre><code class="language-bash">$ boot --dependencies org.clojars.micha/boot-cp            # load with-cp task that helps exporting minimal classpath to file
       --dependencies com.andrewmcveigh/cljs-time:&quot;0.4.0&quot;  # load dependency you actually want to try
       with-cp -w --file .classpath                        # write classpath to a file `.classpath`
</code></pre><p>The list of dependencies is now written to <code>.classpath</code>. You can re-use this file if your dependency hasn&apos;t changed.</p><p>Now we&apos;re ready to start the Planck REPL. It&apos;s fast! Even faster when you use the <code>K</code> option which caches compiled ClojureScript.</p><pre><code class="language-bash">$ planck -Kc `cat .classpath` -e &quot;(require &apos;[cljs-time.core :as t])&quot; -r
cljs.user=&gt; (require &apos;[cljs-time.local :as l])
cljs.user=&gt; (str (-&gt; (t/plus (t/now) (t/hours 30)) (t/to-default-time-zone)))
&quot;20161025T220847&quot;
</code></pre><h2 id="final-thoughts">Final thoughts</h2><p>Typing directly in a REPL only goes so far. For larger expressions it is more convenient to write in a text editor and then send the code to the REPL. For experiments started with Leiningen or Boot you can use an nREPL client. I use <a href="https://github.com/clojure-emacs/cider">CIDER</a>. For Planck you can use <a href="http://planck-repl.org/ides.html">inf-clojure</a>.</p><p>That&apos;s it. I hope this also helpful to beginners. Performing little Clojure experiments can grow into an addiction. Before you know it, you&apos;re soaked into your first Clojure project.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/clojure-from-scala.html</id>
    <link href="https://blog.michielborkent.nl/clojure-from-scala.html"/>
    <title>Using the Clojure REPL with Java or Scala</title>
    <updated>2016-07-26T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Clojure is a tool that enables interactive development and runtime inspection. Even when we work in other programming languages, Clojure can still be useful. Especially when that other language lives on the JVM.</p><p>Let&apos;s take Scala for example. Scala has a REPL. The REPL can be used to test-drive software in development. But it doesn&apos;t really let you inspect a running program when you didn&apos;t start it with <code>sbt console</code>. So let&apos;s use Clojure for that. We will walk through a simple Scala program that allows runtime inspection of an otherwise unknown state.</p><p>We&apos;ll need an sbt project for this example. Make a directory and put a <code>build.sbt</code> in it. The only dependency in this example is Clojure.</p><pre><code class="language-bash">scalaVersion := &quot;2.11.8&quot;

libraryDependencies ++= Seq(
  &quot;org.clojure&quot; % &quot;clojure&quot; % &quot;1.8.0&quot;
)
</code></pre><p>In <code>src/main/scala/example.scala</code> we add the following imports:</p><pre><code class="language-scala">import clojure.java.api.Clojure
import clojure.java.api.Clojure.{`var` =&gt; cvar}
</code></pre><p>We&apos;ll be using <a href="http://clojure.github.io/clojure/javadoc/">Clojure&apos;s Java API</a>.  In Scala <code>var</code> is a reserved keyword, so I&apos;m renaming it to <code>cvar</code>, since I don&apos;t like the backticks in my code.</p><p>Next, let&apos;s create an object that will contain some random value:</p><pre><code class="language-scala">object BusinessLogic {
  val x = Math.random() // I wonder what this value is at runtime... 
}
</code></pre><p>Also, let&apos;s create an <code>App</code> so we can run our program with <code>sbt run</code>:</p><pre><code class="language-scala">object Main extends App {
}
</code></pre><p>If we would execute <code>sbt run</code>, we would never know the value of <code>x</code> in <code>BusinessLogic</code>. We could add a <code>println</code>, but what if <code>x</code> was a <code>var</code> and it&apos;s value would change over time? Clojure lets us inspect this value at any given point in time. We&apos;ll start a <a href="http://clojure.org/reference/repl_and_main#_launching_a_socket_server">socket server</a> that is available since Clojure 1.8.0.</p><pre><code class="language-scala">object Main extends App {
  val require = cvar(&quot;clojure.core&quot;,&quot;require&quot;)
  require.invoke(Clojure.read(&quot;clojure.core.server&quot;))
  val startServer = cvar(&quot;clojure.core.server&quot;,&quot;start-server&quot;)
  val options = Clojure.read(&quot;&quot;&quot;{:port 4555 :accept clojure.core.server/repl 
    :name repl :server-daemon false}&quot;&quot;&quot;)
  startServer.invoke(options)
}
</code></pre><p>This may seem a little intimidating, so I&apos;ll explain it line by line. On line 2 we get a reference to Clojure&apos;s <code>require</code> so we can... yes, require namespaces.  On line 3 we read a string so we get the symbol that <code>require</code> needs to load the <code>clojure.core.server</code> namespace.  On line 4 we get a reference to the <code>start-server</code> <code>var</code>. On line 5 we define a bunch of settings. Their meaning can be found <a href="http://clojure.org/reference/repl_and_main#_launching_a_socket_server">here</a>.</p><p>In Clojure this would read as:</p><pre><code class="language-clojure">(require &apos;clojure.core.server)
(clojure.core.server/start-server 
  {:port 4555
   :accept clojure.core.server/repl
   :name &apos;repl
   :server-daemon false})
</code></pre><p>but since we&apos;re coming from Scala and have to use Clojure&apos;s Java API, it looks a bit more involved.</p><p>On the last line we invoke <code>start-server</code> with said options. When we execute <code>sbt run</code> again, the process will block, because <code>:server-daemon</code> was set to <code>false</code>:</p><pre><code class="language-scala">~/dev/scala/cljrepl $ sbt run
[info] Loading global plugins from /Users/Borkdude/.sbt/0.13/plugins
[info] Set current project to cljrepl (in build file:/Users/Borkdude/Dropbox/dev/scala/cljrepl/)
[info] Compiling 1 Scala source to /Users/Borkdude/Dropbox/dev/scala/cljrepl/target/scala-2.11/classes...
[info] Running Main
</code></pre><p>This gives us the chance to connect to the socket repl with good ol&apos; telnet:</p><pre><code class="language-bash">~ $ rlwrap telnet localhost 4555
Trying 127.0.0.1...
Connected to localhost.
Escape character is &apos;^]&apos;.
user=&gt; (import &apos;BusinessLogic)
BusinessLogic
user=&gt; (BusinessLogic/x)
0.722431948099764 ;; &lt;-- aah! 
user=&gt; :repl/quit
Connection closed by foreign host.
</code></pre><p>See what we did there?</p><p>Clojure&apos;s socket REPL also supports initialization via a JVM property. To try this, add these lines to <code>build.sbt</code>:</p><pre><code class="language-scala">fork := true
javaOptions := Seq(&quot;-Dclojure.server.repl={:port 4555 :accept clojure.core.server/repl :server-daemon false}&quot;)
</code></pre><p>The <code>App</code> can now be reduced to something like:</p><pre><code class="language-scala">object Main extends App {
  val require = cvar(&quot;clojure.core&quot;,&quot;require&quot;)
}
</code></pre><p>This doesn&apos;t do much except taking care that Clojure is initialized (for more info, read the last paragraph in <a href="http://stackoverflow.com/questions/2181774/calling-clojure-from-java/23555959#23555959">this Stackoverflow answer</a>).</p><p>This Scala example translates fairly straightforward to Java. Now don&apos;t tell your boss you&apos;re using a different programming language. After all, Clojure is just a Java library that gives you superpowers :-).</p><p>PS: it may be wise to turn this off in production because of the security risk; on the other hand, a Clojure REPL has saved my day more than once in the past!</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/from-leiningen-to-boot.html</id>
    <link href="https://blog.michielborkent.nl/from-leiningen-to-boot.html"/>
    <title>Migrating a Leiningen project to boot</title>
    <updated>2015-06-06T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Edit: this post made it to the front page of Hacker News. Thanks!</p><img src="assets/boot-lein-2015/hacker-news-lein2boot.png"><p>Boot is a new build tool for Clojure. To get acquainted with it, I decided to migrate a fairly non-trivial Leiningen project to Boot.</p><p>You can find the entire project including the Leiningen <code>project.clj</code> file and Boot&apos;s <code>build.boot</code> file <a href="https://github.com/borkdude/lein2boot">here</a>.</p><p>Disclaimer: this is not a comprehensive Boot tutorial. For a detailed introduction to the concepts of Boot I refer to the <a href="http://boot-clj.com/">Boot website</a>.</p><h2 id="requirements">Requirements</h2><p>I wanted my Boot project to have the same features as my Leiningen project:</p><ul><li>Managing dependencies</li><li>Setting source and resource paths</li><li>Building ClojureScript</li><li>Automatic reloading of Clojure and ClojureScript source code during development</li><li>A Clojure and ClojureScript REPL</li><li>Setting the initial namespace for a REPL</li><li>Setting a global var like <code>*print-length*</code></li><li>Packaging the project as a standalone jar that runs in an embedded server</li></ul><h2 id="walkthrough">Walkthrough</h2><p>First let&apos;s walk through the Leiningen <code>project.clj</code> step by step and see how it translated into a <code>build.boot</code> file.</p><h3 id="paths">Paths</h3><p>Here we tell Leiningen where our source files and resources are. Also we declare what directories must be emptied if we want to clean up generated files:</p><pre><code class="language-clojure">:source-paths [&quot;src&quot;]
:resource-paths [&quot;assets&quot; &quot;out&quot;]
:clean-targets ^{:protect false} [:target-path :compile-path &quot;out/public/out&quot;]
</code></pre><p>In the <code>build.boot</code> file this is done by a call to <code>set-env!</code>:</p><pre><code class="language-clojure">(set-env!
  :source-paths #{&quot;src&quot; &quot;src-cljs&quot;}
  :resource-paths #{&quot;assets&quot;}
  ,,,)
</code></pre><p>Boot has the concept of immutable filesets. Each task receives a fileset and produces one.  The last task outputs its fileset to a target directory, which is <code>target</code> by default. Boot will clean stale files from target automatically before it emits a new fileset there. There is never a need to clean something in Boot.</p><h3 id="dependencies">Dependencies</h3><p>Next we describe which dependencies the project has. In Leiningen this is done as follows:</p><pre><code class="language-clojure">:dependencies [[org.clojure/clojure &quot;1.6.0&quot;]
               [org.clojure/clojurescript &quot;0.0-3211&quot;]
               [org.clojure/core.async &quot;0.1.346.0-17112a-alpha&quot;]
               [ring-server &quot;0.4.0&quot;]
               [org.webjars/bootstrap &quot;3.2.0&quot;]
               [cljs-http &quot;0.1.30&quot;]
               [compojure &quot;1.3.4&quot;]
               [liberator &quot;0.13&quot;]
               [fogus/ring-edn &quot;0.2.0&quot;]
               [clj-json &quot;0.5.3&quot;]
               [reagent &quot;0.5.0&quot;]
               [prismatic/schema &quot;0.4.3&quot;]]
</code></pre><p>In Boot this is done similarly, still inside the call to <code>set-env!</code>:</p><pre><code class="language-clojure">(set-env!
    ,,,
    :dependencies &apos;[[org.clojure/clojure &quot;1.6.0&quot;]
                    [org.clojure/clojurescript &quot;0.0-3211&quot;]
                    [org.clojure/core.async &quot;0.1.346.0-17112a-alpha&quot;]
                    [ring-server &quot;0.4.0&quot;]
                    [org.webjars/bootstrap &quot;3.2.0&quot;]
                    [cljs-http &quot;0.1.30&quot;]
                    [compojure &quot;1.3.4&quot;]
                    [liberator &quot;0.13&quot;]
                    [fogus/ring-edn &quot;0.2.0&quot;]
                    [clj-json &quot;0.5.3&quot;]
                    [reagent &quot;0.5.0&quot;]
                    [prismatic/schema &quot;0.4.3&quot;]
                    ,,,
                    ])
</code></pre><h3 id="initial-repl-namespace">Initial REPL namespace</h3><p>The next line we encounter in <code>project.clj</code> is:</p><pre><code class="language-clojure">:repl-options {:init-ns animals.server}
</code></pre><p>This makes the <code>animals.server</code> namespace the starting point for every REPL session. In <code>build.boot</code> it is accomplished like this:</p><pre><code class="language-clojure">(task-options! repl {:init-ns &apos;animals.server})
</code></pre><p>Boot has several tasks built in and <code>repl</code> is one of them. It supports the option <code>init-ns</code>. With <code>task-options!</code> you can set some default options per task that are global to the project. To see all the options that <code>repl</code> provides, you can issue <code>-h</code> from the command line:</p><p><code>$ boot repl -h</code></p><p>or call <code>(doc repl)</code> from a Boot REPL session.</p><h3 id="global-var-setting">Global var setting</h3><p>Next is this line from <code>project.clj</code>:</p><pre><code class="language-clojure">:global-vars {*print-length* 20}
</code></pre><p>This sets the var <code>clojure.core/*print-length*</code> to <code>20</code>. If we print collections we&apos;ll never see more than 20 items:</p><pre><code class="language-clojure">user=&gt; (println (range))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ,,,)
nil
</code></pre><p>In Boot I attempted to do it like this:</p><pre><code class="language-clojure">(alter-var-root (var *print-length*) (fn [v] 20))
</code></pre><p>Unfortunately this caused a <a href="https://github.com/boot-clj/boot/issues/218">bug</a> in Boot&apos;s <code>jar</code> task. Later I <a href="https://github.com/boot-clj/boot/issues/218#issuecomment-109582851">learned</a> that it&apos;s not a good idea at all to do this in Boot, because there can be multiple Clojure runtimes (pods) in one JVM. Since I was going to use this setting only in the REPL, this is a better solution:</p><pre><code class="language-clojure">(task-options!
 repl {:init-ns &apos;animals.server
       :eval &apos;(set! *print-length* 20)})
</code></pre><h3 id="task-dependencies">Task dependencies</h3><p>Leiningen has the concept of <a href="https://github.com/technomancy/Leiningen/blob/master/doc/PLUGINS.md">plugins</a>. Plugins typically perform a task as part of a Leiningen build. Two popular plugins are <a href="https://github.com/emezeske/lein-cljsbuild">lein cljsbuild</a> and <a href="https://github.com/bhauman/lein-figwheel">lein figwheel</a>. <code>lein cljsbuild</code> is an interface to the ClojureScript compiler. <code>lein Figwheel</code> lets you push resources to a browser, typically freshly compiled ClojureScript or CSS. It also gives you a ClojureScript REPL and a web server which allows you to serve some static files or even a Ring handler. In this example I don&apos;t use Figwheel&apos;s web server for running my Ring handler, because I use Ring&apos;s standalone Jetty server that comes with automatic code reloading middleware and allows for an initial function to be executed before the handler is started: features that are lacking from Figwheel as far as I know.</p><p>In Leiningen plugins are included like this:</p><pre><code class="language-clojure">:plugins [[lein-cljsbuild &quot;1.0.5&quot;]
          [lein-figwheel &quot;0.3.1&quot;]]
</code></pre><p>In Boot tasks are included as normal dependencies and scoped with <code>:test</code>:</p><pre><code class="language-clojure">(set-env!
  ,,,
  :dependencies &apos;[[adzerk/boot-cljs &quot;0.0-3269-2&quot; :scope &quot;test&quot;]
                  [adzerk/boot-cljs-repl &quot;0.1.9&quot; :scope &quot;test&quot;]
                  [adzerk/boot-reload &quot;0.2.6&quot; :scope &quot;test&quot;]
                  [pandeiro/boot-http &quot;0.6.3-SNAPSHOT&quot; :scope &quot;test&quot;]])
</code></pre><p>The first dependency is Boot&apos;s interface to the ClojureScript compiler. The latter three dependencies together offer more or less the same as Figwheel: a ClojureScript, live reloading of resources in the browser and a web server to serve static files or a Ring handler.</p><h3 id="building-clojurescript">Building ClojureScript</h3><p>In Leiningen ClojureScript is built using the <code>lein cljsbuild</code> plugin. My configuration for this plugin looks as follows:</p><pre><code class="language-clojure">:cljsbuild {:builds {:dev {:source-paths [&quot;src-cljs&quot; &quot;src-cljs-dev&quot;]
                           :figwheel {:on-jsload &quot;animals.main/fig-reload&quot;}
                           :compiler {:output-to &quot;out/public/main.js&quot;
                                       :output-dir &quot;out/public/out&quot;
                                       :optimizations :none
                                       :asset-path &quot;out&quot;
                                       :main &quot;animals.main&quot;
                                       :source-map true}}
                     :prod {:source-paths [&quot;src-cljs&quot; &quot;src-cljs-prod&quot;]
                              :compiler {:output-to &quot;out/public/main.js&quot;
                                         :optimizations :advanced}}}}
</code></pre><p>In Boot configuring the location of where generated JavaScript will end up is done by placing an <code>.edn</code> file at the corresponding location in the resources tree. In this project I placed it in <code>resources/public</code> and named it <code>main.cljs.edn</code> with the following content:</p><pre><code class="language-clojure">{:require [animals.main]
 :compiler-options {:asset-path &quot;out&quot;}}
</code></pre><p>This gives you the same config as in the Leiningen example with respect to the name of the main JavaScript file, <code>:asset-path</code> and the <code>:main</code> namespace.</p><p>I use different source folders for development and production, so I can have some environment specific configuration. For example, in development I enable console print and define a function for Figwheel that will be executed when new ClojureScript is pushed to the browser:</p><pre><code class="language-clojure">(enable-console-print!)

(defonce init
  (do (println &quot;starting application&quot;) 
      (reagent/render [crud/animals]
                      (js/document.getElementById &quot;app&quot;))))

(defn fig-reload []
  (println &quot;reloading reagent&quot;)
  (reagent/render [crud/animals]
                  (js/document.getElementById &quot;app&quot;)))
</code></pre><p>In my production ClojureScript I set <code>*print-fn*</code> to <code>identity</code>, because else I would get errors when there was still a <code>println</code> around in my code:</p><pre><code class="language-clojure">;; no println output in production code
(set! cljs.core/*print-fn* identity)

(reagent/render [crud/animals]
                (js/document.getElementById &quot;app&quot;))
</code></pre><h3 id="developing">Developing</h3><p>In Leiningen I would start my development like this.</p><p>In one terminal, I would start the web server:</p><pre><code>lein repl
(start-server)
</code></pre><p>In another terminal, I would start Figwheel:</p><pre><code>lein clean &amp;&amp; lein figwheel dev
</code></pre><p>Figwheel invokes the ClojureScript compiler and the ClojureScript compiler outputs JavaScript to the <code>out</code> directory.</p><p>Note that using this setup, I need to run two JVMs.</p><p>In Boot the development flow is one task composed of multiple tasks:</p><pre><code class="language-clojure">(deftask dev []
  (set-env!
   :source-paths #(conj % &quot;src-cljs-dev&quot;))
  (comp
   (serve :handler &apos;animals.api/handler
          :reload true
          :init &apos;animals.api/init)
   (watch)
   (reload :on-jsload &apos;animals.main/fig-reload)
   (cljs-repl)
   (cljs)))
</code></pre><p>Only one JVM needed!</p><p>There is no need to worry about cleaning directies, since each task outputs an immutable fileset that the next task can use. Generated files end up in <code>target</code> by default, which gets cleaned before a new fileset is committed there.</p><p>The <code>serve</code> task will be the first one to be invoked. By default <code>serve</code> runs a Jetty server, but it is possible to select <code>http-kit</code>. It will reload Clojure files automatically, is able to run a Ring handler and also executes an initial function before the handler is started.</p><p>The next task in our Boot pipeline is <code>watch</code>. This task waits for file changes in any of the source or resource paths and then invokes the rest of the pipeline. The rest of the pipeline is also invoked one time for the initial fileset. An example:</p><pre><code class="language-clojure">(deftask watch-example []
  (comp
    (watch)
    (show :fileset true)))
</code></pre><p>In this example <code>show</code> prints out the fileset that it received as a tree. When we invoke it we see the initial fileset tree. When we add a file, the watch task will invoke <code>show</code> again and we would see the new fileset tree with the added file.</p><p>Back to our development pipeline:</p><pre><code class="language-clojure">(deftask dev []
  (set-env!
   :source-paths #(conj % &quot;src-cljs-dev&quot;))
  (comp
   (serve :handler &apos;animals.api/handler
          :reload true
          :init &apos;animals.api/init)
   (watch)
   (reload :on-jsload &apos;animals.main/fig-reload)
   (cljs-repl)
   (cljs)))
</code></pre><p>Whenever a file changes, the <code>reload</code> task is invoked. This will send changed assets to the browser via a websocket connection. The task after that, <code>cljs-repl</code> starts an nrepl server in which it is possible to start a ClojureScript REPL. This task also covers our requirement to have a normal Clojure REPL session with our program. Finally, the <code>cljs</code> task compile ClojureScript to JavaScript. I am not sure if it matters if <code>cljs-repl</code> comes before or after <code>watch</code>, but <code>cljs</code> surely has to come after it, since it has to see new filesets for incremental compilation.</p><h3 id="standalone-jar">Standalone jar</h3><p>The final requirement is producing a standalone jar. In Leiningen this is done with the <code>uberjar</code> task. We need to tell Leiningen where it can find the main namespace that will have the <code>-main</code> function that will be invoked when the jar is run. Also we need to aot that namespace:</p><pre><code class="language-clojure">:aot [animals.uberjar]
:main animals.uberjar
</code></pre><p>Before producing a standalone jar, we must invoke the ClojureScript compiler to produce production worthy JavaScript. For convenience we can make an <code>alias</code> that combines all these steps:</p><pre><code class="language-clojure">:aliases {&quot;build&quot; [&quot;do&quot; &quot;clean&quot; [&quot;cljsbuild&quot; &quot;once&quot; &quot;prod&quot;] &quot;uberjar&quot;]}
</code></pre><p>Note that <code>uberjar</code> will invoke <code>clean</code> also. One problem that arose while writing this blog was that I had the entire <code>out</code> directory in <code>:clean-targets</code>, so when <code>cljsbuild</code> was done, <code>uberjar</code> would remove its output again. You will never have this kind of problem with Boot.</p><p>In Boot our <code>build</code> task looks like this:</p><pre><code class="language-clojure">(deftask build-cljs []
  (set-env!
   :source-paths #(conj % &quot;src-cljs-prod&quot;))
  (cljs :optimizations :advanced))

(deftask build []
  (comp
   (build-cljs)
   (aot :namespace &apos;#{animals.uberjar})
   (pom :project &apos;animals
        :version &quot;1.0.0&quot;)
   (uber)
   (jar :main &apos;animals.uberjar)))
</code></pre><p>First we invoke the sub-task <code>build-cljs</code> which includes sources from <code>src-cljs-prod</code> and produces optimized JavaScript. The next task performs aot on the main namespace. Then a pom file is produced. The <code>uber</code> task adds jar entries from dependencies to the fileset. Finally, the <code>jar</code> task produces a jar file from the fileset with the main namespace set to <code>animals.uberjar</code>. I love how Boot decomposes these tasks, so you can actually see what is going on when you produce a standalone artifact.</p><h2 id="issues">Issues</h2><p>During this blog post I ran into a couple of issues with Boot.</p><p>The first issue had to do with dependency resolution and Clojure versions. This <a href="https://github.com/boot-clj/boot/issues/210">issue</a> has been solved. Thanks Alan Dipert!</p><p>Another issue was that the <code>reload</code> task didn&apos;t have the concept of an <code>asset-path</code>. I needed to work around this by creating an extra route in my handler:</p><pre><code class="language-clojure">(defroutes routes
  ,,,
  (resources &quot;/&quot;)
  (resources &quot;/public&quot;) ;; extra route
  ,,,)
</code></pre><p>This problem will be solved in a future version of <code>reload</code>. See this <a href="https://github.com/adzerk-oss/boot-reload/issues/18">issue</a>.</p><h2 id="conclusion">Conclusion</h2><p>Leiningen is a battle tested tool and probably the safest bet if you&apos;re just starting with Clojure. However, Boot has certainly sparked my interest. It has an elegant design and a more functional feel to it. I&apos;ll certainly use it on a future project.</p><p>Here are my recommendations based on my brief experience with Boot.</p><p>Use Leiningen if you:</p><ul><li>want to get started fast and like to get help from the majority of the Clojure community</li><li>don&apos;t want to take risks in terms of stability</li><li>like configuration and convenience over programmability and composition</li></ul><p>Use Boot if you:</p><ul><li>like programs more than configuration files</li><li>don&apos;t like to think about cleaning directories</li><li>need to run one JVM for the entire development process (in Leiningen I needed two: one for Clojure and one for ClojureScript)</li><li>need to perform builds tasks with mutually exclusive dependencies</li></ul><p>Thanks for reading my blogpost. Feedback is appreciated. Did I misunderstand something about Boot? Please let me know!</p><h2 id="credits">Credits</h2><p>Thanks to <a href="http://tailrecursion.com/~alan/index.cgi/index">Alan Dipert</a>, <a href="http://www.martinklepsch.org/">Martin Klepsch</a>, <a href="http://estsauver.com/">Earl S. Sauver</a> and some other fine folks in the #boot channel on <a href="http://clojurians.net">Slack</a>.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/my-clojurescript-adventure-at-oredev.html</id>
    <link href="https://blog.michielborkent.nl/my-clojurescript-adventure-at-oredev.html"/>
    <title>My ClojureScript adventure at Øredev</title>
    <updated>2014-11-16T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><h2 id="tl;dr">tl;dr</h2><p>November 6th 2014 I was given the chance to speak about ClojureScript and React at the Swedish developer conference <a href="http://oredev.org/2014/speakers/michiel-borkent">Øredev</a>. You will find the videos and slides of my talks below. The talk about ClojureScript and React seems to be more popular and it has better sound quality, so you may want to skip straight to that one.</p><img align="center" src="/assets/oredev-2014/michiel_clojurescript_ftw.jpg"><h2 id="how-i-got-there">How I got there</h2><p>On October 7th I received an e-mail from the organization of Øredev. One of their speakers, <a href="https://twitter.com/annapawlicka">Anna Pawlicka</a>, who was going to speak about ClojureScript had cancelled (for urgent private reasons). She had passed them some names of people they could ask to replace her. Apparently I was on this list and received an e-mail. After some consideration I accepted this invitation. It would be my first appearance on a bigger (&gt; 1000 participants) developer conference. So in the month leading up to this conference I was pretty nervous and excited. Luckily I could practice my preliminary talks at two local meetups and had lots of people providing me with useful feedback.</p><h2 id="the-talks">The talks</h2><p>The conference expected two talks of both 40 minutes. 40 minutes is a short time, so I had to select my slides and the level of detail very carefully.</p><h3 id="clojurescript-for-the-web">ClojureScript for the web</h3><p>My first talk was about ClojureScript for web applications in general. I explained the most important features of Clojure(Script). Unfortunately the sound volume of the video is a bit low.</p><p>The description of the talk for the conference was:</p><p>Over the last few years we have seen the rise of browser applications. Instead of rendering all UI server side, JavaScript driven client applications are now being widely adopted. While JavaScript is a flexible and powerful language, it has its shortcomings. This is where languages that compile to JavaScript step in. ClojureScript is one of them and offers its own powerful features to the front end developer. In this talk you will get an overview of what ClojureScript development looks like and how it may simplify your application.</p><p>Video:</p><iframe src="//player.vimeo.com/video/111214648" width="600" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <p><a href="http://vimeo.com/111214648">CLOJURESCRIPT FOR THE WEB</a> from <a href="http://vimeo.com/user4280938">&Oslash;redev Conference</a> on <a href="https://vimeo.com">Vimeo</a>.</p><p>The slides can be downloaded <a href="http://michielborkent.nl/oredev14/ClojureScript_for_the_web.pdf">here</a>. Related code is <a href="https://github.com/borkdude/oredev2014">here</a>.</p><h3 id="clojurescript-interfaces-to-react">ClojureScript interfaces to React</h3><p>The second talk was about using ClojureScript in combination with the React library. I showed two approaches: Om and Reagent. I have spent more time and detail on Reagent, because this library is easier to explain in a 40 minute talk.</p><p>The description of the talk for the conference:</p><p>React is a JavaScript library for creating declarative UIs. It was created by Facebook to simplify writing applications consisting of many components. React allows you to describe how the UI should look and renders it automatically via one way data binding. It achieves good performance by using a virtual DOM that prevents unnecessary and expensive DOM manipulations. Even better performance can be achieved by leveraging the immutable data structures of ClojureScript. This is an approach taken by Om and Reagent. In this talk you will get an impression of using ClojureScript together with React in practice.</p><p>Video:</p><iframe src="//player.vimeo.com/video/111289716" width="600" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> <p><a href="http://vimeo.com/111289716">CLOJURESCRIPT INTERFACES TO REACT</a> from <a href="http://vimeo.com/user4280938">&Oslash;redev Conference</a> on <a href="https://vimeo.com">Vimeo</a>.</p><p>The slides can be downloaded <a href="http://michielborkent.nl/oredev14/ClojureScript_interfaces_to_React.pdf">here</a>. Related code is <a href="https://github.com/borkdude/oredev2014">here</a>.</p><h2 id="the-conference">The conference</h2><p>Øredev is very well organized. I didn&apos;t have to worry about a thing: plane tickets, hotel, vegan food, quality coffee, ice breaking social events: all arranged by them. If you ever have the chance to speak at Øredev: I can highly recommend it!</p><img align="center" src="/assets/oredev-2014/badge.jpg" width="50%"><img align="center" src="/assets/oredev-2014/vegan-food-oredev.jpg" width="50%"><p>I wasn&apos;t the only person doing Clojure-related talks. <a href="https://twitter.com/rkneufeld">Ryan Neufield</a>, the main author of the Clojure Cookbook and Pedestal contributor was there talking about Datomic and Pedestal. Rob Ashton shared his lessons learned while creating a database with Clojure. Neal Ford talked on functional thinking in Java, Scala and Clojure. Here&apos;s a picture of Ryan presenting about Pedestal:</p><img align="center" src="/assets/oredev-2014/ryan-pedestal.jpg" width="50%"><h2 id="thanks">Thanks</h2><p>During these 40 minute talks I didn&apos;t have the time to thank people who helped me during my month of preparation in one way or another. Here is a list of people and companies I would like to thank for their help or support:</p><ul><li>Anders Janmyr</li><li><a href="http://www.twitter.com/annapawlicka">Anna Pawlicka</a></li><li><a href="http://www.twitter.com/lalage_">Barbara Borkent</a></li><li><a href="http://www.twitter.com/swannodette">David Nolen</a></li><li>Denis Fuenzalida</li><li>Emily Holweck</li><li><a href="http://www.finalist.nl">Finalist</a> (company)</li><li><a href="http://www.jayway.com">Jayway</a> (company)</li><li><a href="http://www.twitter.com/mamersfo">Martin van Amersfoorth</a></li><li>Matthijs Steen</li><li>Ustun Ozgur</li><li><a href="http://www.twitter.com/vijaykiran">Vijay Kiran</a></li></ul><h2 id="resources">Resources</h2><p>Lastly, for what it&apos;s worth, here is a raw list of resources that I found interesting to study while I was preparing my talks. Have fun with those!</p><ul><li><a href="http://shop.oreilly.com/product/0636920025139.do">Clojurescript Up and Running</a></li><li><a href="http://www.infoq.com/news/2014/01/om-react">http://www.infoq.com/news/2014/01/om-react</a></li><li><a href="http://www.lexicallyscoped.com/2013/12/25/slice-of-reactjs-and-cljs.html">http://www.lexicallyscoped.com/2013/12/25/slice-of-reactjs-and-cljs.html</a></li><li><a href="http://adamsolove.com/js/clojure/2014/01/06/om-experience-report.html">http://adamsolove.com/js/clojure/2014/01/06/om-experience-report.html</a></li><li><a href="http://www.joshlehman.me/rewriting-the-react-tutorial-in-om/">http://www.joshlehman.me/rewriting-the-react-tutorial-in-om/</a></li><li><a href="https://t.co/bzQcj0OsPW">https://t.co/bzQcj0OsPW</a> - PureScript</li><li><a href="http://2013.jsconf.eu/speakers/pete-hunt-react-rethinking-best-practices.html">http://2013.jsconf.eu/speakers/pete-hunt-react-rethinking-best-practices.html</a></li><li><a href="https://www.youtube.com/watch?v=SiFwRtCnxv4">https://www.youtube.com/watch?v=SiFwRtCnxv4</a> - Nolen on immutability</li><li><a href="https://www.youtube.com/watch?v=-DX3vJiqxm4">https://www.youtube.com/watch?v=-DX3vJiqxm4</a> - Secrets of the Virtual DOM</li><li><a href="http://www.funnyant.com/reactjs-what-is-it/">http://www.funnyant.com/reactjs-what-is-it/</a></li><li><a href="https://twitter.com/swannodette/status/407750614727524352">https://twitter.com/swannodette/status/407750614727524352</a> - historic tweet of David Nolen porting React code to Cljs</li><li><a href="http://spootnik.org/entries/2014/10/26_from-angularjs-to-om-a-walk-through.html">http://spootnik.org/entries/2014/10/26_from-angularjs-to-om-a-walk-through.html</a> - from Angular to Om</li><li><a href="http://www.infoq.com/presentations/ClojureScript-Javelin">http://www.infoq.com/presentations/ClojureScript-Javelin</a></li><li><a href="https://github.com/enaqx/awesome-react">https://github.com/enaqx/awesome-react</a></li><li><a href="http://stackoverflow.com/questions/21109361/why-is-reacts-concept-of-virtual-dom-said-to-be-more-performant-than-dirty-mode">http://stackoverflow.com/questions/21109361/why-is-reacts-concept-of-virtual-dom-said-to-be-more-performant-than-dirty-mode</a></li><li><a href="https://github.com/swannodette/om/blob/master/src/om/core.cljs#L250">https://github.com/swannodette/om/blob/master/src/om/core.cljs#L250</a></li><li><a href="https://www.youtube.com/watch?v=noiGVQoyYHw#t=72">https://www.youtube.com/watch?v=noiGVQoyYHw#t=72</a> - Clojure: 10 big ideas</li><li><a href="https://keminglabs.com/blog/cljs-app-designs/">https://keminglabs.com/blog/cljs-app-designs/</a> - A sampler of ClojureScript application designs</li><li><a href="http://teropa.info/blog/2013/10/18/single-page-webapps-in-clojurescript-with-pedestal.html">http://teropa.info/blog/2013/10/18/single-page-webapps-in-clojurescript-with-pedestal.html</a> - SPA in Pedestal</li><li><a href="https://groups.google.com/d/topic/pedestal-users/jODwmJUIUcg/discussion">https://groups.google.com/d/topic/pedestal-users/jODwmJUIUcg/discussion</a> - Why Pedestal App is (probably) discontinued</li><li><a href="http://blog.cognitect.com/blog/2014/10/24/analysis-of-the-state-of-clojure-and-clojurescript-survey-2014">http://blog.cognitect.com/blog/2014/10/24/analysis-of-the-state-of-clojure-and-clojurescript-survey-2014</a> - Clojure 2014 survey</li></ul></div>]]></content>
  </entry>
  <entry>
    <id>https://blog.michielborkent.nl/figwheel-keep-om-turning.html</id>
    <link href="https://blog.michielborkent.nl/figwheel-keep-om-turning.html"/>
    <title>Figwheel keep Om turning!</title>
    <updated>2014-09-25T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>How to combine figwheel, Om and Ring in one application</p><h2 id="tl;dr">tl;dr</h2><p>In this article you will find a configuration of figwheel with Om and a Ring server in one application.</p><p>The following issues will be addressed:</p><ul><li>Om root component will be remounted upon code reload</li><li>App-state is lost when code is reloaded</li><li>Code changes in other cljs files do not cause a re-render</li></ul><h2 id="let&apos;s-get-om-with-it">Let&apos;s get Om with it</h2><p>For a few weeks I have been using Clojurescript and <a href="https://github.com/swannodette/om">Om</a> for front end development. Om is a Clojurescript library based on the famous <a href="http://facebook.github.io/react/">React</a>. <a href="https://github.com/bhauman/lein-figwheel">Figwheel</a> is a tool that can speed up Clojurescript and Om development by reloading code in the browser without refreshing an entire page.</p><p>Figwheel comes in the form of a <a href="http://leiningen.org/">leiningen</a> plugin that uses <a href="https://github.com/emezeske/lein-cljsbuild">lein-cljsbuild</a> to compile Clojurescript and pushes the resulting Javascript to the browser, which is then reloaded. Together with React this is a powerful combination. As you change code in your editor and press save, the changes can be instantly reflected in the page you were viewing... if you configure things properly.</p><p>The project I&apos;m currently working on consists of several Clojurescript files. Often an Om component resides in a file of its own. For my workflow it would make sense to be able to edit a component in one file, save the code and see the change in the browser immediately.  So here is what I&apos;ve done.</p><p>Let&apos;s make a project based on the <a href="https://github.com/borkdude/wrom">wrom</a> template.</p><pre><code class="language-bash">$ lein new wrom example
$ find .
.
./.gitignore
./project.clj
./resources
./resources/public
./resources/public/index.html
./resources/public/style.css
./src
./src/example
./src/example/client.cljs
./src/example/server.clj
</code></pre><p>The application comprises a server and client part. All sources files reside in one directory <code>src</code>. Let&apos;s add figwheel to our project. Add <code>[figwheel &quot;0.1.4-SNAPSHOT&quot;]</code> to <code>:dependencies</code> and <code>[lein-figwheel &quot;0.1.4-SNAPSHOT&quot;]</code> to <code>plugins</code>. Your <code>project.clj</code> should now look like this:</p><pre><code class="language-clojure">(defproject example &quot;0.1.0-SNAPSHOT&quot;
  :description &quot;FIXME: write this!&quot;
  :url &quot;http://example.com/FIXME&quot;

  :dependencies [[org.clojure/clojure &quot;1.6.0&quot;]
                 [org.clojure/clojurescript &quot;0.0-2322&quot;]
                 [org.clojure/core.async &quot;0.1.267.0-0d7780-alpha&quot;]
                 [org.webjars/react &quot;0.11.1&quot;]
                 [om &quot;0.7.1&quot;]
                 [cljs-http &quot;0.1.14&quot;]
                 [ring/ring-core &quot;1.3.1&quot;]
                 [ring/ring-jetty-adapter &quot;1.3.1&quot;]
                 [figwheel &quot;0.1.4-SNAPSHOT&quot;]]

  :plugins [[lein-cljsbuild &quot;1.0.4-SNAPSHOT&quot;]
            [lein-figwheel &quot;0.1.4-SNAPSHOT&quot;]
            [lein-ring &quot;0.8.10&quot;]]

  :source-paths [&quot;src&quot;]

  :cljsbuild {:builds [{:id &quot;example&quot;
                        :source-paths [&quot;src&quot;]
                        :compiler
                        {:output-to &quot;resources/public/example.js&quot;
                         :output-dir &quot;resources/public/out&quot;
                         :optimizations :none
                         :source-map true}}]}

  :ring {:handler example.server/app
         :nrepl {:start? true :port 4500}
         :port 8090}

  :global-vars {*print-length* 20})
</code></pre><p>Let&apos;s edit <code>client.cljs</code>. In the namespace declaration under <code>:require</code> add <code>[figwheel.client :as fw]</code>. Now we&apos;ll hook up figwheel so it can send changes in our project to a browser. Because we use Ring with the Jetty adapter as an external server, we have to tell figwheel explicitly where it&apos;s websocket is, since it can&apos;t just connect to the same origin.</p><pre><code class="language-clojure">(fw/watch-and-reload
 :websocket-url   &quot;ws://localhost:3449/figwheel-ws&quot;
 :jsload-callback
 (fn []
   (println &quot;reloaded&quot;)))
</code></pre><p>Start Ring and Figwheel independently, both from inside the <code>example</code> directory. In one terminal type <code>lein figwheel</code> (or optionally supply the name of the build: <code>lein figwheel example</code>). It&apos;s best to wait for the clojurescript compilation to complete before starting Ring.</p><pre><code>$ lein figwheel
Compiling ClojureScript.
Figwheel: Starting server at http://localhost:3449
Figwheel: Serving files from &apos;(dev-resources|resources)/public&apos;
Compiling &quot;resources/public/example.js&quot; from [&quot;src&quot;]...
Successfully compiled &quot;resources/public/example.js&quot; in 20.297 seconds.
notifying browser that file changed:  /example.js
notifying browser that file changed:  /out/goog/deps.js
notifying browser that file changed:  /out/example/client.js
</code></pre><p>In another terminal type <code>lein ring server</code>. If you&apos;re lucky a browser will open automatically to <code>localhost:8090/index.html</code> and you will see the text <code>Hello world from server!</code>. This text really came from the Ring handler in <code>server.clj</code>. If you open a developer console, you will see that figwheel has connected to the browser:</p><p>{% img center /images/2014-09/figwheel/figwheel-connecting.png %}</p><p>Now let&apos;s see if figwheel will pick up a code change in client.cljs. Let&apos;s change the <code>render</code> function to:</p><pre><code class="language-clojure">(render [_]
       (dom/div
        nil
        (dom/h1 nil (:text app))
        (dom/p nil &quot;Hello from Michiel!&quot;)))
</code></pre><p>If everything worked, in the browser you will almost immediately see that your change is reloaded and re-rendered by Om.</p><h2 id="om-root-component-will-be-remounted-upon-code-reload">Om root component will be remounted upon code reload</h2><p>One problem of making changes in the file where the call to <code>om/root</code> resides is that the entire component tree will be unmounted and replaced by a new instance. To verify my claim, let&apos;s add line 6 and 19-21 from the snippet below:</p><pre><code class="language-clojure">(om/root
 (fn [app owner]
   (reify
     om/IWillMount
     (will-mount [_]
       (println &quot;I will mount&quot;)
       (go (let [response (&lt;! (http/get
                               (str &quot;/welcome-message&quot;)))]
             (if (= (:status response)
                    200)
               (om/update! app :text (:body response))
               (om/update! app :text &quot;Server error&quot;)))))
     om/IRender
     (render [_]
       (dom/div
        nil
        (dom/h1 nil (:text app))
        (dom/p nil &quot;Hello from Michiel!&quot;)))
     om/IWillUnmount
     (will-unmount [_]
       (println &quot;I will unmount&quot;))))
 app-state
 {:target (. js/document (getElementById &quot;app&quot;))})
</code></pre><p>Now make a change anywhere in the source code and save the file. In the browser&apos;s console you will see that Om mounted the component. Now change the source again and press save. You&apos;ll see that Om unmounted the component and mounted a new instance of the component. You really have to pay attention to this, because if you created resources or <code>go</code> loops in <code>will-mount</code> and you didn&apos;t clean them up in <code>will-unmount</code>, things can get really messy when you have lots of code reloads. The <code>go</code> loops from unmounted instances will just keep running and your program can get unpredictable. So, the solution to this problem is to keep track of your resources and take the appropriate actions in the <code>will-unmount</code>.</p><h2 id="app-state-is-lost-when-code-is-reloaded">App-state is lost when code is reloaded</h2><p>Let&apos;s change our app state to</p><pre><code class="language-clojure">(def app-state (atom {:text &quot;&quot; :button &quot;unclicked&quot;}))
</code></pre><p>and the render function to</p><pre><code class="language-clojure">(render [_]
       (dom/div
        nil
        (dom/p nil (pr-str app))
        (dom/button #js {:onClick #(om/update! app
                                              :button &quot;clicked&quot;)}
                    &quot;Click to change state&quot;)))
</code></pre><p>In the render function we show a printed version of the cursor. Now let&apos;s click the button. The <code>app-state</code> updated and the component is reflecting this. Now let&apos;s change the code of <code>client.cljs</code> and save. What do we see? Our app-state is back to the initial state. This is because <code>app-state</code> is being redefined by the code reload. To avoid this, change <code>def</code> to <code>defonce</code>:</p><pre><code class="language-clojure">(defonce app-state (atom {:text &quot;&quot; :button &quot;unclicked&quot;}))
</code></pre><p>Now the app-state will survive a code reload. Sometimes it&apos;s that easy to write re-loadable code.</p><h2 id="code-changes-in-other-cljs-files-do-not-cause-a-re-render">Code changes in other cljs files do not cause a re-render</h2><p>Let&apos;s make a second file called <code>child.cljs</code> like this:</p><pre><code class="language-clojure">(ns example.child
  (:require-macros [cljs.core.async.macros :refer (go)])
  (:require [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true]))

(defn child [cursor owner]
  (om/component
   (dom/div nil
            (dom/p nil &quot;I&apos;m a child.&quot;)
            (dom/p nil (str &quot;I have local state: &quot;
                            (pr-str (om/get-state owner))))
            (dom/button #js {:onClick
                             #(om/update-state! owner
                                                :clicks inc)}
                        &quot;Click me to update my local state&quot;))))
</code></pre><p>Let&apos;s <code>require</code> and <code>om/build</code> this child component in our root component, so it will appear on the page. I omitted irrelevant parts.</p><pre><code class="language-clojure">(ns example.client
  ,,,
  (:require [om.core :as om :include-macros true]
            ,,,
            [example.child :refer (child)]))

,,,

(om/root
 (fn [app owner]
   (reify
     ,,,
     om/IRender
     (render [_]
       (om/build child app))
     ,,,  ))
 app-state
 {:target (. js/document (getElementById &quot;app&quot;))})
,,,
</code></pre><p>I&apos;m not entirely sure if figwheel handles changes in namespace declarations well, so just refresh the page. You will see the button from the child component on the screen. Click a few times:</p><p>{% img center /images/2014-09/figwheel/child-component1.png %}</p><p>Now let&apos;s change some code of the child component. For example, change the text in the button to &quot;Click me to update me!&quot;. When saved, you won&apos;t see the change reflected in your browser. figwheel has reloaded child.cljs but the problem is that Om doesn&apos;t &apos;know&apos; about this. Let&apos;s tell Om. Let&apos;s summon the power of <code>core.async</code>.</p><p>Change the <code>:require</code> entry for <code>core.async</code> to <code>[cljs.core.async :refer [&lt;! chan put!]]</code> so we can create channels and put something in them.</p><p>In client.cljs add a channel. Place it below the definition of <code>app-state</code>:</p><pre><code>(defonce re-render-ch (chan))
</code></pre><p>In <code>will-mount</code> we&apos;ll now spawn a <code>go</code> loop that keeps reading from <code>re-render-ch</code>:</p><pre><code class="language-clojure">(will-mount [_]
  (println &quot;I will mount&quot;)
  (go (loop []
    (when (&lt;! re-render-ch)
      (om/refresh! owner)
      (recur)))))
</code></pre><p>All we have to do now is put a (truthy) message into the channel and the root component will re-render itself. This can be done in the callback provided to <code>fw/watch-and-reload</code>:</p><pre><code class="language-clojure">(fw/watch-and-reload
 :websocket-url &quot;ws://localhost:3449/figwheel-ws&quot;
 :jsload-callback
 (fn []
   (println &quot;reloaded&quot;)
   (put! re-render-ch true)))
</code></pre><p>Refresh the page so everything is in place. Now change the text of the button again in child.cljs and you&apos;ll see the component being instantly re-rendered in the browser. Observe however that all local state in the child component is lost. Because the code of the child component changed, Om has to remount the component. Again, be conscious of resources and go loops hat are creating during the mount phase and clean them up if necessary.</p><p>Let&apos;s change to child to show and update the cursor instead of local state.</p><pre><code class="language-clojure">(defn child [cursor owner]
  (om/component
   (dom/div nil
            (dom/p nil &quot;I&apos;m a child.&quot;)
            (dom/p nil (str &quot;My cursor:&quot;
                            (pr-str cursor)))
            (dom/button #js {:onClick
                             #(om/transact!
                               cursor
                               :clicks inc)}
                        &quot;Click me!&quot;))))
</code></pre><p>Click a few times and you&apos;ll see something like this:</p><p>{% img center /images/2014-09/figwheel/child-component2.png %}</p><p>Now change the text of the button in child.cljs again and save. You&apos;ll see that the state of the cursor is preserved, as expected.</p><h2 id="update-october-11th-2014">Update October 11th 2014</h2><p>The use of a channel to refresh a component was a little invasive and to be honest, I didn&apos;t like it much. Arne Brasseur pointed out in the comments that refreshing of Om components can be implemented simpler, because <code>om/root</code> is idempotent. This means it may be called multiple times and all will be well.</p><p>I changed the code in <code>main.cljs</code> according to the suggestion of Arne:</p><pre><code class="language-clojure">(ns example.client
  (:require-macros [cljs.core.async.macros :refer (go)])
  (:require [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true]
            [cljs.core.async :refer [&lt;! chan put!]]
            [cljs-http.client :as http]
            [figwheel.client :as fw]
            [example.child :refer (child)]))

(enable-console-print!)

(defonce app-state (atom {:text &quot;&quot;}))

(defn main []
  (om/root
   (fn [app owner]
     (reify
       om/IRender
       (render [_]
         (dom/div
          nil
          (om/build child app)))
       om/IWillUnmount
       (will-unmount [_]
         (println &quot;I will unmount&quot;))))
   app-state
   {:target (. js/document (getElementById &quot;app&quot;))}))

(fw/watch-and-reload
 :websocket-url &quot;ws://localhost:3449/figwheel-ws&quot;
 :jsload-callback
 (fn []
   (println &quot;reloaded&quot;)
   (main)))

(defonce initial-call-to-main (main))
</code></pre><p>The differences:</p><ul><li>no invasive channel and call to <code>om/refresh!</code></li><li>the call to <code>om/root</code> is now wrapped inside a function <code>main</code></li><li><code>main</code> is called on initial page load and will be called by figwheel upon code reload (no matter which ClojureScript file, which the point of putting the call to <code>main</code> here)</li></ul><p>Arne Brasseur is the author of the excellent <a href="https://github.com/plexus/chestnut">Chestnut</a> template, that embeds Figwheel as one of its dev tools. I suggest you try it out if you haven&apos;t. David Nolen, the author of Om, just published a <a href="https://www.youtube.com/watch?v=gI3fJKmvgq4">demo video</a> of Chestnut.</p><p>The completed (and updated) code of this blog post can be viewed <a href="https://github.com/borkdude/figwheel-keep-om-turning">here</a>.</p><p>If you liked my post or want to suggest an improvement, please leave a comment. Thanks for reading!</p></div>]]></content>
  </entry>
</feed>
