@famgia/omnify-typescript 0.0.64 → 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/{chunk-53QQ3AMT.js → chunk-4L77AHAC.js} +544 -23
- package/dist/chunk-4L77AHAC.js.map +1 -0
- package/dist/index.cjs +543 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +561 -27
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +13 -7
- package/dist/plugin.d.ts +13 -7
- package/dist/plugin.js +19 -6
- package/dist/plugin.js.map +1 -1
- package/package.json +10 -2
- package/dist/chunk-53QQ3AMT.js.map +0 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
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(`
|
|
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 '
|
|
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: "
|
|
1234
|
-
description: "Directory for generated TypeScript
|
|
1235
|
-
default: "types/
|
|
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/
|
|
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,
|