UNPKG

@api-platform/client-generator

Version:

Generate apps built with Next, Nuxt, Quasar, React, React Native, Vue or Vuetify for any API documented using Hydra or OpenAPI

154 lines (136 loc) 5.04 kB
#!/usr/bin/env node import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import "isomorphic-fetch"; import { program } from "commander"; import apiDocParser from "@api-platform/api-doc-parser"; import generators from "./generators.js"; const dirname = path.dirname(fileURLToPath(import.meta.url)); const packageJson = JSON.parse( fs.readFileSync(`${dirname}/../package.json`, "utf-8") ); async function main() { program .version(packageJson.version) .description( "Generate apps built with Next, Nuxt, Quasar, React, React Native, Vue or Vuetify for any API documented using Hydra or OpenAPI" ) .usage("entrypoint outputDirectory") .option( "-r, --resource [resourceName]", "Generate CRUD for the given resource" ) .option( "-p, --hydra-prefix [hydraPrefix]", "The hydra prefix used by the API", "hydra:" ) .option("--username [username]", "Username for basic auth (Hydra only)") .option("--password [password]", "Password for basic auth (Hydra only)") .option("--bearer [bearer]", "Token for bearer auth (Hydra only)") .option( "-g, --generator [generator]", 'The generator to use, one of "next", "nuxt", "quasar", "react", "react-native", "typescript", "vue", "vuetify" or a path to a custom generator of your choice', "next" ) .option( "-t, --template-directory [templateDirectory]", "The templates directory base to use. Final directory will be ${templateDirectory}/${generator}", `${dirname}/../templates/` ) .option( "-f, --format [hydra|openapi3|openapi2]", '"hydra", "openapi3" or "openapi2"', "hydra" ) .option( "-s, --server-path [serverPath]", "Path to express server file to allow route dynamic addition (Next.js generator only)" ) .parse(process.argv); if ( 2 !== program.args.length && (!process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT || !process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT) ) { program.help(); } const options = program.opts(); const entrypoint = program.args[0] || process.env.API_PLATFORM_CLIENT_GENERATOR_ENTRYPOINT; const outputDirectory = program.args[1] || process.env.API_PLATFORM_CLIENT_GENERATOR_OUTPUT; const entrypointWithSlash = entrypoint.endsWith("/") ? entrypoint : entrypoint + "/"; const generator = (await generators(options.generator))({ hydraPrefix: options.hydraPrefix, templateDirectory: options.templateDirectory, }); const resourceToGenerate = options.resource ? options.resource.toLowerCase() : null; const serverPath = options.serverPath ? options.serverPath.toLowerCase() : null; const parser = (entrypointWithSlash) => { // parserOptions are used to set headers on the hydra-requests const parserOptions = {}; // options refers to the opts set via the CLI if (options.username && options.password) { const encoded = Buffer.from( `${options.username}:${options.password}` ).toString("base64"); parserOptions.headers = new Headers(); parserOptions.headers.set("Authorization", `Basic ${encoded}`); } if (options.bearer) { parserOptions.headers = new Headers(); parserOptions.headers.set("Authorization", `Bearer ${options.bearer}`); } switch (options.format) { case "swagger": // deprecated case "openapi2": return apiDocParser.parseSwaggerDocumentation(entrypointWithSlash); case "openapi3": return apiDocParser.parseOpenApi3Documentation(entrypointWithSlash); default: return apiDocParser.parseHydraDocumentation( entrypointWithSlash, parserOptions ); } }; // check generator dependencies generator.checkDependencies(outputDirectory, serverPath); parser(entrypointWithSlash) .then((ret) => { ret.api.resources .filter(({ deprecated }) => !deprecated) .filter((resource) => { const nameLc = resource.name.toLowerCase(); const titleLc = resource.title.toLowerCase(); return ( null === resourceToGenerate || nameLc === resourceToGenerate || titleLc === resourceToGenerate ); }) .map((resource) => { const filterDeprecated = (list) => list.filter(({ deprecated }) => !deprecated); resource.fields = filterDeprecated(resource.fields); resource.readableFields = filterDeprecated(resource.readableFields); resource.writableFields = filterDeprecated(resource.writableFields); generator.generate(ret.api, resource, outputDirectory, serverPath); return resource; }) // display helps after all resources have been generated to check relation dependency for example .forEach((resource) => generator.help(resource, outputDirectory)); }) .catch((e) => { console.log(e); }); } main();