-
Notifications
You must be signed in to change notification settings - Fork 230
Commit
* init changes * update loaders * update example app * update import statements in cli spec * move test files to fixtures * move v3 test files to fixtures * refactor existing tests for utils * add named exports to utils * refactor examples tests * refactor examples tests * reading json files * update existing test suites * use createRequire() * remove airbnb-base because no babel and transpilation * start refactor definition loader * feat: complete loadDefinition * start deleting the cli * start moving the cli to examples * remove commander * retry ci * retry ci * still inconsistent behavior, unfortunately * run without caching * upgrade deps * remove unused files * move validation in one place * refactor organize function * make spec operations transparent to library * refactor spec.prepare() tests * add spec.clean() tests * move encoding test at its implementation * add some coverage for the finalize method * Making main function async * Add some coverage * 100% on utilities, yey * add tests for spec.extract() * improve coverage * Update landing page readme * full coverage, on paper * move loadDefinition * Update docs
- chore/workspaces
- (#240)
- v7
- (#240)
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ | |
.c9 | ||
.nvm | ||
.eslintrc.js | ||
external.jsdoc | ||
examples/ | ||
docs/ | ||
jsdoc/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
lts/erbium | ||
lts/fermium |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
test/files/v2/wrong_syntax.json | ||
test/files/v2/wrong_syntax.yaml | ||
test/fixtures/wrong/example.js | ||
test/fixtures/wrong/example.json | ||
test/fixtures/wrong/example.yaml |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#!/usr/bin/env node | ||
import { promises as fs } from 'fs'; | ||
import { pathToFileURL } from 'url'; | ||
import { loadDefinition } from './utils.js'; | ||
|
||
import swaggerJsdoc from '../../index.js'; | ||
|
||
/** | ||
* Handle CLI arguments in your preferred way. | ||
* @see https://nodejs.org/en/knowledge/command-line/how-to-parse-command-line-arguments/ | ||
*/ | ||
const args = process.argv.slice(2); | ||
|
||
/** | ||
* Extract definition | ||
* Pass an absolute specifier with file:/// to the loader. | ||
* The relative and bare specifiers would be based on assumptions which are not stable. | ||
* For example, if path from cli `examples/app/parameters.*` goes in, it will be assumed as bare, which is wrong. | ||
*/ | ||
const definitionUrl = pathToFileURL( | ||
args.splice( | ||
args.findIndex((i) => i === '--definition'), | ||
2 | ||
)[1] // Definition file is always only one. | ||
); | ||
|
||
// Because "Parsing error: Cannot use keyword 'await' outside an async function" | ||
(async () => { | ||
/** | ||
* We're using an example module loader which you can swap with your own implemenentation. | ||
*/ | ||
const swaggerDefinition = await loadDefinition(definitionUrl.href); | ||
|
||
// Extract apis | ||
// remove --apis flag | ||
args.splice(0, 1); | ||
// the rest of this example can be treated as the contents of the --apis | ||
const apis = args; | ||
|
||
// Use the library | ||
const spec = await swaggerJsdoc({ swaggerDefinition, apis }); | ||
|
||
// Save specification place and format | ||
await fs.writeFile('swagger.json', JSON.stringify(spec, null, 2)); | ||
|
||
console.log('Specification has been created successfully!'); | ||
})(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { promises as fs } from 'fs'; | ||
import { createRequire } from 'module'; | ||
import { dirname, resolve } from 'path'; | ||
import { fileURLToPath } from 'url'; | ||
import { spawnSync } from 'child_process'; | ||
import { loadDefinition } from './utils.js'; | ||
|
||
const require = createRequire(import.meta.url); | ||
const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
const cli = `${__dirname}/cli.js`; | ||
|
||
describe('Example command line application', () => { | ||
it('should produce results matching reference specification', () => { | ||
const { stderr, stdout } = spawnSync(cli, [ | ||
'--definition', | ||
'examples/swaggerDefinition/example.js', | ||
'--apis', | ||
'examples/app/parameters.*', | ||
'examples/app/route*', | ||
]); | ||
expect(stderr.toString()).toBe(''); | ||
expect(stdout.toString()).toBe( | ||
'Specification has been created successfully!\n' | ||
); | ||
const refSpec = require('./reference-specification.json'); | ||
const resSpec = require(`${process.cwd()}/swagger.json`); | ||
expect(resSpec).toEqual(refSpec); | ||
}); | ||
|
||
afterAll(async () => { | ||
await fs.unlink(`${process.cwd()}/swagger.json`); | ||
}); | ||
}); | ||
|
||
describe('loadDefinition', () => { | ||
const example = '../swaggerDefinition/example'; | ||
|
||
it('should throw on bad input', async () => { | ||
await expect(loadDefinition('bad/path/to/nowhere')).rejects.toThrow( | ||
'Definition file should be any of the following: .js, .mjs, .cjs, .json, .yml, .yaml' | ||
); | ||
}); | ||
|
||
it('should support .json', async () => { | ||
const def = resolve(__dirname, `${example}.json`); | ||
const result = await loadDefinition(def); | ||
expect(result).toEqual({ | ||
info: { | ||
title: 'Hello World', | ||
version: '1.0.0', | ||
description: 'A sample API', | ||
}, | ||
}); | ||
}); | ||
|
||
it('should support .yaml', async () => { | ||
const def = resolve(__dirname, `${example}.yaml`); | ||
const result = await loadDefinition(def); | ||
expect(result).toEqual({ | ||
info: { | ||
title: 'Hello World', | ||
version: '1.0.0', | ||
description: 'A sample API', | ||
}, | ||
}); | ||
}); | ||
|
||
it('should support .js', async () => { | ||
const def = resolve(__dirname, `${example}.js`); | ||
const result = await loadDefinition(def); | ||
expect(result).toEqual({ | ||
info: { | ||
title: 'Hello World', | ||
version: '1.0.0', | ||
description: 'A sample API', | ||
}, | ||
}); | ||
}); | ||
|
||
it('should support .cjs', async () => { | ||
const def = resolve(__dirname, `${example}.cjs`); | ||
const result = await loadDefinition(def); | ||
expect(result).toEqual({ | ||
info: { | ||
title: 'Hello World', | ||
version: '1.0.0', | ||
description: 'A sample API', | ||
}, | ||
}); | ||
}); | ||
|
||
it('should support .mjs', async () => { | ||
const def = resolve(__dirname, `${example}.mjs`); | ||
const result = await loadDefinition(def); | ||
expect(result).toEqual({ | ||
info: { | ||
title: 'Hello World', | ||
version: '1.0.0', | ||
description: 'A sample API', | ||
}, | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
{ | ||
"info": { | ||
"title": "Hello World", | ||
"version": "1.0.0", | ||
"description": "A sample API" | ||
}, | ||
"swagger": "2.0", | ||
"paths": { | ||
"/login": { | ||
"post": { | ||
"description": "Login to the application", | ||
"tags": ["Users", "Login"], | ||
"produces": ["application/json"], | ||
"parameters": [ | ||
{ | ||
"$ref": "#/parameters/username" | ||
}, | ||
{ | ||
"name": "password", | ||
"description": "User's password.", | ||
"in": "formData", | ||
"required": true, | ||
"type": "string" | ||
} | ||
], | ||
"responses": { | ||
"200": { | ||
"description": "login", | ||
"schema": { | ||
"type": "object", | ||
"$ref": "#/definitions/Login" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"/hello": { | ||
"get": { | ||
"description": "Returns the homepage", | ||
"responses": { | ||
"200": { | ||
"description": "hello world" | ||
} | ||
} | ||
} | ||
}, | ||
"/": { | ||
"get": { | ||
"description": "Returns the homepage", | ||
"responses": { | ||
"200": { | ||
"description": "hello world" | ||
} | ||
} | ||
} | ||
}, | ||
"/users": { | ||
"get": { | ||
"description": "Returns users", | ||
"tags": ["Users"], | ||
"produces": ["application/json"], | ||
"responses": { | ||
"200": { | ||
"description": "users" | ||
} | ||
} | ||
}, | ||
"post": { | ||
"description": "Returns users", | ||
"tags": ["Users"], | ||
"produces": ["application/json"], | ||
"parameters": [ | ||
{ | ||
"$ref": "#/parameters/username" | ||
} | ||
], | ||
"responses": { | ||
"200": { | ||
"description": "users" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"definitions": { | ||
"Login": { | ||
"required": ["username", "password"], | ||
"properties": { | ||
"username": { | ||
"type": "string" | ||
}, | ||
"password": { | ||
"type": "string" | ||
}, | ||
"path": { | ||
"type": "string" | ||
} | ||
} | ||
} | ||
}, | ||
"responses": {}, | ||
"parameters": { | ||
"username": { | ||
"name": "username", | ||
"description": "Username to use for login.", | ||
"in": "formData", | ||
"required": true, | ||
"type": "string" | ||
} | ||
}, | ||
"securityDefinitions": {}, | ||
"tags": [ | ||
{ | ||
"name": "Users", | ||
"description": "User management and login" | ||
}, | ||
{ | ||
"name": "Login", | ||
"description": "Login" | ||
}, | ||
{ | ||
"name": "Accounts", | ||
"description": "Accounts" | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { createRequire } from 'module'; | ||
import { extname } from 'path'; | ||
import { promises as fs } from 'fs'; | ||
import yaml from 'yaml'; | ||
|
||
/** | ||
* @param {string} definitionPath path to the swaggerDefinition | ||
*/ | ||
export async function loadDefinition(definitionPath) { | ||
const loadModule = async () => { | ||
const esmodule = await import(definitionPath); | ||
return esmodule.default; | ||
}; | ||
const loadCJS = () => { | ||
const require = createRequire(import.meta.url); | ||
return require(definitionPath); | ||
}; | ||
const loadJson = async () => { | ||
const fileContents = await fs.readFile(definitionPath); | ||
return JSON.parse(fileContents); | ||
}; | ||
const loadYaml = async () => { | ||
const fileContents = await fs.readFile(definitionPath); | ||
return yaml.parse(String(fileContents)); | ||
}; | ||
|
||
const LOADERS = { | ||
'.js': loadModule, | ||
'.mjs': loadModule, | ||
'.cjs': loadCJS, | ||
'.json': loadJson, | ||
'.yml': loadYaml, | ||
'.yaml': loadYaml, | ||
}; | ||
|
||
const loader = LOADERS[extname(definitionPath)]; | ||
|
||
if (loader === undefined) { | ||
throw new Error( | ||
`Definition file should be any of the following: ${Object.keys( | ||
LOADERS | ||
).join(', ')}` | ||
); | ||
} | ||
|
||
const result = await loader(); | ||
|
||
return result; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,10 @@ | ||
/* istanbul ignore file */ | ||
|
||
const host = `http://${process.env.IP}:${process.env.PORT}`; | ||
|
||
module.exports = { | ||
export default { | ||
info: { | ||
// API informations (required) | ||
title: 'Hello World', // Title (required) | ||
version: '1.0.0', // Version (required) | ||
description: 'A sample API', // Description (optional) | ||
}, | ||
host, // Host (optional) | ||
basePath: '/', // Base path (optional) | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* istanbul ignore file */ | ||
|
||
export default { | ||
info: { | ||
// API informations (required) | ||
title: 'Hello World', // Title (required) | ||
version: '1.0.0', // Version (required) | ||
description: 'A sample API', // Description (optional) | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,25 @@ | ||
module.exports = require('./src/lib'); | ||
import { prepare, extract, organize, finalize } from './src/specification.js'; | ||
import { validateOptions } from './src/utils.js'; | ||
|
||
/** | ||
* Main function | ||
* @param {object} options - Configuration options | ||
* @param {string} options.encoding Optional, passed to read file function options. Defaults to 'utf8'. | ||
* @param {string} options.format Optional, defaults to '.json' - target file format '.yml' or '.yaml'. | ||
* @param {object} options.swaggerDefinition | ||
* @param {object} options.definition | ||
* @param {array} options.apis | ||
* @returns {object|string} Output specification as json or yaml | ||
*/ | ||
const lib = async (options) => { | ||
validateOptions(options); | ||
|
||
const spec = prepare(options); | ||
const parts = await extract(options); | ||
|
||
organize(spec, parts); | ||
|
||
return finalize(spec, options); | ||
}; | ||
|
||
export default lib; |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Large diffs are not rendered by default.