ljharb / qs

A querystring parser with nesting support
BSD 3-Clause "New" or "Revised" License
8.47k stars 731 forks source link

Keeping nesting with custom decoder ? #454

Open Altho opened 1 year ago

Altho commented 1 year ago

Hello,

I am using parse() on a node server (vanilla node http server, not express) to parse a long, not known in advance, querrystring to JSON. I also need to convert the values to the correct type. I understand that qs doesn't do type coercion by design. Here is my issue

If i just use parse without options every value is a string but my nested values are correctly displayed. But if I use a custom decoder to convert the types :

const data = qs.parse(body, {
        decoder(value) {
          if (/^(\d+|\d*\.\d+)$/.test(value)) {
            return parseFloat(value);
          }

          const keywords: Record<string, any> = {
            true: true,
            false: false,
            null: null,
            undefined: undefined,
          };

          if (value in keywords) {
            return keywords[value];
          }

          return value;
        },
      });

then I lost nesting. How do I manage to keep the nesting along type coercion ?

ljharb commented 1 year ago

First, i would suggest not using in, since your keywords inherits from Object.prototype - use Object.hasOwn (https://npmjs.com/object.hasown).

Separately, the issue is that you're not using the decoder correctly. Try this:

const keywords: Record<string, any> = {
  __proto__: null,
  true: true,
  false: false,
  null: null,
  undefined: undefined,
};

const data = qs.parse(body, {
  decoder(value, defaultDecoder, ...rest) {
    if (/^(\d+|\d*\.\d+)$/.test(value)) {
      return parseFloat(value);
    }

    if (Object.hasOwn(keywords, value)) {
      return keywords[value];
    }

    return defaultDecoder(value, ...rest);
  },
});