From dfc0ef4427a58826b34fd61451e3f9beae997c66 Mon Sep 17 00:00:00 2001 From: Tim van der Lippe Date: Fri, 18 Apr 2025 08:41:03 +0000 Subject: [PATCH] Add support for tags Tags added to methods are now automatically appended to the existing list of global tags. Fixes #65 --- lib/generate-doc.js | 13 +++- lib/minimum-doc.js | 3 +- test/_routes.js | 2 +- test/index.js | 186 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 200 insertions(+), 4 deletions(-) diff --git a/lib/generate-doc.js b/lib/generate-doc.js index cb59904..4c69203 100644 --- a/lib/generate-doc.js +++ b/lib/generate-doc.js @@ -9,7 +9,8 @@ module.exports = function generateDocument (baseDocument, router, basePath) { openapi: minimumViableDocument.openapi }, baseDocument, { info: Object.assign({}, minimumViableDocument.info, baseDocument.info), - paths: Object.assign({}, minimumViableDocument.paths, baseDocument.paths) + paths: Object.assign({}, minimumViableDocument.paths, baseDocument.paths), + tags: [...minimumViableDocument.tags, ...(baseDocument.tags || [])] }) // Iterate the middleware stack and add any paths and schemas, etc @@ -23,6 +24,16 @@ module.exports = function generateDocument (baseDocument, router, basePath) { return } + if (schema.tags) { + schema.tags.forEach((tag) => { + if (!doc.tags.find((docTag) => docTag.name === tag)) { + doc.tags.push({ + name: tag + }) + } + }) + } + const operation = Object.assign({}, schema) // Add route params to schema diff --git a/lib/minimum-doc.js b/lib/minimum-doc.js index c3fef55..8f0c8cf 100644 --- a/lib/minimum-doc.js +++ b/lib/minimum-doc.js @@ -6,5 +6,6 @@ module.exports = { title: 'Express App', version: '1.0.0' }, - paths: {} + paths: {}, + tags: [] } diff --git a/test/_routes.js b/test/_routes.js index 30ed39f..830b9a4 100644 --- a/test/_routes.js +++ b/test/_routes.js @@ -90,7 +90,7 @@ module.exports = function () { .get(`${openapi.defaultRoutePrefix}.json`) .expect(200, (err, res) => { assert(!err, err) - assert.strictEqual(Object.keys((res.body.paths))[0], '/{id}/') + assert.strictEqual(Object.keys((res.body.paths))[0], '(?:/([^/]+?))/') done() }) }) diff --git a/test/index.js b/test/index.js index 36a2ff6..ca3d71e 100644 --- a/test/index.js +++ b/test/index.js @@ -60,7 +60,8 @@ suite(name, function () { title: 'Test App', version: '1.0.0' }, - paths: {} + paths: {}, + tags: [] }) }) @@ -653,6 +654,189 @@ suite(name, function () { }) }) + test('support tags', (done) => { + const app = express() + const oapi = openapi() + + const firstTag = oapi.path({ + tags: [ + 'first-tag' + ], + responses: { + 204: { + description: 'Successful response', + content: { + 'application/json': {} + } + } + } + }) + + app.get('/endpoint', firstTag, (req, res) => { + res.status(204).send() + }) + + const secondTag = oapi.path({ + tags: [ + 'second-tag', + 'third-tag' + ], + responses: { + 204: { + description: 'Successful response', + content: { + 'application/json': {} + } + } + } + }) + + app.get('/another-endpoint', secondTag, (req, res) => { + res.status(204).send() + }) + + app.use(oapi) + + supertest(app) + .get(`${openapi.defaultRoutePrefix}.json`) + .expect(200, (err, res) => { + assert(!err, err) + SwaggerParser.validate(res.body, (err, api) => { + if (err) { + logDocument(api) + + done(err) + } + + assert(Object.keys(api.paths).length === 2) + + assert.deepStrictEqual(api.tags, [{ + name: 'first-tag' + }, { + name: 'second-tag' + }, { + name: 'third-tag' + }]) + + done() + }) + }) + }) + + test('support tags with base document', (done) => { + const app = express() + const oapi = openapi({ + tags: [ + { + name: 'first-tag' + } + ] + }) + + const secondTag = oapi.path({ + tags: [ + 'second-tag', + 'third-tag' + ], + responses: { + 204: { + description: 'Successful response', + content: { + 'application/json': {} + } + } + } + }) + + app.get('/another-endpoint', secondTag, (req, res) => { + res.status(204).send() + }) + + app.use(oapi) + + supertest(app) + .get(`${openapi.defaultRoutePrefix}.json`) + .expect(200, (err, res) => { + assert(!err, err) + SwaggerParser.validate(res.body, (err, api) => { + if (err) { + logDocument(api) + + done(err) + } + + assert(Object.keys(api.paths).length === 1) + + assert.deepStrictEqual(api.tags, [{ + name: 'first-tag' + }, { + name: 'second-tag' + }, { + name: 'third-tag' + }]) + + done() + }) + }) + }) + + test('prefer global tags over method tags', (done) => { + const app = express() + const oapi = openapi({ + tags: [ + { + name: 'first-tag', + description: 'Description of first tag' + } + ] + }) + + const firstTag = oapi.path({ + tags: [ + 'first-tag', + 'second-tag' + ], + responses: { + 204: { + description: 'Successful response', + content: { + 'application/json': {} + } + } + } + }) + + app.get('/endpoint', firstTag, (req, res) => { + res.status(204).send() + }) + + app.use(oapi) + + supertest(app) + .get(`${openapi.defaultRoutePrefix}.json`) + .expect(200, (err, res) => { + assert(!err, err) + SwaggerParser.validate(res.body, (err, api) => { + if (err) { + logDocument(api) + + done(err) + } + + assert(Object.keys(api.paths).length === 1) + + assert.deepStrictEqual(api.tags, [{ + name: 'first-tag', + description: 'Description of first tag' + }, { + name: 'second-tag' + }]) + + done() + }) + }) + }) + // Other tests require('./_validate')() require('./_regexRoutes')()