<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gabriel Vaquer</title>
    <description>The latest articles on Forem by Gabriel Vaquer (@brielov).</description>
    <link>https://forem.com/brielov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F511844%2Fdbfd9191-2f12-4868-ae7b-aebd2ac46b38.JPG</url>
      <title>Forem: Gabriel Vaquer</title>
      <link>https://forem.com/brielov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brielov"/>
    <language>en</language>
    <item>
      <title>I Needed Date Math in Formulas, So I Built a Compiler (and Learned a Lot)</title>
      <dc:creator>Gabriel Vaquer</dc:creator>
      <pubDate>Wed, 19 Nov 2025 12:04:09 +0000</pubDate>
      <link>https://forem.com/brielov/i-needed-date-math-in-formulas-so-i-built-a-compiler-and-learned-a-lot-104m</link>
      <guid>https://forem.com/brielov/i-needed-date-math-in-formulas-so-i-built-a-compiler-and-learned-a-lot-104m</guid>
      <description>&lt;p&gt;I recently shipped a small expression language called &lt;strong&gt;littlewing&lt;/strong&gt;, written in TypeScript, now in production at my company. It parses and evaluates formulas like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;basePrice * (1 - discount) + seasonalBonus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Marketing stores these formulas in the database, and they get evaluated at runtime.&lt;/p&gt;

&lt;p&gt;Nothing unusual so far – lots of companies do the same. But marketing now wants something bigger:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“We want a &lt;strong&gt;visual formula builder&lt;/strong&gt; where we can create and update our pricing logic ourselves… without developers.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cue dramatic music.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Didn’t Just Use an Existing Library
&lt;/h2&gt;

&lt;p&gt;We were already using &lt;code&gt;expr-eval&lt;/code&gt;. Great little library, but two big blockers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It has no concept of &lt;strong&gt;dates&lt;/strong&gt;, but marketing needed formulas like:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;paymentDate &amp;lt; NOW() + FROM_DAYS(7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;It doesn’t expose the &lt;strong&gt;AST&lt;/strong&gt;, so building a visual editor on top of it would be painful.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And since &lt;code&gt;expr-eval&lt;/code&gt; hasn’t been updated since 2019, I decided:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If we’re going to build a drag-and-drop formula editor, we should own the language behind it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Context: I Am Not a Compiler Engineer
&lt;/h2&gt;

&lt;p&gt;I’m a self-taught developer.&lt;/p&gt;

&lt;p&gt;No CS degree. Didn’t finish high school. I’ve been writing web apps for 13 years, but compilers were always… mysterious. Something Real Computer Scientists™ did in university.&lt;/p&gt;

&lt;p&gt;And normally, I never would have attempted building one from scratch.&lt;/p&gt;

&lt;p&gt;But I had something new this time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a clear spec&lt;/li&gt;
&lt;li&gt;a real business need&lt;/li&gt;
&lt;li&gt;and a strict deadline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I tried an experiment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let’s build a production-ready parser + interpreter with AI pair programming.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Split: What I Did vs What AI Did
&lt;/h2&gt;

&lt;p&gt;A lot of people are afraid of others “reading their code and thinking they cheated”. I’ll just be upfront:&lt;/p&gt;

&lt;p&gt;This project was absolutely accelerated by AI.&lt;/p&gt;

&lt;p&gt;But it wasn’t “AI built everything while I drank mate.”&lt;/p&gt;

&lt;p&gt;Here’s roughly how the work was divided:&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Was Good At:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;generating a working lexer and parser quickly&lt;/li&gt;
&lt;li&gt;filling in tedious boilerplate&lt;/li&gt;
&lt;li&gt;writing test cases&lt;/li&gt;
&lt;li&gt;explaining tricky concepts (like Pratt parsing) clearly&lt;/li&gt;
&lt;li&gt;reminding me of edge cases I might forget&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  I Had To:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;design the language&lt;/li&gt;
&lt;li&gt;decide how ASTs should look&lt;/li&gt;
&lt;li&gt;make performance tradeoffs&lt;/li&gt;
&lt;li&gt;profile and optimize hot paths&lt;/li&gt;
&lt;li&gt;simplify things for future UI tooling&lt;/li&gt;
&lt;li&gt;rewrite and refactor a lot of internals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn’t want a compiler for the sake of writing a compiler. I wanted a &lt;strong&gt;foundation for a no-code UI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That shaped every decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Design (This Part Was Definitely Me)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Only one data type: &lt;code&gt;number&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;No strings. No booleans. No types of types.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because for pricing logic, numbers were enough. And it dramatically simplifies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the runtime&lt;/li&gt;
&lt;li&gt;the AST&lt;/li&gt;
&lt;li&gt;the editor UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Dates are numbers
&lt;/h3&gt;

&lt;p&gt;A JavaScript &lt;code&gt;Date&lt;/code&gt; is just a number (milliseconds since epoch), so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deadline = NOW() + FROM_DAYS(7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;works exactly like normal addition. No special cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Exposed AST from day one
&lt;/h3&gt;

&lt;p&gt;If the editor is going to &lt;em&gt;manipulate formulas as trees&lt;/em&gt;, the parser had to return an AST that was easy to work with, construct, and serialize.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Override system
&lt;/h3&gt;

&lt;p&gt;Marketing can define default variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;discount = 0.15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then runtime can override them (think user-specific pricing).&lt;/p&gt;

&lt;p&gt;Clean, predictable, obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  Parsing: The Part I Was Afraid Of
&lt;/h2&gt;

&lt;p&gt;I’d tried reading about parsing before and bounced off hard. Every explanation pointed to dense stuff: LR grammars, shift/reduce conflicts, the Dragon Book…&lt;/p&gt;

&lt;p&gt;I asked AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Explain to me how to parse expressions with operator precedence.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It introduced me to &lt;strong&gt;Pratt parsing&lt;/strong&gt;, which blew my mind because it’s so… normal.&lt;/p&gt;

&lt;p&gt;The whole expression parser is essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseExpression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minPrecedence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parsePrefix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getPrecedence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;peekToken&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;minPrecedence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInfix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;30 lines later, I was parsing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nested expressions&lt;/li&gt;
&lt;li&gt;arbitrary operator precedence&lt;/li&gt;
&lt;li&gt;unary operators&lt;/li&gt;
&lt;li&gt;ternaries&lt;/li&gt;
&lt;li&gt;function calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I felt like someone had revealed the magic trick in a card illusion.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tuple-Based AST Instead of Objects
&lt;/h2&gt;

&lt;p&gt;Most tutorial ASTs look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BinaryOp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is fine, but feels heavy in a UI where you’re constantly creating and transforming nodes.&lt;/p&gt;

&lt;p&gt;I replaced them with tuples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nodeType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;leftNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rightNode&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;smaller&lt;/li&gt;
&lt;li&gt;faster&lt;/li&gt;
&lt;li&gt;no property names to repeat&lt;/li&gt;
&lt;li&gt;Pattern matching is simpler:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;NodeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Binary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in React, building trees becomes trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No boilerplate.&lt;/p&gt;

&lt;p&gt;This also led to a decent chunk of performance improvements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Out of the box, littlewing was already faster than &lt;code&gt;expr-eval&lt;/code&gt;, but I profiled and optimized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cursor-based lexer (no substring allocations)&lt;/li&gt;
&lt;li&gt;AST visitors that avoid recursion where possible&lt;/li&gt;
&lt;li&gt;minimized GC churn&lt;/li&gt;
&lt;li&gt;simple code paths over clever abstractions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for situations where formulas run &lt;strong&gt;thousands of times per request&lt;/strong&gt;, I added optional JIT:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AST → JavaScript function string&lt;/li&gt;
&lt;li&gt;compiled with &lt;code&gt;new Function(...)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speedups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;small formulas: ~22×&lt;/li&gt;
&lt;li&gt;heavy formulas: up to 97×&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is initial compilation cost. Use when evaluating repeatedly.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI Didn’t Replace Me — It Let Me Move Faster
&lt;/h2&gt;

&lt;p&gt;Let’s be real:&lt;/p&gt;

&lt;p&gt;If I had built this on my own knowledge alone, learning everything from scratch, it probably would have taken two months.&lt;/p&gt;

&lt;p&gt;AI compressed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;learning curve&lt;/li&gt;
&lt;li&gt;boilerplate&lt;/li&gt;
&lt;li&gt;test scaffolding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;in exchange for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;refactoring&lt;/li&gt;
&lt;li&gt;decision-making&lt;/li&gt;
&lt;li&gt;understanding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you treat AI like StackOverflow with autocomplete, you get garbage.&lt;/p&gt;

&lt;p&gt;If you treat it like an intern who writes code you must review, profile, and rewrite as needed, you can move extremely fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Compilers aren’t magic
&lt;/h3&gt;

&lt;p&gt;They’re mostly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tokenizing strings&lt;/li&gt;
&lt;li&gt;building trees&lt;/li&gt;
&lt;li&gt;walking trees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else is just detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t abstract too early
&lt;/h3&gt;

&lt;p&gt;Simple code profiled well. “Clever” structures often slowed things down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Projects get better when you know where they’re going
&lt;/h3&gt;

&lt;p&gt;The reason littlewing works is because it was designed with the editor in mind before writing any code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using AI doesn’t make you a fraud
&lt;/h3&gt;

&lt;p&gt;Not understanding your own code does.&lt;/p&gt;

&lt;p&gt;I understand every part of littlewing because I had to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;question it&lt;/li&gt;
&lt;li&gt;debug it&lt;/li&gt;
&lt;li&gt;rewrite it&lt;/li&gt;
&lt;li&gt;make it production-worthy&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install littlewing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;littlewing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  late = paymentDate &amp;gt; (NOW() + FROM_DAYS(7))
  late ? 0.05 : 0
`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;defaultContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;paymentDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This wasn’t a project about building a compiler.&lt;/p&gt;

&lt;p&gt;It was about giving non-technical teammates the power to build pricing logic without waiting for a developer ticket to be picked up.&lt;/p&gt;

&lt;p&gt;AI didn’t write littlewing for me.&lt;/p&gt;

&lt;p&gt;AI helped me &lt;strong&gt;ship something I wasn’t sure I was capable of building in the time I had&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And that’s not cheating — that’s using your tools.&lt;/p&gt;

&lt;p&gt;If you want to explore the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/brielov/littlewing" rel="noopener noreferrer"&gt;https://github.com/brielov/littlewing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Playground: &lt;a href="https://littlewing-demo.vercel.app" rel="noopener noreferrer"&gt;https://littlewing-demo.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm: &lt;code&gt;littlewing&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to build a visual formula editor or no-code logic builder, littlewing might save you some groundwork.&lt;/p&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PS: Before anyone asks—yes, the blog post was pair-written with AI too. I’m just staying consistent with the architecture.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>programming</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
