@omnifyjp/ts 0.3.0
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/cli.d.ts +13 -0
- package/dist/cli.js +180 -0
- package/dist/enum-generator.d.ts +28 -0
- package/dist/enum-generator.js +253 -0
- package/dist/generator.d.ts +19 -0
- package/dist/generator.js +330 -0
- package/dist/i18n-generator.d.ts +10 -0
- package/dist/i18n-generator.js +143 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/interface-generator.d.ts +31 -0
- package/dist/interface-generator.js +341 -0
- package/dist/php/base-model-generator.d.ts +7 -0
- package/dist/php/base-model-generator.js +70 -0
- package/dist/php/factory-generator.d.ts +7 -0
- package/dist/php/factory-generator.js +95 -0
- package/dist/php/faker-mapper.d.ts +12 -0
- package/dist/php/faker-mapper.js +206 -0
- package/dist/php/index.d.ts +18 -0
- package/dist/php/index.js +40 -0
- package/dist/php/locales-generator.d.ts +7 -0
- package/dist/php/locales-generator.js +135 -0
- package/dist/php/model-generator.d.ts +7 -0
- package/dist/php/model-generator.js +396 -0
- package/dist/php/naming-helper.d.ts +22 -0
- package/dist/php/naming-helper.js +61 -0
- package/dist/php/relation-builder.d.ts +12 -0
- package/dist/php/relation-builder.js +147 -0
- package/dist/php/request-generator.d.ts +7 -0
- package/dist/php/request-generator.js +221 -0
- package/dist/php/resource-generator.d.ts +7 -0
- package/dist/php/resource-generator.js +178 -0
- package/dist/php/schema-reader.d.ts +28 -0
- package/dist/php/schema-reader.js +79 -0
- package/dist/php/service-provider-generator.d.ts +7 -0
- package/dist/php/service-provider-generator.js +64 -0
- package/dist/php/trait-generator.d.ts +6 -0
- package/dist/php/trait-generator.js +104 -0
- package/dist/php/type-mapper.d.ts +25 -0
- package/dist/php/type-mapper.js +217 -0
- package/dist/php/types.d.ts +61 -0
- package/dist/php/types.js +68 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.js +6 -0
- package/dist/zod-generator.d.ts +32 -0
- package/dist/zod-generator.js +428 -0
- package/package.json +31 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — Zod Schema Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates Zod schemas alongside TypeScript interfaces for form validation.
|
|
5
|
+
*/
|
|
6
|
+
import type { SchemaDefinition, ZodPropertySchema, SchemaDisplayNames, GeneratorOptions } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate Zod schemas for all properties in a schema.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateZodSchemas(schema: SchemaDefinition, options: GeneratorOptions): ZodPropertySchema[];
|
|
11
|
+
/**
|
|
12
|
+
* Generate display names and placeholders for a schema.
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateDisplayNames(schema: SchemaDefinition, options: GeneratorOptions): SchemaDisplayNames;
|
|
15
|
+
/**
|
|
16
|
+
* Get fields to exclude from create/update schemas.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getExcludedFields(schema: SchemaDefinition): {
|
|
19
|
+
create: Set<string>;
|
|
20
|
+
update: Set<string>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Format Zod schemas section for a base file.
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatZodSchemasSection(schemaName: string, zodSchemas: ZodPropertySchema[], displayNames: SchemaDisplayNames, excludedFields: {
|
|
26
|
+
create: Set<string>;
|
|
27
|
+
update: Set<string>;
|
|
28
|
+
}): string;
|
|
29
|
+
/**
|
|
30
|
+
* Format user model file with Zod re-exports.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatZodModelFile(schemaName: string): string;
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — Zod Schema Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates Zod schemas alongside TypeScript interfaces for form validation.
|
|
5
|
+
*/
|
|
6
|
+
import { toSnakeCase } from './interface-generator.js';
|
|
7
|
+
/**
|
|
8
|
+
* Get localized display name as multi-locale object.
|
|
9
|
+
*/
|
|
10
|
+
function getMultiLocaleDisplayName(value, locales, fallbackLocale, defaultValue) {
|
|
11
|
+
if (!value) {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const locale of locales)
|
|
14
|
+
result[locale] = defaultValue;
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === 'string') {
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const locale of locales)
|
|
20
|
+
result[locale] = value;
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const locale of locales) {
|
|
25
|
+
result[locale] = value[locale] ?? value[fallbackLocale] ?? value['en'] ?? defaultValue;
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate Zod schema string for a property type.
|
|
31
|
+
*/
|
|
32
|
+
function getZodSchemaForType(propDef, _fieldName, options) {
|
|
33
|
+
const isNullable = propDef.nullable ?? false;
|
|
34
|
+
let schema = '';
|
|
35
|
+
// Check for simple custom types
|
|
36
|
+
const simpleType = options.customTypes.simple[propDef.type];
|
|
37
|
+
if (simpleType) {
|
|
38
|
+
schema = 'z.string()';
|
|
39
|
+
if (simpleType.length) {
|
|
40
|
+
schema += `.max(${simpleType.length})`;
|
|
41
|
+
}
|
|
42
|
+
if (isNullable) {
|
|
43
|
+
schema += '.optional().nullable()';
|
|
44
|
+
}
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
47
|
+
switch (propDef.type) {
|
|
48
|
+
case 'String':
|
|
49
|
+
case 'Text':
|
|
50
|
+
case 'MediumText':
|
|
51
|
+
case 'LongText':
|
|
52
|
+
case 'Password':
|
|
53
|
+
schema = 'z.string()';
|
|
54
|
+
if (!isNullable)
|
|
55
|
+
schema += '.min(1)';
|
|
56
|
+
if (propDef.maxLength || propDef.length) {
|
|
57
|
+
schema += `.max(${propDef.maxLength ?? propDef.length})`;
|
|
58
|
+
}
|
|
59
|
+
if (propDef.minLength && propDef.minLength > 1) {
|
|
60
|
+
schema = schema.replace('.min(1)', `.min(${propDef.minLength})`);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case 'Email':
|
|
64
|
+
schema = 'z.string().email()';
|
|
65
|
+
if (propDef.maxLength || propDef.length) {
|
|
66
|
+
schema += `.max(${propDef.maxLength ?? propDef.length ?? 255})`;
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
case 'TinyInt':
|
|
70
|
+
case 'Int':
|
|
71
|
+
case 'BigInt':
|
|
72
|
+
schema = 'z.number().int()';
|
|
73
|
+
if (propDef.min !== undefined)
|
|
74
|
+
schema += `.gte(${propDef.min})`;
|
|
75
|
+
if (propDef.max !== undefined)
|
|
76
|
+
schema += `.lte(${propDef.max})`;
|
|
77
|
+
break;
|
|
78
|
+
case 'Float':
|
|
79
|
+
case 'Decimal':
|
|
80
|
+
schema = 'z.number()';
|
|
81
|
+
if (propDef.min !== undefined)
|
|
82
|
+
schema += `.gte(${propDef.min})`;
|
|
83
|
+
if (propDef.max !== undefined)
|
|
84
|
+
schema += `.lte(${propDef.max})`;
|
|
85
|
+
break;
|
|
86
|
+
case 'Boolean':
|
|
87
|
+
schema = 'z.boolean()';
|
|
88
|
+
break;
|
|
89
|
+
case 'Date':
|
|
90
|
+
schema = 'z.string().date()';
|
|
91
|
+
break;
|
|
92
|
+
case 'DateTime':
|
|
93
|
+
case 'Timestamp':
|
|
94
|
+
schema = 'z.string().datetime({ offset: true })';
|
|
95
|
+
break;
|
|
96
|
+
case 'Time':
|
|
97
|
+
schema = 'z.string().time()';
|
|
98
|
+
break;
|
|
99
|
+
case 'Json':
|
|
100
|
+
schema = 'z.unknown()';
|
|
101
|
+
break;
|
|
102
|
+
case 'EnumRef':
|
|
103
|
+
if (typeof propDef.enum === 'string') {
|
|
104
|
+
schema = `z.nativeEnum(${propDef.enum})`;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
schema = 'z.string()';
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
case 'Enum':
|
|
111
|
+
if (typeof propDef.enum === 'string') {
|
|
112
|
+
schema = `z.nativeEnum(${propDef.enum})`;
|
|
113
|
+
}
|
|
114
|
+
else if (Array.isArray(propDef.enum)) {
|
|
115
|
+
const values = propDef.enum.map(v => `'${v}'`).join(', ');
|
|
116
|
+
schema = `z.enum([${values}])`;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
schema = 'z.string()';
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
case 'Lookup':
|
|
123
|
+
schema = 'z.number().int().positive()';
|
|
124
|
+
break;
|
|
125
|
+
case 'Association':
|
|
126
|
+
case 'File':
|
|
127
|
+
return '';
|
|
128
|
+
default:
|
|
129
|
+
schema = 'z.string()';
|
|
130
|
+
}
|
|
131
|
+
if (isNullable && schema) {
|
|
132
|
+
schema += '.optional().nullable()';
|
|
133
|
+
}
|
|
134
|
+
if (propDef.pattern && schema) {
|
|
135
|
+
schema += `.regex(/${propDef.pattern}/)`;
|
|
136
|
+
}
|
|
137
|
+
return schema;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Generate Zod schemas for compound type expanded columns.
|
|
141
|
+
*/
|
|
142
|
+
function generateCompoundTypeSchemas(propName, schema, options) {
|
|
143
|
+
const expanded = schema.expandedProperties?.[propName];
|
|
144
|
+
if (!expanded)
|
|
145
|
+
return [];
|
|
146
|
+
const schemas = [];
|
|
147
|
+
const compoundDef = options.customTypes.compound[expanded.sourceType];
|
|
148
|
+
const propDef = schema.properties?.[propName];
|
|
149
|
+
const propFields = propDef?.fields;
|
|
150
|
+
for (const col of expanded.columns) {
|
|
151
|
+
const fieldOverride = propFields?.[col.suffix];
|
|
152
|
+
const compoundField = compoundDef?.fields.find(f => f.suffix === col.suffix);
|
|
153
|
+
const isNullable = col.nullable ?? compoundField?.nullable ?? false;
|
|
154
|
+
let zodSchema;
|
|
155
|
+
if (col.type === 'Enum' && compoundField?.enumRef) {
|
|
156
|
+
// Enum reference (e.g., Prefecture)
|
|
157
|
+
zodSchema = `z.nativeEnum(${compoundField.enumRef})`;
|
|
158
|
+
if (isNullable)
|
|
159
|
+
zodSchema += '.optional().nullable()';
|
|
160
|
+
}
|
|
161
|
+
else if (col.type === 'Enum' && col.enum) {
|
|
162
|
+
// Inline enum
|
|
163
|
+
const values = col.enum.map(v => `'${v}'`).join(', ');
|
|
164
|
+
zodSchema = `z.enum([${values}])`;
|
|
165
|
+
if (isNullable)
|
|
166
|
+
zodSchema += '.optional().nullable()';
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// String type with length
|
|
170
|
+
zodSchema = 'z.string()';
|
|
171
|
+
if (!isNullable)
|
|
172
|
+
zodSchema += '.min(1)';
|
|
173
|
+
const length = fieldOverride?.length ?? col.length;
|
|
174
|
+
if (length)
|
|
175
|
+
zodSchema += `.max(${length})`;
|
|
176
|
+
if (isNullable)
|
|
177
|
+
zodSchema += '.optional().nullable()';
|
|
178
|
+
}
|
|
179
|
+
schemas.push({
|
|
180
|
+
fieldName: col.name,
|
|
181
|
+
schema: zodSchema,
|
|
182
|
+
inCreate: true,
|
|
183
|
+
inUpdate: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return schemas;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Generate Zod schemas for all properties in a schema.
|
|
190
|
+
*/
|
|
191
|
+
export function generateZodSchemas(schema, options) {
|
|
192
|
+
const schemas = [];
|
|
193
|
+
if (!schema.properties)
|
|
194
|
+
return schemas;
|
|
195
|
+
const propNames = schema.propertyOrder ?? Object.keys(schema.properties);
|
|
196
|
+
for (const propName of propNames) {
|
|
197
|
+
const propDef = schema.properties[propName];
|
|
198
|
+
if (!propDef)
|
|
199
|
+
continue;
|
|
200
|
+
// Check for compound type expansion
|
|
201
|
+
if (schema.expandedProperties?.[propName]) {
|
|
202
|
+
schemas.push(...generateCompoundTypeSchemas(propName, schema, options));
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const zodSchema = getZodSchemaForType(propDef, propName, options);
|
|
206
|
+
if (!zodSchema)
|
|
207
|
+
continue;
|
|
208
|
+
schemas.push({
|
|
209
|
+
fieldName: toSnakeCase(propName),
|
|
210
|
+
schema: zodSchema,
|
|
211
|
+
inCreate: true,
|
|
212
|
+
inUpdate: true,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return schemas;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generate display names and placeholders for a schema.
|
|
219
|
+
*/
|
|
220
|
+
export function generateDisplayNames(schema, options) {
|
|
221
|
+
const { locales, fallbackLocale } = options;
|
|
222
|
+
const displayName = getMultiLocaleDisplayName(schema.displayName, locales, fallbackLocale, schema.name);
|
|
223
|
+
const propertyDisplayNames = {};
|
|
224
|
+
const propertyPlaceholders = {};
|
|
225
|
+
if (schema.properties) {
|
|
226
|
+
const propNames = schema.propertyOrder ?? Object.keys(schema.properties);
|
|
227
|
+
for (const propName of propNames) {
|
|
228
|
+
const propDef = schema.properties[propName];
|
|
229
|
+
if (!propDef)
|
|
230
|
+
continue;
|
|
231
|
+
const fieldName = toSnakeCase(propName);
|
|
232
|
+
// Compound type: expand to individual fields
|
|
233
|
+
if (schema.expandedProperties?.[propName]) {
|
|
234
|
+
const expanded = schema.expandedProperties[propName];
|
|
235
|
+
// Add compound-level displayName
|
|
236
|
+
if (propDef.displayName) {
|
|
237
|
+
propertyDisplayNames[fieldName] = getMultiLocaleDisplayName(propDef.displayName, locales, fallbackLocale, propName);
|
|
238
|
+
}
|
|
239
|
+
for (const col of expanded.columns) {
|
|
240
|
+
const fieldOverride = propDef.fields?.[col.suffix];
|
|
241
|
+
// Display name for expanded field
|
|
242
|
+
const labelSource = fieldOverride?.displayName;
|
|
243
|
+
if (labelSource) {
|
|
244
|
+
propertyDisplayNames[col.name] = getMultiLocaleDisplayName(labelSource, locales, fallbackLocale, col.suffix);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
// Fallback: parent displayName + suffix
|
|
248
|
+
const parentLabel = getMultiLocaleDisplayName(propDef.displayName, locales, fallbackLocale, propName);
|
|
249
|
+
const suffixed = {};
|
|
250
|
+
for (const locale of locales) {
|
|
251
|
+
suffixed[locale] = `${parentLabel[locale]} (${col.suffix})`;
|
|
252
|
+
}
|
|
253
|
+
propertyDisplayNames[col.name] = suffixed;
|
|
254
|
+
}
|
|
255
|
+
// Placeholder for expanded field
|
|
256
|
+
if (fieldOverride?.placeholder) {
|
|
257
|
+
propertyPlaceholders[col.name] = getMultiLocaleDisplayName(fieldOverride.placeholder, locales, fallbackLocale, '');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
// Regular field display name
|
|
263
|
+
propertyDisplayNames[fieldName] = getMultiLocaleDisplayName(propDef.displayName, locales, fallbackLocale, propName);
|
|
264
|
+
// Placeholder
|
|
265
|
+
if (propDef.placeholder) {
|
|
266
|
+
propertyPlaceholders[fieldName] = getMultiLocaleDisplayName(propDef.placeholder, locales, fallbackLocale, '');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return { displayName, propertyDisplayNames, propertyPlaceholders };
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get fields to exclude from create/update schemas.
|
|
274
|
+
*/
|
|
275
|
+
export function getExcludedFields(schema) {
|
|
276
|
+
const createExclude = new Set();
|
|
277
|
+
const updateExclude = new Set();
|
|
278
|
+
if (schema.options?.id !== false) {
|
|
279
|
+
createExclude.add('id');
|
|
280
|
+
updateExclude.add('id');
|
|
281
|
+
}
|
|
282
|
+
if (schema.options?.timestamps !== false) {
|
|
283
|
+
for (const f of ['created_at', 'updated_at']) {
|
|
284
|
+
createExclude.add(f);
|
|
285
|
+
updateExclude.add(f);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (schema.options?.softDelete) {
|
|
289
|
+
createExclude.add('deleted_at');
|
|
290
|
+
updateExclude.add('deleted_at');
|
|
291
|
+
}
|
|
292
|
+
return { create: createExclude, update: updateExclude };
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Format Zod schemas section for a base file.
|
|
296
|
+
*/
|
|
297
|
+
export function formatZodSchemasSection(schemaName, zodSchemas, displayNames, excludedFields) {
|
|
298
|
+
const parts = [];
|
|
299
|
+
const lowerName = schemaName.charAt(0).toLowerCase() + schemaName.slice(1);
|
|
300
|
+
// I18n section
|
|
301
|
+
parts.push(`// ============================================================================\n`);
|
|
302
|
+
parts.push(`// I18n (Internationalization)\n`);
|
|
303
|
+
parts.push(`// ============================================================================\n\n`);
|
|
304
|
+
parts.push(`/**\n * Unified i18n object for ${schemaName}\n */\n`);
|
|
305
|
+
parts.push(`export const ${lowerName}I18n = {\n`);
|
|
306
|
+
parts.push(` label: ${JSON.stringify(displayNames.displayName)},\n`);
|
|
307
|
+
parts.push(` fields: {\n`);
|
|
308
|
+
for (const [propName, labelMap] of Object.entries(displayNames.propertyDisplayNames)) {
|
|
309
|
+
const placeholderMap = displayNames.propertyPlaceholders[propName];
|
|
310
|
+
parts.push(` ${propName}: {\n`);
|
|
311
|
+
parts.push(` label: ${JSON.stringify(labelMap)},\n`);
|
|
312
|
+
if (placeholderMap) {
|
|
313
|
+
parts.push(` placeholder: ${JSON.stringify(placeholderMap)},\n`);
|
|
314
|
+
}
|
|
315
|
+
parts.push(` },\n`);
|
|
316
|
+
}
|
|
317
|
+
parts.push(` },\n`);
|
|
318
|
+
parts.push(`} as const;\n\n`);
|
|
319
|
+
// Zod Schemas section
|
|
320
|
+
parts.push(`// ============================================================================\n`);
|
|
321
|
+
parts.push(`// Zod Schemas\n`);
|
|
322
|
+
parts.push(`// ============================================================================\n\n`);
|
|
323
|
+
parts.push(`/** Field schemas for ${schemaName} */\n`);
|
|
324
|
+
parts.push(`export const base${schemaName}Schemas = {\n`);
|
|
325
|
+
for (const prop of zodSchemas) {
|
|
326
|
+
parts.push(` ${prop.fieldName}: ${prop.schema},\n`);
|
|
327
|
+
}
|
|
328
|
+
parts.push(`} as const;\n\n`);
|
|
329
|
+
// Create Schema
|
|
330
|
+
const createFields = zodSchemas.filter(p => p.inCreate && !excludedFields.create.has(p.fieldName));
|
|
331
|
+
parts.push(`/** Create schema for ${schemaName} */\n`);
|
|
332
|
+
parts.push(`export const base${schemaName}CreateSchema = z.object({\n`);
|
|
333
|
+
for (const prop of createFields) {
|
|
334
|
+
parts.push(` ${prop.fieldName}: base${schemaName}Schemas.${prop.fieldName},\n`);
|
|
335
|
+
}
|
|
336
|
+
parts.push(`});\n\n`);
|
|
337
|
+
// Update Schema
|
|
338
|
+
parts.push(`/** Update schema for ${schemaName} */\n`);
|
|
339
|
+
parts.push(`export const base${schemaName}UpdateSchema = base${schemaName}CreateSchema.partial();\n\n`);
|
|
340
|
+
// Inferred Types
|
|
341
|
+
parts.push(`// ============================================================================\n`);
|
|
342
|
+
parts.push(`// Inferred Types\n`);
|
|
343
|
+
parts.push(`// ============================================================================\n\n`);
|
|
344
|
+
parts.push(`export type Base${schemaName}Create = z.infer<typeof base${schemaName}CreateSchema>;\n`);
|
|
345
|
+
parts.push(`export type Base${schemaName}Update = z.infer<typeof base${schemaName}UpdateSchema>;\n\n`);
|
|
346
|
+
// Helper Functions
|
|
347
|
+
parts.push(`// ============================================================================\n`);
|
|
348
|
+
parts.push(`// I18n Helper Functions\n`);
|
|
349
|
+
parts.push(`// ============================================================================\n\n`);
|
|
350
|
+
parts.push(`/** Get model label for a specific locale */\n`);
|
|
351
|
+
parts.push(`export function get${schemaName}Label(locale: string): string {\n`);
|
|
352
|
+
parts.push(` return ${lowerName}I18n.label[locale as keyof typeof ${lowerName}I18n.label] ?? ${lowerName}I18n.label['en'] ?? '${schemaName}';\n`);
|
|
353
|
+
parts.push(`}\n\n`);
|
|
354
|
+
parts.push(`/** Get field label for a specific locale */\n`);
|
|
355
|
+
parts.push(`export function get${schemaName}FieldLabel(field: string, locale: string): string {\n`);
|
|
356
|
+
parts.push(` const fieldI18n = ${lowerName}I18n.fields[field as keyof typeof ${lowerName}I18n.fields];\n`);
|
|
357
|
+
parts.push(` if (!fieldI18n) return field;\n`);
|
|
358
|
+
parts.push(` return fieldI18n.label[locale as keyof typeof fieldI18n.label] ?? fieldI18n.label['en'] ?? field;\n`);
|
|
359
|
+
parts.push(`}\n\n`);
|
|
360
|
+
parts.push(`/** Get field placeholder for a specific locale */\n`);
|
|
361
|
+
parts.push(`export function get${schemaName}FieldPlaceholder(field: string, locale: string): string {\n`);
|
|
362
|
+
parts.push(` const fieldI18n = ${lowerName}I18n.fields[field as keyof typeof ${lowerName}I18n.fields];\n`);
|
|
363
|
+
parts.push(` if (!fieldI18n || !('placeholder' in fieldI18n)) return '';\n`);
|
|
364
|
+
parts.push(` const placeholder = fieldI18n.placeholder as Record<string, string>;\n`);
|
|
365
|
+
parts.push(` return placeholder[locale] ?? placeholder['en'] ?? '';\n`);
|
|
366
|
+
parts.push(`}\n`);
|
|
367
|
+
return parts.join('');
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Format user model file with Zod re-exports.
|
|
371
|
+
*/
|
|
372
|
+
export function formatZodModelFile(schemaName) {
|
|
373
|
+
const lowerName = schemaName.charAt(0).toLowerCase() + schemaName.slice(1);
|
|
374
|
+
return `/**
|
|
375
|
+
* ${schemaName} Model
|
|
376
|
+
*
|
|
377
|
+
* This file extends the auto-generated base interface.
|
|
378
|
+
* You can add custom methods, computed properties, or override types/schemas here.
|
|
379
|
+
* This file will NOT be overwritten by the generator.
|
|
380
|
+
*/
|
|
381
|
+
|
|
382
|
+
import { z } from 'zod';
|
|
383
|
+
import type { ${schemaName} as ${schemaName}Base } from './base/${schemaName}.js';
|
|
384
|
+
import {
|
|
385
|
+
base${schemaName}Schemas,
|
|
386
|
+
base${schemaName}CreateSchema,
|
|
387
|
+
base${schemaName}UpdateSchema,
|
|
388
|
+
${lowerName}I18n,
|
|
389
|
+
get${schemaName}Label,
|
|
390
|
+
get${schemaName}FieldLabel,
|
|
391
|
+
get${schemaName}FieldPlaceholder,
|
|
392
|
+
} from './base/${schemaName}.js';
|
|
393
|
+
|
|
394
|
+
// ============================================================================
|
|
395
|
+
// Types (extend or re-export)
|
|
396
|
+
// ============================================================================
|
|
397
|
+
|
|
398
|
+
export interface ${schemaName} extends ${schemaName}Base {
|
|
399
|
+
// Add custom properties here
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ============================================================================
|
|
403
|
+
// Schemas (extend or re-export)
|
|
404
|
+
// ============================================================================
|
|
405
|
+
|
|
406
|
+
export const ${lowerName}Schemas = { ...base${schemaName}Schemas };
|
|
407
|
+
export const ${lowerName}CreateSchema = base${schemaName}CreateSchema;
|
|
408
|
+
export const ${lowerName}UpdateSchema = base${schemaName}UpdateSchema;
|
|
409
|
+
|
|
410
|
+
// ============================================================================
|
|
411
|
+
// Types
|
|
412
|
+
// ============================================================================
|
|
413
|
+
|
|
414
|
+
export type ${schemaName}Create = z.infer<typeof ${lowerName}CreateSchema>;
|
|
415
|
+
export type ${schemaName}Update = z.infer<typeof ${lowerName}UpdateSchema>;
|
|
416
|
+
|
|
417
|
+
// Re-export i18n and helpers
|
|
418
|
+
export {
|
|
419
|
+
${lowerName}I18n,
|
|
420
|
+
get${schemaName}Label,
|
|
421
|
+
get${schemaName}FieldLabel,
|
|
422
|
+
get${schemaName}FieldPlaceholder,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Re-export base type for internal use
|
|
426
|
+
export type { ${schemaName}Base };
|
|
427
|
+
`;
|
|
428
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@omnifyjp/ts",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "TypeScript model type generator from Omnify schemas.json",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"omnify-ts": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"generate-l12": "node dist/cli.js --config ../../examples/l12/omnify.yaml",
|
|
15
|
+
"test": "vitest run"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"commander": "^13.0.0",
|
|
19
|
+
"yaml": "^2.7.0",
|
|
20
|
+
"zod": "^3.24.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.0.0",
|
|
24
|
+
"typescript": "^5.7.0",
|
|
25
|
+
"vitest": "^4.0.18"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT"
|
|
31
|
+
}
|