Content AND Presentation

2026-02-09 Node modules working as command-line scripts revisited

Over five years ago I wrote a short post about writing JavaScript scripts which also work as CJS modules. I wrote that I didn’t know how to perform a similar trick with ESM modules, and that it might even be impossible. Well, I was wrong. I found a solution in the book Shell scripting with Node.js by Axel Rauschmayer. He proposes the following solution in the chapter about file system paths and file URLs:

import {fileURLToPath} from 'node:url';

const modulePath = fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) {
    main();
}

(well actually, his solution is a bit more complex, but this is the gist of it – head to his book for more details).

I started using it and it worked great… until it didn’t. It turned out that I was able to trick this code by symlinking to my script and calling the symlink instead. After a bit of poking around, I arrived at this code:

import {fileURLToPath} from 'node:url';
import {realpath} from 'node:fs/promises';

const modulePath = await realpath(fileURLToPath(import.meta.url));
if (await realpath(process.argv[1]) === modulePath) {
        main();
}

Note that it uses top-level await, which Node.js has been supporting for some time now.

From now on, I can both call my ESM script directly (even as a symlink) or import it in other code (for example, unit tests).

That’s it for today, thanks for reading!

CategoryEnglish, CategoryBlog, CategoryJavaScript

Comments on this page

2026-02-02 git-link

I have recently discovered a great little package called git-link. It is a wonderful addition to Emacs’ Git-related capabilities. Its purpose is to create links to various Git repositories (it supports GitHub, BitBucket, GitLab and several others) based on where the point is.

The main entry points are two functions, git-link and git-link-commit. The former creates a link to the file in the current buffer. By default, the link points to the current line; with a prefix argument of - (a single minus), the link contains no line number. This function is really smart – it works in git-timemachine and Magit buffers. (One issue I found is that when a file name was changed and git-timemachine shows a version from before the change, the link contains the “new” name, pointing to a “resource not found” page on BitBucket. Given how file renames are a major pain in Git, this is neither unexpected nor very disappointing.)

The other function, git-link-commit, creates a link to the commit hash at point, and that’s pretty much it. (Well, there is more – for example, git-link-homepage creates a link to the repository’s homepage, which is nice, but probably less useful. There are also a bunch of user options, the most useful being probably git-link-open-in-browser, which opens the link in a browser in addition to showing it in the echo area and putting it on top of the kill ring. Also, the three functions support some more prefix arguments – see their docstrings for details.)

One of the things I found lacking is a git-link-dwim function which would call git-link-commit if the point is on a commit hash and git-link otherwise. Also, recognizing branch names in addition to commit hashes would be pretty nice.

The former is easy to fix:

(defun git-link-dwim ()
  "Call `git-link-commit' if on a hash or `git-link' otherwise."
  (interactive)
  (let ((word (word-at-point t)))
    (call-interactively
     (if (string-match-p "^[a-fA-F0-9]\\{7,40\\}$" (or word ""))
         #'git-link-commit
       #'git-link))))

The latter would require more work. It could use git to list the branches in the repository, then construct a regex matching all of them (Elisp has the wonderful regexp-opt function which does exactly that!) and use looking-at to determine if the point is on a branch name. This would require the point to be on the beginning of the branch name, though. An alternative would be to use (thing-at-point 'filename t) – syntactically, branch names are just filenames (or at least something very similar), so it could work, too. Either way, this is a slightly larger project I am currently not that interested in, so I’ll stay with my git-link-dwim command.

Anyway, big thanks to sshaw for writing this extremely useful package!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryGit

Comments on this page

2026-01-26 A simple but nice PostgreSQL trick with timestamps and nulls

I had a pretty busy week, so today I only have a short PostgreSQL tip I learned recently. Assume that you have a table of users, and it has two columns containing timestamps: created_at and deleted_at. The former is non-nullable, but the latter can contain nulls (for users who were never deleted). Let’s assume that you want to select all users who existed at some point in time, say today at midnight. Until recently, I would do something like this:

select *
from user
where
  created_at <= '2026-01-26'
  and ('2026-01-26' < deleted_at or deleted_at is null)

since, according to normal SQL rules, '2026-01-26' < null yields null and not false.

However, PostgreSQL (unlike the SQL standard) supports a few special values for dates and timestamps, and one of them is infinity. This means that I can combine it with the very useful coalesce function and write this:

select *
from user
where
  created_at <= '2026-01-26'
  and '2026-01-26' < coalesce(deleted_at, 'infinity')

(Of course, you might be tempted to use between, but please don’t do this.)

Of course, I could just use infinity as the default value for the deleted_at column, but this is definitely not a good practice.

That’s it for today, see you next week!

CategoryEnglish, CategoryBlog, CategoryPostgreSQL

Comments on this page

More...

CategoryEnglish, CategoryBlog