<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Imre Toth's Portfolio</title>
  <subtitle>Open Source Projects and Technical Thoughts</subtitle>
  <link href="https://imre.dev/feed.xml" rel="self"/>
  <link href="https://imre.dev"/>
  <updated>2026-03-29T00:00:00Z</updated>
  <id>https://imre.dev/</id>
  <author>
    <name>Imre Toth</name>
  </author>
  
  <entry>
    <title>Building a DSL in JavaScript Without a Build Step</title>
    <link href="https://imre.dev/dsl-framework-intro/"/>
    <updated>2026-03-29T00:00:00Z</updated>
    <id>https://imre.dev/dsl-framework-intro/</id>
    <content type="html">&lt;h1&gt;Building a DSL in JavaScript Without a Build Step&lt;/h1&gt;
&lt;p&gt;Every codebase eventually grows its own informal language. You start with functions like &lt;code&gt;createUser(name, email, role)&lt;/code&gt;, and before long the signature is eight arguments deep and nobody remembers what the fifth one does.&lt;/p&gt;
&lt;p&gt;The standard fixes — options objects, builder classes, method chaining — all work, but they require you to design the API up front. Change your domain, change your schema. That rigidity is the real cost.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/311ecode/dsl-framework&quot;&gt;&lt;strong&gt;dsl-framework&lt;/strong&gt;&lt;/a&gt; takes a different approach: instead of defining an API, you define a &lt;em&gt;language&lt;/em&gt;, and let the execution follow from the syntax.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Core Idea&lt;/h2&gt;
&lt;p&gt;A traditional fluent API executes as it chains:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;new QueryBuilder()
  .select(&#39;name&#39;)    // executes: adds &#39;name&#39; to SELECT
  .from(&#39;users&#39;)     // executes: sets table to &#39;users&#39;
  .where(&#39;active&#39;)   // executes: adds WHERE clause
  .run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;dsl-framework separates &lt;em&gt;recording&lt;/em&gt; from &lt;em&gt;executing&lt;/em&gt;. The chain builds up a data structure — an abstract syntax tree — and nothing happens until you invoke it with &lt;code&gt;()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const factory = dslFramework();

const result = factory()
  .select(&#39;name&#39;)
  .from(&#39;users&#39;)
  .where(&#39;active&#39;)
  ();   // ← this is the trigger
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That closing &lt;code&gt;()&lt;/code&gt; collapses the chain into a plain data structure you can inspect, transform, or pass to a handler.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What the Data Looks Like&lt;/h2&gt;
&lt;p&gt;Under the hood, each dotted segment becomes a chunk in &lt;code&gt;returnArrayChunks&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const result = factory().Hello.world(&#39;!&#39;).data;

console.log(result.returnArrayChunks);
// [[&#39;Hello&#39;], [&#39;world&#39;, &#39;!&#39;]]

console.log(result.returnArray());
// [&#39;Hello&#39;, &#39;world&#39;, &#39;!&#39;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arguments attach to the command that precedes them. The structure is simple enough to traverse by hand, but the framework ships with utilities so you rarely have to.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Responding to Commands&lt;/h2&gt;
&lt;p&gt;The real power shows up when you pass a callback. The callback receives the parsed data and decides what to do with it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const greet = factory((err, data) =&amp;gt; {
  const loud = data.command.has(&#39;loud&#39;);
  const message = data.returnArray().join(&#39; &#39;);
  return loud ? message.toUpperCase() : message;
});

await greet.hello.world();        // &#39;hello world&#39;
await greet.hello.world.loud();   // &#39;HELLO WORLD&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that &lt;code&gt;loud&lt;/code&gt; isn&#39;t a function you defined anywhere. It&#39;s just a word in the chain. The callback checks whether it appeared and branches accordingly. Adding new &amp;quot;keywords&amp;quot; to your language costs zero infrastructure.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Validating Structure&lt;/h2&gt;
&lt;p&gt;The command parser ships with logical operators for checking what&#39;s in a chain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;factory((err, data) =&amp;gt; {
  if (!data.command.hasAnd(&#39;Task&#39;, &#39;Deadline&#39;)) {
    return &#39;incomplete&#39;;
  }

  const taskName = data.arguments(&#39;Task&#39;, &#39;firstArgument&#39;);
  const deadline = data.arguments(&#39;Deadline&#39;, &#39;firstArgument&#39;);

  return `${taskName} due ${deadline}`;
})
  .Task(&#39;Write tests&#39;)
  .Deadline(&#39;2026-04-01&#39;)
  ();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;hasAnd&lt;/code&gt;, &lt;code&gt;hasOr&lt;/code&gt;, &lt;code&gt;hasXor&lt;/code&gt; — these read almost like English, which is the point. The DSL you write ends up looking like the domain it describes.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Lazy Execution as a Feature&lt;/h2&gt;
&lt;p&gt;Because the chain doesn&#39;t execute until &lt;code&gt;()&lt;/code&gt;, you can pass a &lt;em&gt;pending command&lt;/em&gt; between modules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Start a command in one place
const pending = factory().Task(&#39;Code review&#39;);

// Hand it to another module that adds context
function addPriority(cmd) {
  return cmd.priority(&#39;high&#39;);
}

// Execute later
addPriority(pending)();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This turns your DSL into a first-class value. You&#39;re not calling functions — you&#39;re constructing a command object through syntax, and shipping it wherever it needs to go.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Where It Goes From Here&lt;/h2&gt;
&lt;p&gt;dsl-framework is the foundation for two other tools in this portfolio:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://imre.dev/dsl-framework-macros/&quot;&gt;Metaprogramming in JS: Building a Native Macro System&lt;/a&gt;&lt;/strong&gt; — goes deeper on the Proxy engine and the macro philosophy behind it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://imre.dev/demeter-di-introduction/&quot;&gt;The Architecture of Demeter-DI: Fluent Interfaces and the Law of Demeter&lt;/a&gt;&lt;/strong&gt; — shows how the same pattern drives a full dependency injection container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The install is one line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install dsl-framework
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/311ecode/dsl-framework&quot;&gt;View on GitHub&lt;/a&gt; · &lt;a href=&quot;https://www.npmjs.com/package/dsl-framework&quot;&gt;View on NPM&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Your Bash Toolset is Software Now</title>
    <link href="https://imre.dev/packagesh-your-bash-toolset-is-software-now/"/>
    <updated>2026-03-22T00:00:00Z</updated>
    <id>https://imre.dev/packagesh-your-bash-toolset-is-software-now/</id>
    <content type="html">&lt;h1&gt;Your Bash Toolset is Software Now&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -sL https://github.com/tothimre/packagesh/releases/latest/download/packagesh_loader.run)
source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s the install. No sudo. No package manager. No runtime. After that, &lt;code&gt;packagesh&lt;/code&gt; is a function in your shell — ready to bundle and publish your own Bash tools the same way.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Problem it Solves&lt;/h2&gt;
&lt;p&gt;Bash functions loaded into the global namespace are the fastest CLI you can have. No PATH lookup. No subprocess spawn. No runtime to boot. You call &lt;code&gt;my_tool&lt;/code&gt; and it runs — because it &lt;em&gt;is&lt;/em&gt; your shell.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;source ~/.bashrc
my_tool --do-the-thing   # instant. it&#39;s a function.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But sharing those functions has always been awkward. Copy-paste into &lt;code&gt;~/.bashrc&lt;/code&gt; and it rots. &lt;code&gt;git clone&lt;/code&gt; a dotfiles repo and you&#39;re managing a repo per machine. None of these fit the shape of &lt;em&gt;&amp;quot;I have 30 bash functions I want everywhere, always current, zero ceremony.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;packagesh fits that shape.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What it Does&lt;/h2&gt;
&lt;p&gt;Point it at a directory, tell it which functions are public:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;packagesh --project=/path/to/my-tool &#92;
    --helpable-functions=&amp;quot;my_tool&amp;quot; &#92;
    --public-functions=&amp;quot;my_tool,my_tool_helper&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It runs the full pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. Bundle       — collects your .sh files into one loader
2. Inject help  — bakes -h documentation into the bundle
3. Snapshot     — saves a .readable pre-mangle copy for debugging
4. Mangle       — renames private functions with random suffixes
5. Wrap         — generates a self-extracting .run installer
6. Smoke test   — runs your main command to verify the bundle works
7. Publish      — uploads to GitHub Releases (skips if unchanged or --no-push)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output lands in &lt;code&gt;dist/&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dist/
├── my_tool_loader          # mangled production bundle
├── my_tool_loader.readable # pre-mangle, for debugging
└── my_tool_loader.run      # self-extracting installer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your users install it the same way you installed packagesh:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bash &amp;lt;(curl -sL https://github.com/you/my-tool/releases/latest/download/my_tool_loader.run)
source ~/.bashrc
my_tool   # it&#39;s there
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Namespace Safety&lt;/h2&gt;
&lt;p&gt;Sourcing multiple Bash scripts into the same shell session causes collisions. A &lt;code&gt;_helper&lt;/code&gt; in one tool stomps the &lt;code&gt;_helper&lt;/code&gt; in another.&lt;/p&gt;
&lt;p&gt;packagesh mangles every private function with a random per-bundle suffix at build time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# source
_private_helper() { ... }

# after mangling
_private_helper_a3f9c2e1b8d47f05() { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Public functions stay clean. Everything internal is isolated. Source ten bundles into the same session, nothing collides. The &lt;code&gt;.readable&lt;/code&gt; snapshot keeps it debuggable when you need to look inside.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Idempotent Publish&lt;/h2&gt;
&lt;p&gt;The publish step normalizes the bundle before hashing — stripping the random suffixes mangling introduces — then compares against the last published hash.&lt;/p&gt;
&lt;p&gt;Run it a hundred times. It only cuts a release when something actually changed. Safe to wire into CI on every merge:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# in your github actions workflow
- run: publish_my_tool
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No noise. No 400 identical releases.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;For the Monorepo&lt;/h2&gt;
&lt;p&gt;packagesh works equally well in a large org with a monorepo full of Bash utilities. Build multiple projects in one shot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;packagesh --project=/tools/linter;/tools/formatter;/tools/deployer &#92;
    --helpable-functions=&amp;quot;main_cmd&amp;quot; &#92;
    --public-functions=&amp;quot;main_cmd&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All bundles land in &lt;code&gt;dist/&lt;/code&gt; inside the first path. The platform team publishes a blessed toolset. Engineers run the &lt;code&gt;.run&lt;/code&gt; installer once, source their bashrc, and the org&#39;s standard CLI is just there — on laptops, in CI containers, in onboarding scripts.&lt;/p&gt;
&lt;p&gt;No wiki page saying &lt;em&gt;&amp;quot;copy this script to &lt;code&gt;/usr/local/bin&lt;/code&gt;.&amp;quot;&lt;/em&gt; No Ansible playbook to maintain. Just a &lt;code&gt;.run&lt;/code&gt; file and a bashrc hook.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Meta Part&lt;/h2&gt;
&lt;p&gt;packagesh is distributed using packagesh. The installer you ran at the top of this article was built and published by the tool itself.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;gst&lt;/p&gt;
&lt;h2&gt;What&#39;s Next&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Part 2&lt;/strong&gt; covers the development loop — the transparency map that lets you iterate on live functions without rebuilding the bundle, and &lt;code&gt;packagesh_shell&lt;/code&gt; for interactive testing inside a loaded session.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Part 3&lt;/strong&gt; covers vendoring: how shared utilities get bundled into your tool without becoming a dependency you manage.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/311ecode/packagesh&quot;&gt;View on GitHub: 311ecode/packagesh&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Architecture of Demeter-DI: Fluent Interfaces and the Law of Demeter</title>
    <link href="https://imre.dev/demeter-di-introduction/"/>
    <updated>2026-02-16T00:00:00Z</updated>
    <id>https://imre.dev/demeter-di-introduction/</id>
    <content type="html">&lt;p&gt;The core philosophy of &lt;strong&gt;Demeter-DI&lt;/strong&gt; is rooted in two distinct technical goals: adhering to the &lt;strong&gt;Law of Demeter (LoD)&lt;/strong&gt; and providing a fluent, domain-specific language (DSL) for dependency management using the &lt;strong&gt;dsl-framework&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Why the Shift?&lt;/h3&gt;
&lt;p&gt;In our early technical explorations, we encountered significant bottlenecks when dealing with project scale. The shift to a pure Node.js architecture allowed us to implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous FS traversal:&lt;/strong&gt; For non-blocking dependency resolution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regex Buffering:&lt;/strong&gt; To handle replacements and resolutions in memory before I/O.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atomic Operations:&lt;/strong&gt; Ensuring that container builds don&#39;t leave the application in a partial state.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The DSL Framework: The Engine Room&lt;/h3&gt;
&lt;p&gt;The real power behind Demeter-DI isn&#39;t just the injection; it&#39;s the &lt;strong&gt;dsl-framework&lt;/strong&gt;. This allows developers to chain methods like &lt;code&gt;.define()&lt;/code&gt;, &lt;code&gt;.compose()&lt;/code&gt;, and &lt;code&gt;.create()&lt;/code&gt; into a readable, expressive narrative.&lt;/p&gt;
&lt;p&gt;By using Proxy objects, we&#39;ve removed the need to manually invoke service functions with parentheses when accessing them from the container.&lt;/p&gt;
&lt;h3&gt;Core Implementation Patterns&lt;/h3&gt;
&lt;h4&gt;1. Define: Constants and Parameters&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;define&lt;/code&gt; method is procedural and functional. It isolates constants from logic, promoting readability.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const container = containerFactoryFactory
    .define(&#39;PI&#39;, 3.14)
    .define(&#39;API_URL&#39;, &#39;[https://api.example.com](https://api.example.com)&#39;)();

&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. Compose: Lazy Singletons&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;compose&lt;/code&gt; creates a small DSL within your container. It utilizes &lt;strong&gt;Lazy Initialization&lt;/strong&gt;—the service is executed only once, the first time it is accessed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// The service is evaluated only when container.myService is called the first time.
containerFactoryFactory.compose(&#39;myService&#39;, (dep1, dep2) =&amp;gt; dep1 + dep2, [&#39;dep1&#39;, &#39;dep2&#39;]);

&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. Create: The Factory Pattern&lt;/h4&gt;
&lt;p&gt;Unlike &lt;code&gt;compose&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt; evaluates every time it is called. This is essential for resource-heavy operations or scenarios where a fresh instance is required (e.g., test fixtures).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Useful for overriding complex services in test environments
containerFactoryFactory.create(&#39;complexService&#39;, () =&amp;gt; [&#39;fixture&#39;, &#39;data&#39;]);

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Architectural Benefits: The Law of Demeter&lt;/h3&gt;
&lt;p&gt;Demeter-DI enforces the principle that an object should only interact with its immediate neighbors. By managing dependencies through a container, you decouple the &amp;quot;how&amp;quot; of service creation from the &amp;quot;what&amp;quot; of service usage.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Loose Coupling:&lt;/strong&gt; Services don&#39;t need to know how to instantiate their dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testability:&lt;/strong&gt; Redefining a service with &lt;code&gt;.create()&lt;/code&gt; allows for instant mocking without touching the business logic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atomic Consistency:&lt;/strong&gt; The closing function call &lt;code&gt;()&lt;/code&gt; triggers the final container build, ensuring all links are resolved.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By unifying the fluent interface of the &lt;a href=&quot;https://imre.dev/dsl-framework-intro/&quot;&gt;Building a DSL in JavaScript Without a Build Step&lt;/a&gt; with a strict DI container, we&#39;ve built a tool that values developer ergonomics as much as architectural purity. It is built for a JS/TS world where clarity and performance must coexist.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Metaprogramming in JS: Building a Native Macro System</title>
    <link href="https://imre.dev/dsl-framework-macros/"/>
    <updated>2026-02-16T00:00:00Z</updated>
    <id>https://imre.dev/dsl-framework-macros/</id>
    <content type="html">&lt;p&gt;Inspired by Paul Graham&#39;s &lt;a href=&quot;https://paulgraham.com/avg.html&quot;&gt;“Beating the Averages”&lt;/a&gt; and the expressive power of Lisp macros, the &lt;a href=&quot;https://github.com/311ecode/dsl-framework&quot;&gt;&lt;strong&gt;dsl-framework&lt;/strong&gt;&lt;/a&gt; was born from a desire to treat JavaScript code as a malleable data structure without relying on string manipulation or complex build-time annotations.&lt;/p&gt;
&lt;h3&gt;The &amp;quot;Git Macro&amp;quot; Philosophy&lt;/h3&gt;
&lt;p&gt;In Lisp, macros allow you to transform code before it executes. In JavaScript, we don&#39;t have a native macro system, but we do have &lt;strong&gt;Proxies&lt;/strong&gt;. &lt;code&gt;dsl-framework&lt;/code&gt; utilizes the &lt;code&gt;Proxy&lt;/code&gt; object to intercept property access and function calls, effectively building an Abstract Syntax Tree (AST) in real-time as you type.&lt;/p&gt;
&lt;h3&gt;How it Works: The Proxy Engine&lt;/h3&gt;
&lt;p&gt;At the heart of the framework lies the &lt;code&gt;caller&lt;/code&gt; Proxy (found in &lt;code&gt;src/core/index.js&lt;/code&gt;). Every time you &amp;quot;dot&amp;quot; into a new command or &amp;quot;invoke&amp;quot; a function in the chain, the framework doesn&#39;t execute logic—it records intent.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const caller = new Proxy(callerRaw, {
  get (obj, prop) {
    // Intercepts .commandName
    state.setCommandName(prop);
    return caller; // Returns itself to allow infinite chaining
  },
  apply (target, thisArg, argumentsList) {
    // Intercepts (&#39;arguments&#39;)
    return target(...argumentsList);
  }
});

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Execution Trigger: The Closing &lt;code&gt;()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Unlike traditional fluent interfaces (like jQuery), where each method immediately returns a modified version of the original object or triggers an action, &lt;code&gt;dsl-framework&lt;/code&gt; treats the entire chain as a &lt;strong&gt;Sequence&lt;/strong&gt;. It silently builds up state until you tell it to stop.&lt;/p&gt;
&lt;p&gt;How do you tell it you&#39;re finished? By invoking the chain with an empty function call: &lt;code&gt;()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;First-Class Sequences: The &lt;code&gt;pendingCommand&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;One of the most powerful features of this architecture is that the chain remains a live, transferable object until that final invocation. We call this a &lt;code&gt;pendingCommand&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because the Proxy keeps returning itself, you can pass a partial command across different modules, layers, or functions. This allows for incredibly terse code where different parts of your application &amp;quot;fill in&amp;quot; the data before the final execution.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// 1. Start a command in one part of your app
const pendingCommand = dsl().Task.create(&#39;Code review&#39;);

// 2. Pass it around! You can add more context later
function addMetadata(cmd) {
  return cmd.priority(&#39;high&#39;).tag(&#39;urgent&#39;);
}

const enrichedCommand = addMetadata(pendingCommand);

// 3. The closing () finally triggers the execution
const result = enrichedCommand(); 

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &amp;quot;lazy execution&amp;quot; turns your DSL into a first-class citizen. You aren&#39;t just calling functions; you are constructing a command object through syntax.&lt;/p&gt;
&lt;h3&gt;The Evolution of a Command&lt;/h3&gt;
&lt;p&gt;Consider the sequence: &lt;code&gt;.Task.create(&#39;Code review&#39;, { due: &#39;2023-10-05&#39; })()&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.Task&lt;/code&gt;&lt;/strong&gt;: The Proxy&#39;s &lt;code&gt;get&lt;/code&gt; trap is triggered. It stores &amp;quot;Task&amp;quot; as the current command name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.create&lt;/code&gt;&lt;/strong&gt;: The previous command (&amp;quot;Task&amp;quot;) is pushed into storage, and &amp;quot;create&amp;quot; becomes the new active command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;(&#39;Code review&#39;, ...)&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;apply&lt;/code&gt; trap is triggered. It takes the arguments and attaches them to the &amp;quot;create&amp;quot; command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;()&lt;/code&gt;&lt;/strong&gt;: The empty invocation triggers the end of the sequence, packaging everything into a readable data structure.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Parser: Code as Data&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;command-parser&lt;/code&gt; (in &lt;code&gt;src/core/command-parser/index.js&lt;/code&gt;) provides the framework&#39;s &amp;quot;Macro&amp;quot; capabilities. Once the chain is executed, it allows you to query the structure of the sequence using logical operators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.hasAnd(&#39;Task&#39;, &#39;Deadline&#39;)&lt;/code&gt;&lt;/strong&gt;: Ensures the sequence contains both required elements before proceeding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.arguments(&#39;Task&#39;, &#39;firstArgument&#39;)&lt;/code&gt;&lt;/strong&gt;: Extracts specific data points without manual array indexing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;A Different Kind of Flexibility&lt;/h3&gt;
&lt;p&gt;Traditional JavaScript APIs often require specific parameters in a strict order. If you need to add a parameter, you change the function signature. If you need to change the order, you refactor every call site.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;dsl-framework&lt;/code&gt;, you are building a &lt;strong&gt;Domain Specific Language&lt;/strong&gt;. The logic is entirely decoupled from the syntax. You can evolve your software naturally, adding new &amp;quot;keywords&amp;quot; to your DSL without breaking existing integrations. It provides a way to treat your code as pure data, allowing you to design APIs that adapt to your domain, rather than forcing your domain to adapt to rigid functions.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Naming and renaming things...</title>
    <link href="https://imre.dev/naming-and-renaming/"/>
    <updated>2026-02-07T00:00:00Z</updated>
    <id>https://imre.dev/naming-and-renaming/</id>
    <content type="html">&lt;h1&gt;Naming and renaming things...&lt;/h1&gt;
&lt;p&gt;Naming things is easily one of the most frustrating parts of development. I’m convinced that half of &amp;quot;clarity&amp;quot; in a project is just giving parts the right labels.&lt;/p&gt;
&lt;p&gt;However, as codebases grow—especially now that we can generate blocks of code so quickly—things get messy fast. A standard &amp;quot;Search and Replace All&amp;quot; is too much of a sledgehammer. I wanted something more like a scalpel. Asking an LLM to rename a whole project is hit-or-miss and usually misses the architectural nuances you actually care about. I built this tool to handle the heavy lifting while keeping the codebase intact.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/311ecode/deepShift&quot;&gt;View on GitHub: 311ecode/deepShift&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;DeepShift: Precise project refactoring&lt;/h2&gt;
&lt;p&gt;DeepShift is a collection of utilities for project-wide renaming. It treats a &amp;quot;name&amp;quot; as an identity that exists across your folders, filenames, and the code itself.&lt;/p&gt;
&lt;h3&gt;Context-Aware Changes&lt;/h3&gt;
&lt;p&gt;This tool is for those moments when a name is baked into everything. If you have a directory called &lt;code&gt;iDoNotKnow&lt;/code&gt;, a file inside it called &lt;code&gt;iDoNotKnow.ts&lt;/code&gt;, and a variable inside that called &lt;code&gt;iDoNotKnow&lt;/code&gt;, DeepShift handles it all at once:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structural moves:&lt;/strong&gt; It can shift paths deeply (like moving &lt;code&gt;old/&lt;/code&gt; into &lt;code&gt;very/deep/new/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Atomic updates:&lt;/strong&gt; It renames the directory, then the files, then every variable and import reference in one go.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Syncing:&lt;/strong&gt; It keeps the folder structure and internal logic aligned, even if you flatten or extend paths.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Tools&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;deepShift&lt;/strong&gt;
The core engine. It handles global string replacements, path moves, and renames files or directories if you target them specifically. Use this for variable renames, fixing typos, or moving specific paths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;codeShift&lt;/strong&gt;
This looks for filenames that match a pattern, renames them, and then fixes every import and reference across the project. Good for renaming components (e.g., changing &lt;code&gt;User.ts&lt;/code&gt; to &lt;code&gt;Account.ts&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;dirShift&lt;/strong&gt;
Specifically for directories. It renames folder structures and then runs a cleanup to fix any broken relative imports caused by the move. Useful for restructuring architectural layers, like moving &lt;code&gt;utils/&lt;/code&gt; to &lt;code&gt;helpers/&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Comparison&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Goal&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Tool&lt;/th&gt;
&lt;th style=&quot;text-align:left&quot;&gt;Logic&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Rename &lt;code&gt;userId&lt;/code&gt; to &lt;code&gt;accId&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;deepShift&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Content only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Rename &lt;code&gt;src/auth/&lt;/code&gt; to &lt;code&gt;src/identity/&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;dirShift&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Directory move + ref fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Swap &lt;code&gt;utils/&lt;/code&gt; for &lt;code&gt;helpers/&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;dirShift&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Recursive folder patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align:left&quot;&gt;Rename &lt;code&gt;User.ts&lt;/code&gt; to &lt;code&gt;Account.ts&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;codeShift&lt;/td&gt;
&lt;td style=&quot;text-align:left&quot;&gt;File match + ref fix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h3&gt;Evolution and Performance&lt;/h3&gt;
&lt;p&gt;The first version of DeepShift was written in Bash. It was simple and had zero dependencies, but it eventually hit a wall. On projects larger than 50KB, global replacements started taking upwards of ten seconds.&lt;/p&gt;
&lt;p&gt;I decided to rewrite it in Node.js. Since I already had a solid Bash-level test suite, porting the logic was straightforward. I kept the integration tests but gained a significant speed boost. Now, even heavy refactors happen almost instantly.&lt;/p&gt;
&lt;h3&gt;Engineering Standards&lt;/h3&gt;
&lt;p&gt;I focused on three things: &lt;strong&gt;Precision, Automation, and Safety.&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Git Integration:&lt;/strong&gt; It checks &lt;code&gt;.gitignore&lt;/code&gt; and runs safety checks before touching your files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loop Prevention:&lt;/strong&gt; It won&#39;t get stuck in an infinite loop trying to rename &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;ab&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-Platform:&lt;/strong&gt; The logic works across both GNU &lt;code&gt;sed&lt;/code&gt; (Linux) and BSD &lt;code&gt;sed&lt;/code&gt; (macOS).&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
</feed>
