Repository: BRIKEV/express-jsdoc-swagger (js)

Issue:
[Enhancement] Components property Array of other components
**Is your feature request related to a problem? Please describe.**
We fixed the problem with multiple primitive types on one property in this commit https://github.com/BRIKEV/express-jsdoc-swagger/commit/b2bd217b341102d40f2fa89e6d2d68f54e680a84 but we need to do the same for Components references. It should be similar like we do in [schemas](https://github.com/BRIKEV/express-jsdoc-swagger/blob/master/transforms/paths/schema.js) 

**Describe the solution you'd like**
We need to display and Album schema with an Array of Songs schemas.


Pull request description:
Components array refs
### What kind of change does this PR introduce? (check at least one)
 - [ ] Bugfix
 - [x] Feature
 - [x] Test
 - [x] Docs
 - [x] Refactor
 - [ ] Build-related changes
 - [ ] Other, please describe:

### Description:
This PR fixes #62 

Patch:
diff --git a/examples/components/simple.js b/examples/components/simple.js
index 7f13549..edbb5b6 100644
--- a/examples/components/simple.js
+++ b/examples/components/simple.js
@@ -49,4 +49,10 @@ expressJSDocSwagger(app)(options);
  * @property {array<number>} years
  */
 
+/**
+ * Album
+ * @typedef {object} Album
+ * @property {array<Song>} Songs
+ */
+
 app.listen(port, () => logger.info(`Example app listening at http://localhost:${port}`));
diff --git a/transforms/components/index.js b/transforms/components/index.js
index d290922..73f353d 100644
--- a/transforms/components/index.js
+++ b/transforms/components/index.js
@@ -1,6 +1,6 @@
 const { getTagInfo, getTagsInfo } = require('../utils/tags');
 const mapDescription = require('../utils/mapDescription');
-const refSchema = require('../utils/refSchema');
+const { refSchema, formatRefSchema } = require('../utils/refSchema');
 const addEnumValues = require('../utils/enumValues');
 const formatDescription = require('../utils/formatDescription');
 const combineSchema = require('../utils/combineSchema');
@@ -22,21 +22,28 @@ const addTypeApplication = (applications, expression) => {
   };
 };
 
+const addRefSchema = (typeName, applications, elements) => {
+  if (!typeName && !elements) return { items: formatRefSchema(applications) };
+  return {};
+};
+
 const formatProperties = properties => {
   if (!properties || !Array.isArray(properties)) return {};
   return properties.reduce((acum, property) => {
     const name = getPropertyName(property);
-    const { name: typeName, applications, expression } = property.type;
-    const type = typeName;
+    const {
+      name: typeName, applications, expression, elements,
+    } = property.type;
     const [descriptionValue, enumValues] = formatDescription(property.description);
     const [description, format] = mapDescription(descriptionValue);
     return {
       ...acum,
       [name]: {
         description,
-        ...refSchema(type),
-        ...combineSchema(property.type.elements),
+        ...refSchema(typeName),
+        ...combineSchema(elements),
         ...addTypeApplication(applications, expression),
+        ...addRefSchema(typeName, applications, elements),
         ...(format ? { format } : {}),
         ...addEnumValues(enumValues),
       },
diff --git a/transforms/paths/schema.js b/transforms/paths/schema.js
index 8a6d456..f319dfc 100644
--- a/transforms/paths/schema.js
+++ b/transforms/paths/schema.js
@@ -2,7 +2,7 @@ const chalk = require('chalk');
 
 const combineSchema = require('../utils/combineSchema');
 const addEnumValues = require('../utils/enumValues');
-const refSchema = require('../utils/refSchema');
+const { refSchema, formatRefSchema } = require('../utils/refSchema');
 
 const getSchema = (entity, message) => (type, enumValues = []) => {
   if (!type) {
@@ -20,11 +20,7 @@ const getSchema = (entity, message) => (type, enumValues = []) => {
   };
   const notPrimitiveType = !nameType;
   if (notPrimitiveType && !type.elements) {
-    const items = type.applications || [];
-    const parseItems = items.reduce((itemAcc, itemTypes) => ({
-      ...itemAcc,
-      ...refSchema(itemTypes.name),
-    }), {});
+    const parseItems = formatRefSchema(type.applications);
     schema = {
       ...schema,
       type: type.expression.name,
diff --git a/transforms/utils/combineSchema.js b/transforms/utils/combineSchema.js
index 96af318..cad24b4 100644
--- a/transforms/utils/combineSchema.js
+++ b/transforms/utils/combineSchema.js
@@ -1,5 +1,5 @@
 const chalk = require('chalk');
-const refSchema = require('./refSchema');
+const { refSchema } = require('./refSchema');
 
 const VALID_TYPES = ['oneOf', 'anyOf', 'allOf'];
 
diff --git a/transforms/utils/refSchema.js b/transforms/utils/refSchema.js
index 904e9c8..03783af 100644
--- a/transforms/utils/refSchema.js
+++ b/transforms/utils/refSchema.js
@@ -9,4 +9,12 @@ const refSchema = value => {
   return schema;
 };
 
-module.exports = refSchema;
+const formatRefSchema = (applications = []) => applications.reduce((itemAcc, itemTypes) => ({
+  ...itemAcc,
+  ...refSchema(itemTypes.name),
+}), {});
+
+module.exports = {
+  refSchema,
+  formatRefSchema,
+};


Test patch:
diff --git a/test/transforms/components/index.test.js b/test/transforms/components/index.test.js
index b95e71f..97fb4b8 100644
--- a/test/transforms/components/index.test.js
+++ b/test/transforms/components/index.test.js
@@ -612,4 +612,37 @@ describe('parseComponents method', () => {
     const result = parseComponents({}, parsedJSDocs);
     expect(result).toEqual(expected);
   });
+
+  it('Should parse an album schema with an array of Songs schemas.', () => {
+    const jsodInput = [`
+      /**
+       * Album
+       * @typedef {object} Album
+       * @property {array<Song>} Songs
+       */
+    `];
+    const expected = {
+      components: {
+        schemas: {
+          Album: {
+            type: 'object',
+            required: [],
+            description: 'Album',
+            properties: {
+              Songs: {
+                type: 'array',
+                description: '',
+                items: {
+                  $ref: '#/components/schemas/Song',
+                },
+              },
+            },
+          },
+        },
+      },
+    };
+    const parsedJSDocs = jsdocInfo()(jsodInput);
+    const result = parseComponents({}, parsedJSDocs);
+    expect(result).toEqual(expected);
+  });
 });