@famgia/omnify-typescript 0.0.67 → 0.0.69

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.
Files changed (43) hide show
  1. package/dist/{chunk-4L77AHAC.js → chunk-6I4O23X6.js} +521 -66
  2. package/dist/chunk-6I4O23X6.js.map +1 -0
  3. package/dist/index.cjs +761 -65
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +138 -2
  6. package/dist/index.d.ts +138 -2
  7. package/dist/index.js +227 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugin.cjs +624 -75
  10. package/dist/plugin.cjs.map +1 -1
  11. package/dist/plugin.d.cts +6 -0
  12. package/dist/plugin.d.ts +6 -0
  13. package/dist/plugin.js +96 -11
  14. package/dist/plugin.js.map +1 -1
  15. package/package.json +3 -3
  16. package/scripts/postinstall.js +29 -40
  17. package/stubs/JapaneseAddressField.tsx.stub +289 -0
  18. package/stubs/JapaneseBankField.tsx.stub +212 -0
  19. package/stubs/JapaneseNameField.tsx.stub +194 -0
  20. package/stubs/ai-guides/checklists/react.md.stub +108 -0
  21. package/stubs/ai-guides/cursor/react-design.mdc.stub +289 -0
  22. package/stubs/ai-guides/cursor/react-form.mdc.stub +277 -0
  23. package/stubs/ai-guides/cursor/react-services.mdc.stub +304 -0
  24. package/stubs/ai-guides/cursor/react.mdc.stub +254 -0
  25. package/stubs/ai-guides/react/README.md.stub +221 -0
  26. package/stubs/ai-guides/react/antd-guide.md.stub +294 -0
  27. package/stubs/ai-guides/react/checklist.md.stub +108 -0
  28. package/stubs/ai-guides/react/datetime-guide.md.stub +137 -0
  29. package/stubs/ai-guides/react/design-philosophy.md.stub +363 -0
  30. package/stubs/ai-guides/react/i18n-guide.md.stub +211 -0
  31. package/stubs/ai-guides/react/laravel-integration.md.stub +181 -0
  32. package/stubs/ai-guides/react/service-pattern.md.stub +180 -0
  33. package/stubs/ai-guides/react/tanstack-query.md.stub +339 -0
  34. package/stubs/ai-guides/react/types-guide.md.stub +524 -0
  35. package/stubs/components-index.ts.stub +13 -0
  36. package/stubs/form-validation.ts.stub +106 -0
  37. package/stubs/rules/index.ts.stub +48 -0
  38. package/stubs/rules/kana.ts.stub +291 -0
  39. package/stubs/use-form-mutation.ts.stub +117 -0
  40. package/stubs/zod-i18n.ts.stub +32 -0
  41. package/ai-guides/antdesign-guide.md +0 -401
  42. package/ai-guides/typescript-guide.md +0 -310
  43. package/dist/chunk-4L77AHAC.js.map +0 -1
@@ -1,401 +0,0 @@
1
- # Omnify + Ant Design Integration Guide
2
-
3
- This guide shows how to use Omnify-generated validation rules with Ant Design Forms.
4
-
5
- ## Generated Files
6
-
7
- Omnify generates validation rules in `rules/` directory:
8
- - `rules/{Model}.rules.ts` - Validation rules for each model
9
-
10
- ## File Structure
11
-
12
- ```typescript
13
- // rules/User.rules.ts
14
-
15
- // Display name for model (multi-locale)
16
- export const UserDisplayName: LocaleMap = {
17
- ja: 'ユーザー',
18
- en: 'User',
19
- };
20
-
21
- // Display names for properties (multi-locale)
22
- export const UserPropertyDisplayNames: Record<string, LocaleMap> = {
23
- name: { ja: '名前', en: 'Name' },
24
- email: { ja: 'メールアドレス', en: 'Email' },
25
- };
26
-
27
- // Validation rules with multi-locale messages
28
- export const UserRules: Record<string, ValidationRule[]> = {
29
- name: [
30
- { required: true, message: { ja: '名前は必須です', en: 'Name is required' } },
31
- { max: 100, message: { ja: '名前は100文字以内で入力してください', en: 'Name must be at most 100 characters' } },
32
- ],
33
- email: [
34
- { required: true, message: { ja: 'メールアドレスは必須です', en: 'Email is required' } },
35
- { type: 'email', message: { ja: 'メールアドレスの形式が正しくありません', en: 'Email is not a valid email address' } },
36
- ],
37
- };
38
-
39
- // Helper functions
40
- export function getUserRules(locale: string): Record<string, Rule[]>;
41
- export function getUserDisplayName(locale: string): string;
42
- export function getUserPropertyDisplayName(property: string, locale: string): string;
43
- ```
44
-
45
- ## Basic Usage
46
-
47
- ```tsx
48
- import { Form, Input, Button } from 'antd';
49
- import {
50
- getUserRules,
51
- getUserDisplayName,
52
- getUserPropertyDisplayName
53
- } from '@/types/model/rules/User.rules';
54
-
55
- interface UserFormProps {
56
- locale?: string;
57
- onSubmit: (values: User) => void;
58
- }
59
-
60
- export function UserForm({ locale = 'ja', onSubmit }: UserFormProps) {
61
- const [form] = Form.useForm();
62
- const rules = getUserRules(locale);
63
-
64
- return (
65
- <Form
66
- form={form}
67
- layout="vertical"
68
- onFinish={onSubmit}
69
- >
70
- <Form.Item
71
- name="name"
72
- label={getUserPropertyDisplayName('name', locale)}
73
- rules={rules.name}
74
- >
75
- <Input placeholder={getUserPropertyDisplayName('name', locale)} />
76
- </Form.Item>
77
-
78
- <Form.Item
79
- name="email"
80
- label={getUserPropertyDisplayName('email', locale)}
81
- rules={rules.email}
82
- >
83
- <Input type="email" />
84
- </Form.Item>
85
-
86
- <Form.Item>
87
- <Button type="primary" htmlType="submit">
88
- {locale === 'ja' ? '送信' : 'Submit'}
89
- </Button>
90
- </Form.Item>
91
- </Form>
92
- );
93
- }
94
- ```
95
-
96
- ## With Edit Mode (Initial Values)
97
-
98
- ```tsx
99
- import { Form, Input, Button, Spin } from 'antd';
100
- import { getUserRules, getUserPropertyDisplayName } from '@/types/model/rules/User.rules';
101
- import { User } from '@/types/model';
102
-
103
- interface UserEditFormProps {
104
- user: User;
105
- locale?: string;
106
- onSubmit: (values: Partial<User>) => void;
107
- loading?: boolean;
108
- }
109
-
110
- export function UserEditForm({ user, locale = 'ja', onSubmit, loading }: UserEditFormProps) {
111
- const [form] = Form.useForm();
112
- const rules = getUserRules(locale);
113
-
114
- // Set initial values when user data changes
115
- React.useEffect(() => {
116
- form.setFieldsValue(user);
117
- }, [user, form]);
118
-
119
- return (
120
- <Spin spinning={loading}>
121
- <Form
122
- form={form}
123
- layout="vertical"
124
- initialValues={user}
125
- onFinish={onSubmit}
126
- >
127
- <Form.Item
128
- name="name"
129
- label={getUserPropertyDisplayName('name', locale)}
130
- rules={rules.name}
131
- >
132
- <Input />
133
- </Form.Item>
134
-
135
- <Form.Item
136
- name="email"
137
- label={getUserPropertyDisplayName('email', locale)}
138
- rules={rules.email}
139
- >
140
- <Input type="email" />
141
- </Form.Item>
142
-
143
- <Form.Item>
144
- <Button type="primary" htmlType="submit" loading={loading}>
145
- {locale === 'ja' ? '更新' : 'Update'}
146
- </Button>
147
- </Form.Item>
148
- </Form>
149
- </Spin>
150
- );
151
- }
152
- ```
153
-
154
- ## Dynamic Locale Switching
155
-
156
- ```tsx
157
- import { Form, Input, Select } from 'antd';
158
- import { useState, useMemo } from 'react';
159
- import { getUserRules, getUserPropertyDisplayName, getUserDisplayName } from '@/types/model/rules/User.rules';
160
-
161
- export function UserFormWithLocale() {
162
- const [locale, setLocale] = useState('ja');
163
- const [form] = Form.useForm();
164
-
165
- // Memoize rules to avoid recalculation
166
- const rules = useMemo(() => getUserRules(locale), [locale]);
167
-
168
- return (
169
- <>
170
- <Select value={locale} onChange={setLocale} style={{ marginBottom: 16 }}>
171
- <Select.Option value="ja">日本語</Select.Option>
172
- <Select.Option value="en">English</Select.Option>
173
- <Select.Option value="vi">Tiếng Việt</Select.Option>
174
- </Select>
175
-
176
- <h2>{getUserDisplayName(locale)}</h2>
177
-
178
- <Form form={form} layout="vertical">
179
- <Form.Item
180
- name="name"
181
- label={getUserPropertyDisplayName('name', locale)}
182
- rules={rules.name}
183
- >
184
- <Input />
185
- </Form.Item>
186
-
187
- <Form.Item
188
- name="email"
189
- label={getUserPropertyDisplayName('email', locale)}
190
- rules={rules.email}
191
- >
192
- <Input type="email" />
193
- </Form.Item>
194
- </Form>
195
- </>
196
- );
197
- }
198
- ```
199
-
200
- ## With Table Columns
201
-
202
- ```tsx
203
- import { Table, TableColumnsType } from 'antd';
204
- import { getUserPropertyDisplayName } from '@/types/model/rules/User.rules';
205
- import { User } from '@/types/model';
206
-
207
- interface UserTableProps {
208
- users: User[];
209
- locale?: string;
210
- loading?: boolean;
211
- }
212
-
213
- export function UserTable({ users, locale = 'ja', loading }: UserTableProps) {
214
- const columns: TableColumnsType<User> = [
215
- {
216
- title: getUserPropertyDisplayName('name', locale),
217
- dataIndex: 'name',
218
- key: 'name',
219
- },
220
- {
221
- title: getUserPropertyDisplayName('email', locale),
222
- dataIndex: 'email',
223
- key: 'email',
224
- },
225
- ];
226
-
227
- return (
228
- <Table
229
- columns={columns}
230
- dataSource={users}
231
- rowKey="id"
232
- loading={loading}
233
- />
234
- );
235
- }
236
- ```
237
-
238
- ## Custom Form Hook
239
-
240
- ```tsx
241
- import { Form, FormInstance } from 'antd';
242
- import { useMemo } from 'react';
243
-
244
- // Generic hook for any model's rules
245
- export function useModelForm<T>(
246
- getRules: (locale: string) => Record<string, any[]>,
247
- locale: string = 'ja'
248
- ): {
249
- form: FormInstance<T>;
250
- rules: Record<string, any[]>;
251
- } {
252
- const [form] = Form.useForm<T>();
253
- const rules = useMemo(() => getRules(locale), [getRules, locale]);
254
-
255
- return { form, rules };
256
- }
257
-
258
- // Usage
259
- import { getUserRules } from '@/types/model/rules/User.rules';
260
-
261
- function MyComponent() {
262
- const { form, rules } = useModelForm(getUserRules, 'ja');
263
-
264
- return (
265
- <Form form={form}>
266
- <Form.Item name="name" rules={rules.name}>
267
- <Input />
268
- </Form.Item>
269
- </Form>
270
- );
271
- }
272
- ```
273
-
274
- ## Modal Form
275
-
276
- ```tsx
277
- import { Modal, Form, Input, message } from 'antd';
278
- import { getUserRules, getUserDisplayName, getUserPropertyDisplayName } from '@/types/model/rules/User.rules';
279
- import { User } from '@/types/model';
280
-
281
- interface UserModalFormProps {
282
- open: boolean;
283
- onClose: () => void;
284
- onSubmit: (values: Partial<User>) => Promise<void>;
285
- initialValues?: Partial<User>;
286
- locale?: string;
287
- }
288
-
289
- export function UserModalForm({
290
- open,
291
- onClose,
292
- onSubmit,
293
- initialValues,
294
- locale = 'ja'
295
- }: UserModalFormProps) {
296
- const [form] = Form.useForm();
297
- const [loading, setLoading] = useState(false);
298
- const rules = getUserRules(locale);
299
-
300
- const handleSubmit = async () => {
301
- try {
302
- const values = await form.validateFields();
303
- setLoading(true);
304
- await onSubmit(values);
305
- message.success(locale === 'ja' ? '保存しました' : 'Saved successfully');
306
- form.resetFields();
307
- onClose();
308
- } catch (error) {
309
- if (error instanceof Error) {
310
- message.error(error.message);
311
- }
312
- } finally {
313
- setLoading(false);
314
- }
315
- };
316
-
317
- return (
318
- <Modal
319
- title={getUserDisplayName(locale)}
320
- open={open}
321
- onCancel={onClose}
322
- onOk={handleSubmit}
323
- confirmLoading={loading}
324
- okText={locale === 'ja' ? '保存' : 'Save'}
325
- cancelText={locale === 'ja' ? 'キャンセル' : 'Cancel'}
326
- >
327
- <Form
328
- form={form}
329
- layout="vertical"
330
- initialValues={initialValues}
331
- >
332
- <Form.Item
333
- name="name"
334
- label={getUserPropertyDisplayName('name', locale)}
335
- rules={rules.name}
336
- >
337
- <Input />
338
- </Form.Item>
339
-
340
- <Form.Item
341
- name="email"
342
- label={getUserPropertyDisplayName('email', locale)}
343
- rules={rules.email}
344
- >
345
- <Input type="email" />
346
- </Form.Item>
347
- </Form>
348
- </Modal>
349
- );
350
- }
351
- ```
352
-
353
- ## Validation Rule Types
354
-
355
- Omnify generates these rule types based on schema:
356
-
357
- | Schema | Generated Rule |
358
- |--------|---------------|
359
- | `required: true` | `{ required: true, message: {...} }` |
360
- | `type: Email` | `{ type: 'email', message: {...} }` |
361
- | `maxLength: N` | `{ max: N, message: {...} }` |
362
- | `minLength: N` | `{ min: N, message: {...} }` |
363
- | `max: N` (numeric) | `{ max: N, type: 'number', message: {...} }` |
364
- | `min: N` (numeric) | `{ min: N, type: 'number', message: {...} }` |
365
- | `pattern: regex` | `{ pattern: /regex/, message: {...} }` |
366
-
367
- ## Built-in Validation Messages
368
-
369
- Omnify includes templates for 5 languages:
370
- - Japanese (ja)
371
- - English (en)
372
- - Vietnamese (vi)
373
- - Korean (ko)
374
- - Chinese (zh)
375
-
376
- Custom templates can be configured in `omnify.config.ts`:
377
-
378
- ```typescript
379
- export default defineConfig({
380
- output: {
381
- typescript: {
382
- validationTemplates: {
383
- required: {
384
- ja: '${displayName}を入力してください',
385
- en: '${displayName} is required',
386
- vi: '${displayName} là bắt buộc',
387
- },
388
- maxLength: {
389
- ja: '${displayName}は${max}文字以内です',
390
- en: '${displayName} must be at most ${max} characters',
391
- },
392
- },
393
- },
394
- },
395
- });
396
- ```
397
-
398
- Available placeholders:
399
- - `${displayName}` - Property display name
400
- - `${min}` - Minimum value/length
401
- - `${max}` - Maximum value/length
@@ -1,310 +0,0 @@
1
- # Omnify TypeScript Generator Guide
2
-
3
- This guide covers TypeScript-specific features and generated code patterns for Omnify.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- # Create new project (recommended)
9
- npx @famgia/omnify create-laravel-project my-app
10
- cd my-app
11
-
12
- # Or initialize in existing project
13
- npx @famgia/omnify init
14
-
15
- # Generate TypeScript types
16
- npx @famgia/omnify generate
17
- ```
18
-
19
- ## Generated Files
20
-
21
- When you run `npx @famgia/omnify generate`, the following TypeScript files are generated:
22
-
23
- - `base/*.ts` - Base model interfaces
24
- - `enum/*.ts` - Enum types with multi-locale labels
25
- - `rules/*.ts` - Ant Design compatible validation rules
26
-
27
- ## Type Generation
28
-
29
- ### Object Schema → Interface
30
-
31
- ```yaml
32
- # yaml-language-server: $schema=./node_modules/.omnify/combined-schema.json
33
- name: User
34
- properties:
35
- id:
36
- type: BigInt
37
- required: true
38
- name:
39
- type: String
40
- required: true
41
- maxLength: 255
42
- email:
43
- type: String
44
- required: true
45
- unique: true
46
- profile:
47
- type: Json
48
- createdAt:
49
- type: DateTime
50
- ```
51
-
52
- Generated:
53
- ```typescript
54
- export interface User {
55
- id: number;
56
- name: string;
57
- email: string;
58
- profile: Record<string, unknown> | null;
59
- createdAt: Date | null;
60
- }
61
- ```
62
-
63
- ## Type Mapping
64
-
65
- | Schema Type | TypeScript Type |
66
- |-------------|-----------------|
67
- | `String` | `string` |
68
- | `Text` | `string` |
69
- | `MediumText` | `string` |
70
- | `LongText` | `string` |
71
- | `TinyInt` | `number` |
72
- | `Int` | `number` |
73
- | `BigInt` | `number` |
74
- | `Float` | `number` |
75
- | `Decimal` | `number` |
76
- | `Boolean` | `boolean` |
77
- | `Date` | `Date` |
78
- | `DateTime` | `Date` |
79
- | `Timestamp` | `Date` |
80
- | `Json` | `Record<string, unknown>` |
81
- | `EnumRef` | Generated enum type |
82
- | `Association` | Related model type / array |
83
-
84
- ## Hidden Schemas
85
-
86
- Schemas with `options.hidden: true` are skipped for TypeScript generation:
87
-
88
- ```yaml
89
- name: AppCache
90
- options:
91
- hidden: true # No TypeScript interface generated
92
- ```
93
-
94
- Use cases:
95
- - System tables (cache, sessions, jobs)
96
- - Tables that don't need frontend types
97
-
98
- ## Enum Generation (Multi-locale)
99
-
100
- ```yaml
101
- # schemas/PostStatus.yaml
102
- name: PostStatus
103
- kind: enum
104
- displayName:
105
- ja: 投稿ステータス
106
- en: Post Status
107
- values:
108
- draft:
109
- ja: 下書き
110
- en: Draft
111
- published:
112
- ja: 公開済み
113
- en: Published
114
- archived:
115
- ja: アーカイブ
116
- en: Archived
117
- ```
118
-
119
- Generated:
120
- ```typescript
121
- export const PostStatus = {
122
- draft: 'draft',
123
- published: 'published',
124
- archived: 'archived',
125
- } as const;
126
-
127
- export type PostStatus = typeof PostStatus[keyof typeof PostStatus];
128
-
129
- // Multi-locale labels
130
- export const PostStatusLabels: Record<PostStatus, Record<string, string>> = {
131
- draft: { ja: '下書き', en: 'Draft' },
132
- published: { ja: '公開済み', en: 'Published' },
133
- archived: { ja: 'アーカイブ', en: 'Archived' },
134
- };
135
-
136
- // Get label for specific locale
137
- export function getPostStatusLabel(value: PostStatus, locale: string = 'en'): string {
138
- return PostStatusLabels[value]?.[locale] ?? PostStatusLabels[value]?.['en'] ?? value;
139
- }
140
-
141
- // Helper functions
142
- export const PostStatusValues = Object.values(PostStatus);
143
- export function isPostStatus(value: unknown): value is PostStatus {
144
- return PostStatusValues.includes(value as PostStatus);
145
- }
146
- ```
147
-
148
- ## Validation Rules (Ant Design)
149
-
150
- Omnify generates Ant Design compatible validation rules in `rules/` directory.
151
-
152
- **See detailed guide:** `.claude/omnify/antdesign-guide.md`
153
-
154
- Quick example:
155
- ```tsx
156
- import { Form, Input } from 'antd';
157
- import { getUserRules, getUserPropertyDisplayName } from './types/model/rules/User.rules';
158
-
159
- function UserForm({ locale = 'ja' }) {
160
- const rules = getUserRules(locale);
161
- return (
162
- <Form>
163
- <Form.Item name="name" label={getUserPropertyDisplayName('name', locale)} rules={rules.name}>
164
- <Input />
165
- </Form.Item>
166
- </Form>
167
- );
168
- }
169
- ```
170
-
171
- ## Association Types
172
-
173
- ### ManyToOne
174
- ```yaml
175
- author:
176
- type: Association
177
- relation: ManyToOne
178
- target: User
179
- ```
180
-
181
- Generated:
182
- ```typescript
183
- export interface Post {
184
- authorId: number;
185
- author?: User; // Optional: loaded relation
186
- }
187
- ```
188
-
189
- ### OneToMany
190
- ```yaml
191
- posts:
192
- type: Association
193
- relation: OneToMany
194
- target: Post
195
- ```
196
-
197
- Generated:
198
- ```typescript
199
- export interface User {
200
- posts?: Post[]; // Optional: loaded relation array
201
- }
202
- ```
203
-
204
- ### ManyToMany
205
- ```yaml
206
- tags:
207
- type: Association
208
- relation: ManyToMany
209
- target: Tag
210
- ```
211
-
212
- Generated:
213
- ```typescript
214
- export interface Post {
215
- tags?: Tag[]; // Optional: loaded relation array
216
- }
217
- ```
218
-
219
- ## Nullable Fields
220
-
221
- Fields without `required: true` are nullable:
222
-
223
- ```yaml
224
- description:
225
- type: LongText # No required: true
226
- ```
227
-
228
- Generated:
229
- ```typescript
230
- description: string | null;
231
- ```
232
-
233
- ## Using Generated Types
234
-
235
- ```typescript
236
- import { User, Post, PostStatus, isPostStatus } from './types/omnify-types';
237
-
238
- // Type-safe object creation
239
- const user: User = {
240
- id: 1,
241
- name: 'John',
242
- email: 'john@example.com',
243
- profile: null,
244
- createdAt: new Date(),
245
- };
246
-
247
- // Enum usage
248
- const status: PostStatus = PostStatus.draft;
249
-
250
- // Type guard
251
- function handleStatus(value: unknown) {
252
- if (isPostStatus(value)) {
253
- console.log('Valid status:', value);
254
- }
255
- }
256
- ```
257
-
258
- ## Commands
259
-
260
- ```bash
261
- # Create new project
262
- npx @famgia/omnify create-laravel-project my-app
263
-
264
- # Generate TypeScript types
265
- npx @famgia/omnify generate
266
-
267
- # Force regenerate all files
268
- npx @famgia/omnify generate --force
269
-
270
- # Only generate TypeScript types
271
- npx @famgia/omnify generate --types-only
272
-
273
- # Validate schemas
274
- npx @famgia/omnify validate
275
- ```
276
-
277
- ## Configuration
278
-
279
- ```typescript
280
- // omnify.config.ts
281
- import { defineConfig } from '@famgia/omnify';
282
- import typescript from '@famgia/omnify-typescript/plugin';
283
-
284
- export default defineConfig({
285
- schemasDir: './schemas',
286
- lockFilePath: './.omnify.lock',
287
-
288
- plugins: [
289
- typescript({
290
- // Output path for TypeScript files
291
- path: './resources/ts/types/models',
292
-
293
- // Generate Ant Design validation rules
294
- generateRules: true,
295
- }),
296
- ],
297
-
298
- locale: {
299
- locales: ['ja', 'en'],
300
- defaultLocale: 'ja',
301
- },
302
- });
303
- ```
304
-
305
- ### Configuration Options
306
-
307
- | Option | Type | Default | Description |
308
- |--------|------|---------|-------------|
309
- | `path` | `string` | `./src/types/model` | TypeScript output directory |
310
- | `generateRules` | `boolean` | `true` | Generate Ant Design validation rules |