@igniter-js/cli 0.2.62 → 0.2.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -19549,12 +19549,18 @@ var PrismaProvider = class {
19549
19549
  return null;
19550
19550
  }
19551
19551
  const fields = model.properties.filter((prop) => prop.type === "field").map((prop) => {
19552
- const isRelation = !/^[A-Z]/.test(prop.fieldType.toString()) && typeof prop.fieldType !== "string";
19552
+ if (prop.type !== "field" || !("fieldType" in prop) || !("name" in prop)) {
19553
+ throw new Error(`Invalid field property structure for ${prop}`);
19554
+ }
19555
+ const fieldType = prop.fieldType;
19556
+ const fieldTypeStr = typeof fieldType === "string" ? fieldType : fieldType?.toString() || "string";
19557
+ const isOptional = "optional" in prop ? prop.optional : false;
19558
+ const isRelation = !/^[A-Z]/.test(fieldTypeStr) && typeof fieldType !== "string";
19553
19559
  return {
19554
19560
  name: prop.name,
19555
- type: mapPrismaTypeToTsType(prop.fieldType),
19561
+ type: mapPrismaTypeToTsType(fieldTypeStr),
19556
19562
  isId: hasAttribute(prop, "id"),
19557
- isRequired: !(prop.optional || hasAttribute(prop, "default")),
19563
+ isRequired: !(isOptional || hasAttribute(prop, "default")),
19558
19564
  isUnique: hasAttribute(prop, "unique"),
19559
19565
  isRelation,
19560
19566
  hasDefault: hasAttribute(prop, "default"),
@@ -19574,6 +19580,28 @@ var PrismaProvider = class {
19574
19580
  throw new Error(`Could not process Prisma schema. Make sure '${this.schemaPath}' exists and is valid.`);
19575
19581
  }
19576
19582
  }
19583
+ /**
19584
+ * Lists all available model names in the Prisma schema.
19585
+ *
19586
+ * @returns A promise that resolves to an array of model names.
19587
+ */
19588
+ async listModels() {
19589
+ try {
19590
+ const schemaContent = await fs4.readFile(this.schemaPath, "utf-8");
19591
+ const ast = (0, import_prisma_ast.getSchema)(schemaContent);
19592
+ const models = ast.list.filter((node) => node.type === "model").map((model) => model.name);
19593
+ logger4.debug(`Found ${models.length} models in schema: ${models.join(", ")}`);
19594
+ return models;
19595
+ } catch (error) {
19596
+ if (error.code === "ENOENT") {
19597
+ logger4.error(`Prisma schema file not found at: ${this.schemaPath}`);
19598
+ return [];
19599
+ } else {
19600
+ logger4.error("Failed to parse Prisma schema for model listing", { error });
19601
+ throw new Error(`Could not process Prisma schema. Make sure '${this.schemaPath}' exists and is valid.`);
19602
+ }
19603
+ }
19604
+ }
19577
19605
  /**
19578
19606
  * Determines if a field's value is automatically managed by the database.
19579
19607
  *
@@ -19599,6 +19627,29 @@ var PrismaProvider = class {
19599
19627
 
19600
19628
  // src/adapters/scaffold.ts
19601
19629
  var logger5 = createChildLogger({ component: "scaffold" });
19630
+ async function hasPrismaSchema() {
19631
+ const possiblePaths = [
19632
+ path6.join(process.cwd(), "prisma", "schema.prisma"),
19633
+ path6.join(process.cwd(), "schema.prisma")
19634
+ ];
19635
+ for (const schemaPath of possiblePaths) {
19636
+ try {
19637
+ await fs5.access(schemaPath);
19638
+ return true;
19639
+ } catch {
19640
+ }
19641
+ }
19642
+ return false;
19643
+ }
19644
+ async function getPrismaModels() {
19645
+ try {
19646
+ const provider = new PrismaProvider();
19647
+ return await provider.listModels();
19648
+ } catch (error) {
19649
+ logger5.debug("Failed to get Prisma models", { error });
19650
+ return [];
19651
+ }
19652
+ }
19602
19653
  function toPascalCase(str) {
19603
19654
  return str.replace(/(^\w|-\w)/g, (g) => g.replace(/-/, "").toUpperCase());
19604
19655
  }
@@ -19811,8 +19862,7 @@ function generateEmptyIndexTemplate(featureName) {
19811
19862
  `;
19812
19863
  }
19813
19864
  async function scaffoldEmptyFeature(featureName, featureDir) {
19814
- const spinner = logger5.spinner(`Creating empty feature '${featureName}'...`);
19815
- spinner.start();
19865
+ logger5.info(`Creating empty feature '${featureName}'...`);
19816
19866
  try {
19817
19867
  await fs5.mkdir(path6.join(featureDir, "controllers"), { recursive: true });
19818
19868
  await fs5.mkdir(path6.join(featureDir, "procedures"), { recursive: true });
@@ -19828,15 +19878,14 @@ async function scaffoldEmptyFeature(featureName, featureDir) {
19828
19878
  path6.join(featureDir, "index.ts"),
19829
19879
  generateEmptyIndexTemplate(featureName)
19830
19880
  );
19831
- spinner.success(`Scaffolded empty feature '${featureName}'`);
19881
+ logger5.success(`Scaffolded empty feature '${featureName}'`);
19832
19882
  } catch (error) {
19833
- spinner.error(`Failed to create empty feature '${featureName}'`);
19883
+ logger5.error(`Failed to create empty feature '${featureName}'`);
19834
19884
  throw error;
19835
19885
  }
19836
19886
  }
19837
19887
  async function scaffoldFeatureFromSchema(featureName, schemaString, featureDir) {
19838
- const spinner = logger5.spinner(`Scaffolding feature '${featureName}' from schema...`);
19839
- spinner.start();
19888
+ logger5.info(`Scaffolding feature '${featureName}' from schema...`);
19840
19889
  try {
19841
19890
  const [providerName, modelName] = schemaString.split(":");
19842
19891
  if (!providerName || !modelName) {
@@ -19847,7 +19896,7 @@ async function scaffoldFeatureFromSchema(featureName, schemaString, featureDir)
19847
19896
  if (!model) {
19848
19897
  throw new Error(`Model '${modelName}' not found using provider '${providerName}'.`);
19849
19898
  }
19850
- spinner.update("Generating files from model schema...");
19899
+ logger5.info("Generating files from model schema...");
19851
19900
  await fs5.mkdir(path6.join(featureDir, "controllers"), { recursive: true });
19852
19901
  await fs5.mkdir(path6.join(featureDir, "procedures"), { recursive: true });
19853
19902
  await writeFile2(
@@ -19866,15 +19915,64 @@ async function scaffoldFeatureFromSchema(featureName, schemaString, featureDir)
19866
19915
  path6.join(featureDir, "index.ts"),
19867
19916
  generateCrudIndexTemplate(featureName)
19868
19917
  );
19869
- spinner.success(`Successfully scaffolded feature '${featureName}' from '${modelName}' model.`);
19918
+ logger5.success(`Successfully scaffolded feature '${featureName}' from '${modelName}' model.`);
19870
19919
  console.log(import_chalk5.default.cyan(`
19871
19920
  \u2705 Next step: Register the '${toCamelCase(featureName)}Controller' in 'src/igniter.router.ts'`));
19872
19921
  } catch (error) {
19873
- spinner.error(`Failed to scaffold feature from schema`);
19922
+ logger5.error(`Failed to scaffold feature from schema`);
19874
19923
  throw error;
19875
19924
  }
19876
19925
  }
19877
- async function handleGenerateFeature(featureName, options) {
19926
+ async function handleGenerateFeature(name, options = {}) {
19927
+ let featureName = name;
19928
+ if (!featureName) {
19929
+ const prompts2 = await import("prompts");
19930
+ const hasPrisma = await hasPrismaSchema();
19931
+ const prismaModels = hasPrisma ? await getPrismaModels() : [];
19932
+ const questions = [
19933
+ {
19934
+ type: "text",
19935
+ name: "featureName",
19936
+ message: "What is the name of your feature?",
19937
+ validate: (input) => {
19938
+ if (!input.trim()) {
19939
+ return "Feature name is required";
19940
+ }
19941
+ if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(input)) {
19942
+ return "Feature name must start with a letter and contain only letters, numbers, hyphens, and underscores";
19943
+ }
19944
+ return true;
19945
+ }
19946
+ }
19947
+ ];
19948
+ if (hasPrisma && prismaModels.length > 0) {
19949
+ questions.push({
19950
+ type: "select",
19951
+ name: "useModel",
19952
+ message: "Would you like to generate CRUD operations from a Prisma model?",
19953
+ choices: [
19954
+ { title: "No, create an empty feature", value: "none" },
19955
+ { title: "Yes, select a Prisma model", value: "select" }
19956
+ ],
19957
+ initial: 0
19958
+ });
19959
+ questions.push({
19960
+ type: (prev) => prev === "select" ? "select" : null,
19961
+ name: "selectedModel",
19962
+ message: "Which Prisma model would you like to use?",
19963
+ choices: prismaModels.map((model) => ({ title: model, value: model }))
19964
+ });
19965
+ }
19966
+ const response = await prompts2.default(questions);
19967
+ if (!response.featureName) {
19968
+ logger5.error("Feature name is required");
19969
+ process.exit(1);
19970
+ }
19971
+ featureName = response.featureName;
19972
+ if (response.useModel === "select" && response.selectedModel) {
19973
+ options.schema = `prisma:${response.selectedModel}`;
19974
+ }
19975
+ }
19878
19976
  const normalizedName = featureName.toLowerCase();
19879
19977
  const featureDir = path6.join(process.cwd(), "src", "features", normalizedName);
19880
19978
  logger5.info(`Scaffolding feature: ${import_chalk5.default.cyan(normalizedName)}`);
@@ -20111,7 +20209,7 @@ generate.command("docs").description("Generate OpenAPI specification and/or inte
20111
20209
  process.exit(1);
20112
20210
  }
20113
20211
  });
20114
- generate.command("feature").description("Scaffold a new feature module").argument("<name>", "The name of the feature (e.g., 'user', 'products')").option("--schema <value>", "Generate from a schema provider (e.g., 'prisma:User')").action(async (name, options) => {
20212
+ generate.command("feature").description("Scaffold a new feature module").argument("[name]", "The name of the feature (e.g., 'user', 'products')").option("--schema <value>", "Generate from a schema provider (e.g., 'prisma:User')").action(async (name, options) => {
20115
20213
  await handleGenerateFeature(name, options);
20116
20214
  });
20117
20215
  generate.command("controller").description("Scaffold a new controller within a feature").argument("<name>", "The name of the controller (e.g., 'profile')").option("-f, --feature <feature>", "The parent feature name", "").action(async (name, options) => {