<?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: asteinarson</title>
    <description>The latest articles on DEV Community by asteinarson (@asteinarson).</description>
    <link>https://dev.to/asteinarson</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%2F592436%2F41f92f6a-6a5a-46f2-964c-8bc75558e4c4.png</url>
      <title>DEV Community: asteinarson</title>
      <link>https://dev.to/asteinarson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asteinarson"/>
    <language>en</language>
    <item>
      <title>Typescript, NodeJS and ES6/ESM Modules</title>
      <dc:creator>asteinarson</dc:creator>
      <pubDate>Wed, 28 Apr 2021 12:06:01 +0000</pubDate>
      <link>https://dev.to/asteinarson/typescript-nodejs-and-es6-esm-modules-18ea</link>
      <guid>https://dev.to/asteinarson/typescript-nodejs-and-es6-esm-modules-18ea</guid>
      <description>&lt;p&gt;I write this as a sequel to &lt;a href="https://dev.to/asteinarson/typescript-node-js-importing-knex-into-es6-module-1poc"&gt;a previous article&lt;/a&gt; of getting ES6 module imports to work with other NPM modules, from TypeScript. &lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CommonJS&lt;/em&gt; import framework (&lt;strong&gt;require&lt;/strong&gt;) is how node.js was developed and getting everything smooth and working with modern static &lt;strong&gt;import&lt;/strong&gt; is sometimes not so easy, and often not well documented.&lt;/p&gt;

&lt;p&gt;I favor static imports, because the syntax and lack of obvious structure around &lt;strong&gt;require&lt;/strong&gt; is just so full of magic and &lt;em&gt;just works&lt;/em&gt; provided you have spent a number of years working inside that universe. &lt;/p&gt;

&lt;h4&gt;
  
  
  Basic settings
&lt;/h4&gt;

&lt;p&gt;As a starter, whether a Node project defaults to CommonJS modules or ESM is decided by two settings - which must correspond. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;tsconfig.json&lt;/em&gt;:&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;"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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'commonjs'.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;package.json&lt;/em&gt;:&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="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; 
   &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'commonjs'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The problem here - relating to TypeScript
&lt;/h2&gt;

&lt;p&gt;If I have a local TS file (&lt;em&gt;utils.ts&lt;/em&gt;) like this:&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;// Invert keys and values of 1-level deep object&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;invert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BaseTypes&lt;/span&gt;&lt;span class="o"&gt;&amp;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;// ... implementation here ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then want to use it from another file:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;invert&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;./utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then that import will only work (everything else being default settings in TS and Node), as long as I stay with &lt;strong&gt;CommonJS&lt;/strong&gt; modules. &lt;/p&gt;

&lt;p&gt;However, when I change over to ESM modules (see below), the compiled Javascript will no longer work. Because Node.js will be trying to import &lt;strong&gt;exactly&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;invert&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;./utils&lt;/span&gt;&lt;span class="dl"&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 honestly, there is no such file - that is &lt;em&gt;./utils&lt;/em&gt; - without the file extension added to it. &lt;/p&gt;

&lt;p&gt;The explanation is that as TypeScript transpiles this, then for CommonJS, it ends up calling &lt;strong&gt;require()&lt;/strong&gt;, and some logic on top of that. And... &lt;strong&gt;require()&lt;/strong&gt; accepts local javascript file names... without file extension.  &lt;/p&gt;

&lt;p&gt;So if I want my code to work with Node with ESM, I need to change it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;invert&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;./utils.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means, I need to have different code bases, if I target CommonJS or ESM. Not very good. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sort of going forwards...
&lt;/h2&gt;

&lt;p&gt;For a while I accepted the compromise of adding &lt;em&gt;.js&lt;/em&gt; to every local import... But then I wanted to add &lt;strong&gt;Jest&lt;/strong&gt; testing on top of this. Which (together with &lt;em&gt;ts-jest&lt;/em&gt;) does its own building of the test files (behind the scenes, I think using Babel). And &lt;strong&gt;ts-jest&lt;/strong&gt; (whatever my &lt;em&gt;tsconfig/package.json&lt;/em&gt; said) would not accept imports from explicit Javascript files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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;invert&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;./utils.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ts-jest errors here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I needed to fix it differently. (Understanding how/why &lt;em&gt;ts-jest&lt;/em&gt; configures TypeScript/Node differently I did not want to enter). &lt;/p&gt;

&lt;h2&gt;
  
  
  A couple of solutions
&lt;/h2&gt;

&lt;p&gt;One approach is to use the NPM module &lt;strong&gt;esm&lt;/strong&gt; - however I never went in that direction. And I would like to avoid pulling in dependencies to solve this. &lt;/p&gt;

&lt;p&gt;But it turns out there is a Node flag to do solve exactly this problem: &lt;em&gt;--experimental-specifier-resolution=node&lt;/em&gt;. (You find it &lt;a href="https://nodejs.org/api/esm.html"&gt;towards the bottom here&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Wow, all settled ? &lt;/p&gt;

&lt;p&gt;Well, we also need to launch Node in some different ways (from terminal, from a Node &lt;strong&gt;bin&lt;/strong&gt; script, from the VsCode debugger, and the last two presents small challenges). &lt;/p&gt;

&lt;h3&gt;
  
  
  Passing Node flags into the VsCode debugger
&lt;/h3&gt;

&lt;p&gt;It turns out there is a &lt;strong&gt;launch.json&lt;/strong&gt; entry for this:&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="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&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="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pwa-node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"runtimeArgs"&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;"--experimental-specifier-resolution=node"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/src/cmd.ts"&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;(Scroll down to &lt;a href="https://code.visualstudio.com/docs/nodejs/nodejs-debugging"&gt;the bottom of this page&lt;/a&gt; for docs). &lt;/p&gt;

&lt;p&gt;And it actually does the job (I found various other suggestions where to put the Node arg, however I think they targeted an old version of the Javascript debugger). &lt;/p&gt;

&lt;h3&gt;
  
  
  Passing Node flags into an Npm bin command
&lt;/h3&gt;

&lt;p&gt;To run a JS script directly from the terminal (without prefixing it with &lt;em&gt;node&lt;/em&gt;) we can use the &lt;em&gt;bin&lt;/em&gt; section of &lt;em&gt;package.json&lt;/em&gt;:&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="nl"&gt;"bin"&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;"my_cmd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./path/to/my/script"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if the target script is JS/TS (yes, it would be), we need to insert a shebang there, to make it executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env node&lt;/span&gt;
// Rest of JS/TS here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the obstacle here is that we cannot pass options to Node in the shebang. Sorry. We stumble into a &lt;em&gt;bash fact of life&lt;/em&gt; here, and there's no simple way around it, for Node/TS/JS. &lt;/p&gt;

&lt;p&gt;There is a magic hack to this &lt;a href="http://sambal.org/2014/02/passing-options-node-shebang-line/"&gt;over here&lt;/a&gt;. However that fulfills my definition of being so cryptic and non-intuitive (for anyone who did not patiently learn Bash internals) that I cannot recommend it. &lt;/p&gt;

&lt;p&gt;The solution instead is to let the &lt;em&gt;bin&lt;/em&gt; command point to a shell script, and let that one invoke Node with required options: &lt;/p&gt;

&lt;p&gt;For me:&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="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"bin"&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;"knemm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./shell/knemm"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and &lt;em&gt;knemm&lt;/em&gt; then being:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash &lt;/span&gt;
&lt;span class="c"&gt;# Get directory of calling script&lt;/span&gt;
&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$DIR&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'.nvm'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt; 
/usr/bin/env node &lt;span class="nt"&gt;--experimental-specifier-resolution&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node &lt;span class="nv"&gt;$DIR&lt;/span&gt;/../lib/cmd-db.js &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The explanation of the ''DIR'' part is that the current directory (inside my Node project) is lost when the command is invoke as a symlink (see below). I need to point to the JS file in a relative way, so I then need the directory. &lt;a href="https://unix.stackexchange.com/questions/17499/get-path-of-current-script-when-executed-through-a-symlink"&gt;Here's background how to find the script dir&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install this, as a global command, I run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then a global symlink appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;knemm 
... &lt;span class="nb"&gt;command &lt;/span&gt;outputs, all ESM imports are resolved! 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(At some point I needed to manually remove those symlinks generated by &lt;em&gt;npm link&lt;/em&gt; as it wouldn't change those, when I edited &lt;em&gt;package.json&lt;/em&gt;.) &lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion
&lt;/h2&gt;

&lt;p&gt;This has taken some hours (over some weeks) to work out, and I write this to summarize the effort and the learning. Partly so I remember better and then maybe it helps someone. &lt;/p&gt;

&lt;p&gt;I hope all rough parts of using modern JS under Node will be gradually smoothened / paved out. &lt;/p&gt;

&lt;p&gt;Of course, the last part of my solution is Linux/Bash centric. But nowadays, with WSL/WSL2, also anyone on Windows can access a good Linux environment. So I do not see a downside with that (that's how all of this was developed). &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>TypeScript / Node.js: Importing  Knex into an ES6 module</title>
      <dc:creator>asteinarson</dc:creator>
      <pubDate>Mon, 05 Apr 2021 17:02:13 +0000</pubDate>
      <link>https://dev.to/asteinarson/typescript-node-js-importing-knex-into-es6-module-1poc</link>
      <guid>https://dev.to/asteinarson/typescript-node-js-importing-knex-into-es6-module-1poc</guid>
      <description>&lt;p&gt;A while back I wrote a file based import in TypeScript as a Node.js cli app. I used Knex for it, in a rather simple way, starting out from this code: &lt;/p&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;Knex&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;knex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Dict&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;./utils.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;_knex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Knex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;connection&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;_knex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Knex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conn&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Knex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Config&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;It just worked, and I didn't think much into why it did, at the time. &lt;/p&gt;

&lt;p&gt;I should add here that for Node.js projects I've tried to move over to using ES6 modules in my server side code (away from CommonJS). That can cause challenges, at times.&lt;/p&gt;

&lt;p&gt;Yesterday, I wanted to do something similar, so I started a new project. A new &lt;em&gt;package.json&lt;/em&gt;, and new &lt;em&gt;tsconfig.json&lt;/em&gt; and I copied and pasted the code below. &lt;strong&gt;It no longer worked!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After a while, I found out that &lt;strong&gt;knex.js&lt;/strong&gt; was resolved to version &lt;em&gt;0.21.18&lt;/em&gt; in my original project and to &lt;em&gt;0.95.4&lt;/em&gt; in my new project (by means of &lt;em&gt;package.json&lt;/em&gt;). &lt;/p&gt;

&lt;p&gt;Reconfiguring my new project back to CommonJS, I got it working, via this line in &lt;em&gt;tsconfig.json&lt;/em&gt;: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CommonJS"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;was&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'ESNext'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;before&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;...and the corresponding in &lt;em&gt;package.json&lt;/em&gt; (I removed &lt;em&gt;'type': 'module'&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;But I did not want to run my code on the server in CommonJS mode! &lt;/p&gt;

&lt;p&gt;I felt the frustration of simply copying code and settings that has worked well before and sitting there with errors in my terminal... What had changed? &lt;/p&gt;

&lt;h3&gt;
  
  
  Different versions of Knex.js
&lt;/h3&gt;

&lt;p&gt;So there was this significant jump, from v0.21.18 to v0.95.4. The issue must be there, somewhere. &lt;/p&gt;

&lt;p&gt;I opened my two projects next to each other and popped up IDE type hints for the same imported Knex object. This is how it looked in the old project: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mc7evkub29vej916gbw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0mc7evkub29vej916gbw.png" alt="The imported object has three type aliases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this is how it looked (very similar code) in the new project: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvb11dkj0asqh9mfn7yp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvb11dkj0asqh9mfn7yp0.png" alt="Here it has only two!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look closely, you see that the first image contains a type alias for the Knex &lt;strong&gt;interface&lt;/strong&gt; - this is missing in the second picture. In both cases, the code (behind the type hints) is: &lt;/p&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;Knex&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;knex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the first case, the symbol &lt;em&gt;Knex&lt;/em&gt; is apparently &lt;strong&gt;both&lt;/strong&gt; the interface type of the Knex package &lt;strong&gt;and&lt;/strong&gt; the function one can invoke, to connect with the database (the default export in CommonJS). &lt;/p&gt;

&lt;p&gt;In the second case, the type information is not there anymore in the default import - it is just a function (with a signature). (If you look at my initial code segment you see that the exact identifier &lt;strong&gt;Knex&lt;/strong&gt; is used in two quite different ways). &lt;/p&gt;

&lt;p&gt;That was the difference. &lt;/p&gt;

&lt;p&gt;How TypeScript gets away with using the same identifier as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A type (the Knex interface)&lt;/li&gt;
&lt;li&gt;A function to be called &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... I don't understand. But that was what dropped away between the earlier and later version of Knex. &lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 1
&lt;/h3&gt;

&lt;p&gt;So my change then was to name another import (to get both the function and the interface):&lt;/p&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;knex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Knex&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;knex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then my new code actually builds and runs... but only in CommonJS mode. Built as an ES6 module, I get this on launching it: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;node lib/cmd.js
file:///home/arst/src/mifl/lib/cmd.js:4
import &lt;span class="o"&gt;{&lt;/span&gt; knex &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s1"&gt;'knex'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         ^^^^
SyntaxError: Named &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="s1"&gt;'knex'&lt;/span&gt; not found. The requested module &lt;span class="s1"&gt;'knex'&lt;/span&gt; is a CommonJS module...


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At this point... it felt like I had exhausted my ways forward. However, I remembered that the code originally was just one single default import. What about keeping that one, &lt;strong&gt;and&lt;/strong&gt; on top of that, doing a named import of the TS interface?  &lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 2
&lt;/h3&gt;

&lt;p&gt;This then was my new attempt: &lt;/p&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;knex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Knex&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;knex&lt;/span&gt;&lt;span class="dl"&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;knex_conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Knex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;connection&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;knex_conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;knex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;conn&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;knex_conn&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 that turns out to work just fine, both when the code is built and run as CommonJS and as an ES module. &lt;/p&gt;

&lt;p&gt;The key point is that the interface type and the function are two different things. And... to get to the actually exported object (from Knex.js), we have to use a default import from an ES module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;It took me a few hours to experiment my way here, and I did not really find very good TypeScript examples using this combination of both default and named imports - particularly when used from an ES module, neither in Knex documentation nor anywhere else. &lt;/p&gt;

&lt;p&gt;What I did find (in issues for Knex on GitHub) was that people had issues running imports in TypeScript, and that some solved it by converting their code into CommonJS. &lt;/p&gt;

&lt;p&gt;Knowing that things had worked just fine from an ES module for me, a year before, made me want to dig deeper. Thus this post. &lt;/p&gt;

&lt;p&gt;I would guess the same pattern applies to many other primarily &lt;em&gt;CommonJS&lt;/em&gt; based packages that one want to import with TypeScript bindings. &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Exploring Directus 9</title>
      <dc:creator>asteinarson</dc:creator>
      <pubDate>Sat, 03 Apr 2021 13:00:37 +0000</pubDate>
      <link>https://dev.to/asteinarson/exploring-directus-9-c17</link>
      <guid>https://dev.to/asteinarson/exploring-directus-9-c17</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Maybe you have heard of the generic DB platform &lt;a href="https://directus.io/"&gt;Directus&lt;/a&gt;, maybe not. In summary it is an intuitive database management tool that leans a bit towards being an application framework. I.e. the feeling when working in it is more that of designing an application specific solution (with exact use of a relational DB), as opposed to specifying exact details within tables and columns. It is this combination that makes it interesting to me. &lt;/p&gt;

&lt;p&gt;For this article, both are fine. I will give you my description of it, point at the features I think are most innovative and describe various ways I can see myself using it.&lt;/p&gt;

&lt;p&gt;Of course, the strengths and interesting use cases I can see depend largely on my particular background. Our backgrounds are likely a bit different. I will share a bit where I come from in this exploration. Maybe there is enough common ground, and maybe enough difference, for something interesting to be communicated. If so, stay put! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;To clarify:&lt;/em&gt; I am not part of the Directus core team. I am however using it for small scale administrative tasks in my own work, and I see  it as quite likely that I will use it product and in client work. And I do submit patches and suggestions to the project.  &lt;/p&gt;

&lt;h3&gt;
  
  
  What is Directus ?
&lt;/h3&gt;

&lt;p&gt;The basic idea is that we want to expose the structure and relationship aspects of SQL databases in an intuitive and application friendly way. The direction of it is to be able to build something specific and useful with Directus and an underlying SQL database. Basically with just working inside of the Directus app, in the browser. &lt;/p&gt;

&lt;p&gt;In more &lt;em&gt;entity parlor&lt;/em&gt;, Directus allows us to define entity types, their relations, to set up  forms where we edit/interact with these entities and to display, filter and search tables (or collections) of such entities. All without coding! (at least to begin with...)&lt;/p&gt;

&lt;p&gt;The Directus platform has been around and evolved  for some 15+ years now. For more background &lt;a href="https://directus.io/organization/"&gt;look here&lt;/a&gt; - with history towards the bottom of the page. It is fully open source and available on &lt;a href="https://github.com/directus/directus"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I first got to know of Directus when it was implemented in PHP, and even if I liked aspects of it, that was a bit of a turn off for me (PHP as practical, as battle tested as it is, is maybe not where next generation technologies first appear). I've had my years in PHP (which were fine), but I was ready there. &lt;/p&gt;

&lt;p&gt;A year ago, I discover that the team behind Directus had started migrating the server part of it over to Node.js and TypeScript. I was excited, as this was also where I was headed.&lt;/p&gt;

&lt;p&gt;So version 9 of Directus is to be all Node.js and Typescript on the server side, and Vue.js and TypeScript on frontend. To my knowledge, it is one of the first times a more structural application framework is implemented within the Node.js platform.  &lt;/p&gt;

&lt;p&gt;At this date (early April 2021) Directus 9.0 is not released yet - but it is nearing. &lt;/p&gt;

&lt;h3&gt;
  
  
  My background and angle
&lt;/h3&gt;

&lt;p&gt;I'm a generic developer who enjoy working on platforms that makes sense. The last decade or so I did backend / full stack work on some different ERP like platforms. The last being implementing e-commerce (and CMS) solutions on the Magento platform (yes... Php). &lt;/p&gt;

&lt;p&gt;I learnt a few things on that road. One is that data types, schemas, entity types (sort of different words for the same thing) is ideally something flexible (or at least extensible, adaptable) on such platforms. In the end, because client needs are like that. &lt;/p&gt;

&lt;p&gt;So it is good to be able to describe these schemas, these entity types, with a combination of more generic code together with some declarative / descriptive configuration. &lt;/p&gt;

&lt;p&gt;I also learnt that (in the world of ERP and their relatives) this generality can become big task to accomplish - if it is to be useful. &lt;/p&gt;

&lt;p&gt;And yes, there are some open source ERP solutions available that do this - like &lt;a href="https://en.wikipedia.org/wiki/Odoo"&gt;Odoo&lt;/a&gt; and &lt;a href="https://erpnext.com/"&gt;ErpNext&lt;/a&gt;. As feature packed and full as these are, they also carry with them aspects such as large footprints, lots of legacy technology, high learning curves, little available (unpaid) support being available. Usually these systems are their own technology stacks - which are sometimes not so main stream. And the effort to implement a small system is usually significant (after all they are geared towards enterprise solutions and budgets). &lt;/p&gt;

&lt;p&gt;So this is where something like Directus comes in. The possibility (with limited means) to build something particular, something structural, relying on the strengths on a relational database, with mostly configuration.  &lt;/p&gt;

&lt;h3&gt;
  
  
  My "litmus test"...
&lt;/h3&gt;

&lt;p&gt;I have a use case that can exercise these qualities. I want to see if it is possible to implement the accounting of my own company, largely relying on the generic capabilities of Directus. &lt;/p&gt;

&lt;p&gt;Accounting (or bookkeeping), as boring as it can appear, relies heavily on structural relations. A &lt;strong&gt;verification&lt;/strong&gt; can refer to an &lt;strong&gt;invoice&lt;/strong&gt;, it contains several &lt;em&gt;rows&lt;/em&gt;, where each refer to an &lt;strong&gt;account&lt;/strong&gt;, and the sum of &lt;em&gt;credit&lt;/em&gt; and &lt;em&gt;debit&lt;/em&gt; on these rows is supposed to sum to exactly &lt;strong&gt;0&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;And that is just the beginning... &lt;/p&gt;

&lt;p&gt;&lt;em&gt;To make you worry less about my bookkeeping...:&lt;/em&gt; Yes, I do implement it in another system. But I'm partly motivated by the lack of flexibility (in that system) to pursue this avenue. &lt;/p&gt;

</description>
      <category>directus</category>
      <category>sql</category>
      <category>generic</category>
      <category>admin</category>
    </item>
  </channel>
</rss>
