Function Node Code Completion for Module (Monaco Editor)

Hi everyone! I've installed v2.0.5 and configured the Monaco Editor.
Firstly, thanks so much to the development team, it's fantastic to see these improvements.

Now, using the 'setup tab' and allowing the use of installed modules within the function node, I've tested that these work, however there is no code completion for these.

Is this expected, or is there something I'm missing? I've tried this with common modules like lodash as well as a couple of unpublished modules I just used for testing (one written in JS directly, and the other in typescript with .d.ts files).

You are not missing anything. When I was developing Monaco for node-red, the impetus was on getting it's working and working stably. It is in the back of my mind about how to import types for modules automatically (and has been discussed n the PR and other places) but I don't have a good working in solution in my head yet.

There is however a temporary working solution. If you can find the d.ts file for a lib, you can place it in in the public folder alongside the other d.ts files. The only prerequisite is that you name it correctly.

For example, if you have d.ts for lodash then try putting that at ...

node_modules/node-red/node_modules/@node-red/editor-client/public/types/other/lodash.d.ts

... in the global install folder (e.g. enter npm root -g to find the global location)

Then restart browser (if that doesnt work, restart node-red)

Let me know if it works (It is very possible I have broken it when making final tweaks for release)

Thanks so much @Steve-Mcl for your quick response.

That has helped a bit but I still don't think it's quite right. When I copy the .d.ts file into the folder you mentioned, as long as I've created a typescript library which uses a namespace of the same name, then code completion will pick up on this. However there is a mismatch between the code completion and the code execution.

For example:

  • If I have a module called foo, and it has namespace foo with all the functions inside it.
  • If I then use tsc to compile this, and ensure the .d.ts file is in the location you mention
  • And install the module via npm
  • And expose this via the setup in the function node
  • I can then see code completion when I type foo inside the monaco editor
  • However I get an error when trying to execute foo.function1()
  • I can make the code work however if I type foo.foo.function1()
  • If I don't use the namespace inside the module, then completion doesn't work, but the execution works as expect at foo.function1().

It is reassuring to hear that there is intent to get this working automatically for included modules in the future, so thanks again!

When creating a module / library, is there anything we should keep in mind to increase it's chances of working with code completion inside future versions of the function node?

Thanks again!

Can you post a link to your nom module and attach the d.ts file?

Thanks so much @Steve-Mcl , I haven't uploaded the module to npm (just used the local folder/directory name to install it). It's a very simple module with the following typescript file:

// export namespace codecompletiontest {

    export function greet (name : string) {
        return `Hello ${name}!`
    }
    
    export function helloWorld () {
        return 'Hello World!'
    }
// }

the js output results in:

"use strict";
// export namespace codecompletiontest {
Object.defineProperty(exports, "__esModule", { value: true });
exports.helloWorld = exports.greet = void 0;
function greet(name) {
    return "Hello " + name + "!";
}
exports.greet = greet;
function helloWorld() {
    return 'Hello World!';
}
exports.helloWorld = helloWorld;
// }
//# sourceMappingURL=codecompletiontest.js.map

and the d.ts is:

export declare function greet(name: string): string;
export declare function helloWorld(): string;
//# sourceMappingURL=codecompletiontest.d.ts.map

In order to show the name completion i need to uncomment the export namespace line, then generate the d.ts (without regenerating the js). The following d.ts after copied into place then works as expected:

export declare namespace codecompletiontest {
    function greet(name: string): string;
    function helloWorld(): string;
}
//# sourceMappingURL=codecompletiontest.d.ts.map

If it's easier for you to see the whole folder I've zipped it up, and as I couldn't upload it here, I've base64 encoded it:

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

Hi

How did you add your js file as a function node require from local file?

Hi @Steve-Mcl ,

I referenced the whole local folder as a an npm module. From the the folder containing the flows.json (on my machine this is ~/.node-red/), I ran:

npm install /path/to/codecompletiontest

the codecompletiontest folder (the one I zipped up and then encoded in my last post) has a package.json file in it so everything seemed to just install, with the contents of /path/to/codecompletiontest/ being added to ~/.node-red/node_modules/codecompletiontest/

Thanks!

ok ta. unfortunately the base64 --> zip didnt work for me (invalid zip). Is your test repo on gitub?

Thanks for giving it a go. I just tested the base64 encode now by clicking on the copy button on the encoded string from my post then running:

pbpaste | base64 -D > codecompletion.zip

(using macOS)

I then could unzip it without issue.

On windows I managed to decode it also by:

  • Pasting the encoded string into a new text file in notepad and saving it as codecompletion.txt
  • Opening cmd and running:
    certutil -decode codecompletion.txt codecompletion.zip
    

The resulting codecompletion.zip file also unzipped without issue.

Odd, it worked this time - hey ho.

ok. I'll take another look this evening & let you know.

Thanks so much @Steve-Mcl , much appreciated!

I'm trying to get this working. For knex would this be the correct file to put in @node-red/editor-client/public/types/other and name it as knex.d.ts?

Function node looks like this:
image