Skip to content

schema input from stdin #870

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

Merged
merged 3 commits into from
Mar 28, 2022
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
7 changes: 7 additions & 0 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ async function main() {
return;
}

// handle stdin schema, exit
if (pathToSpec === "-") {
if (output !== "." && output === OUTPUT_FILE) fs.mkdirSync(path.dirname(flags.output), { recursive: true });
await generateSchema(process.stdin);
return;
}

// handle local schema(s)
const inputSpecPaths = await glob(pathToSpec, { filesOnly: true });
const isGlob = inputSpecPaths.length > 1;
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { URL } from "url";
import load, { resolveSchema, VIRTUAL_JSON_URL } from "./load.js";
import { swaggerVersion } from "./utils.js";
import { transformAll } from "./transform/index.js";
import { Readable } from "stream";
export * from "./types.js"; // expose all types to consumers

export const WARNING_MESSAGE = `/**
Expand All @@ -30,7 +31,7 @@ export const WARNING_MESSAGE = `/**
* @return {Promise<string>} {Promise<string>} Parsed file schema
*/
async function openapiTS(
schema: string | URL | OpenAPI2 | OpenAPI3 | Record<string, SchemaObject>,
schema: string | URL | OpenAPI2 | OpenAPI3 | Record<string, SchemaObject> | Readable,
options: SwaggerToTSOptions = {} as Partial<SwaggerToTSOptions>
): Promise<string> {
const ctx: GlobalContext = {
Expand Down
29 changes: 23 additions & 6 deletions src/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { URL } from "url";
import mime from "mime";
import yaml from "js-yaml";
import { parseRef } from "./utils.js";
import { Readable } from "stream";

type PartialSchema = Record<string, any>; // not a very accurate type, but this is easier to deal with before we know we’re dealing with a valid spec
type SchemaMap = { [url: string]: PartialSchema };
Expand Down Expand Up @@ -95,13 +96,13 @@ interface LoadOptions extends GlobalContext {

/** Load a schema from local path or remote URL */
export default async function load(
schema: URL | PartialSchema,
schema: URL | PartialSchema | Readable,
options: LoadOptions
): Promise<{ [url: string]: PartialSchema }> {
const urlCache = options.urlCache || new Set<string>();

const isJSON = schema instanceof URL === false; // if this is dynamically-passed-in JSON, we’ll have to change a few things
let schemaID = isJSON ? new URL(VIRTUAL_JSON_URL).href : (schema.href as string);
const isJSON = schema instanceof URL === false && !(schema instanceof Readable); // if this is dynamically-passed-in JSON, we’ll have to change a few things
let schemaID = isJSON || schema instanceof Readable ? new URL(VIRTUAL_JSON_URL).href : (schema.href as string);

const schemas = options.schemas;

Expand All @@ -116,9 +117,25 @@ export default async function load(

let contents = "";
let contentType = "";
const schemaURL = schema as URL; // helps TypeScript

if (isFile(schemaURL)) {
const schemaURL = schema instanceof Readable ? new URL(VIRTUAL_JSON_URL) : (schema as URL); // helps TypeScript

if (schema instanceof Readable) {
const readable = schema;
contents = await new Promise<string>((resolve) => {
readable.resume();
readable.setEncoding("utf8");

let content = "";
readable.on("data", (chunk: string) => {
content += chunk;
});

readable.on("end", () => {
resolve(content);
});
});
contentType = "text/yaml";
} else if (isFile(schemaURL)) {
// load local
contents = fs.readFileSync(schemaURL, "utf8");
contentType = mime.getType(schemaID) || "";
Expand Down
9 changes: 9 additions & 0 deletions test/bin/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ describe("cli", () => {
expect(generated.toString("utf8")).to.equal(expected);
});

it("stdin", async () => {
execSync(`${cmd} - -o generated/stdin.ts < ./specs/petstore.yaml`, {
cwd,
});
const generated = fs.readFileSync(new URL("./generated/stdin.ts", cwd), "utf8");
const expected = eol.lf(fs.readFileSync(new URL("./expected/stdin.ts", cwd), "utf8"));
expect(generated).to.equal(expected);
});

it("supports glob paths", async () => {
execSync(`${cmd} "specs/*.yaml" -o generated/`, { cwd }); // Quotes are necessary because shells like zsh treats glob weirdly
const generatedPetstore = fs.readFileSync(new URL("./generated/specs/petstore.ts", cwd), "utf8");
Expand Down
Loading