From 85b173d19eedcf98324242ac48081fbb88136d3b Mon Sep 17 00:00:00 2001 From: CD Cabrera Date: Thu, 16 Feb 2023 01:33:32 -0500 Subject: [PATCH] refactor(buildDocs): consolidate setupDocs (#214) * index, move setupDocs, case CACHE * buildDocs, consolidate setup, build docs funcs --- .../__snapshots__/index.test.js.snap | 46 ---------- src/__tests__/index.test.js | 81 +----------------- .../__snapshots__/buildDocs.test.js.snap | 47 ++++++++++- src/docs/__tests__/buildDocs.test.js | 84 ++++++++++++++++++- src/docs/buildDocs.js | 45 ++++++---- src/index.js | 49 +++-------- src/logger/configLogger.js | 5 ++ 7 files changed, 173 insertions(+), 184 deletions(-) delete mode 100644 src/__tests__/__snapshots__/index.test.js.snap diff --git a/src/__tests__/__snapshots__/index.test.js.snap b/src/__tests__/__snapshots__/index.test.js.snap deleted file mode 100644 index 6ef820f..0000000 --- a/src/__tests__/__snapshots__/index.test.js.snap +++ /dev/null @@ -1,46 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ApiDocMock should handle additional response content types: html mock 1`] = ` -{ - "error": undefined, - "filename": "html.js", - "group": undefined, - "groupTitle": undefined, - "name": "GetHelloWorldHtmlHtml", - "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n\\n\\n hello\\n world\\n","type":"html"}]}", - "title": "", - "type": "get", - "url": "/hello/world/html.html", - "version": "0.0.0", -} -`; - -exports[`ApiDocMock should handle additional response content types: svg mock 1`] = ` -{ - "error": undefined, - "filename": "svg.js", - "group": undefined, - "groupTitle": undefined, - "name": "GetHelloWorldSvgSvg", - "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n\\n\\n\\n\\n","type":"svg"}]}", - "title": "", - "type": "get", - "url": "/hello/world/svg.svg", - "version": "0.0.0", -} -`; - -exports[`ApiDocMock should setup api docs and create a predictable output: setupDocs 1`] = ` -{ - "error": "{"examples":[{"title":"Error-Response:","content":"HTTP/1.1 400 OK\\n{\\n \\"error\\": \\"test\\"\\n}","type":"json"}]}", - "filename": "test.js", - "group": undefined, - "groupTitle": undefined, - "name": "GetHelloWorld", - "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n{\\n \\"success\\": \\"test\\"\\n}","type":"json"}]}", - "title": "", - "type": "get", - "url": "/hello/world/", - "version": "0.0.0", -} -`; diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index e009036..8a24b6e 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -1,10 +1,8 @@ -const { apiDocMock, setupDocs, setupResponse } = require('../'); -const { OPTIONS } = require('../global'); +const { apiDocMock, setupResponse } = require('../'); describe('ApiDocMock', () => { it('should have specific defined properties', () => { expect(apiDocMock).toBeDefined(); - expect(setupDocs).toBeDefined(); expect(setupResponse).toBeDefined(); }); @@ -12,83 +10,6 @@ describe('ApiDocMock', () => { expect(setupResponse()).toBe(null); }); - it('should setup api docs and create a predictable output', () => { - const apiFixture = generateFixture( - `/** - * @api {get} /hello/world/ - * @apiSuccessExample {json} Success-Response: - * HTTP/1.1 200 OK - * { - * "success": "test" - * } - * @apiErrorExample {json} Error-Response: - * HTTP/1.1 400 OK - * { - * "error": "test" - * } - */`, - { dir: './.fixtures/predictable', filename: 'test.js' } - ); - - const [helloWorld] = setupDocs({ ...OPTIONS, watchPath: [apiFixture.dir], docsPath: 'lorem-ipsum' }); - - expect({ - ...helloWorld, - success: JSON.stringify(helloWorld.success), - error: JSON.stringify(helloWorld.error), - group: undefined, - groupTitle: undefined - }).toMatchSnapshot('setupDocs'); - }); - - it('should handle additional response content types', () => { - const htmlFixture = generateFixture( - `/** - * @api {get} /hello/world/html.html - * @apiSuccessExample {html} Success-Response: - * HTTP/1.1 200 OK - * - * - * hello - * world - * - */`, - { dir: './.fixtures/content-types', filename: 'html.js' } - ); - - generateFixture( - `/** - * @api {get} /hello/world/svg.svg - * @apiSuccessExample {svg} Success-Response: - * HTTP/1.1 200 OK - * - * - * - * - * - */`, - { dir: './.fixtures/content-types', filename: 'svg.js', resetDir: false } - ); - - const [html, svg] = setupDocs({ ...OPTIONS, watchPath: [htmlFixture.dir], docsPath: 'lorem-ipsum' }); - - expect({ - ...html, - success: JSON.stringify(html.success), - error: JSON.stringify(html.error), - group: undefined, - groupTitle: undefined - }).toMatchSnapshot('html mock'); - - expect({ - ...svg, - success: JSON.stringify(svg.success), - error: JSON.stringify(svg.error), - group: undefined, - groupTitle: undefined - }).toMatchSnapshot('svg mock'); - }); - it('should throw an error during testing', async () => { const func = async () => apiDocMock(); await expect(func).rejects.toThrow('Server failed to load'); diff --git a/src/docs/__tests__/__snapshots__/buildDocs.test.js.snap b/src/docs/__tests__/__snapshots__/buildDocs.test.js.snap index 195c844..e478180 100644 --- a/src/docs/__tests__/__snapshots__/buildDocs.test.js.snap +++ b/src/docs/__tests__/__snapshots__/buildDocs.test.js.snap @@ -1,3 +1,48 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`BuildDocs should fail a build gracefully: fail 1`] = `{}`; +exports[`BuildDocs should fail a build gracefully: fail 1`] = `[]`; + +exports[`BuildDocs should handle additional response content types: html mock 1`] = ` +{ + "error": undefined, + "filename": "html.js", + "group": undefined, + "groupTitle": undefined, + "name": "GetHelloWorldHtmlHtml", + "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n\\n\\n hello\\n world\\n","type":"html"}]}", + "title": "", + "type": "get", + "url": "/hello/world/html.html", + "version": "0.0.0", +} +`; + +exports[`BuildDocs should handle additional response content types: svg mock 1`] = ` +{ + "error": undefined, + "filename": "svg.js", + "group": undefined, + "groupTitle": undefined, + "name": "GetHelloWorldSvgSvg", + "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n\\n\\n\\n\\n","type":"svg"}]}", + "title": "", + "type": "get", + "url": "/hello/world/svg.svg", + "version": "0.0.0", +} +`; + +exports[`BuildDocs should setup api docs and create a predictable output: setupDocs 1`] = ` +{ + "error": "{"examples":[{"title":"Error-Response:","content":"HTTP/1.1 400 OK\\n{\\n \\"error\\": \\"test\\"\\n}","type":"json"}]}", + "filename": "test.js", + "group": undefined, + "groupTitle": undefined, + "name": "GetHelloWorld", + "success": "{"examples":[{"title":"Success-Response:","content":"HTTP/1.1 200 OK\\n{\\n \\"success\\": \\"test\\"\\n}","type":"json"}]}", + "title": "", + "type": "get", + "url": "/hello/world/", + "version": "0.0.0", +} +`; diff --git a/src/docs/__tests__/buildDocs.test.js b/src/docs/__tests__/buildDocs.test.js index fce9b64..9df4150 100644 --- a/src/docs/__tests__/buildDocs.test.js +++ b/src/docs/__tests__/buildDocs.test.js @@ -1,11 +1,89 @@ -const { buildDocs } = require('../buildDocs'); +const { setupDocs } = require('../buildDocs'); +const { OPTIONS } = require('../../global'); describe('BuildDocs', () => { it('should have specific defined properties', () => { - expect(buildDocs).toBeDefined(); + expect(setupDocs()).toBeDefined(); }); it('should fail a build gracefully', () => { - expect(buildDocs({})).toMatchSnapshot('fail'); + expect(setupDocs({})).toMatchSnapshot('fail'); + }); + + it('should setup api docs and create a predictable output', () => { + const apiFixture = generateFixture( + `/** + * @api {get} /hello/world/ + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "success": "test" + * } + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "error": "test" + * } + */`, + { dir: './.fixtures/predictable', filename: 'test.js' } + ); + + const [helloWorld] = setupDocs({ ...OPTIONS, watchPath: [apiFixture.dir], docsPath: 'lorem-ipsum' }); + + expect({ + ...helloWorld, + success: JSON.stringify(helloWorld.success), + error: JSON.stringify(helloWorld.error), + group: undefined, + groupTitle: undefined + }).toMatchSnapshot('setupDocs'); + }); + + it('should handle additional response content types', () => { + const htmlFixture = generateFixture( + `/** + * @api {get} /hello/world/html.html + * @apiSuccessExample {html} Success-Response: + * HTTP/1.1 200 OK + * + * + * hello + * world + * + */`, + { dir: './.fixtures/content-types', filename: 'html.js' } + ); + + generateFixture( + `/** + * @api {get} /hello/world/svg.svg + * @apiSuccessExample {svg} Success-Response: + * HTTP/1.1 200 OK + * + * + * + * + * + */`, + { dir: './.fixtures/content-types', filename: 'svg.js', resetDir: false } + ); + + const [html, svg] = setupDocs({ ...OPTIONS, watchPath: [htmlFixture.dir], docsPath: 'lorem-ipsum' }); + + expect({ + ...html, + success: JSON.stringify(html.success), + error: JSON.stringify(html.error), + group: undefined, + groupTitle: undefined + }).toMatchSnapshot('html mock'); + + expect({ + ...svg, + success: JSON.stringify(svg.success), + error: JSON.stringify(svg.error), + group: undefined, + groupTitle: undefined + }).toMatchSnapshot('svg mock'); }); }); diff --git a/src/docs/buildDocs.js b/src/docs/buildDocs.js index 1bcfcf2..df7c67d 100644 --- a/src/docs/buildDocs.js +++ b/src/docs/buildDocs.js @@ -1,26 +1,39 @@ const apidoc = require('apidoc'); const { logger } = require('../logger/configLogger'); +const { OPTIONS } = require('../global'); /** - * Compile/build ApiDoc documentation. + * Build ApiDoc documentation. * - * @param {object} params - * @param {object} params.apiDocsConfig - * @returns {object} + * @param {object} options + * @param {OPTIONS.apiDocBaseConfig} options.apiDocBaseConfig + * @param {string[]} options.watchPath + * @param {string} options.docsPath + * @param {string} options.silent + * @returns {*|{}|null} */ -const buildDocs = ({ apiDocsConfig = null } = {}) => { - if (apiDocsConfig) { - try { - const { data } = apidoc.createDoc(apiDocsConfig); - const updatedResult = JSON.parse(data); - logger.info('buildDocs.read.apiJsonFile'); - return updatedResult; - } catch (e) { - logger.error(`buildDocs.apiDoc.createDoc[${e.message}]`); - } +const setupDocs = ({ apiDocBaseConfig, watchPath: src, docsPath: dest, silent } = OPTIONS) => { + if ((!Array.isArray(src) && !src?.length) || !dest) { + return []; } - return {}; + const apiDocsConfig = { + ...apiDocBaseConfig, + src, + dest, + silent: apiDocBaseConfig.silent || silent + }; + + try { + const { data } = apidoc.createDoc(apiDocsConfig); + const updatedResult = JSON.parse(data); + logger.info('buildDocs.read.apiJsonFile'); + return updatedResult; + } catch (e) { + logger.error(`buildDocs.apiDoc.createDoc[${e.message}]`); + } + + return []; }; -module.exports = { buildDocs }; +module.exports = { setupDocs }; diff --git a/src/index.js b/src/index.js index ba445b9..702d394 100644 --- a/src/index.js +++ b/src/index.js @@ -2,39 +2,12 @@ const express = require('express'); const { createHttpTerminator } = require('http-terminator'); const { OPTIONS } = require('./global'); const { logger } = require('./logger/configLogger'); -const { buildDocs } = require('./docs/buildDocs'); +const { setupDocs } = require('./docs/buildDocs'); const { buildRequestHeaders, buildResponse } = require('./api/buildApi'); -const cache = { app: null, httpTerminator: null }; +const CACHE = { app: null, httpTerminator: null }; /** - * Build documentation - * - * @param {object} options - * @param {OPTIONS.apiDocBaseConfig} options.apiDocBaseConfig - * @param {string|string[]} options.watchPath - * @param {string} options.docsPath - * @param {string} options.silent - * @returns {*|{}|null} - */ -const setupDocs = ({ apiDocBaseConfig, watchPath: src, docsPath: dest, silent } = OPTIONS) => { - if ((!Array.isArray(src) && !src?.length) || !dest) { - return []; - } - - const apiJson = buildDocs({ - apiDocsConfig: { - ...apiDocBaseConfig, - src, - dest, - silent: apiDocBaseConfig.silent || silent - } - }); - - return (Array.isArray(apiJson) && apiJson) || []; -}; - -/** - * Build response + * Build api responses * * @param {Array} apiJson * @param {object} options @@ -46,11 +19,11 @@ const setupResponse = (apiJson = [], { port } = OPTIONS) => { let httpTerminator = null; appResponses.forEach(response => { - cache.app[response.type](response.url, response.callback); + CACHE.app[response.type](response.url, response.callback); }); if (routesLoaded) { - const server = cache.app.listen(port, () => logger.info(`listening\t:${port}`)); + const server = CACHE.app.listen(port, () => logger.info(`listening\t:${port}`)); httpTerminator = createHttpTerminator({ server }); @@ -75,14 +48,14 @@ const apiDocMock = async ({ port, watchPath, docsPath } = OPTIONS) => { let httpTerminator = null; if (apiJson.length) { - if (cache?.httpTerminator?.terminate) { - await cache.httpTerminator.terminate(); + if (CACHE?.httpTerminator?.terminate) { + await CACHE.httpTerminator.terminate(); } - cache.app = express(); - cache.app.use(`/docs`, express.static(docsPath)); - cache.app.use(buildRequestHeaders); - cache.httpTerminator = httpTerminator = setupResponse(apiJson); + CACHE.app = express(); + CACHE.app.use(`/docs`, express.static(docsPath)); + CACHE.app.use(buildRequestHeaders); + CACHE.httpTerminator = httpTerminator = setupResponse(apiJson); } if (httpTerminator === null) { diff --git a/src/logger/configLogger.js b/src/logger/configLogger.js index 7f02933..2da778d 100644 --- a/src/logger/configLogger.js +++ b/src/logger/configLogger.js @@ -1,6 +1,11 @@ const { createLogger, format, transports } = require('winston'); const { colorize, combine, timestamp, printf } = format; +/** + * Setup console logging, provide error, info, warn, etc. + * + * @type {{ error: Function, info: Function, warn: Function }} + */ const configLogger = createLogger({ format: combine( colorize(),