In Part 3 I described how I started wrapping libmtp in a Node.js module. Today I discovered napi-macros, which makes writing N-API modules much easier. Recall the getFile function we had from last time:


napi_value getFile(napi_env env, napi_callback_info info) {
    napi_status status;

    size_t argc = 2;
    napi_value argv[2];
    status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Failed to parse arguments");
    }

    int id = 0;
    char path[20];
    napi_get_value_int32(env, argv[0], &id);
    napi_get_value_string_utf8(env, argv[1], path, 20, NULL);

    int ret = LIBMTP_Get_File_To_File(device, id, path, NULL, NULL);

    napi_value retVal;
    status = napi_create_int32(env, ret, &retVal);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, "Unable to create return value");
    }

    return retVal;
}

I remember when I was writing that it felt very verbose. Now, using napi-macros this collapses into:


NAPI_METHOD(getFile) {
  NAPI_ARGV(2)
  NAPI_ARGV_INT32(id, 0)
  NAPI_ARGV_UTF8_MALLOC(path, 1)

  int ret = LIBMTP_Get_File_To_File(device, id, path, NULL, NULL);

  NAPI_RETURN_INT32(ret)
}

Wow, that's quite the difference - succinct and easier to read. I like it!