Repository: glennjones/hapi-swagger
Pull request #692 (2020-12-30 00:15:04)

Fix for issue #323 - .date() vs .date().isoDate()
Adding support for:

Joi.date().iso() -> { type: 'string', format: 'date-time' }
Joi.date().timestamp() -> { type: 'integer' }
Joi.date()-> { type: 'string', format: 'date' } // original behavior

I'd appreciate it if someone who knows the differences between Joi versions took a look at the way the Joi.date() format is detected. The old code didn't seem correct for the version i'm using. I left in a bit of backward compatibility.

sorry about the code format - `eslint --fix` did it's work :(


Patch:
diff --git a/lib/properties.js b/lib/properties.js
index 8ae12cc..186bfd0 100644
--- a/lib/properties.js
+++ b/lib/properties.js
@@ -152,12 +152,21 @@ internals.properties.prototype.parseProperty = function(name, joiObj, parent, pa
       let objectPattern = joiObj.$_terms.patterns[0];
       let patternName = 'string';
       if (objectPattern.schema) {
-        patternName = objectPattern.schema.$_terms.examples
-        && objectPattern.schema.$_terms.examples[0] ? objectPattern.schema.$_terms.examples[0] : objectPattern.schema.type;
+        patternName =
+          objectPattern.schema.$_terms.examples && objectPattern.schema.$_terms.examples[0]
+            ? objectPattern.schema.$_terms.examples[0]
+            : objectPattern.schema.type;
       }
       property.name = name;
       property.properties = {
-        [patternName]: this.parseProperty(patternName, objectPattern.rule, property, parameterType, useDefinitions, isAlt),
+        [patternName]: this.parseProperty(
+          patternName,
+          objectPattern.rule,
+          property,
+          parameterType,
+          useDefinitions,
+          isAlt
+        )
       };
     } else {
       // default empty object
@@ -356,16 +365,24 @@ internals.properties.prototype.parseNumber = function(property, joiObj) {
 };
 
 /**
- * parse date property
+ * parse date property - adds additional schema info based on Joi date formats
  *
  * @param  {Object} property
  * @param  {Object} joiObj
  * @return {Object}
  */
 internals.properties.prototype.parseDate = function(property, joiObj) {
-  if (joiObj._flags.timestamp) {
-    property.type = 'number';
+  const dateFormat = Hoek.reach(joiObj, '_flags.format');
+
+  if (dateFormat === 'timestamp' || dateFormat === 'javascript') {
+    // Seems like the exact name of the format differs for different versions of Joi
+    // Javascript is what is set by Joi.date().timestamp()
+    property.type = 'integer';
     delete property.format;
+  } else if (dateFormat === 'iso') {
+    // Joi.date().iso()
+    property.type = 'string';
+    property.format = 'date-time';
   }
 
   return property;
@@ -384,7 +401,7 @@ internals.properties.prototype.parseDate = function(property, joiObj) {
 internals.properties.prototype.parseObject = function(property, joiObj, name, parameterType, useDefinitions, isAlt) {
   property.properties = {};
 
-  joiObj._ids._byKey.forEach((obj) => {
+  joiObj._ids._byKey.forEach(obj => {
     let keyName = obj.id;
     let itemName = obj.id;
     let joiChildObj = obj.schema;
@@ -634,7 +651,7 @@ internals.getArgByName = function(array, name, key = undefined) {
             return Object.values(array[i].args)[0];
           }
         } else {
-          return true
+          return true;
         }
       }
     }


Test patch:
diff --git a/test/unit/property-test.js b/test/unit/property-test.js
index 2439adc..e5db1c7 100644
--- a/test/unit/property-test.js
+++ b/test/unit/property-test.js
@@ -138,9 +138,10 @@ lab.experiment('property - ', () => {
       type: 'string',
       enum: ['a', 'b']
     });
-    expect(
-      propertiesNoAlt.parseProperty('x', Joi.string().valid('a', 'b', null), null, 'body', true, false)
-    ).to.equal({ type: 'string', enum: ['a', 'b'] });
+    expect(propertiesNoAlt.parseProperty('x', Joi.string().valid('a', 'b', null), null, 'body', true, false)).to.equal({
+      type: 'string',
+      enum: ['a', 'b']
+    });
     expect(
       propertiesNoAlt.parseProperty(
         'x',
@@ -215,7 +216,7 @@ lab.experiment('property - ', () => {
     // and make sure we omit any regex flags (g, i, m) from the
     // resulting pattern
     expect(
-      propertiesNoAlt.parseProperty('x', Joi.string().regex(/^https:\/\/test.com/mi), null, 'body', true, false)
+      propertiesNoAlt.parseProperty('x', Joi.string().regex(/^https:\/\/test.com/im), null, 'body', true, false)
     ).to.equal({
       type: 'string',
       pattern: '^https:\\/\\/test.com'
@@ -395,7 +396,15 @@ lab.experiment('property - ', () => {
   lab.test('parse type date timestamp', () => {
     clearDown();
     expect(propertiesNoAlt.parseProperty('x', Joi.date().timestamp(), null, 'body', true, false)).to.equal({
-      format: 'date', type: 'string'
+      type: 'integer'
+    });
+  });
+
+  lab.test('parse type date iso', () => {
+    clearDown();
+    expect(propertiesNoAlt.parseProperty('x', Joi.date().iso(), null, 'body', true, false)).to.equal({
+      type: 'string',
+      format: 'date-time'
     });
   });
 
@@ -582,7 +591,9 @@ lab.test('parse type object', () => {
   clearDown();
   //console.log(JSON.stringify( propertiesNoAlt.parseProperty('x', Joi.object(), {}, {}, 'formData')  ));
   expect(propertiesNoAlt.parseProperty('x', Joi.object(), null, 'body', false, false)).to.equal({ type: 'object' });
-  expect(propertiesNoAlt.parseProperty('x', Joi.object().keys(), null, 'body', false, false)).to.equal({ type: 'object' });
+  expect(propertiesNoAlt.parseProperty('x', Joi.object().keys(), null, 'body', false, false)).to.equal({
+    type: 'object'
+  });
   expect(
     propertiesNoAlt.parseProperty('x', Joi.object().keys({ a: Joi.string() }), null, 'body', false, false)
   ).to.equal({
@@ -613,9 +624,21 @@ lab.test('parse type object', () => {
     }
   });
   // test without pattern schema example
-  expect(propertiesNoAlt.parseProperty('x', Joi.object().pattern(Joi.string(), Joi.object({
-    y: Joi.string()
-  })), null, 'body', false, false)).to.equal({
+  expect(
+    propertiesNoAlt.parseProperty(
+      'x',
+      Joi.object().pattern(
+        Joi.string(),
+        Joi.object({
+          y: Joi.string()
+        })
+      ),
+      null,
+      'body',
+      false,
+      false
+    )
+  ).to.equal({
     name: 'x',
     type: 'object',
     properties: {
@@ -623,7 +646,7 @@ lab.test('parse type object', () => {
         name: 'string',
         type: 'object',
         properties: {
-          'y': {
+          y: {
             type: 'string'
           }
         }
@@ -631,9 +654,21 @@ lab.test('parse type object', () => {
     }
   });
   // test with pattern schema example
-  expect(propertiesNoAlt.parseProperty('x', Joi.object().pattern(Joi.string().example('a'), Joi.object({
-    y: Joi.string()
-  })), null, 'body', false, false)).to.equal({
+  expect(
+    propertiesNoAlt.parseProperty(
+      'x',
+      Joi.object().pattern(
+        Joi.string().example('a'),
+        Joi.object({
+          y: Joi.string()
+        })
+      ),
+      null,
+      'body',
+      false,
+      false
+    )
+  ).to.equal({
     name: 'x',
     type: 'object',
     properties: {
@@ -641,7 +676,7 @@ lab.test('parse type object', () => {
         name: 'a',
         type: 'object',
         properties: {
-          'y': {
+          y: {
             type: 'string'
           }
         }
@@ -649,9 +684,21 @@ lab.test('parse type object', () => {
     }
   });
   // test with regex as pattern
-  expect(propertiesNoAlt.parseProperty('x', Joi.object().pattern(/\w\d/, Joi.object({
-    y: Joi.string()
-  })), null, 'body', false, false)).to.equal({
+  expect(
+    propertiesNoAlt.parseProperty(
+      'x',
+      Joi.object().pattern(
+        /\w\d/,
+        Joi.object({
+          y: Joi.string()
+        })
+      ),
+      null,
+      'body',
+      false,
+      false
+    )
+  ).to.equal({
     name: 'x',
     type: 'object',
     properties: {
@@ -659,7 +706,7 @@ lab.test('parse type object', () => {
         name: 'string',
         type: 'object',
         properties: {
-          'y': {
+          y: {
             type: 'string'
           }
         }