EJSON.stringify() type signature doesn't match implementation logic

XMLWordPrintableJSON

    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Description

      The type signature of the EJSON.stringify() function allows parameter combinations that don't work as expected. Specifically, when options are passed as the second parameter and space as the third parameter, the space argument is ignored.

      Problem

      The current type signature of stringify is:

      function stringify(
        value: any,
        replacer?: (number | string)[] | ((this: any, key: string, value: any) => any) | EJSONSerializeOptions,
        space?: string | number,
        options?: EJSONSerializeOptions
      ): string
      

      This signature allows a call like:

      EJSON.stringify(object, { relaxed: false }, 2)
      

      which is used by this in tests within js-bson test/bench/etc/generate_documents.ts

      Current Behavior

      With this call, the following happens:

      { relaxed: false }

      is passed as the replacer parameter

      2

      is passed as the space parameter
      The code detects that replacer is an object (but not an array) and treats it as options
      In doing so, space is reset to 0, causing the 2 to be ignored
      Relevant code in src/extended_json.ts:484-488:

      if (replacer != null && typeof replacer === 'object' && !Array.isArray(replacer)) {
        options = replacer;
        replacer = undefined;
        space = 0;  // <-- space is ignored!
      }
      

      Expected Behavior

      The call

      EJSON.stringify(object, { relaxed: false }, 2)

      should either:

      Option 1: Throw an error or be rejected by the TypeScript compiler
      Option 2: Apply the options correctly AND respect the space value of 2

      Reproduction

      import { EJSON, Int32 } from 'bson';
      
      const doc = { int32: new Int32(10) };
      
      // This variant works as expected:
      console.log(EJSON.stringify(doc, undefined, 2));
      // Output: {
      //   "int32": 10
      // }
      
      // This variant does NOT work as expected:
      console.log(EJSON.stringify(doc, { relaxed: false }, 2));
      // Expected output: {
      //   "int32": {
      //     "$numberInt": "10"
      //   }
      // }
      // Actual output: {"int32":{"$numberInt":"10"}}
      // (space is ignored)
      

            Assignee:
            Unassigned
            Reporter:
            Daniel Müller
            None
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: