@dillonkearns/elm-graphql
Version:
<img src="https://cdn.rawgit.com/martimatix/logo-graphqelm/master/logo.svg" alt="dillonearns/elm-graphql logo" width="40%" align="right">
147 lines (138 loc) • 5.4 kB
text/typescript
const { Elm } = require("./Main.elm");
import * as fs from "fs-extra";
import { GraphQLClient } from "graphql-request";
import * as http from "http";
import * as minimist from "minimist";
import * as request from "request";
import { writeFile } from "./formatted-write";
import { introspectionQuery } from "./introspection-query";
import * as glob from "glob";
import * as path from "path";
const npmPackageVersion = require("../../package.json").version;
const elmPackageVersion = require("../../elm.json").version;
const usage = `Usage:
elm-graphql url # generate files based on the schema at \`url\` in folder ./src/Api
elm-graphql url --base My.Api.Submodule # generate files based on the schema at \`url\` in folder ./src/My/Api/Submodule
elm-graphql url --output path/to/src # generates code within path/to/src/Api
elm-graphql url --output path/to/src --base My.Api.Submodule # generates code within path/to/src/My/Api/Submodule
elm-graphql url --excludeDeprecated # excludes deprecated enums and fields (they are included by default)
# Schema file instead of URL
elm-graphql --introspection-file path/to/introspection-response.json
elm-graphql --version # print the current @dillonkearns/elm-graphql version and target elm package version
elm-graphql url [--header 'headerKey: header value'...] # you can supply multiple header args`;
function isGenerated(path: string): boolean {
return (
fs
.readFileSync(path)
.indexOf("Do not manually edit this file, it was auto-generated by") >= 0
);
}
function warnIfContainsNonGenerated(path: string): void {
const files: string[] = glob.sync(path + "/**/*.elm");
const nonGenerated = files.filter(file => !isGenerated(file));
if (nonGenerated.length > 0) {
console.log(
"@dillonkearns/elm-graphql found some files that it did not generate. Please move or delete the following files and run @dillonkearns/elm-graphql again.",
nonGenerated
);
process.exit(1);
}
}
function removeGenerated(path: string): void {
glob.sync(path + "/**/*.elm").forEach(fs.unlinkSync);
}
const targetComment = `-- Do not manually edit this file, it was auto-generated by dillonkearns/elm-graphql
-- https://github.com/dillonkearns/elm-graphql
`;
const args = minimist(process.argv.slice(2));
if (args.version) {
console.log("npm version ", npmPackageVersion);
console.log(
`Targeting elm package dillonkearns/elm-graphql@${elmPackageVersion}`
);
process.exit(0);
}
const baseArgRegex = /^[A-Z][A-Za-z_]*(\.[A-Z][A-Za-z_]*)*$/;
const baseModuleArg: undefined | string = args.base;
const outputPath: string = args.output || "./src";
function isValidBaseArg(baseArg: string): boolean {
return !!baseArg.match(baseArgRegex);
}
if (baseModuleArg && !isValidBaseArg(baseModuleArg)) {
console.log(
`--base was '${baseModuleArg}' but must be in format ${baseArgRegex}`
);
process.exit(1);
}
const excludeDeprecated: boolean =
args.excludeDeprecated === null || args.excludeDeprecated === undefined
? false
: args.excludeDeprecated;
const headerArg: undefined | string | [string] = args.header;
const addHeader = (object: any, header: string) => {
const [headerKey, headerValue] = header.split(":");
object[headerKey] = headerValue;
return object;
};
let headers = {};
if (typeof headerArg === "string") {
addHeader(headers, headerArg);
} else if (headerArg == undefined) {
} else {
headerArg.forEach(header => {
addHeader(headers, header);
});
}
const baseModule = baseModuleArg ? baseModuleArg.split(".") : ["Api"];
function prependBasePath(suffixPath: string): string {
return path.join(outputPath, baseModule.join("/"), suffixPath);
}
const graphqlUrl: undefined | string = args._[0];
const introspectionFile: undefined | string = args["introspection-file"];
if (!(graphqlUrl || introspectionFile)) {
console.log(usage);
process.exit(0);
}
warnIfContainsNonGenerated(prependBasePath("/"));
const onDataAvailable = (data: {}) => {
console.log("Generating files...");
let app = Elm.Main.init({ flags: { data, baseModule } });
app.ports.generatedFiles.subscribe(function(generatedFile: any) {
removeGenerated(prependBasePath("/"));
fs.mkdirpSync(prependBasePath("InputObject"));
fs.mkdirpSync(prependBasePath("Object"));
fs.mkdirpSync(prependBasePath("Interface"));
fs.mkdirpSync(prependBasePath("Union"));
fs.mkdirpSync(prependBasePath("Enum"));
for (let key in generatedFile) {
let filePath = path.join(outputPath, key);
let value = generatedFile[key];
writeFile(filePath, targetComment + value);
}
fs.writeFileSync(
prependBasePath("elm-graphql-metadata.json"),
`{"targetElmPackageVersion": "${elmPackageVersion}", "generatedByNpmPackageVersion": "${npmPackageVersion}"}`
);
console.log("Success!");
});
};
if (introspectionFile) {
const introspectionFileJson = JSON.parse(
fs.readFileSync(introspectionFile).toString()
);
onDataAvailable(introspectionFileJson.data || introspectionFileJson);
} else {
console.log("Fetching GraphQL schema...");
new GraphQLClient(graphqlUrl, {
mode: "cors",
headers: headers
})
.request(introspectionQuery, { includeDeprecated: !excludeDeprecated })
.then(data => {
onDataAvailable(data);
})
.catch(err => {
console.log(err.response || err);
process.exit(1);
});
}