Search code examples
javascriptnode.jscnode-addon-apinode-api

How to get a JavaScript number as a string using Node-API


I'm building a Node.js addon using Node-API.

The logic has been simplified as below,

Use pass js array into the addon and get some filtered array as the output.

Inside the addon, the algorithm will skip any empty strings and false values.

Below is the code snipped of the usage. The whole addon available here: https://replit.com/@dinindu/node-api-addon-compact#addon.c

const addon = require("bindings")("addon.node");

const array = ['0', false, '', {a:'1'}, '2', "str"];
console.log(addon.compact(array)); // expected output: ['0', {a:'1'}, '2', "str"]
// addon.c
#include <assert.h>
#include <node_api.h>
#include <stdlib.h>

#define DECLARE_NAPI_METHOD(name, func) \
  { name, 0, func, 0, 0, 0, napi_default, 0 }

#define DECLARE_WITH_STATUS_CHECK(size, name, func)                       \
  napi_property_descriptor func##_desc = DECLARE_NAPI_METHOD(name, func); \
  status = napi_define_properties(env, exports, size, &func##_desc);      \
  assert(status == napi_ok);

static napi_value compact(napi_env env, napi_callback_info info) {
  size_t argc = 1;
  napi_value args[1];
  napi_get_cb_info(env, info, &argc, args, NULL, NULL);
  
  uint32_t length;
  napi_get_array_length(env, args[0], &length);

  napi_value output_array;
  napi_create_array_with_length(env, NAPI_AUTO_LENGTH, &output_array);

  uint32_t result_index = 0;
  for (size_t i = 0; i < length; i++) {
    napi_value value;
    napi_get_element(env, args[0], i, &value);

    napi_valuetype type;
    napi_typeof(env, value, &type);

    if (type == napi_boolean) {
      bool result;
      napi_get_value_bool(env, value, &result);
      if (result == false) continue;
    }

    char* str_buffer;
    bool str_found = false;
    if (type == napi_string) {
      size_t str_buffer_size;
      napi_get_value_string_utf8(env, value, NULL, 0, &str_buffer_size);

      str_buffer = (char*)calloc(str_buffer_size + 1, sizeof(char));
      size_t str_result;
      napi_get_value_string_utf8(env, value, str_buffer, str_buffer_size, &str_result);

      str_found = true;
      if (*str_buffer == '\0') {
        free(str_buffer);
        str_found = false;
        continue;
      }
    }

    napi_set_element(env, output_array, result_index, value);
    result_index++;
    if (str_found) free(str_buffer);
  }
  
  return output_array;
}

static napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  DECLARE_WITH_STATUS_CHECK(1, "compact", compact)
  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

What I don't understand is, the expected output should contain all values except false and ''. But it seems to skip '0' and '2' as well, which means number characters. I tested it by adding another number after it ('01') and then it works.

Why this is happening? Why C is skipping single character numbers? And how can I get my expected output?

Thanks in advance.


Solution

  • I got resolved this after digging through Node.js source code and making this change,

    I replaced,

    napi_get_value_string_utf8(env, value, str_buffer, str_buffer_size, &str_result); 
    

    with

    napi_get_value_string_utf8(env, value, str_buffer, str_buffer_size + 1, &str_result);
    

    Adding 1 to str_buffer_size simply solves the problem. But I don't understand why, but it fixes my problem anyway.

    This helped me to solve this