Skip to content
This repository has been archived by the owner on Jul 20, 2023. It is now read-only.

Commit

Permalink
Update yargs and accept output file path in CLI (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
lorefnon authored Jul 29, 2022
1 parent ff8b0a0 commit 002c3c5
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 106 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ Try out our pre-compiled Star Wars GraphQL SDK on [CodeSandbox](https://codesand

* **TypeScript 4.1+** is required for [Recursive Conditional Type](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#recursive-conditional-types) support

2. Generate an SDK with `npx @timkendall/tql-gen <schema> > sdk.ts`
2. Generate an SDK with `npx @timkendall/tql-gen <schema> -o sdk.ts`

`<schema>` can be a path to local file or an http endpoint url.

## Usage

Expand Down
3 changes: 1 addition & 2 deletions codegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"prettier": "^2.5.1",
"ts-poet": "^4.5.0",
"ts-toolbelt": "^9.6.0",
"yargs": "^16.1.0"
"yargs": "^17.5.1"
},
"devDependencies": {
"@arkweid/lefthook": "^0.7.7",
Expand All @@ -42,7 +42,6 @@
"@types/node": "^16.11.7",
"@types/node-fetch": "^2.5.7",
"@types/prettier": "^2.1.5",
"@types/yargs": "^15.0.12",
"auto-changelog": "^2.2.1",
"jest": "^27.4.5",
"ts-jest": "^27.1.2",
Expand Down
89 changes: 55 additions & 34 deletions codegen/src/CLI.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,86 @@
import Yargs from "yargs";
import fs from "fs-extra";
import { buildClientSchema, getIntrospectionQuery, printSchema } from "graphql";
import fetch from "node-fetch";
import { getIntrospectionQuery, buildClientSchema, printSchema } from "graphql";
import path from "path";
import Yargs from "yargs/yargs";

import { render } from "./render";

Yargs.command(
"$0 <schema>",
"Generate a fluent TypeScript client for your GraphQL API.",
(yargs) =>
yargs.positional("schema", {
describe: "ex. https://graphql.org/swapi-graphql/",
run().catch((e) => {
console.error(e.message);
process.exit(1);
});

async function run() {
const argv = Yargs(process.argv.slice(2))
.usage(
"$0 <schema>",
"Generate a fluent TypeScript client for your GraphQL API.",
)
.positional("schema", {
type: "string",
demandOption: true,
}),
async (argv) => {
const schemaPath = argv.schema;
describe: "ex. https://graphql.org/swapi-graphql/",
})
.options({
headers: { type: "array" },
output: { type: "string", describe: "Path of output file (typescript)" },
})
.alias("o", "output")
.demandOption(["schema"])
.help("help").argv;

const schema = schemaPath.startsWith("http")
? await remoteSchema(schemaPath, {
headers: normalizeHeaders(argv.headers)
})
: await localSchema(schemaPath);
const schemaPath = argv.schema;

const schema = schemaPath.startsWith("http")
? await remoteSchema(schemaPath, {
headers: normalizeHeaders(argv.headers),
})
: await localSchema(schemaPath);

process.stdout.write(render(schema));
const renderedSchema = render(schema);

if (argv.output) {
const outputPath = path.resolve(argv.output);
console.log("Writing to: ", outputPath);
fs.writeFile(outputPath, renderedSchema);
} else {
process.stdout.write(renderedSchema);
}
).argv;
}

function normalizeHeaders(headers: any): Record<string, string> {
if (typeof headers === "string") {
return normalizeHeaders([headers])
return normalizeHeaders([headers]);
}
if (Array.isArray(headers)) {
const entries = headers
.map(headerArg => {
if (typeof headerArg !== 'string') {
console.warn(`Invalid header ignored: ${headerArg}`)
if (typeof headerArg !== "string") {
console.warn(`Invalid header ignored: ${headerArg}`);
return null;
}
const parts = headerArg.split(':')
const parts = headerArg.split(":");
if (parts.length !== 2) {
console.warn(`Invalid header ignored: ${headerArg}`)
console.warn(`Invalid header ignored: ${headerArg}`);
return null;
}
return parts.map(it => it.trim())
return parts.map(it => it.trim());
})
.filter(Boolean) as [string, string][]
return Object.fromEntries(entries)
.filter(Boolean) as [string, string][];
return Object.fromEntries(entries);
}
if (typeof headers === "object") {
const entries = Object
.entries(headers)
.map(([key, value]) => {
if (typeof value !== 'string') {
console.warn(`Invalid header ignored: ${key}`)
if (typeof value !== "string") {
console.warn(`Invalid header ignored: ${key}`);
return null;
}
return [key, value]
return [key, value];
})
.filter(Boolean) as [string, string][]
return Object.fromEntries(entries)
.filter(Boolean) as [string, string][];
return Object.fromEntries(entries);
}
return {};
}
Expand All @@ -70,13 +91,13 @@ async function localSchema(path: string) {
}

async function remoteSchema(url: string, options: {
headers: Record<string, string>
headers: Record<string, string>;
}) {
const { data, errors } = await fetch(url, {
method: "post",
headers: {
"Content-Type": "application/json",
...options.headers
...options.headers,
},
body: JSON.stringify({
operationName: "IntrospectionQuery",
Expand Down
2 changes: 1 addition & 1 deletion docs/quickstart/codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Codegen currently is required to be manually once at least once before usage. We

## Usage

`npx @timkendall/tql-gen <schema> > sdk.ts`
`npx @timkendall/tql-gen <schema> -o sdk.ts`

- `<schema>`: HTTP(s) endpoint of a GraphQL API w/ introspection enabled or local `.graphql` schema file

Expand Down
Loading

1 comment on commit 002c3c5

@vercel
Copy link

@vercel vercel bot commented on 002c3c5 Jul 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

tql – ./

tql-git-master-timkendall.vercel.app
tql.dev
tql-timkendall.vercel.app

Please sign in to comment.