<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alec Larson</title>
    <description>The latest articles on DEV Community by Alec Larson (@aleclarson).</description>
    <link>https://dev.to/aleclarson</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%2F133505%2Ff3a54985-24b3-45f8-9740-337b90cfbfce.jpg</url>
      <title>DEV Community: Alec Larson</title>
      <link>https://dev.to/aleclarson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aleclarson"/>
    <language>en</language>
    <item>
      <title>Postgres TypeScript bindings for "stored procedures"</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Tue, 17 Dec 2024 21:51:26 +0000</pubDate>
      <link>https://dev.to/aleclarson/postgres-typescript-bindings-for-stored-procedures-56m8</link>
      <guid>https://dev.to/aleclarson/postgres-typescript-bindings-for-stored-procedures-56m8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; If you have preconceived notions about making heavy use of “stored procedures” (personally, I just call them “routines” like Postgres does), then you probably won't like what I'm showing you, and I won't try to convince you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm the creator of pg-nano. It's not an ORM, a query builder, or a basic query driver, but it's closest to the last one. The twist is, it's also a migration tool and a code generator. It's not production-ready yet (more on that below).&lt;/p&gt;

&lt;p&gt;The link: &lt;a href="https://github.com/pg-nano/pg-nano/" rel="noopener noreferrer"&gt;https://github.com/pg-nano/pg-nano/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It generates TypeScript bindings for your native Postgres routines (think &lt;code&gt;CREATE FUNCTION&lt;/code&gt; or &lt;code&gt;CREATE PROCEDURE&lt;/code&gt;, excuse the caps). For views (e.g. CREATE VIEW), pg-nano can infer each column's “nullability” via static analysis. I plan to extend that inference to user-defined routines in the near future, but the generated types are already quite good.&lt;/p&gt;

&lt;p&gt;From your TypeScript application server, you call your Postgres routines with 100% type safety. The query driver uses libpq, the official C driver, under the hood. I've implemented a connection pool, auto-reconnect with exponential backoff, and query streaming on top of libpq.&lt;/p&gt;

&lt;p&gt;It scans a directory for &lt;code&gt;.sql&lt;/code&gt; files and instantly updates your local database instance by diffing the current schema with the desired schema. It only drops data if absolutely necessary. Note that I haven't implemented production migrations yet, which will of course err on the safe side.&lt;/p&gt;

&lt;p&gt;I use a combination of static analysis (parsing your SQL) and introspection (querying Postgres system tables) at compile time to both generate the TypeScript bindings and the migration plan.&lt;/p&gt;

&lt;p&gt;The link again: &lt;a href="https://github.com/pg-nano/pg-nano/" rel="noopener noreferrer"&gt;https://github.com/pg-nano/pg-nano/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I posted all this to get your feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could you see yourself using pg-nano? Why or why not?&lt;/li&gt;
&lt;li&gt;Are there specific features you’d like to see, or concerns you have?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I could really use some beta testers, but even your thoughts would help a great deal.&lt;/p&gt;




&lt;p&gt;In order to get pg-nano production ready, I have a few things left to do.&lt;br&gt;
Database seeding&lt;br&gt;
Migrations in production&lt;br&gt;
Transactions&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Nim Notes</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Thu, 09 Sep 2021 23:22:39 +0000</pubDate>
      <link>https://dev.to/aleclarson/nim-notes-5coc</link>
      <guid>https://dev.to/aleclarson/nim-notes-5coc</guid>
      <description>&lt;h3&gt;
  
  
  Stuff to remember when developing in Nim.
&lt;/h3&gt;

&lt;p&gt;&lt;sup&gt;This post will be updated over time.&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;raise&lt;/code&gt; with &lt;code&gt;Defect&lt;/code&gt; cannot be caught when &lt;code&gt;--panics:on&lt;/code&gt; is used&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can cast &lt;code&gt;noSideEffect&lt;/code&gt; pragma:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nim"&gt;&lt;code&gt;  &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="k"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;noSideEffect&lt;/span&gt;&lt;span class="p"&gt;).}:&lt;/span&gt;
    &lt;span class="c"&gt;# code goes here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Almost always prefer &lt;code&gt;{.inline.}&lt;/code&gt; over &lt;code&gt;template&lt;/code&gt;, as it lets the C compiler decide when it's best to inline a proc&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nim</category>
    </item>
    <item>
      <title>Introducing filespy</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Tue, 16 Mar 2021 14:09:07 +0000</pubDate>
      <link>https://dev.to/aleclarson/introducing-filespy-aej</link>
      <guid>https://dev.to/aleclarson/introducing-filespy-aej</guid>
      <description>&lt;p&gt;Today I wrote a file watching library that wraps &lt;code&gt;@parcel/watcher&lt;/code&gt; as an alternative to Chokidar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alloc/filespy/" rel="noopener noreferrer"&gt;https://github.com/alloc/filespy/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Emits files only&lt;/li&gt;
&lt;li&gt;Crawls &lt;strong&gt;asynchronously&lt;/strong&gt; before watching&lt;/li&gt;
&lt;li&gt;Powered by &lt;code&gt;@parcel/watcher&lt;/code&gt; for native performance, event throttling, and &lt;a href="https://facebook.github.io/watchman/" rel="noopener noreferrer"&gt;Watchman&lt;/a&gt; support&lt;/li&gt;
&lt;li&gt;Tolerates permission errors&lt;/li&gt;
&lt;li&gt;Has powerful pattern syntax
&lt;/li&gt;
&lt;li&gt;Handles renamed directories properly&lt;/li&gt;
&lt;li&gt;Exposes the paths being watched&lt;/li&gt;
&lt;li&gt;Exposes the paths that were skipped&lt;/li&gt;
&lt;li&gt;Ensures file paths use forward slashes&lt;/li&gt;
&lt;li&gt;Protects against reentrancy by using &lt;code&gt;setImmediate&lt;/code&gt; before emitting&lt;/li&gt;
&lt;li&gt;Splits up long-running listeners with &lt;code&gt;setImmediate&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Crashes if you don't handle &lt;code&gt;error&lt;/code&gt; events&lt;/li&gt;
&lt;li&gt;Waits for root directory to exist&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&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="nx"&gt;filespy&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;filespy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;filespy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.[jt]sx?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;all&lt;/span&gt;&lt;span class="dl"&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;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// "file" argument is relative to "cwd"&lt;/span&gt;
  &lt;span class="c1"&gt;// "stats" is from lstat call&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// File created.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// File changed.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// File deleted.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Permission error or watcher failed.&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initial crawl completed. Watcher initialized.&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dirs&lt;/span&gt; &lt;span class="c1"&gt;// Set of watched directories.&lt;/span&gt;
&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="c1"&gt;// Sorted list of watched paths (even directories).&lt;/span&gt;
&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;skipped&lt;/span&gt; &lt;span class="c1"&gt;// Sorted list of existing paths that were skipped.&lt;/span&gt;

&lt;span class="c1"&gt;// List all watched paths within a watched directory.&lt;/span&gt;
&lt;span class="c1"&gt;// Returned paths are relative to cwd.&lt;/span&gt;
&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo/bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Stop watching.&lt;/span&gt;
&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cm"&gt;/** Path relative to cwd */&lt;/span&gt;
    &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cm"&gt;/** Equals null for "delete" events */&lt;/span&gt;
    &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stats&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// https://nodejs.org/api/fs.html#fs_class_fs_stats&lt;/span&gt;
    &lt;span class="cm"&gt;/** The root directory */&lt;/span&gt;
    &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** Permission error or watcher failure */&lt;/span&gt;
  &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** Directory was crawled */&lt;/span&gt;
  &lt;span class="nf"&gt;crawl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** Watcher is ready */&lt;/span&gt;
  &lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** File created */&lt;/span&gt;
  &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** File changed */&lt;/span&gt;
  &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;

  &lt;span class="cm"&gt;/** File deleted */&lt;/span&gt;
  &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern syntax
&lt;/h2&gt;

&lt;p&gt;Filespy mixes globbing with regular expressions, a concept borrowed from &lt;a href="https://github.com/aleclarson/recrawl" rel="noopener noreferrer"&gt;Recrawl&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a path has no separators (&lt;code&gt;/&lt;/code&gt;), only the basename is matched.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'a.js' and 'a/b.js'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Recursivity is implicit.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a/b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// identical to '**/a/b'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use a leading separator to match against the root.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'a.js' not 'a/b.js'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use a trailing separator to match all descendants.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'foo/bar' and 'foo/bar/baz' etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Regular expression syntax is supported. (except dot-all)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.jsx?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'a.js' and 'b.jsx'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.(js|ts)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'a.js' and 'b.ts'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Recursive globbing is supported.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo/**/bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// matches 'foo/bar' and 'foo/a/b/c/bar' etc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>node</category>
      <category>typescript</category>
      <category>fs</category>
    </item>
    <item>
      <title>Keep @types/node out of your React project</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Fri, 13 Nov 2020 01:54:47 +0000</pubDate>
      <link>https://dev.to/aleclarson/keep-types-node-out-of-your-react-project-4k3o</link>
      <guid>https://dev.to/aleclarson/keep-types-node-out-of-your-react-project-4k3o</guid>
      <description>&lt;p&gt;If you're trying to prevent &lt;code&gt;@types/node&lt;/code&gt; (or any other global types package) from leaking into your React project, you will probably end up tinkering with your &lt;code&gt;tsconfig.json&lt;/code&gt; and you'll eventually try disabling implicit type imports altogether like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But first, why is &lt;code&gt;@types/node&lt;/code&gt; leaking into your React components in the first place? Chances are that one of your dev dependencies (eg: &lt;code&gt;@testing-library/react-native&lt;/code&gt; if you're writing a React Native app) relies on &lt;code&gt;@types/node&lt;/code&gt; and so it ends up in your &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Normally, that won't be a problem after you put &lt;code&gt;"types": []&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt;, but sometimes that doesn't work, and you commence pulling your hair out.&lt;/p&gt;

&lt;p&gt;But then, in a stroke of genius, you decide to use the &lt;code&gt;--traceResolution&lt;/code&gt; flag when compiling your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn tsc &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--traceResolution&lt;/span&gt; &lt;span class="nt"&gt;--noEmit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You scour its logs for the culprit, using &lt;code&gt;cmd+f&lt;/code&gt; to save yourself some time. A-ha! Turns out a transient dependency (aka an indirect dependency) has a &lt;a href="https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html" rel="noopener noreferrer"&gt;triple-slash directive&lt;/a&gt; in one of its ambient declarations (aka &lt;code&gt;.d.ts&lt;/code&gt; modules). Behold!&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="c1"&gt;/// &amp;lt;reference types="node" /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You screech in terror!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now there's only one thing to do. Open a PR and maintain a fork until the dreaded &lt;code&gt;&amp;lt;reference&amp;gt;&lt;/code&gt; tag is obliterated from this Earth, never to return.&lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>typescript</category>
    </item>
    <item>
      <title>pretty-quick git trick</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Mon, 15 Apr 2019 22:20:15 +0000</pubDate>
      <link>https://dev.to/aleclarson/pretty-quick-git-trick-3jdc</link>
      <guid>https://dev.to/aleclarson/pretty-quick-git-trick-3jdc</guid>
      <description>&lt;p&gt;A cool thing about using &lt;a href="https://github.com/azz/pretty-quick" rel="noopener noreferrer"&gt;&lt;code&gt;pretty-quick&lt;/code&gt;&lt;/a&gt; in a &lt;a href="https://github.com/typicode/husky" rel="noopener noreferrer"&gt;&lt;code&gt;husky&lt;/code&gt;&lt;/a&gt; pre-commit hook is that it catches unresolved merge conflicts when you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git cherry-pick --continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>javascript</category>
      <category>tools</category>
      <category>discuss</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Recommended tool for viewing a video frame-by-frame?</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Wed, 13 Mar 2019 23:58:11 +0000</pubDate>
      <link>https://dev.to/aleclarson/recommended-tool-for-viewing-a-video-frame-by-frame-155</link>
      <guid>https://dev.to/aleclarson/recommended-tool-for-viewing-a-video-frame-by-frame-155</guid>
      <description>&lt;p&gt;I have a screen recording that I want to view frame-by-frame, to help me debug an animation. What tool would you recommend?&lt;/p&gt;

</description>
      <category>tools</category>
      <category>video</category>
      <category>animation</category>
    </item>
    <item>
      <title>Share your favorite mixes/playlists for programming to!</title>
      <dc:creator>Alec Larson</dc:creator>
      <pubDate>Sat, 09 Mar 2019 20:28:28 +0000</pubDate>
      <link>https://dev.to/aleclarson/share-your-favorite-mixesplaylists-for-programming-to-3k67</link>
      <guid>https://dev.to/aleclarson/share-your-favorite-mixesplaylists-for-programming-to-3k67</guid>
      <description>&lt;p&gt;I'll start us off with &lt;a href="https://www.youtube.com/watch?v=ZSk8k6basWw" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=ZSk8k6basWw&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>music</category>
    </item>
  </channel>
</rss>
