<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: canalun</title>
    <description>The latest articles on Forem by canalun (@canalun).</description>
    <link>https://forem.com/canalun</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%2F850691%2F65c0b2a0-4974-4fa5-b94a-c6a75b56f47c.png</url>
      <title>Forem: canalun</title>
      <link>https://forem.com/canalun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/canalun"/>
    <language>en</language>
    <item>
      <title>Monorepo of Rust CLI &amp; TS+Wasm VSCode</title>
      <dc:creator>canalun</dc:creator>
      <pubDate>Sun, 30 Apr 2023 14:37:16 +0000</pubDate>
      <link>https://forem.com/canalun/monorepo-of-rust-cli-tswasm-vscode-4bme</link>
      <guid>https://forem.com/canalun/monorepo-of-rust-cli-tswasm-vscode-4bme</guid>
      <description>&lt;p&gt;If you use Rust to create CLI, it would be worth &lt;strong&gt;considering create a VSCode extension together&lt;/strong&gt;.&lt;br&gt;
This is because &lt;strong&gt;your Rust script can be used in the extension with almost zero additional cost if you leverage Wasm power!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article is about developing CLI and VSCode extension in the same repository by using Rust and Wasm as below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implement core calculation common to CLI and VSCode &lt;strong&gt;in Rust&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;the CLI itself is implemented &lt;strong&gt;in Rust&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;the VSCode extension is implemented based on TypeScript, and &lt;strong&gt;it calls　the core calculation as Wasm module&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll explain what I developed and how I set up this monorepo system👶&lt;/p&gt;
&lt;h1&gt;
  
  
  Table Of Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;What I developed&lt;/li&gt;
&lt;li&gt;
How to setup monorepo for CLI and VSCode extension

&lt;ul&gt;
&lt;li&gt;1. Overall directory structure
&lt;/li&gt;
&lt;li&gt;2. Separation of core calculation and CLI itself
&lt;/li&gt;
&lt;li&gt;3. Set up a VSCode extension project in Rust project

&lt;ul&gt;
&lt;li&gt;3.1. Where to put config of VSCode extensions
&lt;/li&gt;
&lt;li&gt;3.2. How to call and bundle Wasm (wasmpack and webpack config)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  What I developed &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;What I created is a formatter for MySQL INSERT queries. It organizes them so that they look like a table, that is, the column names and the values ​​in each row are arranged vertically.&lt;/p&gt;

&lt;p&gt;It looks good, doesn't it?🎉&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-m_OC6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4gqi9e2eab4f627pigc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-m_OC6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4gqi9e2eab4f627pigc.gif" alt="The comparison of before and after the format by 'insertfmt'" width="405" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's really useful especially when you have to manage test data in a form of a large number of INSERT queries.&lt;/strong&gt; please try using it!&lt;/p&gt;

&lt;p&gt;CLI: &lt;a href="https://github.com/canalun/insertfmt"&gt;https://github.com/canalun/insertfmt&lt;/a&gt;&lt;br&gt;
VSCode extension: &lt;a href="https://marketplace.visualstudio.com/items?itemName=canalun.insertfmt"&gt;https://marketplace.visualstudio.com/items?itemName=canalun.insertfmt&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  How to setup monorepo for CLI and VSCode extension &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Let's move on to the main topic.&lt;/p&gt;

&lt;p&gt;Again, please remember the overall structure of this repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implement core calculation common to CLI and VSCode &lt;em&gt;in Rust&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;the CLI itself is implemented in &lt;em&gt;Rust&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;the VSCode extension is implemented based on TypeScript, and &lt;em&gt;it calls　the core calculation as Wasm module&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look at the actual sources!!&lt;/p&gt;

&lt;p&gt;FYI: The repository is here, so if you're really interested in this topic, why not check it out👶&lt;br&gt;
&lt;a href="https://github.com/canalun/insertfmt"&gt;https://github.com/canalun/insertfmt&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Overall directory structure &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;First, this is the repo structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── cli
│   └── main.rs     &amp;lt;-------- cli
├── core
│   └── core.rs     &amp;lt;-------- the core calculation
├── Cargo.toml
├── Makefile        &amp;lt;-------- conversion to Wasm is implemented as Make command as mentioned later
├── .vscode         &amp;lt;-------- VSCode ext. debug setting
└── vscode_extension    &amp;lt;---- VSCode ext. directory
    ├── node_modules    
    ├── insertfmt_core  &amp;lt;---- Wasm compile destination
    ├── src
    │   └── extension.ts   &amp;lt;- VSCode ext.
    ├── package.json    &amp;lt;---- VSCode ext. meta info
    └── webpack.config.js  &amp;lt;- configured to bundle all including Wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Separation of core calculation and CLI itself &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As you can see, I separated the core calculation from the cli itself. As the name suggests, &lt;code&gt;core&lt;/code&gt; dir has the core calculation common to the cli and extension, and &lt;code&gt;cli&lt;/code&gt; dir has the cli itself.&lt;/p&gt;

&lt;p&gt;This separation makes it &lt;strong&gt;easy to share the core calculation with the VSCode extension&lt;/strong&gt;. And it may be &lt;strong&gt;useful for release or reuse of the core calculation as one library&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Just as a side note, &lt;code&gt;Cargo.toml&lt;/code&gt; is like this👶&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[package]
name = "insertfmt"
...

[[bin]]
name = "insertfmt"
path = "./cli/main.rs"

[lib]
name = "insertfmt_core"
path = "./core/core.rs"
crate-type = ["cdylib", "rlib"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Set up a VSCode extension project in Rust project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The next is about setting up a VSCode extension project in a Rust project.&lt;/p&gt;

&lt;p&gt;To add a directory for VSCode extension development to an existing Rust project, &lt;strong&gt;you can just run yeoman, &lt;code&gt;npx yo code&lt;/code&gt;, in the root directory of the Rust project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;(The scaffolding tool called yeoman is very useful for VSCode extension development. The link is below.)&lt;br&gt;
&lt;a href="https://yeoman.io/"&gt;https://yeoman.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After running yeoman, you can find a directory for VSCode extension development in the root directory of the Rust project.&lt;/p&gt;

&lt;p&gt;But, here, you should take care of the following two points.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Where to put the config of VSCode extensions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How to bundle and call Wasm&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me explain👶&lt;/p&gt;
&lt;h3&gt;
  
  
  3.1 Where to put config of VSCode extensions (wasmpack and webpack config) &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;First of all, you can roughly categorize configuration files of VSCode extensions into the two types as below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meta information (extension name, version etc.)&lt;/li&gt;
&lt;li&gt;Debug configuration (configuration for running and testing the extension on your local)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the extension project is a typical one (at least if that is a project created by yeoman with no special settings), "meta information" is written in &lt;code&gt;package.json&lt;/code&gt; in the root directory and "debug config" is in &lt;code&gt;launch.json&lt;/code&gt; and &lt;code&gt;tasks.json&lt;/code&gt; in &lt;code&gt;.vscode&lt;/code&gt; dir.&lt;/p&gt;

&lt;p&gt;You have to pay attention especially to your debug config, because &lt;strong&gt;&lt;code&gt;.vscode&lt;/code&gt; directory has to be in the root directory otherwise VSCode does not recognize it&lt;/strong&gt;, and that means you cannot run and debug the extension on your local.&lt;br&gt;
(the workaround might be "Multi-root Workspaces", but idk so much about it...! The info is here: &lt;a href="https://code.visualstudio.com/docs/editor/multi-root-workspaces"&gt;https://code.visualstudio.com/docs/editor/multi-root-workspaces&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So, after initialize an extension project in the existing Rust project, it would be better to &lt;strong&gt;move &lt;code&gt;.vscode&lt;/code&gt; dir of the extension project to the root directory (= the Rust project directory)&lt;/strong&gt; and &lt;strong&gt;change settings in &lt;code&gt;launch.json&lt;/code&gt; and &lt;code&gt;tasks.json&lt;/code&gt; regarding file paths&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Of course, if the existing Rust project also has &lt;code&gt;.vscode&lt;/code&gt; directory, you have to integrate the two directories👶 &lt;/p&gt;
&lt;h3&gt;
  
  
  3.2 How to call and bundle Wasm &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Basically, it's not so difficult to convert your Rust script into Wasm and call it from the extension (+ bundle it).&lt;br&gt;
In short, &lt;strong&gt;all I had to do was just compile the Rust script to Wasm by using &lt;code&gt;wasm-pack&lt;/code&gt;, call it from the extension by dynamic import and change the webpack setting a bit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So let me explain in detail!&lt;/p&gt;

&lt;p&gt;I generated Wasm by &lt;code&gt;wasm-pack&lt;/code&gt;. &lt;strong&gt;I took a bit long time to notice I had to set &lt;code&gt;--target bundler&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;
The make command I use is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gen-wasm-for-extension:
  rm -rf ./vscode_extension/insertfmt_core
  wasm-pack build --target bundler --out-dir ./vscode_extension/insertfmt_core --release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the compiled Wasm is called by &lt;strong&gt;dynamic import&lt;/strong&gt; from the extension .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function activate(context: vscode.ExtensionContext) {
  const disposable = vscode.commands.registerCommand(
    'insertfmt.fmtInsertQueries',
    () =&amp;gt; {
        // after some calculations...
        // ok, let's use wasm
        import('../insertfmt_core').then((module) =&amp;gt; {
          const result = module.format_insert_queries_wasm(text)
          // ...
        })
        // ...
    })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way of using Wasm is also explained in the below MDN doc.&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm#using_the_npm_package_on_the_web"&gt;https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_wasm#using_the_npm_package_on_the_web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But please be careful about your webpack version&lt;/strong&gt;. I'm not very clear at this point, &lt;strong&gt;but webpack 4 and 5 handle Wasm differently&lt;/strong&gt;.&lt;br&gt;
The above MDN doc uses webpack 4, so you may have to change the setting of webpack if you use other versions.&lt;/p&gt;

&lt;p&gt;This time, &lt;strong&gt;the version of webpack I used was &lt;code&gt;webpack@^5.75.0&lt;/code&gt;&lt;/strong&gt;. So, I had to consider the webpack config about Wasm.&lt;br&gt;
After a lot of trial, I arrived at the following setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;experiments: {
    asyncWebAssembly: true,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What is written regarding the webpack params of Wasm varies. Unfortunately, I won't get surprised if you take a tough time to find settings that work...!&lt;br&gt;
If you are also interested in the version of related modules, please see my repository.&lt;br&gt;
&lt;a href="https://github.com/canalun/insertfmt"&gt;https://github.com/canalun/insertfmt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, this article ends here!!&lt;br&gt;
I think this monorepo way is a quite good idea if you use Rust to develop CLI!!&lt;br&gt;
Thank you for reading😊&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
      <category>monorepo</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Safer Type Predicate in TypeScript</title>
      <dc:creator>canalun</dc:creator>
      <pubDate>Thu, 21 Apr 2022 03:49:13 +0000</pubDate>
      <link>https://forem.com/canalun/safer-type-predicate-in-typescript-1f3o</link>
      <guid>https://forem.com/canalun/safer-type-predicate-in-typescript-1f3o</guid>
      <description>&lt;p&gt;TypeScript has a feature called type predicate.&lt;br&gt;
However, this function is NOT 100% type-safe.&lt;br&gt;
So I'd like to introduce &lt;strong&gt;a safer way to use type predicate&lt;/strong&gt; in this article👶&lt;/p&gt;
&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;One of the problems about TypeScript's type predicate is that &lt;strong&gt;it does NOT care whether your type assertion logic is correct&lt;/strong&gt;.&lt;br&gt;
Actually, even if your function cannot determine type properly, compliers will not give you any errors as long as the function is grammatically correct.&lt;/p&gt;

&lt;p&gt;So, when using type predicate, we should take this way; &lt;strong&gt;assign the determination target to a variable of type T|null through your type assertion logic&lt;/strong&gt;👶&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//safer type predicate
function isTypeA(x: typeA | typeB): x is TypeA {
    const maybeTypeA: typeA | null =
        if ([logic which is true only when x is TypeA]) ? x : null
    return !!maybeTypeA
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following, I explain what type predicate is like in TypeScript. And then, see the problem and how the above code solves it.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is type predicate?
&lt;/h1&gt;

&lt;p&gt;In the context of computer science, the word "predicate" means "a function to determine if something is true or false" in a broad sense👶&lt;br&gt;
The following link is easy to understand.&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/3230944/what-does-predicate-mean-in-the-context-of-computer-science"&gt;https://stackoverflow.com/questions/3230944/what-does-predicate-mean-in-the-context-of-computer-science&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, it can be said that "type predicate" means "a function that determines type".&lt;br&gt;
Such a function is implemented not only in TypeScript but also in other languages such as LISP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's important that, when saying type predicate in the context of TypeScript, it specifically means the following function&lt;/strong&gt;(&lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"&gt;official documentation&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//type predicate in TypeScript
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see here, you can easily write a type predicate by changing type of the return value of your type asserting function from boolean to &lt;code&gt;X is T&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And type predicate narrows down type of the variable as follows (from &lt;a href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"&gt;official documentation&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Example usage of type predicate in TypeScript
let pet = getSmallPet();

if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type predicate can perform type assertion which &lt;code&gt;typeof&lt;/code&gt; and &lt;code&gt;instanceof&lt;/code&gt; cannot.&lt;/p&gt;

&lt;h1&gt;
  
  
  When is type predicate insecure?
&lt;/h1&gt;

&lt;p&gt;Although type predicate is useful, it'll be unsafe if the logic to determine type is incorrect.&lt;br&gt;&lt;br&gt;
The following example is clearly incorrect, but ignored by compilers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Example of unsafe type predicate in TypeScript
function isNumber(x: unknown): x is Number {
  return typeof x === "boolean";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a really simple example, but you can overlook and/or make this kind of mistake in complicated codes.&lt;/p&gt;

&lt;h1&gt;
  
  
  How can we write type predicate safely?
&lt;/h1&gt;

&lt;p&gt;So what exactly should we do? Here, the conclusion at the beginning of this article is explained again.&lt;/p&gt;

&lt;p&gt;It's the most important to &lt;strong&gt;assign the determination target to a variable of type T|null through your type assertion logic&lt;/strong&gt;👶.&lt;br&gt;
There are many ways to do this, but for now, ternary operator is convenient.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//safer type predicate
function isTypeA(x: unknown): x is TypeA {
    const maybeTypeA: typeA | null =
        if ([logic which is true only when x is TypeA]) ? x : null
    return !!maybeTypeA
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, the problem is type predicate is seen as CORRECT by compliers even if its logic is incorrect.&lt;br&gt;
So, if you take the above way, &lt;strong&gt;if an not-TypeA argument was determined as TypeA by incorrect logic, the variable 'maybeTypeA' would be null by the ternary operator, and the result would settle to false&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The difference is clear when compared to the typical one as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In the typical way, if the condition is wrong, the type predicate will also return the wrong result.
function isTypeA(x: unknown): x is TypeA {
    return if ([logic which is true only when x is TypeA]).
}

// In this way of writing, if the condition is wrong, type predicate can detect it (i.e. it can return false).
function isTypeA(x: unknown): x is TypeA {
    const maybeTypeA: typeA | null =
        if ([logic which is true only when x is TypeA]) ? x : null
    return !!maybeTypeA
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;May the safe type life be with you👶&lt;/p&gt;

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