Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract and test CLI logic #278

Merged
merged 3 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/PingTest_V1.no-batch.openapi3.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,4 @@
}
}
}
}
}
112 changes: 14 additions & 98 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,35 @@
#!/usr/bin/env node
"use strict";

//console.dir(argv);

//TODO: what to require?
const csdl = require("odata-csdl");
const lib = require("./csdl2openapi");
const minimist = require("minimist");
const fs = require("fs");
const { parseArgs } = require("./cliParts");
const { stringifyStream } = require("@discoveryjs/json-ext");

var unknown = false;

var argv = minimist(process.argv.slice(2), {
string: [
"o",
"openapi-version",
"t",
"target",
"basePath",
"description",
"host",
"levels",
"scheme",
"title",
],
boolean: [
"d",
"diagram",
"h",
"help",
"p",
"pretty",
"u",
"used-schemas-only",
"skipBatchPath",
],
alias: {
d: "diagram",
h: "help",
o: "openapi-version",
p: "pretty",
t: "target",
u: "used-schemas-only",
},
default: {
levels: 4,
pretty: false,
skipBatchPath: false,
},
unknown: (arg) => {
if (arg.substring(0, 1) == "-") {
console.error("Unknown option: " + arg);
unknown = true;
return false;
}
},
});

if (unknown || argv._.length == 0 || argv.h) {
console.log(`Usage: odata-openapi3 <options> <source file>
Options:
--basePath base path (default: /service-root)
--description default description if none is annotated
-d, --diagram include YUML diagram
-h, --help show this info
--host host (default: localhost)
--levels maximum number of path segments
-o, --openapi-version 3.0.0 to 3.0.3 or 3.1.0 (default: 3.0.2)
-p, --pretty pretty-print JSON result
--scheme scheme (default: http)
--skipBatchPath skips the generation of the $batch path, (default: false)
-t, --target target file (default: source file basename + .openapi3.json)
--title default title if none is annotated`);
} else {
//TODO: further input parameters reserved for e.g. referenced CSDL documents
// for (var i = 0; i < argv._.length; i++) {
// convert(argv._[i]);
// }
convert(argv._[0]);
}
const args = parseArgs(process.argv.slice(2));
if (args.unknown)
args.unknown.map((arg) => console.error(`Unknown option: ${arg}`));
if (args.usage) console.log(args.usage);
else convert(args);

function convert(source) {
if (!fs.existsSync(source)) {
console.error("Source file not found: " + source);
function convert(args) {
if (!fs.existsSync(args.source)) {
console.error("Source file not found: " + args.source);
return;
}

const text = fs.readFileSync(source, "utf8");
const text = fs.readFileSync(args.source, "utf8");
const json = text.startsWith("<") ? csdl.xml2json(text) : JSON.parse(text);

const target =
argv.target ||
(source.lastIndexOf(".") <= 0
? source
: source.substring(0, source.lastIndexOf("."))) + ".openapi3.json";
console.log(target);
console.log(args.target);

const messages = [];

const openapi = lib.csdl2openapi(json, {
scheme: argv.scheme,
host: argv.host,
basePath: argv.basePath,
diagram: argv.diagram,
maxLevels: Number(argv.levels),
openapiVersion: argv.o,
messages,
skipBatchPath: argv.skipBatchPath,
defaultTitle: argv.title,
defaultDescription: argv.description,
});
const openapi = lib.csdl2openapi(json, { messages, ...args.options });

stringifyStream(openapi, null, argv.pretty ? 4 : 0).pipe(
fs.createWriteStream(target),
stringifyStream(openapi, null, args.options.pretty ? 4 : 0).pipe(
fs.createWriteStream(args.target),
);

if (messages.length > 0) console.dir(messages);
Expand Down
104 changes: 104 additions & 0 deletions lib/cliParts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* Parse command-line options
*
* Latest version: https://github.com/oasis-tcs/odata-openapi/blob/main/lib/cliOptions.js
*/

const minimist = require("minimist");

module.exports = { parseArgs };

function parseArgs(argv) {
const usage = `Usage: odata-openapi3 <options> <source file>
Options:
--basePath base path (default: /service-root)
--description default description if none is annotated
-d, --diagram include YUML diagram
-h, --help show this info
--host host (default: localhost)
--levels maximum number of path segments
-o, --openapi-version 3.0.0 to 3.0.3 or 3.1.0 (default: 3.0.2)
-p, --pretty pretty-print JSON result
--scheme scheme (default: http)
--skipBatchPath skips the generation of the $batch path, (default: false)
-t, --target target file (default: source file basename + .openapi3.json)
--title default title if none is annotated`;
const unknown = [];

const args = minimist(argv, {
string: [
"basePath",
"description",
"host",
"levels",
"openapi-version",
"scheme",
"target",
"title",
],
boolean: ["diagram", "help", "pretty", "skipBatchPath"],
alias: {
d: "diagram",
h: "help",
o: "openapi-version",
p: "pretty",
t: "target",
},
default: {
pretty: false,
},
unknown: (arg) => {
if (arg.substring(0, 1) == "-") {
unknown.push(arg);
return false;
}
},
});

if (unknown.length > 0 || args.help || args._.length !== 1)
return {
unknown,
usage,
};

const source = args._[0];
const target =
args.target ||
(source.lastIndexOf(".") > 0
? source.substring(0, source.lastIndexOf("."))
: source) + ".openapi3.json";

const options = {};

for (const [name, value] of Object.entries(args)) {
if (name.length === 1) continue;
if (value === false) continue;
switch (name) {
case "description":
options.defaultDescription = value;
break;
case "levels": {
const l = Number(value);
if (!isNaN(l)) options.maxLevels = l;
break;
}
case "openapi-version":
options.openapiVersion = value;
break;
case "target":
break;
case "title":
options.defaultTitle = value;
break;
default:
options[name] = value;
break;
}
}

return {
source,
target,
options,
};
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
},
"scripts": {
"build": "node lib/transform.js",
"pretest": "rm examples/PingTest_V1.no-batch.openapi3.json && node lib/cli.js -p --skipBatchPath -t examples/PingTest_V1.no-batch.openapi3.json examples/PingTest_V1.xml",
"test": "c8 mocha",
"watch": "mocha --watch"
},
Expand Down
Loading