say i want to wrap the discordjs javascript library how do i go about doing that?
for example i want to do this
import { Client, GatewayIntentBits } from 'discord.js';
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === 'ping') {
await interaction.reply('Pong!');
}
});
client.login(TOKEN);
this is what i have so far
{.emit:"""
import { Client, GatewayIntentBits } from 'discord.js';
""".}
proc Client(intents: JsObject): JsObject {.importjs: "Client(#)".}
var client = new Client({ intents: [GatewayIntentBits.Guilds] })
i think i have a ok starting point but i dnt know how to make this work
proc newClient(opts: JsObject): JsObject {.importjs: "new Client(#)".}
or
proc newClient(intents: JsObject): JsObject {.importjs: "new Client({intents: #})".}
I'd probably do something like this:
import std/[jsconsole, asyncjs]
{.emit: "import { Client } from 'discord.js';".}
type
Client = ref object
user: User
User = ref object
tag: cstring
GatewayIntentBits = enum
Guilds = 1
GuildMembers = 2
# ... etc
Interaction = ref object
commandName: cstring
proc newClient(intents: seq[GatewayIntentBits]): Client {.importjs: "new Client({intents: #})".}
proc onReady(client: Client; callback: proc()) {.importjs: "#.on('ready', #)".}
proc onInteractionCreate(client: Client; callback: proc(interaction: Interaction) {.async.}) {.importjs: "#.on('interactionCreate', #)".}
proc login(client: Client; token: cstring) {.importjs: "#.login(#)".}
proc isChatInputCommand(interaction: Interaction): bool {.importjs: "#.isChatInputCommand()".}
proc reply(interaction: Interaction; msg: cstring): Future[void] {.importjs: "#.reply(#)".}
let client = newClient(@[GatewayIntentBits.Guilds])
client.onReady(proc =
console.log("Logged in as", client.user.tag, "!")
)
client.onInteractionCreate(proc(interaction: Interaction) {.async.} =
if not interaction.isChatInputCommand():
return
if interaction.commandName == "ping":
await interaction.reply("Pong!")
)
# client.login(TOKEN) # in the example TOKEN is not defined
Stronger typing for wrapping a library instead of using jsffi/jsobject for all types.
Compile with nim js -d:danger when you're checking the codegen of your wrapper to make sure it produces the js you expect (the output will be less noisy from bounds checking etc)
is there a reason to use jsconsole/console.log over echo other than looks?
anyways Thank you for all your help!
is there a reason to use jsconsole/console.log over echo other than looks?
Yes, for cstrings in particular. Compare the outputs of the following examples (all compiled with -d:danger to remove noise, and cleaned up slightly to make it clearer):
Example 1: using echo with a regular Nim string
let str = "Hello world"
echo str
The generated JS:
function toJSStr(s_33556901) {
// a big function to convert a nim string (array of numbers) to a javascript string
// ...
}
function rawEcho() {
// a function that converts all of its arguments to js strings using toJSStr, and then console.logs them
// ...
}
// the string "Hello world", represented as an array of numbers
var str_536870913 = [72,101,108,108,111,32,119,111,114,108,100];
rawEcho(str_536870913);
Example 2: using echo with a cstring ("compatible string")
let str = cstring "Hello world"
echo str
The generated JS:
function toJSStr(s_33556901) {
// a big function to convert a nim string (array of numbers) to a javascript string
// ...
}
function rawEcho() {
// a function that converts all of its arguments to js strings using toJSStr, and then console.logs them
// ...
}
function cstrToNimstr(c_33556898) {
// a large function that converts a JS string to an array of numbers (the representation of a Nim string)
}
// the "Hello world" string as a JS string
var str_536870913 = "Hello world";
// echo by first converting the JS string to a Nim string
rawEcho(cstrToNimstr(str_536870913));
Example3: using console.log with a cstring
import std/jsconsole
let str = cstring "Hello world"
console.log str
The generated JS:
var str_536870914 = "Hello world";
console.log(str_536870914);
As you can see the final output is the simplest with the lowest overhead. When using the JS backend, a good rule of thumb is to use string when you want compatibility with Nim libraries, and to use cstring when you want compatibility with JS libraries, or smaller codegen output and faster execution.