Repository: BRIKEV/express-jsdoc-swagger
Pull request #3 (2020-05-29 17:43:00)

Tags
Added:
 - Tags transformation
 - Tags into paths transformation


Patch:
diff --git a/transforms/paths/index.js b/transforms/paths/index.js
index dc0b0f8..787dcf0 100644
--- a/transforms/paths/index.js
+++ b/transforms/paths/index.js
@@ -3,6 +3,8 @@ const responsesGenerator = require('./responses');
 const parametersGenerator = require('./parameters');
 const { getTagInfo, getTagsInfo } = require('../utils/tags');
 
+const formatTags = (tags = []) => tags.map(({ description: name }) => name);
+
 const parsePath = path => {
   debug(`Transforms path: ${JSON.stringify(path)}`);
   if (!path.description || !path.tags) return {};
@@ -14,6 +16,7 @@ const parsePath = path => {
   const summary = getTagInfo(tags, 'summary');
   const returnValues = getTagsInfo(tags, 'return');
   const paramValues = getTagsInfo(tags, 'param');
+  const tagsValues = getTagsInfo(tags, 'tags');
   const responses = responsesGenerator(returnValues);
   const parameters = parametersGenerator(paramValues);
   return {
@@ -22,6 +25,7 @@ const parsePath = path => {
         summary: summary && summary.description ? summary.description : '',
         responses,
         parameters,
+        tags: formatTags(tagsValues),
       },
     },
   };
diff --git a/transforms/tags/index.js b/transforms/tags/index.js
new file mode 100644
index 0000000..087a512
--- /dev/null
+++ b/transforms/tags/index.js
@@ -0,0 +1,27 @@
+const { flatArray, getIndexBy } = require('../utils/arrays');
+
+const FILTER_TAG_KEY = 'name';
+
+const formatTags = ({ tags = [] }) => tags.map(tag => {
+  const [name, description] = tag.description.split(' - ');
+  return {
+    name,
+    description,
+  };
+});
+
+const filterDuplicateTags = tags => (
+  tags.filter(({ name }, i) => getIndexBy(tags, FILTER_TAG_KEY, name) === i)
+);
+
+const parseTags = (swaggerObject = {}, data) => {
+  if (!data || !Array.isArray(data)) return { tags: [] };
+  const tags = flatArray(data.map(formatTags));
+  const uniqTags = filterDuplicateTags(tags);
+  return {
+    ...swaggerObject,
+    tags: uniqTags,
+  };
+};
+
+module.exports = parseTags;
diff --git a/transforms/utils/arrays.js b/transforms/utils/arrays.js
new file mode 100644
index 0000000..cfd352c
--- /dev/null
+++ b/transforms/utils/arrays.js
@@ -0,0 +1,13 @@
+
+const flatArray = elements => (
+  elements.reduce((acc, val) => acc.concat(val), [])
+);
+
+const getIndexBy = (elements, key, value) => (
+  elements.findIndex(element => element[key] === value)
+);
+
+module.exports = {
+  flatArray,
+  getIndexBy,
+};


Test patch:
diff --git a/test/transforms/paths/index.test.js b/test/transforms/paths/index.test.js
index ff6b29c..02f7aaf 100644
--- a/test/transforms/paths/index.test.js
+++ b/test/transforms/paths/index.test.js
@@ -36,6 +36,7 @@ describe('setPaths method', () => {
           get: {
             summary: 'This is the summary or description of the endpoint',
             parameters: [],
+            tags: [],
             responses: {
               200: {
                 description: 'success response',
@@ -71,6 +72,7 @@ describe('setPaths method', () => {
             get: {
               summary: '',
               responses: {},
+              tags: [],
               parameters: [{
                 allowEmptyValue: false,
                 deprecated: false,
@@ -104,6 +106,7 @@ describe('setPaths method', () => {
             get: {
               summary: '',
               responses: {},
+              tags: [],
               parameters: [],
             },
           },
@@ -127,6 +130,7 @@ describe('setPaths method', () => {
             get: {
               summary: '',
               responses: {},
+              tags: [],
               parameters: [{
                 allowEmptyValue: false,
                 deprecated: true,
@@ -164,6 +168,7 @@ describe('setPaths method', () => {
             get: {
               summary: '',
               responses: {},
+              tags: [],
               parameters: [{
                 allowEmptyValue: false,
                 deprecated: true,
@@ -214,6 +219,7 @@ describe('setPaths method', () => {
             get: {
               summary: 'This is the summary or description of the endpoint',
               parameters: [],
+              tags: [],
               responses: {
                 200: {
                   description: 'success response',
@@ -261,6 +267,7 @@ describe('setPaths method', () => {
               summary: 'This is the summary or description of the endpoint',
               responses: {},
               parameters: [],
+              tags: [],
             },
           },
         },
@@ -286,6 +293,7 @@ describe('setPaths method', () => {
             get: {
               summary: 'This is the summary or description of the endpoint',
               parameters: [],
+              tags: [],
               responses: {
                 200: {
                   description: 'success response',
diff --git a/test/transforms/paths/tags.test.js b/test/transforms/paths/tags.test.js
new file mode 100644
index 0000000..b56ae96
--- /dev/null
+++ b/test/transforms/paths/tags.test.js
@@ -0,0 +1,58 @@
+const jsdocInfo = require('../../../consumers/jsdocInfo');
+const setPaths = require('../../../transforms/paths');
+
+describe('Paths - tags', () => {
+  it('Should parse jsdoc tags params into array with tag name', () => {
+    const jsodInput = [`
+      /**
+       * GET /api/v1
+       * @tags album
+       */
+    `];
+    const expected = {
+      paths: {
+        '/api/v1': {
+          get: {
+            summary: '',
+            tags: [
+              'album',
+            ],
+            responses: {},
+            parameters: [],
+          },
+        },
+      },
+    };
+    const parsedJSDocs = jsdocInfo()(jsodInput);
+    const result = setPaths({}, parsedJSDocs);
+    expect(result).toEqual(expected);
+  });
+
+  it('Should parse jsdoc multiple tags params into array of tags', () => {
+    const jsodInput = [`
+      /**
+       * GET /api/v1
+       * @tags album
+       * @tags Years
+       */
+    `];
+    const expected = {
+      paths: {
+        '/api/v1': {
+          get: {
+            summary: '',
+            tags: [
+              'album',
+              'Years',
+            ],
+            responses: {},
+            parameters: [],
+          },
+        },
+      },
+    };
+    const parsedJSDocs = jsdocInfo()(jsodInput);
+    const result = setPaths({}, parsedJSDocs);
+    expect(result).toEqual(expected);
+  });
+});
diff --git a/test/transforms/tags/index.test.js b/test/transforms/tags/index.test.js
new file mode 100644
index 0000000..5f5a2dc
--- /dev/null
+++ b/test/transforms/tags/index.test.js
@@ -0,0 +1,90 @@
+const jsdocInfo = require('../../../consumers/jsdocInfo');
+const parseTags = require('../../../transforms/tags');
+
+describe('parseTags method', () => {
+  it('should return empty tags array with not params', () => {
+    const initialState = {};
+    const tags = undefined;
+    const expected = {
+      tags: [],
+    };
+    const result = parseTags(initialState, tags);
+    expect(result).toEqual(expected);
+  });
+
+  it('should return empty tags array with not an array as parameter', () => {
+    const initialState = {};
+    const tags = 2;
+    const expected = {
+      tags: [],
+    };
+    const result = parseTags(initialState, tags);
+    expect(result).toEqual(expected);
+  });
+
+  it('Should parse jsdoc tags into tags array with name and description', () => {
+    const jsodInput = [`
+      /**
+       * GET /api/v1/album
+       * @tags album - album tag description
+       */
+    `,
+    `
+      /**
+       * GET /api/v1/artists
+       * @tags artist - artist tag description
+       */
+    `];
+    const expected = {
+      tags: [
+        {
+          name: 'album',
+          description: 'album tag description',
+        },
+        {
+          name: 'artist',
+          description: 'artist tag description',
+        },
+      ],
+    };
+    const parsedJSDocs = jsdocInfo()(jsodInput);
+    const result = parseTags({}, parsedJSDocs);
+    expect(result).toEqual(expected);
+  });
+
+  it('Should parse jsdoc tags into tags array without duplicate tags', () => {
+    const jsodInput = [`
+      /**
+       * GET /api/v1/album
+       * @tags album - album tag description
+       */
+    `,
+    `
+      /**
+       * GET /api/v1/years
+       * @tags artist - artist tag description
+       */
+    `,
+    `
+      /**
+       * GET /api/v1/artists
+       * @tags artist - artist tag description
+       */
+    `];
+    const expected = {
+      tags: [
+        {
+          name: 'album',
+          description: 'album tag description',
+        },
+        {
+          name: 'artist',
+          description: 'artist tag description',
+        },
+      ],
+    };
+    const parsedJSDocs = jsdocInfo()(jsodInput);
+    const result = parseTags({}, parsedJSDocs);
+    expect(result).toEqual(expected);
+  });
+});