@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 +112 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +112 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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(
|
|
19561
|
+
type: mapPrismaTypeToTsType(fieldTypeStr),
|
|
19556
19562
|
isId: hasAttribute(prop, "id"),
|
|
19557
|
-
isRequired: !(
|
|
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
|
-
|
|
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
|
-
|
|
19881
|
+
logger5.success(`Scaffolded empty feature '${featureName}'`);
|
|
19832
19882
|
} catch (error) {
|
|
19833
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19922
|
+
logger5.error(`Failed to scaffold feature from schema`);
|
|
19874
19923
|
throw error;
|
|
19875
19924
|
}
|
|
19876
19925
|
}
|
|
19877
|
-
async function handleGenerateFeature(
|
|
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("
|
|
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) => {
|