diff --git a/.gitignore b/.gitignore index 85f3484..1ce5892 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ node_modules/ -dist/ .nyc_output/ tmp/ .vscode coverage/ -docs/ \ No newline at end of file +docs/ diff --git a/dist/editor.js b/dist/editor.js new file mode 100644 index 0000000..6519ac8 --- /dev/null +++ b/dist/editor.js @@ -0,0 +1,78 @@ +#!/usr/bin/env node +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const path_1 = __importDefault(require("path")); +const fs_1 = __importDefault(require("fs")); +const util_1 = __importDefault(require("util")); +const colors_1 = __importDefault(require("colors")); +const serve_static_1 = __importDefault(require("serve-static")); +const config_1 = __importDefault(require("./util/config")); +const browser_1 = __importDefault(require("./util/browser")); +// swagger-editor must be served from root +const SWAGGER_EDITOR_SERVE_PATH = '/'; +// swagger-editor expects to GET the file here +const SWAGGER_EDITOR_LOAD_PATH = '/oas/spec'; +// swagger-editor PUTs the file back here +const SWAGGER_EDITOR_SAVE_PATH = '/oas/spec'; +// map dir for UI +const SWAGGER_EDITOR_UI_PATH = '/swagger-editor'; +// swagger-editor GETs the configuration files +const SWAGGER_EDITOR_CONFIG_PATH = '/config/defaults.json'; +exports.edit = (options) => { + if (!fs_1.default.existsSync(options.file)) { + console.error(colors_1.default.red(`The OpenAPI file provided ${options.file} does not exist.`)); + return; + } + const app = require('connect')(); + // save the file from swagger-editor + app.use(SWAGGER_EDITOR_SAVE_PATH, (req, res, next) => { + if (req.method !== 'PUT') { + return next(); + } + const stream = fs_1.default.createWriteStream(options.file); + req.pipe(stream); + stream.on('finish', () => { + res.end('ok'); + }); + }); + // retrieve the project swagger file for the swagger-editor + app.use(SWAGGER_EDITOR_LOAD_PATH, serve_static_1.default(options.file)); + app.use(SWAGGER_EDITOR_CONFIG_PATH, (req, res, next) => { + if (req.method !== 'GET') { + return next(); + } + res.end(JSON.stringify(config_1.default.editorConfig)); + }); + // load swagger-editor with use custom index + app.use(SWAGGER_EDITOR_SERVE_PATH, serve_static_1.default(path_1.default.resolve(__dirname, '..', 'src/'))); + app.use(SWAGGER_EDITOR_UI_PATH, serve_static_1.default(config_1.default.editorPath)); + // start editor in browser // + const http = require('http'); + const server = http.createServer(app); + const hostname = options.host || '127.0.0.1'; + let port = options.port || 0; + let editorUrl; + server.listen(port, hostname, () => { + port = server.address().port; + editorUrl = util_1.default.format('http://%s:%d/?url=/oas/spec', hostname, port); + const editApiUrl = util_1.default.format('http://%s:%d/oas/spec', hostname, port); + const dontKillMessage = '- Do not terminate this process or close this window until finished editing -'; + console.log(colors_1.default.green(`*** ${config_1.default.name} ***`)); + if (!options.silent) { + browser_1.default.open(editorUrl, (err) => { + if (err) { + console.error(err); + } + console.log(colors_1.default.gray(dontKillMessage)); + }); + } + else { + console.log(`Running ${config_1.default.name} server. You can make GET and PUT calls to ${editApiUrl}`); + console.log(colors_1.default.gray(dontKillMessage)); + } + }); +}; +exports.default = exports.edit; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..0d0450c --- /dev/null +++ b/dist/index.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const fs_1 = __importDefault(require("fs")); +const path_1 = __importDefault(require("path")); +const colors_1 = __importDefault(require("colors")); +const commander_1 = __importDefault(require("commander")); +const editor_1 = require("./editor"); +commander_1.default + .version('0.5.3', '-v, --version') + .option('-f, --file [file]', 'File') + .option('-h, --host [host]', 'Host') + .option('-p, --port [port]', 'Port') + .option('-s --silent', 'Run without launching the browser') + .parse(process.argv); +const file = path_1.default.resolve(commander_1.default.file || 'src/api/v1/api.yaml'); +if (!fs_1.default.existsSync(file)) { + console.error(colors_1.default.red(`The OpenAPI file provided ${file} does not exist.`)); +} +const options = Object.assign({ file }, commander_1.default.port && { port: commander_1.default.port }, commander_1.default.host && { host: commander_1.default.host }, { silent: commander_1.default.silent }); +editor_1.edit(options); diff --git a/dist/util/browser.js b/dist/util/browser.js new file mode 100644 index 0000000..ce240e6 --- /dev/null +++ b/dist/util/browser.js @@ -0,0 +1,64 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const child_process_1 = __importDefault(require("child_process")); +const config_1 = __importDefault(require("./config")); +const platformOpeners = { + darwin(url, cb) { + const browser = escape(config_1.default.browser); + if (browser) { + openBrowser(`Open -a ${browser}`, url, cb); + } + else { + openBrowser('Open', url, cb); + } + }, + win32(url, cb) { + const browser = escape(config_1.default.browser); + if (browser) { + openBrowser(`Start ${browser}`, url, cb); + } + else { + openBrowser('Start ""', url, cb); + } + }, + linux(url, cb) { + const browser = escape(config_1.default.browser); + if (browser) { + openBrowser(browser, url, cb); + } + else { + openBrowser('xdg-open', url, cb); + } + }, + other(url, cb) { + const browser = escape(config_1.default.browser); + if (browser) { + openBrowser(browser, url, cb); + } + else { + cb(new Error('must specify browser in config')); + } + }, +}; +// note: platform parameter is just for testing... +function open(url, cb, platform) { + platform = platform || process.platform; + if (!platformOpeners[platform]) { + platform = 'other'; + } + platformOpeners[platform](url, cb); +} +function openBrowser(command, url, cb) { + if (config_1.default.debug) { + console.log(`command: ${command}`); + } + console.log(`Opening browser to: ${url}`); + child_process_1.default.exec(`${command} "${escape(url)}"`, cb); +} +const escape = (s) => !s ? s : s.replace(/"/g, '\\\"'); +exports.default = { + open, +}; diff --git a/dist/util/config.js b/dist/util/config.js new file mode 100644 index 0000000..ac66435 --- /dev/null +++ b/dist/util/config.js @@ -0,0 +1,27 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const path_1 = __importDefault(require("path")); +const fs_1 = __importDefault(require("fs")); +const colors_1 = __importDefault(require("colors")); +const config = { + name: 'OpenAPI Swagger Editor', + rootDir: path_1.default.resolve(__dirname, '../../'), + editorPath: require.resolve('swagger-editor-dist'), + userHome: process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], + debug: !!process.env.DEBUG, + nodeModules: '', + editorConfig: {}, + browser: '', +}; +config.nodeModules = path_1.default.resolve(config.rootDir, 'node_modules'); +config.editorPath = path_1.default.dirname(config.editorPath); +if (!fs_1.default.existsSync(config.nodeModules)) { + console.error(colors_1.default.red(`Node modules path ${config.nodeModules} does not exist.`)); +} +if (!fs_1.default.existsSync(config.editorPath)) { + console.error(colors_1.default.red(`Editor dist path ${config.editorPath} does not exist.`)); +} +exports.default = config; diff --git a/src/index.ts b/src/index.ts index 3e153f8..d0a8249 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import { edit } from './editor'; cmd .version('0.5.3', '-v, --version') .option('-f, --file [file]', 'File') + .option('-h, --host [host]', 'Host') .option('-p, --port [port]', 'Port') .option('-s --silent', 'Run without launching the browser') .parse(process.argv); @@ -21,6 +22,7 @@ if (!fs.existsSync(file)) { const options = { file, ...cmd.port && { port: cmd.port }, + ...cmd.host && { host: cmd.host }, silent: cmd.silent, };