@famgia/omnify-typescript 0.0.65 → 0.0.66

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/plugin.cjs CHANGED
@@ -918,11 +918,460 @@ function generateRulesFiles(schemas, options = {}) {
918
918
  return files;
919
919
  }
920
920
 
921
+ // src/zod-generator.ts
922
+ function getMultiLocaleDisplayName2(value, locales, fallbackLocale, defaultValue) {
923
+ if (!value) {
924
+ const result2 = {};
925
+ for (const locale of locales) {
926
+ result2[locale] = defaultValue;
927
+ }
928
+ return result2;
929
+ }
930
+ if (typeof value === "string") {
931
+ const result2 = {};
932
+ for (const locale of locales) {
933
+ result2[locale] = value;
934
+ }
935
+ return result2;
936
+ }
937
+ const result = {};
938
+ for (const locale of locales) {
939
+ result[locale] = value[locale] ?? value[fallbackLocale] ?? value["en"] ?? defaultValue;
940
+ }
941
+ return result;
942
+ }
943
+ function getZodSchemaForType(propDef, fieldName, customTypes) {
944
+ const def = propDef;
945
+ const isNullable = def.nullable ?? false;
946
+ let schema = "";
947
+ if (customTypes) {
948
+ const customType = customTypes.get(propDef.type);
949
+ if (customType && !customType.compound) {
950
+ const sqlType = customType.sql?.sqlType || "VARCHAR";
951
+ schema = "z.string()";
952
+ if (customType.sql?.length) {
953
+ schema += `.max(${customType.sql.length})`;
954
+ }
955
+ if (isNullable) {
956
+ schema += ".optional().nullable()";
957
+ }
958
+ return schema;
959
+ }
960
+ }
961
+ switch (propDef.type) {
962
+ case "String":
963
+ case "Text":
964
+ case "MediumText":
965
+ case "LongText":
966
+ case "Password":
967
+ schema = "z.string()";
968
+ if (!isNullable) {
969
+ schema += ".min(1)";
970
+ }
971
+ if (def.maxLength || def.length) {
972
+ schema += `.max(${def.maxLength ?? def.length})`;
973
+ }
974
+ if (def.minLength && def.minLength > 1) {
975
+ schema = schema.replace(".min(1)", `.min(${def.minLength})`);
976
+ }
977
+ break;
978
+ case "Email":
979
+ schema = "z.string().email()";
980
+ if (def.maxLength || def.length) {
981
+ schema += `.max(${def.maxLength ?? def.length ?? 255})`;
982
+ }
983
+ break;
984
+ case "TinyInt":
985
+ case "Int":
986
+ case "BigInt":
987
+ schema = "z.number().int()";
988
+ if (def.min !== void 0) {
989
+ schema += `.gte(${def.min})`;
990
+ }
991
+ if (def.max !== void 0) {
992
+ schema += `.lte(${def.max})`;
993
+ }
994
+ break;
995
+ case "Float":
996
+ schema = "z.number()";
997
+ if (def.min !== void 0) {
998
+ schema += `.gte(${def.min})`;
999
+ }
1000
+ if (def.max !== void 0) {
1001
+ schema += `.lte(${def.max})`;
1002
+ }
1003
+ break;
1004
+ case "Boolean":
1005
+ schema = "z.boolean()";
1006
+ break;
1007
+ case "Date":
1008
+ schema = "z.string().date()";
1009
+ break;
1010
+ case "DateTime":
1011
+ case "Timestamp":
1012
+ schema = "z.string().datetime({ offset: true })";
1013
+ break;
1014
+ case "Time":
1015
+ schema = "z.string().time()";
1016
+ break;
1017
+ case "Json":
1018
+ schema = "z.unknown()";
1019
+ break;
1020
+ case "Enum":
1021
+ if (typeof def.enum === "string") {
1022
+ schema = `${def.enum}Schema`;
1023
+ } else if (Array.isArray(def.enum)) {
1024
+ const values = def.enum.map((v) => `'${v}'`).join(", ");
1025
+ schema = `z.enum([${values}])`;
1026
+ } else {
1027
+ schema = "z.string()";
1028
+ }
1029
+ break;
1030
+ case "Select":
1031
+ if (def.options && def.options.length > 0) {
1032
+ const values = def.options.map((v) => `'${v}'`).join(", ");
1033
+ schema = `z.enum([${values}])`;
1034
+ } else {
1035
+ schema = "z.string()";
1036
+ }
1037
+ break;
1038
+ case "Lookup":
1039
+ schema = "z.number().int().positive()";
1040
+ break;
1041
+ case "Association":
1042
+ return "";
1043
+ case "File":
1044
+ return "";
1045
+ default:
1046
+ schema = "z.string()";
1047
+ }
1048
+ if (isNullable && schema) {
1049
+ schema += ".optional().nullable()";
1050
+ }
1051
+ if (def.pattern && schema) {
1052
+ schema += `.regex(/${def.pattern}/)`;
1053
+ }
1054
+ return schema;
1055
+ }
1056
+ function generateCompoundTypeSchemas(propName, propDef, customType, options) {
1057
+ const schemas = [];
1058
+ const propFields = propDef.fields;
1059
+ const locales = options.localeConfig?.locales ?? ["en"];
1060
+ const fallbackLocale = options.localeConfig?.fallbackLocale ?? "en";
1061
+ if (!customType.expand) return schemas;
1062
+ for (const field of customType.expand) {
1063
+ const fieldName = `${toSnakeCase(propName)}_${toSnakeCase(field.suffix)}`;
1064
+ const fieldOverride = propFields?.[field.suffix];
1065
+ const isNullable = fieldOverride?.nullable ?? propDef.nullable ?? false;
1066
+ const length = fieldOverride?.length ?? field.sql?.length;
1067
+ let schema = "z.string()";
1068
+ if (!isNullable) {
1069
+ schema += ".min(1)";
1070
+ }
1071
+ if (length) {
1072
+ schema += `.max(${length})`;
1073
+ }
1074
+ if (isNullable) {
1075
+ schema += ".optional().nullable()";
1076
+ }
1077
+ const propDisplayName = getMultiLocaleDisplayName2(
1078
+ propDef.displayName,
1079
+ locales,
1080
+ fallbackLocale,
1081
+ propName
1082
+ );
1083
+ schemas.push({
1084
+ fieldName,
1085
+ schema,
1086
+ inCreate: true,
1087
+ inUpdate: true,
1088
+ comment: `${propDisplayName["en"] ?? propName} (${field.suffix})`
1089
+ });
1090
+ }
1091
+ return schemas;
1092
+ }
1093
+ function generateZodSchemas(schema, options) {
1094
+ const schemas = [];
1095
+ const customTypes = options.customTypes;
1096
+ if (!schema.properties) return schemas;
1097
+ for (const [propName, propDef] of Object.entries(schema.properties)) {
1098
+ if (customTypes) {
1099
+ const customType = customTypes.get(propDef.type);
1100
+ if (customType?.compound) {
1101
+ schemas.push(...generateCompoundTypeSchemas(propName, propDef, customType, options));
1102
+ continue;
1103
+ }
1104
+ }
1105
+ const zodSchema = getZodSchemaForType(propDef, propName, customTypes);
1106
+ if (!zodSchema) continue;
1107
+ const fieldName = toSnakeCase(propName);
1108
+ schemas.push({
1109
+ fieldName,
1110
+ schema: zodSchema,
1111
+ inCreate: true,
1112
+ inUpdate: true,
1113
+ comment: void 0
1114
+ });
1115
+ }
1116
+ return schemas;
1117
+ }
1118
+ function generateDisplayNames(schema, options) {
1119
+ const locales = options.localeConfig?.locales ?? ["en"];
1120
+ const fallbackLocale = options.localeConfig?.fallbackLocale ?? "en";
1121
+ const customTypes = options.customTypes;
1122
+ const displayName = getMultiLocaleDisplayName2(
1123
+ schema.displayName,
1124
+ locales,
1125
+ fallbackLocale,
1126
+ schema.name
1127
+ );
1128
+ const propertyDisplayNames = {};
1129
+ if (schema.properties) {
1130
+ for (const [propName, propDef] of Object.entries(schema.properties)) {
1131
+ const prop = propDef;
1132
+ const fieldName = toSnakeCase(propName);
1133
+ if (customTypes) {
1134
+ const customType = customTypes.get(propDef.type);
1135
+ if (customType?.compound && customType.expand) {
1136
+ for (const field of customType.expand) {
1137
+ const expandedFieldName = `${fieldName}_${toSnakeCase(field.suffix)}`;
1138
+ propertyDisplayNames[expandedFieldName] = getMultiLocaleDisplayName2(
1139
+ prop.displayName,
1140
+ locales,
1141
+ fallbackLocale,
1142
+ propName
1143
+ );
1144
+ for (const locale of locales) {
1145
+ propertyDisplayNames[expandedFieldName] = {
1146
+ ...propertyDisplayNames[expandedFieldName],
1147
+ [locale]: `${propertyDisplayNames[expandedFieldName][locale]} (${field.suffix})`
1148
+ };
1149
+ }
1150
+ }
1151
+ continue;
1152
+ }
1153
+ }
1154
+ propertyDisplayNames[fieldName] = getMultiLocaleDisplayName2(
1155
+ prop.displayName,
1156
+ locales,
1157
+ fallbackLocale,
1158
+ propName
1159
+ );
1160
+ }
1161
+ }
1162
+ return { displayName, propertyDisplayNames };
1163
+ }
1164
+ function getExcludedFields(schema, customTypes) {
1165
+ const createExclude = /* @__PURE__ */ new Set();
1166
+ const updateExclude = /* @__PURE__ */ new Set();
1167
+ if (schema.options?.id !== false) {
1168
+ createExclude.add("id");
1169
+ updateExclude.add("id");
1170
+ }
1171
+ if (schema.options?.timestamps !== false) {
1172
+ createExclude.add("created_at");
1173
+ createExclude.add("updated_at");
1174
+ updateExclude.add("created_at");
1175
+ updateExclude.add("updated_at");
1176
+ }
1177
+ if (schema.options?.softDelete) {
1178
+ createExclude.add("deleted_at");
1179
+ updateExclude.add("deleted_at");
1180
+ }
1181
+ if (schema.properties) {
1182
+ if (schema.properties["emailVerifiedAt"] || schema.properties["email_verified_at"]) {
1183
+ createExclude.add("email_verified_at");
1184
+ updateExclude.add("email_verified_at");
1185
+ }
1186
+ }
1187
+ if (schema.properties && customTypes) {
1188
+ for (const [propName, propDef] of Object.entries(schema.properties)) {
1189
+ const customType = customTypes.get(propDef.type);
1190
+ if (customType?.accessors) {
1191
+ for (const accessor of customType.accessors) {
1192
+ const fieldName = `${toSnakeCase(propName)}_${toSnakeCase(accessor.name)}`;
1193
+ createExclude.add(fieldName);
1194
+ updateExclude.add(fieldName);
1195
+ }
1196
+ }
1197
+ }
1198
+ }
1199
+ return { create: createExclude, update: updateExclude };
1200
+ }
1201
+ function formatZodSchemasSection(schemaName, zodSchemas, displayNames, excludedFields) {
1202
+ const parts = [];
1203
+ const lowerName = schemaName.charAt(0).toLowerCase() + schemaName.slice(1);
1204
+ parts.push(`// ============================================================================
1205
+ `);
1206
+ parts.push(`// Display Names
1207
+ `);
1208
+ parts.push(`// ============================================================================
1209
+
1210
+ `);
1211
+ parts.push(`/** Display name for ${schemaName} */
1212
+ `);
1213
+ parts.push(`export const ${schemaName}DisplayName = ${JSON.stringify(displayNames.displayName, null, 2)} as const;
1214
+
1215
+ `);
1216
+ parts.push(`/** Property display names for ${schemaName} */
1217
+ `);
1218
+ parts.push(`export const ${schemaName}PropertyDisplayNames = {
1219
+ `);
1220
+ for (const [propName, localeMap] of Object.entries(displayNames.propertyDisplayNames)) {
1221
+ parts.push(` ${propName}: ${JSON.stringify(localeMap)},
1222
+ `);
1223
+ }
1224
+ parts.push(`} as const;
1225
+
1226
+ `);
1227
+ parts.push(`// ============================================================================
1228
+ `);
1229
+ parts.push(`// Zod Schemas
1230
+ `);
1231
+ parts.push(`// ============================================================================
1232
+
1233
+ `);
1234
+ parts.push(`/** Field schemas for ${schemaName} */
1235
+ `);
1236
+ parts.push(`export const base${schemaName}Schemas = {
1237
+ `);
1238
+ for (const prop of zodSchemas) {
1239
+ if (prop.comment) {
1240
+ parts.push(` /** ${prop.comment} */
1241
+ `);
1242
+ }
1243
+ parts.push(` ${prop.fieldName}: ${prop.schema},
1244
+ `);
1245
+ }
1246
+ parts.push(`} as const;
1247
+
1248
+ `);
1249
+ const createFields = zodSchemas.filter((p) => p.inCreate && !excludedFields.create.has(p.fieldName));
1250
+ parts.push(`/** Create schema for ${schemaName} (POST requests) */
1251
+ `);
1252
+ parts.push(`export const base${schemaName}CreateSchema = z.object({
1253
+ `);
1254
+ for (const prop of createFields) {
1255
+ parts.push(` ${prop.fieldName}: base${schemaName}Schemas.${prop.fieldName},
1256
+ `);
1257
+ }
1258
+ parts.push(`});
1259
+
1260
+ `);
1261
+ parts.push(`/** Update schema for ${schemaName} (PUT/PATCH requests) */
1262
+ `);
1263
+ parts.push(`export const base${schemaName}UpdateSchema = base${schemaName}CreateSchema.partial();
1264
+
1265
+ `);
1266
+ parts.push(`// ============================================================================
1267
+ `);
1268
+ parts.push(`// Inferred Types
1269
+ `);
1270
+ parts.push(`// ============================================================================
1271
+
1272
+ `);
1273
+ parts.push(`export type Base${schemaName}Create = z.infer<typeof base${schemaName}CreateSchema>;
1274
+ `);
1275
+ parts.push(`export type Base${schemaName}Update = z.infer<typeof base${schemaName}UpdateSchema>;
1276
+
1277
+ `);
1278
+ parts.push(`// ============================================================================
1279
+ `);
1280
+ parts.push(`// Helper Functions
1281
+ `);
1282
+ parts.push(`// ============================================================================
1283
+
1284
+ `);
1285
+ parts.push(`/** Get display name for a specific locale */
1286
+ `);
1287
+ parts.push(`export function get${schemaName}DisplayName(locale: string): string {
1288
+ `);
1289
+ parts.push(` return ${schemaName}DisplayName[locale as keyof typeof ${schemaName}DisplayName] ?? ${schemaName}DisplayName['en'] ?? '${schemaName}';
1290
+ `);
1291
+ parts.push(`}
1292
+
1293
+ `);
1294
+ parts.push(`/** Get property display name for a specific locale */
1295
+ `);
1296
+ parts.push(`export function get${schemaName}PropertyDisplayName(property: string, locale: string): string {
1297
+ `);
1298
+ parts.push(` const names = ${schemaName}PropertyDisplayNames[property as keyof typeof ${schemaName}PropertyDisplayNames];
1299
+ `);
1300
+ parts.push(` if (!names) return property;
1301
+ `);
1302
+ parts.push(` return names[locale as keyof typeof names] ?? names['en'] ?? property;
1303
+ `);
1304
+ parts.push(`}
1305
+ `);
1306
+ return parts.join("");
1307
+ }
1308
+ function formatZodModelFile(schemaName) {
1309
+ const lowerName = schemaName.charAt(0).toLowerCase() + schemaName.slice(1);
1310
+ return `/**
1311
+ * ${schemaName} Model
1312
+ *
1313
+ * This file extends the auto-generated base interface.
1314
+ * You can add custom methods, computed properties, or override types/schemas here.
1315
+ * This file will NOT be overwritten by the generator.
1316
+ */
1317
+
1318
+ import { z } from 'zod';
1319
+ import type { ${schemaName} as ${schemaName}Base } from './base/${schemaName}.js';
1320
+ import {
1321
+ base${schemaName}Schemas,
1322
+ base${schemaName}CreateSchema,
1323
+ base${schemaName}UpdateSchema,
1324
+ ${schemaName}DisplayName,
1325
+ ${schemaName}PropertyDisplayNames,
1326
+ get${schemaName}DisplayName,
1327
+ get${schemaName}PropertyDisplayName,
1328
+ } from './base/${schemaName}.js';
1329
+
1330
+ // ============================================================================
1331
+ // Types (extend or re-export)
1332
+ // ============================================================================
1333
+
1334
+ export interface ${schemaName} extends ${schemaName}Base {
1335
+ // Add custom properties here
1336
+ }
1337
+
1338
+ // ============================================================================
1339
+ // Schemas (extend or re-export)
1340
+ // ============================================================================
1341
+
1342
+ export const ${lowerName}Schemas = { ...base${schemaName}Schemas };
1343
+ export const ${lowerName}CreateSchema = base${schemaName}CreateSchema;
1344
+ export const ${lowerName}UpdateSchema = base${schemaName}UpdateSchema;
1345
+
1346
+ // ============================================================================
1347
+ // Types
1348
+ // ============================================================================
1349
+
1350
+ export type ${schemaName}Create = z.infer<typeof ${lowerName}CreateSchema>;
1351
+ export type ${schemaName}Update = z.infer<typeof ${lowerName}UpdateSchema>;
1352
+
1353
+ // Re-export display names and helpers
1354
+ export {
1355
+ ${schemaName}DisplayName,
1356
+ ${schemaName}PropertyDisplayNames,
1357
+ get${schemaName}DisplayName,
1358
+ get${schemaName}PropertyDisplayName,
1359
+ };
1360
+
1361
+ // Re-export base type for internal use
1362
+ export type { ${schemaName}Base };
1363
+ `;
1364
+ }
1365
+
921
1366
  // src/generator.ts
922
1367
  var DEFAULT_OPTIONS = {
923
1368
  readonly: false,
924
1369
  // Changed: interfaces should be mutable for forms/mutations
925
- strictNullChecks: true
1370
+ strictNullChecks: true,
1371
+ generateZodSchemas: true,
1372
+ // Generate Zod schemas by default
1373
+ generateRules: false
1374
+ // Legacy Ant Design rules (deprecated, ignored when generateZodSchemas=true)
926
1375
  };
927
1376
  function generateBaseHeader() {
928
1377
  return `/**
@@ -943,7 +1392,21 @@ function generateModelHeader(schemaName) {
943
1392
 
944
1393
  `;
945
1394
  }
946
- function generateUtilityTypes(schemaName, schema) {
1395
+ function getComputedFields(schema, customTypes) {
1396
+ const computedFields = [];
1397
+ if (!schema.properties) return computedFields;
1398
+ for (const [propName, propDef] of Object.entries(schema.properties)) {
1399
+ const snakeName = toSnakeCase(propName);
1400
+ const customType = customTypes?.get(propDef.type);
1401
+ if (customType?.accessors) {
1402
+ for (const accessor of customType.accessors) {
1403
+ computedFields.push(`${snakeName}_${toSnakeCase(accessor.name)}`);
1404
+ }
1405
+ }
1406
+ }
1407
+ return computedFields;
1408
+ }
1409
+ function generateUtilityTypes(schemaName, schema, customTypes) {
947
1410
  const parts = [];
948
1411
  const excludeFields = [];
949
1412
  if (schema.options?.id !== false) {
@@ -955,6 +1418,13 @@ function generateUtilityTypes(schemaName, schema) {
955
1418
  if (schema.options?.softDelete) {
956
1419
  excludeFields.push("'deleted_at'");
957
1420
  }
1421
+ if (schema.properties?.["emailVerifiedAt"] || schema.properties?.["email_verified_at"]) {
1422
+ excludeFields.push("'email_verified_at'");
1423
+ }
1424
+ const computedFields = getComputedFields(schema, customTypes);
1425
+ for (const field of computedFields) {
1426
+ excludeFields.push(`'${field}'`);
1427
+ }
958
1428
  const omitType = excludeFields.length > 0 ? `Omit<${schemaName}, ${excludeFields.join(" | ")}>` : schemaName;
959
1429
  parts.push(`
960
1430
  /** For creating new ${schemaName} (POST requests) */`);
@@ -989,6 +1459,10 @@ function generateBaseInterfaceFile(schemaName, schemas, options) {
989
1459
  throw new Error(`Interface not found for schema: ${schemaName}`);
990
1460
  }
991
1461
  const parts = [generateBaseHeader()];
1462
+ if (options.generateZodSchemas) {
1463
+ parts.push(`import { z } from 'zod';
1464
+ `);
1465
+ }
992
1466
  const dateImports = needsDateTimeImports(iface);
993
1467
  const commonImports = [];
994
1468
  if (dateImports.dateTime) commonImports.push("DateTimeString");
@@ -1003,12 +1477,20 @@ function generateBaseInterfaceFile(schemaName, schemas, options) {
1003
1477
  `);
1004
1478
  }
1005
1479
  parts.push("\n");
1006
- } else if (commonImports.length > 0) {
1480
+ } else if (commonImports.length > 0 || options.generateZodSchemas) {
1007
1481
  parts.push("\n");
1008
1482
  }
1009
1483
  parts.push(formatInterface(iface));
1010
1484
  parts.push("\n");
1011
- parts.push(generateUtilityTypes(schemaName, schema));
1485
+ if (options.generateZodSchemas) {
1486
+ const zodSchemas = generateZodSchemas(schema, options);
1487
+ const displayNames = generateDisplayNames(schema, options);
1488
+ const excludedFields = getExcludedFields(schema, options.customTypes);
1489
+ parts.push("\n");
1490
+ parts.push(formatZodSchemasSection(schemaName, zodSchemas, displayNames, excludedFields));
1491
+ } else {
1492
+ parts.push(generateUtilityTypes(schemaName, schema, options.customTypes));
1493
+ }
1012
1494
  return {
1013
1495
  filePath: `base/${schemaName}.ts`,
1014
1496
  content: parts.join(""),
@@ -1038,7 +1520,16 @@ function generateTypeAliasFile(alias) {
1038
1520
  overwrite: true
1039
1521
  };
1040
1522
  }
1041
- function generateModelFile(schemaName) {
1523
+ function generateModelFile(schemaName, options) {
1524
+ if (options.generateZodSchemas) {
1525
+ return {
1526
+ filePath: `${schemaName}.ts`,
1527
+ content: formatZodModelFile(schemaName),
1528
+ types: [schemaName],
1529
+ overwrite: false
1530
+ // Never overwrite user models
1531
+ };
1532
+ }
1042
1533
  const parts = [generateModelHeader(schemaName)];
1043
1534
  parts.push(`import type { ${schemaName} as ${schemaName}Base } from './base/${schemaName}.js';
1044
1535
 
@@ -1158,34 +1649,64 @@ function generateIndexFile(schemas, enums, typeAliases, options) {
1158
1649
  }
1159
1650
  parts.push("\n");
1160
1651
  }
1161
- parts.push(`// Models (with Create/Update utility types)
1162
- `);
1163
- for (const schema of Object.values(schemas)) {
1164
- if (schema.kind === "enum") continue;
1165
- if (schema.options?.hidden === true) continue;
1166
- parts.push(`export type { ${schema.name} } from './${schema.name}.js';
1167
- `);
1168
- parts.push(`export type { ${schema.name}Create, ${schema.name}Update } from './base/${schema.name}.js';
1169
- `);
1170
- }
1171
- if (options.generateRules) {
1172
- parts.push(`
1173
- // Validation Rules
1652
+ if (options.generateZodSchemas) {
1653
+ parts.push(`// Models (with Zod schemas and Create/Update types)
1174
1654
  `);
1175
1655
  for (const schema of Object.values(schemas)) {
1176
1656
  if (schema.kind === "enum") continue;
1177
1657
  if (schema.options?.hidden === true) continue;
1658
+ const lowerName = schema.name.charAt(0).toLowerCase() + schema.name.slice(1);
1659
+ parts.push(`export type { ${schema.name}, ${schema.name}Create, ${schema.name}Update } from './${schema.name}.js';
1660
+ `);
1178
1661
  parts.push(`export {
1179
1662
  `);
1180
- parts.push(` get${schema.name}Rules,
1663
+ parts.push(` ${lowerName}Schemas,
1664
+ `);
1665
+ parts.push(` ${lowerName}CreateSchema,
1666
+ `);
1667
+ parts.push(` ${lowerName}UpdateSchema,
1668
+ `);
1669
+ parts.push(` ${schema.name}DisplayName,
1670
+ `);
1671
+ parts.push(` ${schema.name}PropertyDisplayNames,
1181
1672
  `);
1182
1673
  parts.push(` get${schema.name}DisplayName,
1183
1674
  `);
1184
1675
  parts.push(` get${schema.name}PropertyDisplayName,
1185
1676
  `);
1186
- parts.push(`} from './rules/${schema.name}.rules.js';
1677
+ parts.push(`} from './${schema.name}.js';
1187
1678
  `);
1188
1679
  }
1680
+ } else {
1681
+ parts.push(`// Models (with Create/Update utility types)
1682
+ `);
1683
+ for (const schema of Object.values(schemas)) {
1684
+ if (schema.kind === "enum") continue;
1685
+ if (schema.options?.hidden === true) continue;
1686
+ parts.push(`export type { ${schema.name} } from './${schema.name}.js';
1687
+ `);
1688
+ parts.push(`export type { ${schema.name}Create, ${schema.name}Update } from './base/${schema.name}.js';
1689
+ `);
1690
+ }
1691
+ if (options.generateRules) {
1692
+ parts.push(`
1693
+ // Validation Rules
1694
+ `);
1695
+ for (const schema of Object.values(schemas)) {
1696
+ if (schema.kind === "enum") continue;
1697
+ if (schema.options?.hidden === true) continue;
1698
+ parts.push(`export {
1699
+ `);
1700
+ parts.push(` get${schema.name}Rules,
1701
+ `);
1702
+ parts.push(` get${schema.name}DisplayName,
1703
+ `);
1704
+ parts.push(` get${schema.name}PropertyDisplayName,
1705
+ `);
1706
+ parts.push(`} from './rules/${schema.name}.rules.js';
1707
+ `);
1708
+ }
1709
+ }
1189
1710
  }
1190
1711
  return {
1191
1712
  filePath: "index.ts",
@@ -1213,9 +1734,9 @@ function generateTypeScript(schemas, options = {}) {
1213
1734
  for (const schema of Object.values(schemas)) {
1214
1735
  if (schema.kind === "enum") continue;
1215
1736
  if (schema.options?.hidden === true) continue;
1216
- files.push(generateModelFile(schema.name));
1737
+ files.push(generateModelFile(schema.name, opts));
1217
1738
  }
1218
- if (opts.generateRules) {
1739
+ if (!opts.generateZodSchemas && opts.generateRules) {
1219
1740
  const rulesFiles = generateRulesFiles(schemas, opts);
1220
1741
  files.push(...rulesFiles);
1221
1742
  }
@@ -1230,16 +1751,25 @@ var TYPESCRIPT_CONFIG_SCHEMA = {
1230
1751
  {
1231
1752
  key: "modelsPath",
1232
1753
  type: "path",
1233
- label: "Models Output Path",
1234
- description: "Directory for generated TypeScript model files",
1235
- default: "types/models",
1754
+ label: "Schemas Output Path",
1755
+ description: "Directory for generated TypeScript types and Zod schemas",
1756
+ default: "types/schemas",
1757
+ group: "output"
1758
+ },
1759
+ {
1760
+ key: "generateZodSchemas",
1761
+ type: "boolean",
1762
+ label: "Generate Zod Schemas",
1763
+ description: "Generate Zod schemas alongside TypeScript types for form validation",
1764
+ default: true,
1236
1765
  group: "output"
1237
1766
  }
1238
1767
  ]
1239
1768
  };
1240
1769
  function resolveOptions(options) {
1241
1770
  return {
1242
- modelsPath: options?.modelsPath ?? "types/models"
1771
+ modelsPath: options?.modelsPath ?? "types/schemas",
1772
+ generateZodSchemas: options?.generateZodSchemas ?? true
1243
1773
  };
1244
1774
  }
1245
1775
  function typescriptPlugin(options) {
@@ -1253,7 +1783,11 @@ function typescriptPlugin(options) {
1253
1783
  name: "typescript-models",
1254
1784
  description: "Generate TypeScript model definitions",
1255
1785
  generate: async (ctx) => {
1256
- const files = generateTypeScript(ctx.schemas);
1786
+ const files = generateTypeScript(ctx.schemas, {
1787
+ generateZodSchemas: resolved.generateZodSchemas,
1788
+ localeConfig: ctx.localeConfig,
1789
+ customTypes: ctx.customTypes
1790
+ });
1257
1791
  return files.map((file) => ({
1258
1792
  path: `${resolved.modelsPath}/${file.filePath}`,
1259
1793
  content: file.content,