Skip to content

nfnl Conversion Guide

Russ Tokuyama edited this page Sep 7, 2024 · 8 revisions

Last update: 09/07/2024

This work was merged into the nfnl-migration branch and renamed to the main branch. See Discussion #605.


These guidelines (as suggested by @Olical) should be useful when converting Conjure source files from Aniseed to nfnl on the nfnl-migration branch.

See the nfnl API docs for the equivalent Aniseed functions.

How to approach the nfnl conversion

  • Keep the use of Aniseed modules in the code for now.
  • Optionally, migrate to nfnl versions of the modules like str and core. If there are any issues then just stick with Aniseed for now.
  • This first pass aims to remove Aniseed for compiling Fennel into Lua. Completely dropping Aniseed will take more time to complete.
    • Dropping Aniseed will require migrating to Neovim's built-in functions that were integrated from nvim.lua in 2019. aniseed.nvim provides the nvim.lua functions by being a wrapper over them.
  • Beware that busted tests may blow up without any helpful error messages. This can be triggered by not returning nil in the tail position of your test function. This is caused by the assertion returning a non-nil value.
    • Here's an example of the test output:
      ║Success ||      conjure.dynamic type-guard                                
      ║Fail    ||      conjure.dynamic type-guard                                
      ║            error in error handling                                       
      ║                                                                          
      ║Success:        13                                                        
      ║Failed :        1                                                         
      ║Errors :        0 
    
    • Here's an example of returning nil from a test function:
    (describe "current-client-module-name"                                       
      (fn []                                                                     
        (describe "with-filetype"                                                
          (fn []                                                                 
            (it "returns the fennel module when we're in a fennel file"          
              (fn []                                                             
                ;; Error in error handling?                                      
                (assert.same                                                     
                  {:filetype "fennel"                                            
                   :module-name "conjure.client.fennel.aniseed"}                 
                  (client.with-filetype "fennel" #(client.current-client-module-name)))
                nil))))))
    

Translate source

  • Replace module with calls to nfnl's autoload to load deps.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    (module conjure.buffer                     | (local {: autoload} (require :nfnl.module))
      {autoload {nvim conjure.aniseed.nvim     | (local nvim (autoload :conjure.aniseed.nvim))
                 a conjure.aniseed.core        | (local a (autoload :nfnl.core))
                 str conjure.aniseed.string    | (local str (autoload :nfnl.string))
                 text conjure.text}})          | (local text (autoload :conjure.text))
    
  • Remove import-macros statements.

    (import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed)
    
  • Replace defn with fn.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    (defn form [opts]                          | (fn form [opts]
    
  • Replace defn- with fn (private function; don't export).

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    (defn- getpos [expr]                       | (fn getpos [expr]
    
  • Replace defonce with local.

  • Replace def- with local (private name; don't export).

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    (defonce conjure-source-directory          | (local conjure-source-directory
    (def- cats-and-dogs                        | (local cats-and-dogs
    
  • Optional: Replace if-let with a let and an if. nfnl.macros provides the equivalent.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
      (if-let [node (ts.get-leaf)]             |   (let [node (ts.get-leaf)]
                                               |     (if node
        {:range (ts.range node)                |       {:range (ts.range node)
         :content (ts.node->str node)}         |        :content (ts.node->str node)}
        {:range nil                            |       {:range nil
         :content nil})                        |        :content nil}))
    
  • Remove *module* at bottom of the file.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    *module*                                   |
    
  • Add a table at the bottom of the file to export anything public. NOTE: As recommended by https://fennel-lang.org/style.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
                                               | {: form
                                               |  : prompt
                                               |  : prompt-char}
    

Translate test files

  • Create the equivalent of tests for aniseed-legacy-tests/ in fnl/conjure-spec/. However, don't convert the legacy tests.

    Legacy                                     | Busted
    -------------------------------------------+------------------------------------------------
    `<module>-test.fnl`                        | `<module>_spec.fnl`
    
  • Remove module and replace with requires for plenary and busted.

    Legacy                                          | Busted
    ------------------------------------------------+------------------------------------------------
                                                    | (local {: describe : it} (require :plenary.busted))
                                                    | (local assert (require :luassert.assert))
                                                    |
    (module conjure.fs-test                         | (describe "fs"
                                                    |   (fn []
                                                    |     (describe ...) ;; a test
      {require {fs conjure.fs                       | (local fs (require :conjure.fs))
                nvim conjure.aniseed.nvim}})        | (local nvim (require :conjure.aniseed.nvim))
    
  • Replace deftest with describe.

  • Replace t.= with assert.are.equals.

  • Replace t.pr= with assert.same.

  • Replace t.ok? with assert.is_true. You may need to look closely at what the legacy test is trying to do to determine if this is appropriate.

    Legacy                                                   | Busted
    ---------------------------------------------------------+------------------------------------------------
    (deftest config-dir                                      | (describe "config-dir"
      (t.= "/home/conjure/.config/conjure" (fs.config-dir))  |   (assert.are.equals "/home/conjure/.config/conjure"
                                                             |                      (fs.config-dir))
      (t.pr= [] (fs.split-path ""))                          |   (assert.same [] (fs.split-path "")))
    

Run the new tests

  • Run scripts/setup-test-deps to set up a hidden directory, .test-config/ which acts as the test environment.

  • Run scripts/test to execute the new tests under the lua/conjure-spec/ directory.

  • If your Neovim is set up with Conjure, Plenary, Aniseed, and nfnl, you can run the busted tests from the Neovim command line with:

    :PlenaryBustedDirectory lua/conjure-spec
    

    Or run a single test file with:

    :PlenaryBustedFile lua/conjure-spec/fs_spec.lua
    
  • If you're dog-fooding (using the nfnl-migration branch with your working Neovim config), be sure to restart your Neovim or start a new one in another terminal or command window. This ensures that the newly compiled Lua files will be used when running the busted tests.