UNPKG

@blitzjs/cli

Version:
236 lines (235 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Generate = void 0; const tslib_1 = require("tslib"); const generator_1 = require("@blitzjs/generator"); const command_1 = require("@oclif/command"); const chalk_1 = (0, tslib_1.__importDefault)(require("chalk")); const logging_1 = require("next/dist/server/lib/logging"); const command_2 = require("../command"); const prompt_aborted_1 = require("../errors/prompt-aborted"); const debug = require("debug")("blitz:generate"); const getIsTypeScript = () => (0, tslib_1.__awaiter)(void 0, void 0, void 0, function* () { return require("fs").existsSync(require("path").join(yield require("next/dist/server/lib/utils").getProjectRoot(process.cwd()), "tsconfig.json")); }); var ResourceType; (function (ResourceType) { ResourceType["All"] = "all"; ResourceType["Crud"] = "crud"; ResourceType["Model"] = "model"; ResourceType["Pages"] = "pages"; ResourceType["Queries"] = "queries"; ResourceType["Query"] = "query"; ResourceType["Mutations"] = "mutations"; ResourceType["Mutation"] = "mutation"; ResourceType["Resource"] = "resource"; })(ResourceType || (ResourceType = {})); function modelName(input = "") { return (0, generator_1.singleCamel)(input); } function modelNames(input = "") { return (0, generator_1.pluralCamel)(input); } function ModelName(input = "") { return (0, generator_1.singlePascal)(input); } function ModelNames(input = "") { return (0, generator_1.pluralPascal)(input); } const generatorMap = { [ResourceType.All]: [ generator_1.PageGenerator, generator_1.FormGenerator, generator_1.QueriesGenerator, generator_1.MutationsGenerator, generator_1.ModelGenerator, ], [ResourceType.Crud]: [generator_1.MutationsGenerator, generator_1.QueriesGenerator], [ResourceType.Model]: [generator_1.ModelGenerator], [ResourceType.Pages]: [generator_1.PageGenerator, generator_1.FormGenerator], [ResourceType.Queries]: [generator_1.QueriesGenerator], [ResourceType.Query]: [generator_1.QueryGenerator], [ResourceType.Mutations]: [generator_1.MutationsGenerator], [ResourceType.Mutation]: [generator_1.MutationGenerator], [ResourceType.Resource]: [generator_1.QueriesGenerator, generator_1.MutationsGenerator, generator_1.ModelGenerator], }; class Generate extends command_2.Command { promptForTargetDirectory(paths) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () { return require("enquirer") .prompt({ name: "directory", type: "select", message: "Please select a target directory:", choices: paths, }) .then((resp) => resp.directory); }); } genericConfirmPrompt(message) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () { return require("enquirer") .prompt({ name: "continue", type: "select", message: message, choices: ["Yes", "No"], }) .then((resp) => resp.continue === "Yes"); }); } handleNoContext(message) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () { const shouldCreateNewRoot = yield this.genericConfirmPrompt(message); if (!shouldCreateNewRoot) { (0, logging_1.baseLogger)({ displayDateTime: false }).error("Could not determine proper location for files. Aborting."); this.exit(0); } }); } getModelNameAndContext(modelName, context) { const modelSegments = modelName.split(/[\\/]/); if (modelSegments.length > 1) { return { model: modelSegments[modelSegments.length - 1], context: require("path").join(...modelSegments.slice(0, modelSegments.length - 1)), }; } if (Boolean(context)) { const contextSegments = context.split(/[\\/]/); return { model: modelName, context: require("path").join(...contextSegments), }; } return { model: modelName, }; } validateModelName(modelName) { const RESERVED_MODEL_NAMES = ["page", "api", "query", "mutation"]; if (RESERVED_MODEL_NAMES.includes(modelName)) { throw new Error(`Names ${RESERVED_MODEL_NAMES} or their plurals cannot be used as model names`); } if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(modelName)) { throw new Error(`Invalid model name: "${modelName}". Model names need to adhere to this regular expression: [A-Za-z][A-Za-z0-9_]*`); } } run() { var _a; return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () { const { args, argv, flags } = this.parse(Generate); debug("args: ", args); debug("flags: ", flags); process.env.BLITZ_APP_DIR = process.cwd(); try { const { model, context } = this.getModelNameAndContext(args.model, flags.context); const singularRootContext = modelName(model); this.validateModelName(singularRootContext); const { loadConfigProduction } = yield Promise.resolve().then(() => (0, tslib_1.__importStar)(require("next/dist/server/config-shared"))); const blitzConfig = loadConfigProduction(process.cwd()); const generators = generatorMap[args.type]; for (const GeneratorClass of generators) { const generator = new GeneratorClass({ destinationRoot: require("path").resolve(), templateDir: (_a = blitzConfig.codegen) === null || _a === void 0 ? void 0 : _a.templateDir, extraArgs: argv.slice(2).filter((arg) => !arg.startsWith("-")), modelName: singularRootContext, modelNames: modelNames(singularRootContext), ModelName: ModelName(singularRootContext), ModelNames: ModelNames(singularRootContext), parentModel: modelName(flags.parent), parentModels: modelNames(flags.parent), ParentModel: ModelName(flags.parent), ParentModels: ModelNames(flags.parent), name: (0, generator_1.uncapitalize)(model), Name: (0, generator_1.capitalize)(model), dryRun: flags["dry-run"], context: context, useTs: yield getIsTypeScript(), }); yield generator.run(); } console.log(" "); // new line } catch (err) { if (err instanceof prompt_aborted_1.PromptAbortedError) this.exit(0); (0, logging_1.baseLogger)({ displayDateTime: false }).error(err); this.exit(1); } }); } } exports.Generate = Generate; Generate.description = "Generate new files for your Blitz project"; Generate.aliases = ["g"]; Generate.strict = false; Generate.args = [ { name: "type", required: true, description: "What files to generate", options: Object.keys(generatorMap).map((s) => s.toLowerCase()), }, { name: "model", required: true, description: 'The name of your model, like "user". Can be singular or plural - same result', }, ]; Generate.flags = { help: command_1.flags.help({ char: "h" }), context: command_1.flags.string({ char: "c", description: "Provide a context folder within which we'll place the generated files for better code organization. You can also supply this in the name of the model to be generated (e.g. `blitz generate query admin/projects`). Combining the `--context` flags and supplying context via the model name in the same command is not supported.", }), parent: command_1.flags.string({ char: "p", description: "Specify a parent model to be used for generating nested routes for dependent data when generating pages, or to create hierarchical validation in queries and mutations. The code will be generated with the nested data model in mind. Most often this should be used in conjunction with 'blitz generate all'", }), "dry-run": command_1.flags.boolean({ char: "d", description: "Show what files will be created without writing them to disk", }), env: command_1.flags.string({ char: "e", description: "Set app environment name", }), }; Generate.examples = [ `${chalk_1.default.dim("# The 'crud' type will generate all queries & mutations for a model")} > blitz generate crud productVariant `, `${chalk_1.default.dim("# The 'all' generator will scaffold out everything possible for a model")} > blitz generate all products `, `${chalk_1.default.dim("# The '--context' flag will allow you to generate files in a nested folder")} > blitz generate pages projects --admin `, `${chalk_1.default.dim("# Context can also be supplied in the model name directly")} > blitz generate pages admin/projects `, `${chalk_1.default.dim(`# To generate nested routes for dependent models (e.g. Projects that contain # Tasks), specify a parent model. For example, this command generates pages under # app/tasks/pages/projects/[projectId]/tasks/`)} > blitz generate all tasks --parent=projects `, `${chalk_1.default.dim(`# Database models can also be generated directly from the CLI # Model fields can be specified with any generator that generates # a database model ("all", "model", "resource"). Both of the below # will generate the proper database model for a Task.`)} > blitz generate model task \\ name:string \\ completed:boolean:default=false \\ belongsTo:project? > blitz generate all tasks \\ name:string \\ completed:boolean:default=false \\ belongsTo:project? `, `${chalk_1.default.dim(`# Sometimes you want just a single query with no generated # logic. Generating "query" instead of "queries" will give you a more # customizable template.`)} > blitz generate query getUserSession`, ];