BRIKEV / express-jsdoc-swagger

Swagger OpenAPI 3.x generator
https://brikev.github.io/express-jsdoc-swagger-docs/#/
MIT License
216 stars 30 forks source link

[BUG] Three-dimensional Array `type` breaks #195

Open mrclean-oa opened 2 years ago

mrclean-oa commented 2 years ago

Describe the bug I am working with GeoJSON data and the data is represented as the following:

{
   "type":"MultiLineString",
   "coordinates":[
      [
         [
            10,
            10,
            0
         ],
         [
            20,
            20,
            1
         ],
         [
            10,
            40,
            2
         ]
      ]
   ]
}

So I would like to type the endpoint accordingly using a @typedef, I'm especially excited about using express-oas-validator, so I'd really like to get this to work:

/**
 * Index 0: The valid numbers for Longitude are between -180 and 180
 * Index 1: The valid numbers for Latitude are between -90 and 90
 * Index 2: The valid numbers for Altitude is a number greater than or equal to 0
 * @typedef {[number, number, number]} CoordinateArray
 */
/**
 * @typedef {object} GeoJSON
 * @property {string} type - enum:MultiLineString - the GeoJSON type
 * @property {array<array<array<CoordinateArray>>>} coordinates - the coordinates to the location
 */

When the coordinates property is {array<array<CoordinateArray>>} it works great, but you'll notice I'm missing a dimension. I have two arrays for property, and the tuple for the three numbers, yet it drops one of the arrays, see the image: Screen Shot 2021-10-13 at 3 56 07 PM

When I add one more dimension (required for GeoJSON), it breaks in a confusing way, see "broken" image: Screen Shot 2021-10-13 at 3 56 47 PM

It thinks it's an array of strings.

I thought I might be defining the tuple incorrectly, because of the dropped array mentioned earlier, so I tried a work around:

/**
 * @typedef {array} CoordinateArray
 * @property {number} - 0: The valid numbers for Longitude are between -180 and 180
 * @property {number} - 1: The valid numbers for Latitude are between -90 and 90
 * @property {number} - 2: The valid numbers for Altitude is a number greater than or equal to 0
 * 
 */

But then it comes out as an object instead of an array... that's no good.

So I tried doing this:

/**
 * Index 0: The valid numbers for Longitude are between -180 and 180
 * Index 1: The valid numbers for Latitude are between -90 and 90
 * Index 2: The valid numbers for Altitude is a number greater than or equal to 0
 * @typedef {[number, number, number][]} CoordinateArray
 */
/**
 * @typedef {object} GeoJSON
 * @property {string} type - enum:MultiLineString - the GeoJSON type
 * @property {array<array<CoordinateArray>>} coordinates - the coordinates to the location
 */

Adding brackets to the typedef for CoordinateArray, but it yields the same result as the "broken" screenshot.

At this point, I believe this is a bug with express-jsdoc-swagger, or maybe I'm doing something wrong?

To Reproduce

/**
 * Index 0: The valid numbers for Longitude are between -180 and 180
 * Index 1: The valid numbers for Latitude are between -90 and 90
 * Index 2: The valid numbers for Altitude is a number greater than or equal to 0
 * @typedef {[number, number, number]} CoordinateArray
 */
/**
 * @typedef {object} GeoJSON
 * @property {string} type - enum:MultiLineString - the GeoJSON type
 * @property {array<array<array<CoordinateArray>>>} coordinates - the coordinates to the location
 */

Expected behavior I would expect to see this in Swagger UI:

{
  "id": 0,
  "id_user": 0,
  "geom": {
    "type": "MultiLineString",
    "coordinates": [
      [
        [
           0,
           0,
           0,
         ]
      ]
    ]
  },
  "title": "string",
  "notes": "string",
  "created_at": "2021-10-13T21:56:36.600Z",
  "updated_at": "2021-10-13T21:56:36.600Z"
}

Which would be equivalent to [number, number, number][][]. I'd love to define min and max values on the tuple but I'll settle for anything that unblocks me and would enable me to use the validation package y'all wrote.

Screenshots When the coordinates property is {array<array<CoordinateArray>>} it works great, see the image: Screen Shot 2021-10-13 at 3 56 07 PM

When I add one more dimension (required for GeoJSON), it breaks in a confusing way: Screen Shot 2021-10-13 at 3 56 47 PM

Desktop (please complete the following information):

Additional context Nope, nothing that I can think of

mrclean-oa commented 2 years ago

This JSDoc issue resolves 2D arrays, yet it is still seems present, since CoordinateArray[][] does not even render the coordinates key when I use bracket notation.

mrclean-oa commented 2 years ago

If it helps for debugging I manually ran doctrine (using the one installed by express-jsdoc-swagger):

const doctrine = require('doctrine');

var ast = doctrine.parse(
  `/**
    * Index 0 is Longitude - The valid numbers for Longitude are between -180 and 180.
    * Index 1 is Latitude - The valid numbers for Latitude are between -90 and 90.
    * Index 2 is Altitude - The valid numbers for Altitude is a number greater than or equal to 0.
    * @typedef {[integer, integer, integer]} CoordinateArray
    */
  /**
   * GeoJSON is a format for encoding a variety of geographic data structures using JavaScript Object Notation (JSON).
   * @typedef {object} GeoJSON
   * @property {string} type - enum:MultiLineString,Point,Position,MultiPoint,LineString,Polygon,MultiPolygon,GeometryCollection - the GeoJSON type
   * @property {array<array<CoordinatesArray>>} coordinates - the coordinates to the location
   */`,
  { unwrap: true }
);

console.log(JSON.stringify(ast, null, 2));

And got this result:

{
  "description": "Index 0 is Longitude - The valid numbers for Longitude are between -180 and 180.\nIndex 1 is Latitude - The valid numbers for Latitude are between -90 and 90.\nIndex 2 is Altitude - The valid numbers for Altitude is a number greater than or equal to 0.",
  "tags": [
    {
      "title": "typedef",
      "description": null,
      "type": {
        "type": "ArrayType",
        "elements": [
          {
            "type": "NameExpression",
            "name": "integer"
          },
          {
            "type": "NameExpression",
            "name": "integer"
          },
          {
            "type": "NameExpression",
            "name": "integer"
          }
        ]
      },
      "name": "CoordinateArray"
    },
    {
      "title": "typedef",
      "description": null,
      "type": {
        "type": "NameExpression",
        "name": "object"
      },
      "name": "GeoJSON"
    },
    {
      "title": "property",
      "description": "enum:MultiLineString,Point,Position,MultiPoint,LineString,Polygon,MultiPolygon,GeometryCollection - the GeoJSON type",
      "type": {
        "type": "NameExpression",
        "name": "string"
      },
      "name": "type"
    },
    {
      "title": "property",
      "description": "the coordinates to the location",
      "type": {
        "type": "TypeApplication",
        "expression": {
          "type": "NameExpression",
          "name": "array"
        },
        "applications": [
          {
            "type": "TypeApplication",
            "expression": {
              "type": "NameExpression",
              "name": "array"
            },
            "applications": [
              {
                "type": "NameExpression",
                "name": "CoordinatesArray"
              }
            ]
          }
        ]
      },
      "name": "coordinates"
    }
  ]
}

I don't know how to judge the result, but would be happy to close this if it appears to be a doctrine problem.