@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,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — Main Generator
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates TypeScript code generation from schemas.json.
|
|
5
|
+
* Reads the JSON, builds options, calls sub-generators, and assembles output files.
|
|
6
|
+
*
|
|
7
|
+
* Output structure:
|
|
8
|
+
* base/{SchemaName}.ts — Auto-generated interfaces + Zod + i18n (always overwritten)
|
|
9
|
+
* enum/{EnumName}.ts — Auto-generated enums (always overwritten)
|
|
10
|
+
* common.ts — Shared types (DateTimeString, etc.)
|
|
11
|
+
* i18n.ts — Validation messages + locale helpers
|
|
12
|
+
* {SchemaName}.ts — User-editable models extending base (created once, never overwritten)
|
|
13
|
+
* index.ts — Re-exports (always overwritten)
|
|
14
|
+
*/
|
|
15
|
+
import { schemaToInterface, formatInterface, needsDateTimeImports, } from './interface-generator.js';
|
|
16
|
+
import { generateEnums, generatePluginEnums, formatEnum, formatTypeAlias, extractInlineEnums, } from './enum-generator.js';
|
|
17
|
+
import { generateZodSchemas, generateDisplayNames, getExcludedFields, formatZodSchemasSection, formatZodModelFile, } from './zod-generator.js';
|
|
18
|
+
import { generateI18nFileContent } from './i18n-generator.js';
|
|
19
|
+
/** Auto-generated file header. */
|
|
20
|
+
function generateBaseHeader() {
|
|
21
|
+
return `/**
|
|
22
|
+
* ⚠️ DO NOT EDIT THIS FILE! ⚠️
|
|
23
|
+
* このファイルを編集しないでください!
|
|
24
|
+
*
|
|
25
|
+
* Auto-generated by omnify-ts from schemas.json.
|
|
26
|
+
* Any manual changes will be OVERWRITTEN on next generation.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
/** Build GeneratorOptions from schemas.json. */
|
|
32
|
+
function buildOptions(input) {
|
|
33
|
+
return {
|
|
34
|
+
locales: input.locale.locales,
|
|
35
|
+
defaultLocale: input.locale.defaultLocale,
|
|
36
|
+
fallbackLocale: input.locale.fallbackLocale,
|
|
37
|
+
customTypes: input.customTypes,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Generate a base interface file for a schema. */
|
|
41
|
+
function generateBaseInterfaceFile(schemaName, schemas, options) {
|
|
42
|
+
const schema = schemas[schemaName];
|
|
43
|
+
if (!schema)
|
|
44
|
+
throw new Error(`Schema not found: ${schemaName}`);
|
|
45
|
+
const iface = schemaToInterface(schema, schemas, options);
|
|
46
|
+
const parts = [generateBaseHeader()];
|
|
47
|
+
// Zod import
|
|
48
|
+
parts.push(`import { z } from 'zod';\n`);
|
|
49
|
+
// DateTimeString / DateString imports
|
|
50
|
+
const dateImports = needsDateTimeImports(iface);
|
|
51
|
+
const commonImports = [];
|
|
52
|
+
if (dateImports.dateTime)
|
|
53
|
+
commonImports.push('DateTimeString');
|
|
54
|
+
if (dateImports.date)
|
|
55
|
+
commonImports.push('DateString');
|
|
56
|
+
if (commonImports.length > 0) {
|
|
57
|
+
parts.push(`import type { ${commonImports.join(', ')} } from '../common.js';\n`);
|
|
58
|
+
}
|
|
59
|
+
// Enum imports (schema enums + plugin enums are all in ../enum/)
|
|
60
|
+
if (iface.enumDependencies && iface.enumDependencies.length > 0) {
|
|
61
|
+
for (const enumName of iface.enumDependencies) {
|
|
62
|
+
parts.push(`import { ${enumName} } from '../enum/${enumName}.js';\n`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Dependency imports (other schema interfaces in base/)
|
|
66
|
+
if (iface.dependencies && iface.dependencies.length > 0) {
|
|
67
|
+
for (const dep of iface.dependencies) {
|
|
68
|
+
parts.push(`import type { ${dep} } from './${dep}.js';\n`);
|
|
69
|
+
}
|
|
70
|
+
parts.push('\n');
|
|
71
|
+
}
|
|
72
|
+
else if (commonImports.length > 0 || (iface.enumDependencies && iface.enumDependencies.length > 0)) {
|
|
73
|
+
parts.push('\n');
|
|
74
|
+
}
|
|
75
|
+
// Interface
|
|
76
|
+
parts.push(formatInterface(iface));
|
|
77
|
+
parts.push('\n');
|
|
78
|
+
// Zod schemas + i18n
|
|
79
|
+
const zodSchemas = generateZodSchemas(schema, options);
|
|
80
|
+
const displayNames = generateDisplayNames(schema, options);
|
|
81
|
+
const excludedFields = getExcludedFields(schema);
|
|
82
|
+
parts.push('\n');
|
|
83
|
+
parts.push(formatZodSchemasSection(schemaName, zodSchemas, displayNames, excludedFields));
|
|
84
|
+
return {
|
|
85
|
+
filePath: `base/${schemaName}.ts`,
|
|
86
|
+
content: parts.join(''),
|
|
87
|
+
types: [schemaName, `${schemaName}Create`, `${schemaName}Update`],
|
|
88
|
+
overwrite: true,
|
|
89
|
+
category: 'base',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Generate an enum file. */
|
|
93
|
+
function generateEnumFile(enumDef, isPlugin) {
|
|
94
|
+
const parts = [generateBaseHeader()];
|
|
95
|
+
parts.push(formatEnum(enumDef));
|
|
96
|
+
parts.push('\n');
|
|
97
|
+
return {
|
|
98
|
+
filePath: `${enumDef.name}.ts`,
|
|
99
|
+
content: parts.join(''),
|
|
100
|
+
types: [enumDef.name],
|
|
101
|
+
overwrite: true,
|
|
102
|
+
category: isPlugin ? 'plugin-enum' : 'enum',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Generate a type alias file. */
|
|
106
|
+
function generateTypeAliasFile(alias) {
|
|
107
|
+
const parts = [generateBaseHeader()];
|
|
108
|
+
parts.push(formatTypeAlias(alias));
|
|
109
|
+
parts.push('\n');
|
|
110
|
+
return {
|
|
111
|
+
filePath: `${alias.name}.ts`,
|
|
112
|
+
content: parts.join(''),
|
|
113
|
+
types: [alias.name],
|
|
114
|
+
overwrite: true,
|
|
115
|
+
category: 'enum',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Generate user model file. */
|
|
119
|
+
function generateModelFile(schemaName) {
|
|
120
|
+
return {
|
|
121
|
+
filePath: `${schemaName}.ts`,
|
|
122
|
+
content: formatZodModelFile(schemaName),
|
|
123
|
+
types: [schemaName],
|
|
124
|
+
overwrite: false,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** Generate common.ts with shared types. */
|
|
128
|
+
function generateCommonFile(options) {
|
|
129
|
+
const localeUnion = options.locales.map(l => `'${l}'`).join(' | ');
|
|
130
|
+
const content = `${generateBaseHeader()}/**
|
|
131
|
+
* Locale map for multi-language support.
|
|
132
|
+
*/
|
|
133
|
+
export interface LocaleMap {
|
|
134
|
+
[locale: string]: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Supported locales in this project.
|
|
139
|
+
*/
|
|
140
|
+
export type Locale = ${localeUnion};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* ISO 8601 date-time string.
|
|
144
|
+
*/
|
|
145
|
+
export type DateTimeString = string;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* ISO 8601 date string (YYYY-MM-DD).
|
|
149
|
+
*/
|
|
150
|
+
export type DateString = string;
|
|
151
|
+
`;
|
|
152
|
+
return {
|
|
153
|
+
filePath: 'common.ts',
|
|
154
|
+
content,
|
|
155
|
+
types: ['LocaleMap', 'Locale', 'DateTimeString', 'DateString'],
|
|
156
|
+
overwrite: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** Generate i18n.ts with validation messages. */
|
|
160
|
+
function generateI18nFile(options) {
|
|
161
|
+
return {
|
|
162
|
+
filePath: 'i18n.ts',
|
|
163
|
+
content: generateBaseHeader() + generateI18nFileContent(options),
|
|
164
|
+
types: ['validationMessages', 'getMessage', 'getMessages'],
|
|
165
|
+
overwrite: true,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Generate index.ts re-exports. */
|
|
169
|
+
function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
|
|
170
|
+
const parts = [generateBaseHeader()];
|
|
171
|
+
// Common types
|
|
172
|
+
parts.push(`// Common Types\n`);
|
|
173
|
+
parts.push(`export type { LocaleMap, Locale, DateTimeString, DateString } from './common.js';\n\n`);
|
|
174
|
+
// I18n
|
|
175
|
+
parts.push(`// i18n (Internationalization)\n`);
|
|
176
|
+
parts.push(`export {\n`);
|
|
177
|
+
parts.push(` defaultLocale,\n`);
|
|
178
|
+
parts.push(` fallbackLocale,\n`);
|
|
179
|
+
parts.push(` supportedLocales,\n`);
|
|
180
|
+
parts.push(` validationMessages,\n`);
|
|
181
|
+
parts.push(` getMessage,\n`);
|
|
182
|
+
parts.push(` getMessages,\n`);
|
|
183
|
+
parts.push(`} from './i18n.js';\n\n`);
|
|
184
|
+
// Schema enums
|
|
185
|
+
if (schemaEnums.length > 0) {
|
|
186
|
+
parts.push(`// Schema Enums\n`);
|
|
187
|
+
for (const enumDef of schemaEnums) {
|
|
188
|
+
parts.push(`export {\n`);
|
|
189
|
+
parts.push(` ${enumDef.name},\n`);
|
|
190
|
+
parts.push(` ${enumDef.name}Values,\n`);
|
|
191
|
+
parts.push(` is${enumDef.name},\n`);
|
|
192
|
+
parts.push(` get${enumDef.name}Label,\n`);
|
|
193
|
+
parts.push(` get${enumDef.name}Extra,\n`);
|
|
194
|
+
parts.push(`} from './enum/${enumDef.name}.js';\n`);
|
|
195
|
+
}
|
|
196
|
+
parts.push('\n');
|
|
197
|
+
}
|
|
198
|
+
// Plugin enums
|
|
199
|
+
if (pluginEnums.length > 0) {
|
|
200
|
+
parts.push(`// Plugin Enums\n`);
|
|
201
|
+
for (const enumDef of pluginEnums) {
|
|
202
|
+
parts.push(`export {\n`);
|
|
203
|
+
parts.push(` ${enumDef.name},\n`);
|
|
204
|
+
parts.push(` ${enumDef.name}Values,\n`);
|
|
205
|
+
parts.push(` is${enumDef.name},\n`);
|
|
206
|
+
parts.push(` get${enumDef.name}Label,\n`);
|
|
207
|
+
parts.push(` get${enumDef.name}Extra,\n`);
|
|
208
|
+
parts.push(`} from './enum/${enumDef.name}.js';\n`);
|
|
209
|
+
}
|
|
210
|
+
parts.push('\n');
|
|
211
|
+
}
|
|
212
|
+
// Inline enum type aliases
|
|
213
|
+
if (typeAliases.length > 0) {
|
|
214
|
+
parts.push(`// Inline Enums (Type Aliases)\n`);
|
|
215
|
+
for (const alias of typeAliases) {
|
|
216
|
+
parts.push(`export {\n`);
|
|
217
|
+
parts.push(` type ${alias.name},\n`);
|
|
218
|
+
parts.push(` ${alias.name}Values,\n`);
|
|
219
|
+
parts.push(` is${alias.name},\n`);
|
|
220
|
+
parts.push(` get${alias.name}Label,\n`);
|
|
221
|
+
parts.push(` get${alias.name}Extra,\n`);
|
|
222
|
+
parts.push(`} from './enum/${alias.name}.js';\n`);
|
|
223
|
+
}
|
|
224
|
+
parts.push('\n');
|
|
225
|
+
}
|
|
226
|
+
// Models
|
|
227
|
+
parts.push(`// Models (with Zod schemas, i18n, and Create/Update types)\n`);
|
|
228
|
+
for (const schema of Object.values(schemas)) {
|
|
229
|
+
if (schema.kind === 'enum')
|
|
230
|
+
continue;
|
|
231
|
+
if (schema.options?.hidden === true)
|
|
232
|
+
continue;
|
|
233
|
+
const lowerName = schema.name.charAt(0).toLowerCase() + schema.name.slice(1);
|
|
234
|
+
parts.push(`export type { ${schema.name}, ${schema.name}Create, ${schema.name}Update } from './${schema.name}.js';\n`);
|
|
235
|
+
parts.push(`export {\n`);
|
|
236
|
+
parts.push(` ${lowerName}Schemas,\n`);
|
|
237
|
+
parts.push(` ${lowerName}CreateSchema,\n`);
|
|
238
|
+
parts.push(` ${lowerName}UpdateSchema,\n`);
|
|
239
|
+
parts.push(` ${lowerName}I18n,\n`);
|
|
240
|
+
parts.push(` get${schema.name}Label,\n`);
|
|
241
|
+
parts.push(` get${schema.name}FieldLabel,\n`);
|
|
242
|
+
parts.push(` get${schema.name}FieldPlaceholder,\n`);
|
|
243
|
+
parts.push(`} from './${schema.name}.js';\n`);
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
filePath: 'index.ts',
|
|
247
|
+
content: parts.join(''),
|
|
248
|
+
types: [],
|
|
249
|
+
overwrite: true,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Reserved names that cannot be used as schema names.
|
|
254
|
+
* These would collide with auto-generated infrastructure files at root level.
|
|
255
|
+
* Comparison is case-insensitive because macOS/Windows file systems are case-insensitive.
|
|
256
|
+
*
|
|
257
|
+
* Note: "common" and "i18n" are lowercase and schema names are PascalCase,
|
|
258
|
+
* so they won't collide on case-sensitive FS. But "Index" would collide with "index.ts".
|
|
259
|
+
*/
|
|
260
|
+
const RESERVED_NAMES = new Set(['index', 'common', 'i18n']);
|
|
261
|
+
/**
|
|
262
|
+
* Validate that no schema name collides with reserved file names.
|
|
263
|
+
*/
|
|
264
|
+
function validateSchemaNames(schemas) {
|
|
265
|
+
for (const schema of Object.values(schemas)) {
|
|
266
|
+
if (schema.kind === 'enum')
|
|
267
|
+
continue;
|
|
268
|
+
const lower = schema.name.toLowerCase();
|
|
269
|
+
if (RESERVED_NAMES.has(lower)) {
|
|
270
|
+
throw new Error(`Schema name "${schema.name}" is reserved by omnify-ts (collides with ${lower}.ts). ` +
|
|
271
|
+
`Please rename this schema.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Generate all TypeScript files from schemas.json input.
|
|
277
|
+
*/
|
|
278
|
+
export function generateTypeScript(input) {
|
|
279
|
+
const options = buildOptions(input);
|
|
280
|
+
const schemas = input.schemas;
|
|
281
|
+
// Validate no reserved name collisions
|
|
282
|
+
validateSchemaNames(schemas);
|
|
283
|
+
const files = [];
|
|
284
|
+
// Schema enums (e.g., PostStatus)
|
|
285
|
+
const schemaEnums = generateEnums(schemas, options);
|
|
286
|
+
for (const enumDef of schemaEnums) {
|
|
287
|
+
files.push(generateEnumFile(enumDef, false));
|
|
288
|
+
}
|
|
289
|
+
// Plugin enums (e.g., Prefecture, BankAccountType from customTypes.enums)
|
|
290
|
+
const pluginEnums = generatePluginEnums(input.customTypes.enums, options);
|
|
291
|
+
for (const enumDef of pluginEnums) {
|
|
292
|
+
files.push(generateEnumFile(enumDef, true));
|
|
293
|
+
}
|
|
294
|
+
// Inline enums from properties (type aliases or full enums)
|
|
295
|
+
const inlineEnums = extractInlineEnums(schemas, options);
|
|
296
|
+
const inlineTypeAliases = [];
|
|
297
|
+
for (const item of inlineEnums) {
|
|
298
|
+
if (item.enum) {
|
|
299
|
+
schemaEnums.push(item.enum);
|
|
300
|
+
files.push(generateEnumFile(item.enum, false));
|
|
301
|
+
}
|
|
302
|
+
else if (item.typeAlias) {
|
|
303
|
+
inlineTypeAliases.push(item.typeAlias);
|
|
304
|
+
files.push(generateTypeAliasFile(item.typeAlias));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Base interface files
|
|
308
|
+
for (const schema of Object.values(schemas)) {
|
|
309
|
+
if (schema.kind === 'enum')
|
|
310
|
+
continue;
|
|
311
|
+
if (schema.options?.hidden === true)
|
|
312
|
+
continue;
|
|
313
|
+
files.push(generateBaseInterfaceFile(schema.name, schemas, options));
|
|
314
|
+
}
|
|
315
|
+
// Model files (user-editable, created once)
|
|
316
|
+
for (const schema of Object.values(schemas)) {
|
|
317
|
+
if (schema.kind === 'enum')
|
|
318
|
+
continue;
|
|
319
|
+
if (schema.options?.hidden === true)
|
|
320
|
+
continue;
|
|
321
|
+
files.push(generateModelFile(schema.name));
|
|
322
|
+
}
|
|
323
|
+
// Common types
|
|
324
|
+
files.push(generateCommonFile(options));
|
|
325
|
+
// I18n
|
|
326
|
+
files.push(generateI18nFile(options));
|
|
327
|
+
// Index re-exports
|
|
328
|
+
files.push(generateIndexFile(schemas, schemaEnums, pluginEnums, inlineTypeAliases));
|
|
329
|
+
return files;
|
|
330
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — I18n Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates validation message templates and locale helpers.
|
|
5
|
+
*/
|
|
6
|
+
import type { GeneratorOptions } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate i18n.ts file content with validation messages and locale helpers.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateI18nFileContent(options: GeneratorOptions): string;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — I18n Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates validation message templates and locale helpers.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Default validation messages for all supported locales.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_VALIDATION_MESSAGES = {
|
|
10
|
+
required: {
|
|
11
|
+
en: '${displayName} is required',
|
|
12
|
+
ja: '${displayName}は必須です',
|
|
13
|
+
vi: '${displayName} là bắt buộc',
|
|
14
|
+
ko: '${displayName}은(는) 필수입니다',
|
|
15
|
+
zh: '${displayName}为必填项',
|
|
16
|
+
},
|
|
17
|
+
minLength: {
|
|
18
|
+
en: '${displayName} must be at least ${min} characters',
|
|
19
|
+
ja: '${displayName}は${min}文字以上で入力してください',
|
|
20
|
+
vi: '${displayName} phải có ít nhất ${min} ký tự',
|
|
21
|
+
ko: '${displayName}은(는) ${min}자 이상이어야 합니다',
|
|
22
|
+
zh: '${displayName}至少需要${min}个字符',
|
|
23
|
+
},
|
|
24
|
+
maxLength: {
|
|
25
|
+
en: '${displayName} must be at most ${max} characters',
|
|
26
|
+
ja: '${displayName}は${max}文字以内で入力してください',
|
|
27
|
+
vi: '${displayName} tối đa ${max} ký tự',
|
|
28
|
+
ko: '${displayName}은(는) ${max}자 이하여야 합니다',
|
|
29
|
+
zh: '${displayName}不能超过${max}个字符',
|
|
30
|
+
},
|
|
31
|
+
min: {
|
|
32
|
+
en: '${displayName} must be at least ${min}',
|
|
33
|
+
ja: '${displayName}は${min}以上で入力してください',
|
|
34
|
+
vi: '${displayName} phải lớn hơn hoặc bằng ${min}',
|
|
35
|
+
ko: '${displayName}은(는) ${min} 이상이어야 합니다',
|
|
36
|
+
zh: '${displayName}必须大于等于${min}',
|
|
37
|
+
},
|
|
38
|
+
max: {
|
|
39
|
+
en: '${displayName} must be at most ${max}',
|
|
40
|
+
ja: '${displayName}は${max}以下で入力してください',
|
|
41
|
+
vi: '${displayName} phải nhỏ hơn hoặc bằng ${max}',
|
|
42
|
+
ko: '${displayName}은(는) ${max} 이하여야 합니다',
|
|
43
|
+
zh: '${displayName}必须小于等于${max}',
|
|
44
|
+
},
|
|
45
|
+
email: {
|
|
46
|
+
en: 'Please enter a valid email address',
|
|
47
|
+
ja: '有効なメールアドレスを入力してください',
|
|
48
|
+
vi: 'Vui lòng nhập địa chỉ email hợp lệ',
|
|
49
|
+
ko: '유효한 이메일 주소를 입력하세요',
|
|
50
|
+
zh: '请输入有效的电子邮件地址',
|
|
51
|
+
},
|
|
52
|
+
url: {
|
|
53
|
+
en: 'Please enter a valid URL',
|
|
54
|
+
ja: '有効なURLを入力してください',
|
|
55
|
+
vi: 'Vui lòng nhập URL hợp lệ',
|
|
56
|
+
ko: '유효한 URL을 입력하세요',
|
|
57
|
+
zh: '请输入有效的URL',
|
|
58
|
+
},
|
|
59
|
+
pattern: {
|
|
60
|
+
en: '${displayName} format is invalid',
|
|
61
|
+
ja: '${displayName}の形式が正しくありません',
|
|
62
|
+
vi: '${displayName} không đúng định dạng',
|
|
63
|
+
ko: '${displayName} 형식이 올바르지 않습니다',
|
|
64
|
+
zh: '${displayName}格式不正确',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Generate i18n.ts file content with validation messages and locale helpers.
|
|
69
|
+
*/
|
|
70
|
+
export function generateI18nFileContent(options) {
|
|
71
|
+
const { locales, defaultLocale, fallbackLocale } = options;
|
|
72
|
+
// Filter messages to configured locales only
|
|
73
|
+
const filteredMessages = {};
|
|
74
|
+
for (const [key, msgs] of Object.entries(DEFAULT_VALIDATION_MESSAGES)) {
|
|
75
|
+
filteredMessages[key] = {};
|
|
76
|
+
for (const locale of locales) {
|
|
77
|
+
if (msgs[locale]) {
|
|
78
|
+
filteredMessages[key][locale] = msgs[locale];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const messagesJson = JSON.stringify(filteredMessages, null, 2);
|
|
83
|
+
return `import type { LocaleMap } from './common.js';
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Default locale for this project.
|
|
87
|
+
*/
|
|
88
|
+
export const defaultLocale = '${defaultLocale}' as const;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Fallback locale when requested locale is not found.
|
|
92
|
+
*/
|
|
93
|
+
export const fallbackLocale = '${fallbackLocale}' as const;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Supported locales in this project.
|
|
97
|
+
*/
|
|
98
|
+
export const supportedLocales = ${JSON.stringify(locales)} as const;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Validation messages for all supported locales.
|
|
102
|
+
*/
|
|
103
|
+
export const validationMessages = ${messagesJson} as const;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get validation message for a specific key and locale.
|
|
107
|
+
* Supports template placeholders: \${displayName}, \${min}, \${max}, etc.
|
|
108
|
+
*/
|
|
109
|
+
export function getMessage(
|
|
110
|
+
key: string,
|
|
111
|
+
locale: string,
|
|
112
|
+
params: Record<string, string | number> = {},
|
|
113
|
+
): string {
|
|
114
|
+
const messages = validationMessages[key as keyof typeof validationMessages];
|
|
115
|
+
if (!messages) return key;
|
|
116
|
+
|
|
117
|
+
let message = (messages as LocaleMap)[locale]
|
|
118
|
+
?? (messages as LocaleMap)[fallbackLocale]
|
|
119
|
+
?? (messages as LocaleMap)[defaultLocale]
|
|
120
|
+
?? key;
|
|
121
|
+
|
|
122
|
+
for (const [param, value] of Object.entries(params)) {
|
|
123
|
+
message = message.replace(new RegExp(\`\\\\\\$\\{\${param}\\}\`, 'g'), String(value));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return message;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get all validation messages for a specific locale.
|
|
131
|
+
*/
|
|
132
|
+
export function getMessages(locale: string): Record<string, string> {
|
|
133
|
+
const result: Record<string, string> = {};
|
|
134
|
+
for (const [key, messages] of Object.entries(validationMessages)) {
|
|
135
|
+
result[key] = (messages as LocaleMap)[locale]
|
|
136
|
+
?? (messages as LocaleMap)[fallbackLocale]
|
|
137
|
+
?? (messages as LocaleMap)[defaultLocale]
|
|
138
|
+
?? key;
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
`;
|
|
143
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — Public API
|
|
3
|
+
*
|
|
4
|
+
* TypeScript model type generator from Omnify schemas.json.
|
|
5
|
+
*/
|
|
6
|
+
export { generateTypeScript } from './generator.js';
|
|
7
|
+
export type { SchemasJson, SchemaDefinition, PropertyDefinition, TypeScriptFile, TSInterface, TSProperty, TSEnum, TSEnumValue, TSTypeAlias, GeneratorOptions, LocalizedString, LocaleMap, } from './types.js';
|
|
8
|
+
export { schemaToInterface, formatInterface, formatProperty, generateInterfaces, getPropertyType, toSnakeCase, } from './interface-generator.js';
|
|
9
|
+
export { generateEnums, generatePluginEnums, formatEnum, formatTypeAlias, extractInlineEnums, toPascalCase, toEnumMemberName, } from './enum-generator.js';
|
|
10
|
+
export { generateZodSchemas, generateDisplayNames, getExcludedFields, formatZodSchemasSection, formatZodModelFile, } from './zod-generator.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — Public API
|
|
3
|
+
*
|
|
4
|
+
* TypeScript model type generator from Omnify schemas.json.
|
|
5
|
+
*/
|
|
6
|
+
export { generateTypeScript } from './generator.js';
|
|
7
|
+
export { schemaToInterface, formatInterface, formatProperty, generateInterfaces, getPropertyType, toSnakeCase, } from './interface-generator.js';
|
|
8
|
+
export { generateEnums, generatePluginEnums, formatEnum, formatTypeAlias, extractInlineEnums, toPascalCase, toEnumMemberName, } from './enum-generator.js';
|
|
9
|
+
export { generateZodSchemas, generateDisplayNames, getExcludedFields, formatZodSchemasSection, formatZodModelFile, } from './zod-generator.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @omnify/ts — TypeScript Interface Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates TypeScript interfaces from schema definitions.
|
|
5
|
+
* Handles compound type expansion via expandedProperties, association types,
|
|
6
|
+
* enum references, and all standard property types.
|
|
7
|
+
*/
|
|
8
|
+
import type { SchemaDefinition, PropertyDefinition, TSInterface, TSProperty, GeneratorOptions } from './types.js';
|
|
9
|
+
/** Convert PascalCase/camelCase to snake_case. */
|
|
10
|
+
export declare function toSnakeCase(str: string): string;
|
|
11
|
+
/** Gets TypeScript type for a property. */
|
|
12
|
+
export declare function getPropertyType(property: PropertyDefinition, allSchemas: Record<string, SchemaDefinition>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert a property to TSProperty array.
|
|
15
|
+
* Compound types expand to multiple properties via expandedProperties.
|
|
16
|
+
* MorphTo and ManyToOne also return multiple properties (FK + relation).
|
|
17
|
+
*/
|
|
18
|
+
export declare function propertyToTSProperties(propertyName: string, property: PropertyDefinition, schema: SchemaDefinition, allSchemas: Record<string, SchemaDefinition>, options: GeneratorOptions): TSProperty[];
|
|
19
|
+
/** Generate a TSInterface from a schema definition. */
|
|
20
|
+
export declare function schemaToInterface(schema: SchemaDefinition, allSchemas: Record<string, SchemaDefinition>, options: GeneratorOptions): TSInterface;
|
|
21
|
+
/** Format a TypeScript property line. */
|
|
22
|
+
export declare function formatProperty(property: TSProperty): string;
|
|
23
|
+
/** Format a TypeScript interface. */
|
|
24
|
+
export declare function formatInterface(iface: TSInterface): string;
|
|
25
|
+
/** Generate interfaces for all non-enum, non-hidden schemas. */
|
|
26
|
+
export declare function generateInterfaces(schemas: Record<string, SchemaDefinition>, options: GeneratorOptions): TSInterface[];
|
|
27
|
+
/** Check if interface uses DateTimeString or DateString types. */
|
|
28
|
+
export declare function needsDateTimeImports(iface: TSInterface): {
|
|
29
|
+
dateTime: boolean;
|
|
30
|
+
date: boolean;
|
|
31
|
+
};
|