@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.
- package/dist/{chunk-4L77AHAC.js → chunk-6I4O23X6.js} +521 -66
- package/dist/chunk-6I4O23X6.js.map +1 -0
- package/dist/index.cjs +761 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +138 -2
- package/dist/index.d.ts +138 -2
- package/dist/index.js +227 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin.cjs +624 -75
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.js +96 -11
- package/dist/plugin.js.map +1 -1
- package/package.json +3 -3
- package/scripts/postinstall.js +29 -40
- package/stubs/JapaneseAddressField.tsx.stub +289 -0
- package/stubs/JapaneseBankField.tsx.stub +212 -0
- package/stubs/JapaneseNameField.tsx.stub +194 -0
- package/stubs/ai-guides/checklists/react.md.stub +108 -0
- package/stubs/ai-guides/cursor/react-design.mdc.stub +289 -0
- package/stubs/ai-guides/cursor/react-form.mdc.stub +277 -0
- package/stubs/ai-guides/cursor/react-services.mdc.stub +304 -0
- package/stubs/ai-guides/cursor/react.mdc.stub +254 -0
- package/stubs/ai-guides/react/README.md.stub +221 -0
- package/stubs/ai-guides/react/antd-guide.md.stub +294 -0
- package/stubs/ai-guides/react/checklist.md.stub +108 -0
- package/stubs/ai-guides/react/datetime-guide.md.stub +137 -0
- package/stubs/ai-guides/react/design-philosophy.md.stub +363 -0
- package/stubs/ai-guides/react/i18n-guide.md.stub +211 -0
- package/stubs/ai-guides/react/laravel-integration.md.stub +181 -0
- package/stubs/ai-guides/react/service-pattern.md.stub +180 -0
- package/stubs/ai-guides/react/tanstack-query.md.stub +339 -0
- package/stubs/ai-guides/react/types-guide.md.stub +524 -0
- package/stubs/components-index.ts.stub +13 -0
- package/stubs/form-validation.ts.stub +106 -0
- package/stubs/rules/index.ts.stub +48 -0
- package/stubs/rules/kana.ts.stub +291 -0
- package/stubs/use-form-mutation.ts.stub +117 -0
- package/stubs/zod-i18n.ts.stub +32 -0
- package/ai-guides/antdesign-guide.md +0 -401
- package/ai-guides/typescript-guide.md +0 -310
- package/dist/chunk-4L77AHAC.js.map +0 -1
package/dist/plugin.d.cts
CHANGED
|
@@ -41,6 +41,12 @@ interface TypeScriptPluginOptions {
|
|
|
41
41
|
* @default true
|
|
42
42
|
*/
|
|
43
43
|
generateZodSchemas?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Path for React utility stubs (hooks, components, lib).
|
|
46
|
+
* Set to false to disable stub generation.
|
|
47
|
+
* @default 'omnify'
|
|
48
|
+
*/
|
|
49
|
+
stubsPath?: string | false;
|
|
44
50
|
}
|
|
45
51
|
/**
|
|
46
52
|
* Creates the TypeScript plugin with the specified options.
|
package/dist/plugin.d.ts
CHANGED
|
@@ -41,6 +41,12 @@ interface TypeScriptPluginOptions {
|
|
|
41
41
|
* @default true
|
|
42
42
|
*/
|
|
43
43
|
generateZodSchemas?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Path for React utility stubs (hooks, components, lib).
|
|
46
|
+
* Set to false to disable stub generation.
|
|
47
|
+
* @default 'omnify'
|
|
48
|
+
*/
|
|
49
|
+
stubsPath?: string | false;
|
|
44
50
|
}
|
|
45
51
|
/**
|
|
46
52
|
* Creates the TypeScript plugin with the specified options.
|
package/dist/plugin.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generateTypeScript
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-6I4O23X6.js";
|
|
4
4
|
|
|
5
5
|
// src/plugin.ts
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
var __dirname = path.dirname(__filename);
|
|
6
11
|
var TYPESCRIPT_CONFIG_SCHEMA = {
|
|
7
12
|
fields: [
|
|
8
13
|
{
|
|
@@ -20,15 +25,38 @@ var TYPESCRIPT_CONFIG_SCHEMA = {
|
|
|
20
25
|
description: "Generate Zod schemas alongside TypeScript types for form validation",
|
|
21
26
|
default: true,
|
|
22
27
|
group: "output"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "stubsPath",
|
|
31
|
+
type: "path",
|
|
32
|
+
label: "React Stubs Path",
|
|
33
|
+
description: "Directory for React utility stubs (hooks, components). Leave empty to disable.",
|
|
34
|
+
default: "omnify",
|
|
35
|
+
group: "output"
|
|
23
36
|
}
|
|
24
37
|
]
|
|
25
38
|
};
|
|
26
39
|
function resolveOptions(options) {
|
|
27
40
|
return {
|
|
28
41
|
modelsPath: options?.modelsPath ?? "types/schemas",
|
|
29
|
-
generateZodSchemas: options?.generateZodSchemas ?? true
|
|
42
|
+
generateZodSchemas: options?.generateZodSchemas ?? true,
|
|
43
|
+
stubsPath: options?.stubsPath ?? "omnify"
|
|
30
44
|
};
|
|
31
45
|
}
|
|
46
|
+
var STUB_FILES = [
|
|
47
|
+
{
|
|
48
|
+
stub: "CompoundField.tsx.stub",
|
|
49
|
+
output: "components/CompoundField.tsx"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
stub: "use-form-mutation.ts.stub",
|
|
53
|
+
output: "hooks/use-form-mutation.ts"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
stub: "form-validation.ts.stub",
|
|
57
|
+
output: "lib/form-validation.ts"
|
|
58
|
+
}
|
|
59
|
+
];
|
|
32
60
|
function typescriptPlugin(options) {
|
|
33
61
|
const resolved = resolveOptions(options);
|
|
34
62
|
return {
|
|
@@ -43,17 +71,74 @@ function typescriptPlugin(options) {
|
|
|
43
71
|
const files = generateTypeScript(ctx.schemas, {
|
|
44
72
|
generateZodSchemas: resolved.generateZodSchemas,
|
|
45
73
|
localeConfig: ctx.localeConfig,
|
|
46
|
-
customTypes: ctx.customTypes
|
|
74
|
+
customTypes: ctx.customTypes,
|
|
75
|
+
pluginEnums: ctx.pluginEnums
|
|
47
76
|
});
|
|
48
|
-
return files.map((file) =>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
77
|
+
return files.map((file) => {
|
|
78
|
+
let outputPath;
|
|
79
|
+
if (file.category === "enum") {
|
|
80
|
+
const enumPath = resolved.modelsPath.replace(/\/schemas\/?$/, "/enum");
|
|
81
|
+
outputPath = `${enumPath}/${file.filePath}`;
|
|
82
|
+
} else {
|
|
83
|
+
outputPath = `${resolved.modelsPath}/${file.filePath}`;
|
|
55
84
|
}
|
|
56
|
-
|
|
85
|
+
return {
|
|
86
|
+
path: outputPath,
|
|
87
|
+
content: file.content,
|
|
88
|
+
type: "type",
|
|
89
|
+
skipIfExists: !file.overwrite,
|
|
90
|
+
// Invert: overwrite=true means skipIfExists=false
|
|
91
|
+
metadata: {
|
|
92
|
+
types: file.types
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "typescript-stubs",
|
|
100
|
+
description: "Generate React utility stubs (hooks, components)",
|
|
101
|
+
generate: async () => {
|
|
102
|
+
if (resolved.stubsPath === false) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
const outputs = [];
|
|
106
|
+
const stubsDir = path.join(__dirname, "..", "stubs");
|
|
107
|
+
for (const { stub, output } of STUB_FILES) {
|
|
108
|
+
const stubPath = path.join(stubsDir, stub);
|
|
109
|
+
if (fs.existsSync(stubPath)) {
|
|
110
|
+
const content = fs.readFileSync(stubPath, "utf-8");
|
|
111
|
+
outputs.push({
|
|
112
|
+
path: `${resolved.stubsPath}/${output}`,
|
|
113
|
+
content,
|
|
114
|
+
type: "other",
|
|
115
|
+
skipIfExists: true
|
|
116
|
+
// Never overwrite - user can customize
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
outputs.push({
|
|
121
|
+
path: `${resolved.stubsPath}/components/index.ts`,
|
|
122
|
+
content: `export { CompoundField, type FieldConfig } from './CompoundField';
|
|
123
|
+
`,
|
|
124
|
+
type: "other",
|
|
125
|
+
skipIfExists: true
|
|
126
|
+
});
|
|
127
|
+
outputs.push({
|
|
128
|
+
path: `${resolved.stubsPath}/hooks/index.ts`,
|
|
129
|
+
content: `export { useFormMutation } from './use-form-mutation';
|
|
130
|
+
`,
|
|
131
|
+
type: "other",
|
|
132
|
+
skipIfExists: true
|
|
133
|
+
});
|
|
134
|
+
outputs.push({
|
|
135
|
+
path: `${resolved.stubsPath}/lib/index.ts`,
|
|
136
|
+
content: `export { zodRule, requiredRule } from './form-validation';
|
|
137
|
+
`,
|
|
138
|
+
type: "other",
|
|
139
|
+
skipIfExists: true
|
|
140
|
+
});
|
|
141
|
+
return outputs;
|
|
57
142
|
}
|
|
58
143
|
}
|
|
59
144
|
]
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @famgia/omnify-typescript - Plugin\n *\n * Plugin for generating TypeScript type definitions and Zod schemas from Omnify schemas.\n *\n * Output structure:\n * - types/schemas/base/[SchemaName].ts - Auto-generated base interfaces + Zod schemas, always overwritten\n * - types/schemas/enum/[EnumName].ts - Auto-generated enums/type aliases, always overwritten\n * - types/schemas/[SchemaName].ts - Extends base, user can customize, never overwritten\n * - types/schemas/index.ts - Re-exports, always overwritten\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@famgia/omnify';\n * import typescript from '@famgia/omnify-typescript/plugin';\n *\n * export default defineConfig({\n * plugins: [\n * typescript({\n * modelsPath: 'types/schemas', // default\n * generateZodSchemas: true, // default\n * }),\n * ],\n * });\n * ```\n */\n\nimport type { OmnifyPlugin, GeneratorOutput, GeneratorContext, PluginConfigSchema } from '@famgia/omnify-types';\nimport { generateTypeScript } from './generator.js';\n\n/**\n * Configuration schema for TypeScript plugin UI settings\n */\nconst TYPESCRIPT_CONFIG_SCHEMA: PluginConfigSchema = {\n fields: [\n {\n key: 'modelsPath',\n type: 'path',\n label: 'Schemas Output Path',\n description: 'Directory for generated TypeScript types and Zod schemas',\n default: 'types/schemas',\n group: 'output',\n },\n {\n key: 'generateZodSchemas',\n type: 'boolean',\n label: 'Generate Zod Schemas',\n description: 'Generate Zod schemas alongside TypeScript types for form validation',\n default: true,\n group: 'output',\n },\n ],\n};\n\n/**\n * Options for the TypeScript plugin.\n */\nexport interface TypeScriptPluginOptions {\n /**\n * Path for TypeScript model files.\n * @default 'types/schemas'\n */\n modelsPath?: string;\n /**\n * Generate Zod schemas alongside TypeScript types.\n * @default true\n */\n generateZodSchemas?: boolean;\n}\n\n/**\n * Resolved options with defaults applied.\n */\ninterface ResolvedOptions {\n modelsPath: string;\n generateZodSchemas: boolean;\n}\n\n/**\n * Resolves options with defaults.\n */\nfunction resolveOptions(options?: TypeScriptPluginOptions): ResolvedOptions {\n return {\n modelsPath: options?.modelsPath ?? 'types/schemas',\n generateZodSchemas: options?.generateZodSchemas ?? true,\n };\n}\n\n/**\n * Creates the TypeScript plugin with the specified options.\n *\n * @param options - Plugin configuration options\n * @returns OmnifyPlugin configured for TypeScript generation\n */\nexport default function typescriptPlugin(options?: TypeScriptPluginOptions): OmnifyPlugin {\n const resolved = resolveOptions(options);\n\n return {\n name: '@famgia/omnify-typescript',\n version: '0.0.1',\n configSchema: TYPESCRIPT_CONFIG_SCHEMA,\n\n generators: [\n {\n name: 'typescript-models',\n description: 'Generate TypeScript model definitions',\n\n generate: async (ctx: GeneratorContext): Promise<GeneratorOutput[]> => {\n const files = generateTypeScript(ctx.schemas, {\n generateZodSchemas: resolved.generateZodSchemas,\n localeConfig: ctx.localeConfig,\n customTypes: ctx.customTypes,\n });\n\n return files.map((file) =>
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["/**\n * @famgia/omnify-typescript - Plugin\n *\n * Plugin for generating TypeScript type definitions and Zod schemas from Omnify schemas.\n *\n * Output structure:\n * - types/schemas/base/[SchemaName].ts - Auto-generated base interfaces + Zod schemas, always overwritten\n * - types/schemas/enum/[EnumName].ts - Auto-generated enums/type aliases, always overwritten\n * - types/schemas/[SchemaName].ts - Extends base, user can customize, never overwritten\n * - types/schemas/index.ts - Re-exports, always overwritten\n *\n * @example\n * ```typescript\n * import { defineConfig } from '@famgia/omnify';\n * import typescript from '@famgia/omnify-typescript/plugin';\n *\n * export default defineConfig({\n * plugins: [\n * typescript({\n * modelsPath: 'types/schemas', // default\n * generateZodSchemas: true, // default\n * }),\n * ],\n * });\n * ```\n */\n\nimport type { OmnifyPlugin, GeneratorOutput, GeneratorContext, PluginConfigSchema } from '@famgia/omnify-types';\nimport { generateTypeScript } from './generator.js';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Configuration schema for TypeScript plugin UI settings\n */\nconst TYPESCRIPT_CONFIG_SCHEMA: PluginConfigSchema = {\n fields: [\n {\n key: 'modelsPath',\n type: 'path',\n label: 'Schemas Output Path',\n description: 'Directory for generated TypeScript types and Zod schemas',\n default: 'types/schemas',\n group: 'output',\n },\n {\n key: 'generateZodSchemas',\n type: 'boolean',\n label: 'Generate Zod Schemas',\n description: 'Generate Zod schemas alongside TypeScript types for form validation',\n default: true,\n group: 'output',\n },\n {\n key: 'stubsPath',\n type: 'path',\n label: 'React Stubs Path',\n description: 'Directory for React utility stubs (hooks, components). Leave empty to disable.',\n default: 'omnify',\n group: 'output',\n },\n ],\n};\n\n/**\n * Options for the TypeScript plugin.\n */\nexport interface TypeScriptPluginOptions {\n /**\n * Path for TypeScript model files.\n * @default 'types/schemas'\n */\n modelsPath?: string;\n /**\n * Generate Zod schemas alongside TypeScript types.\n * @default true\n */\n generateZodSchemas?: boolean;\n /**\n * Path for React utility stubs (hooks, components, lib).\n * Set to false to disable stub generation.\n * @default 'omnify'\n */\n stubsPath?: string | false;\n}\n\n/**\n * Resolved options with defaults applied.\n */\ninterface ResolvedOptions {\n modelsPath: string;\n generateZodSchemas: boolean;\n stubsPath: string | false;\n}\n\n/**\n * Resolves options with defaults.\n */\nfunction resolveOptions(options?: TypeScriptPluginOptions): ResolvedOptions {\n return {\n modelsPath: options?.modelsPath ?? 'types/schemas',\n generateZodSchemas: options?.generateZodSchemas ?? true,\n stubsPath: options?.stubsPath ?? 'omnify',\n };\n}\n\n/**\n * Stub file definitions for React utilities.\n */\nconst STUB_FILES = [\n {\n stub: 'CompoundField.tsx.stub',\n output: 'components/CompoundField.tsx',\n },\n {\n stub: 'use-form-mutation.ts.stub',\n output: 'hooks/use-form-mutation.ts',\n },\n {\n stub: 'form-validation.ts.stub',\n output: 'lib/form-validation.ts',\n },\n];\n\n/**\n * Creates the TypeScript plugin with the specified options.\n *\n * @param options - Plugin configuration options\n * @returns OmnifyPlugin configured for TypeScript generation\n */\nexport default function typescriptPlugin(options?: TypeScriptPluginOptions): OmnifyPlugin {\n const resolved = resolveOptions(options);\n\n return {\n name: '@famgia/omnify-typescript',\n version: '0.0.1',\n configSchema: TYPESCRIPT_CONFIG_SCHEMA,\n\n generators: [\n {\n name: 'typescript-models',\n description: 'Generate TypeScript model definitions',\n\n generate: async (ctx: GeneratorContext): Promise<GeneratorOutput[]> => {\n const files = generateTypeScript(ctx.schemas, {\n generateZodSchemas: resolved.generateZodSchemas,\n localeConfig: ctx.localeConfig,\n customTypes: ctx.customTypes,\n pluginEnums: ctx.pluginEnums,\n });\n\n return files.map((file) => {\n // Determine output path based on category\n let outputPath: string;\n if (file.category === 'enum') {\n // Enum files go to ../enum/ folder (sibling to schemas)\n const enumPath = resolved.modelsPath.replace(/\\/schemas\\/?$/, '/enum');\n outputPath = `${enumPath}/${file.filePath}`;\n } else {\n outputPath = `${resolved.modelsPath}/${file.filePath}`;\n }\n\n return {\n path: outputPath,\n content: file.content,\n type: 'type' as const,\n skipIfExists: !file.overwrite, // Invert: overwrite=true means skipIfExists=false\n metadata: {\n types: file.types,\n },\n };\n });\n },\n },\n {\n name: 'typescript-stubs',\n description: 'Generate React utility stubs (hooks, components)',\n\n generate: async (): Promise<GeneratorOutput[]> => {\n // Skip if stubs disabled\n if (resolved.stubsPath === false) {\n return [];\n }\n\n const outputs: GeneratorOutput[] = [];\n const stubsDir = path.join(__dirname, '..', 'stubs');\n\n for (const { stub, output } of STUB_FILES) {\n const stubPath = path.join(stubsDir, stub);\n if (fs.existsSync(stubPath)) {\n const content = fs.readFileSync(stubPath, 'utf-8');\n outputs.push({\n path: `${resolved.stubsPath}/${output}`,\n content,\n type: 'other' as const,\n skipIfExists: true, // Never overwrite - user can customize\n });\n }\n }\n\n // Generate index files\n outputs.push({\n path: `${resolved.stubsPath}/components/index.ts`,\n content: `export { CompoundField, type FieldConfig } from './CompoundField';\\n`,\n type: 'other' as const,\n skipIfExists: true,\n });\n\n outputs.push({\n path: `${resolved.stubsPath}/hooks/index.ts`,\n content: `export { useFormMutation } from './use-form-mutation';\\n`,\n type: 'other' as const,\n skipIfExists: true,\n });\n\n outputs.push({\n path: `${resolved.stubsPath}/lib/index.ts`,\n content: `export { zodRule, requiredRule } from './form-validation';\\n`,\n type: 'other' as const,\n skipIfExists: true,\n });\n\n return outputs;\n },\n },\n ],\n };\n}\n\n// Named export for flexibility\nexport { typescriptPlugin };\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@famgia/omnify-typescript",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.69",
|
|
4
4
|
"description": "TypeScript type definitions generator for Omnify schemas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
33
|
"scripts",
|
|
34
|
-
"
|
|
34
|
+
"stubs"
|
|
35
35
|
],
|
|
36
36
|
"keywords": [
|
|
37
37
|
"omnify",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"directory": "packages/typescript-generator"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@famgia/omnify-types": "0.0.
|
|
51
|
+
"@famgia/omnify-types": "0.0.79"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"zod": "^3.0.0"
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @famgia/omnify-typescript postinstall
|
|
5
|
+
* Copies TypeScript AI guides to .claude/omnify/
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
import fs from 'fs';
|
|
4
9
|
import path from 'path';
|
|
5
10
|
import { fileURLToPath } from 'url';
|
|
@@ -7,64 +12,48 @@ import { fileURLToPath } from 'url';
|
|
|
7
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
13
|
const __dirname = path.dirname(__filename);
|
|
9
14
|
|
|
10
|
-
function
|
|
11
|
-
//
|
|
12
|
-
|
|
15
|
+
function main() {
|
|
16
|
+
// Skip in CI
|
|
17
|
+
if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Skip in monorepo source (but allow examples/)
|
|
22
|
+
const projectDir = process.env.INIT_CWD || process.cwd();
|
|
23
|
+
if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Find project root
|
|
28
|
+
let dir = projectDir;
|
|
13
29
|
const nodeModulesIndex = dir.indexOf('node_modules');
|
|
14
30
|
if (nodeModulesIndex !== -1) {
|
|
15
31
|
dir = dir.substring(0, nodeModulesIndex - 1);
|
|
16
32
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return dir;
|
|
33
|
+
if (!fs.existsSync(path.join(dir, 'package.json'))) {
|
|
34
|
+
return;
|
|
20
35
|
}
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
const omnifyDir = path.join(
|
|
37
|
+
// Copy ai-guides to .claude/omnify/
|
|
38
|
+
const omnifyDir = path.join(dir, '.claude', 'omnify');
|
|
26
39
|
const aiGuidesDir = path.join(__dirname, '..', 'ai-guides');
|
|
27
40
|
|
|
28
41
|
try {
|
|
29
|
-
// Create target directory
|
|
30
42
|
if (!fs.existsSync(omnifyDir)) {
|
|
31
43
|
fs.mkdirSync(omnifyDir, { recursive: true });
|
|
32
44
|
}
|
|
33
45
|
|
|
34
|
-
// Copy all files from ai-guides directory
|
|
35
46
|
if (fs.existsSync(aiGuidesDir)) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (fs.statSync(srcPath).isFile()) {
|
|
42
|
-
fs.copyFileSync(srcPath, destPath);
|
|
43
|
-
console.log(` Created .claude/omnify/${file}`);
|
|
47
|
+
for (const file of fs.readdirSync(aiGuidesDir)) {
|
|
48
|
+
const src = path.join(aiGuidesDir, file);
|
|
49
|
+
const dest = path.join(omnifyDir, file);
|
|
50
|
+
if (fs.statSync(src).isFile()) {
|
|
51
|
+
fs.copyFileSync(src, dest);
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
|
-
|
|
48
|
-
return true;
|
|
49
55
|
} catch {
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function main() {
|
|
55
|
-
if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Skip if in omnify-ts monorepo (source code), but allow examples/
|
|
60
|
-
const projectDir = process.env.INIT_CWD || process.cwd();
|
|
61
|
-
if (projectDir.includes('omnify-ts') && !projectDir.includes('omnify-ts/examples')) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const projectRoot = findProjectRoot();
|
|
66
|
-
if (projectRoot) {
|
|
67
|
-
copyAiGuidesToProject(projectRoot);
|
|
56
|
+
// Silent fail
|
|
68
57
|
}
|
|
69
58
|
}
|
|
70
59
|
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JapaneseAddressField - Japanese address input component
|
|
3
|
+
* Handles postal code, prefecture, address fields with postal code lookup
|
|
4
|
+
*/
|
|
5
|
+
import { useState, useCallback } from 'react';
|
|
6
|
+
import { Form, Input, Select, Button, message } from 'antd';
|
|
7
|
+
import { SearchOutlined, LoadingOutlined } from '@ant-design/icons';
|
|
8
|
+
import type { FormInstance } from 'antd';
|
|
9
|
+
import type { RuleObject } from 'antd/es/form';
|
|
10
|
+
import { zodRule } from '../lib/form-validation';
|
|
11
|
+
import { getZodLocale } from '../lib/zod-i18n';
|
|
12
|
+
import { Prefecture, PrefectureValues, getPrefectureLabel, getPrefectureExtra } from '../enum/plugin/Prefecture';
|
|
13
|
+
|
|
14
|
+
interface I18nConfig {
|
|
15
|
+
fields: Record<string, { label?: Record<string, string>; placeholder?: Record<string, string> }>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface SelectOption {
|
|
19
|
+
value: string | number;
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface PostalLookupResult {
|
|
24
|
+
prefecture?: string;
|
|
25
|
+
prefectureCode?: string;
|
|
26
|
+
prefectureName?: string;
|
|
27
|
+
address1?: string;
|
|
28
|
+
address2?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface JapaneseAddressFieldProps {
|
|
32
|
+
form: FormInstance;
|
|
33
|
+
schemas: Record<string, unknown>;
|
|
34
|
+
i18n: I18nConfig;
|
|
35
|
+
prefix?: string;
|
|
36
|
+
usePrefectureId?: boolean;
|
|
37
|
+
prefectureOptions?: SelectOption[];
|
|
38
|
+
enablePostalLookup?: boolean;
|
|
39
|
+
showSearchButton?: boolean;
|
|
40
|
+
autoSearch?: boolean;
|
|
41
|
+
onPostalLookup?: (postalCode: string) => Promise<PostalLookupResult | null>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getLabel(i18n: I18nConfig, field: string, locale: string): string {
|
|
45
|
+
return i18n.fields[field]?.label?.[locale] ?? i18n.fields[field]?.label?.['en'] ?? field;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getPlaceholder(i18n: I18nConfig, field: string, locale: string): string {
|
|
49
|
+
return i18n.fields[field]?.placeholder?.[locale] ?? i18n.fields[field]?.placeholder?.['en'] ?? '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Build prefecture code to string key mapping from generated enum
|
|
53
|
+
const PREFECTURE_CODE_TO_KEY: Record<string, string> = Object.fromEntries(
|
|
54
|
+
PrefectureValues.map((key) => {
|
|
55
|
+
const extra = getPrefectureExtra(key);
|
|
56
|
+
return [String(extra?.code ?? ''), key];
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Build default prefecture options from generated enum
|
|
61
|
+
function buildPrefectureOptions(locale: string): SelectOption[] {
|
|
62
|
+
return PrefectureValues.map((key) => ({
|
|
63
|
+
value: key,
|
|
64
|
+
label: getPrefectureLabel(key, locale),
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Default postal lookup function using zipcloud API
|
|
69
|
+
async function lookupPostalCode(postalCode: string): Promise<PostalLookupResult | null> {
|
|
70
|
+
try {
|
|
71
|
+
const response = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${postalCode}`);
|
|
72
|
+
const data = await response.json();
|
|
73
|
+
|
|
74
|
+
if (data.results && data.results.length > 0) {
|
|
75
|
+
const result = data.results[0];
|
|
76
|
+
const prefectureKey = PREFECTURE_CODE_TO_KEY[result.prefcode];
|
|
77
|
+
return {
|
|
78
|
+
prefecture: prefectureKey,
|
|
79
|
+
prefectureCode: result.prefcode,
|
|
80
|
+
prefectureName: result.address1,
|
|
81
|
+
address1: result.address2,
|
|
82
|
+
address2: result.address3,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('Postal code lookup failed:', error);
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Localized messages
|
|
93
|
+
const MESSAGES = {
|
|
94
|
+
ja: {
|
|
95
|
+
searchAddress: '住所検索',
|
|
96
|
+
searching: '検索中...',
|
|
97
|
+
notFound: '郵便番号が見つかりませんでした',
|
|
98
|
+
error: '住所検索に失敗しました',
|
|
99
|
+
invalidFormat: '郵便番号の形式が正しくありません(例:123-4567)',
|
|
100
|
+
},
|
|
101
|
+
en: {
|
|
102
|
+
searchAddress: 'Search Address',
|
|
103
|
+
searching: 'Searching...',
|
|
104
|
+
notFound: 'Postal code not found',
|
|
105
|
+
error: 'Address lookup failed',
|
|
106
|
+
invalidFormat: 'Invalid postal code format (e.g., 123-4567)',
|
|
107
|
+
},
|
|
108
|
+
vi: {
|
|
109
|
+
searchAddress: 'Tìm địa chỉ',
|
|
110
|
+
searching: 'Đang tìm...',
|
|
111
|
+
notFound: 'Không tìm thấy mã bưu điện',
|
|
112
|
+
error: 'Tìm địa chỉ thất bại',
|
|
113
|
+
invalidFormat: 'Định dạng mã bưu điện không hợp lệ (VD: 123-4567)',
|
|
114
|
+
},
|
|
115
|
+
} as const;
|
|
116
|
+
|
|
117
|
+
function getMessage(key: keyof typeof MESSAGES.ja, locale: string): string {
|
|
118
|
+
return (MESSAGES as any)[locale]?.[key] ?? MESSAGES.ja[key];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function JapaneseAddressField({
|
|
122
|
+
form,
|
|
123
|
+
schemas,
|
|
124
|
+
i18n,
|
|
125
|
+
prefix = 'address',
|
|
126
|
+
usePrefectureId = false,
|
|
127
|
+
prefectureOptions,
|
|
128
|
+
enablePostalLookup = true,
|
|
129
|
+
showSearchButton = true,
|
|
130
|
+
autoSearch = true,
|
|
131
|
+
onPostalLookup,
|
|
132
|
+
}: JapaneseAddressFieldProps) {
|
|
133
|
+
const locale = getZodLocale();
|
|
134
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
135
|
+
|
|
136
|
+
// Field names
|
|
137
|
+
const postalCodeField = `${prefix}_postal_code`;
|
|
138
|
+
const prefectureField = usePrefectureId
|
|
139
|
+
? `${prefix}_prefecture_id`
|
|
140
|
+
: `${prefix}_prefecture`;
|
|
141
|
+
const address1Field = `${prefix}_address1`;
|
|
142
|
+
const address2Field = `${prefix}_address2`;
|
|
143
|
+
const address3Field = `${prefix}_address3`;
|
|
144
|
+
|
|
145
|
+
// Use generated prefecture options
|
|
146
|
+
const options = prefectureOptions ?? buildPrefectureOptions(locale);
|
|
147
|
+
|
|
148
|
+
// Get rules from schemas
|
|
149
|
+
const getRule = (field: string): RuleObject[] => {
|
|
150
|
+
const schema = schemas[field];
|
|
151
|
+
if (!schema) return [];
|
|
152
|
+
return [zodRule(schema as any, getLabel(i18n, field, locale))];
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Check if a field is required by examining its Zod schema description
|
|
156
|
+
const isRequired = (field: string): boolean => {
|
|
157
|
+
const schema = schemas[field];
|
|
158
|
+
if (!schema) return false;
|
|
159
|
+
// Check if schema has .optional() or .nullable() - these make it not required
|
|
160
|
+
const schemaDesc = (schema as any)?._def?.typeName;
|
|
161
|
+
const inner = (schema as any)?._def?.innerType;
|
|
162
|
+
// ZodOptional or ZodNullable means not required
|
|
163
|
+
if (schemaDesc === 'ZodOptional' || schemaDesc === 'ZodNullable') return false;
|
|
164
|
+
if (inner?._def?.typeName === 'ZodOptional' || inner?._def?.typeName === 'ZodNullable') return false;
|
|
165
|
+
return true;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// Lookup address from postal code
|
|
169
|
+
const doLookup = useCallback(async (postalCode: string) => {
|
|
170
|
+
const digits = postalCode.replace(/[^0-9]/g, '');
|
|
171
|
+
if (digits.length !== 7) {
|
|
172
|
+
message.warning(getMessage('invalidFormat', locale));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setIsSearching(true);
|
|
177
|
+
try {
|
|
178
|
+
const lookupFn = onPostalLookup ?? lookupPostalCode;
|
|
179
|
+
const result = await lookupFn(postalCode);
|
|
180
|
+
|
|
181
|
+
if (result) {
|
|
182
|
+
const prefectureValue = usePrefectureId ? result.prefectureCode : result.prefecture;
|
|
183
|
+
form.setFieldsValue({
|
|
184
|
+
[prefectureField]: prefectureValue,
|
|
185
|
+
[address1Field]: result.address1,
|
|
186
|
+
[address2Field]: result.address2,
|
|
187
|
+
});
|
|
188
|
+
} else {
|
|
189
|
+
message.info(getMessage('notFound', locale));
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
message.error(getMessage('error', locale));
|
|
193
|
+
console.error('Postal code lookup failed:', error);
|
|
194
|
+
} finally {
|
|
195
|
+
setIsSearching(false);
|
|
196
|
+
}
|
|
197
|
+
}, [form, locale, onPostalLookup, prefectureField, address1Field, address2Field, usePrefectureId]);
|
|
198
|
+
|
|
199
|
+
const handlePostalCodeChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
200
|
+
const postalCode = e.target.value.replace(/[^0-9]/g, '');
|
|
201
|
+
if (autoSearch && enablePostalLookup && postalCode.length === 7) {
|
|
202
|
+
await doLookup(postalCode);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const handleSearchClick = async () => {
|
|
207
|
+
const postalCode = form.getFieldValue(postalCodeField);
|
|
208
|
+
if (postalCode) {
|
|
209
|
+
await doLookup(postalCode);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<>
|
|
215
|
+
{/* 郵便番号 */}
|
|
216
|
+
<Form.Item
|
|
217
|
+
name={postalCodeField}
|
|
218
|
+
label={getLabel(i18n, postalCodeField, locale)}
|
|
219
|
+
rules={getRule(postalCodeField)}
|
|
220
|
+
required={isRequired(postalCodeField)}
|
|
221
|
+
>
|
|
222
|
+
<Input
|
|
223
|
+
placeholder={getPlaceholder(i18n, postalCodeField, locale)}
|
|
224
|
+
style={{ width: enablePostalLookup && showSearchButton ? 'calc(100% - 110px)' : 150 }}
|
|
225
|
+
onChange={handlePostalCodeChange}
|
|
226
|
+
addonAfter={
|
|
227
|
+
enablePostalLookup && showSearchButton && (
|
|
228
|
+
<Button
|
|
229
|
+
type="text"
|
|
230
|
+
size="small"
|
|
231
|
+
icon={isSearching ? <LoadingOutlined /> : <SearchOutlined />}
|
|
232
|
+
onClick={handleSearchClick}
|
|
233
|
+
disabled={isSearching}
|
|
234
|
+
>
|
|
235
|
+
{getMessage('searchAddress', locale)}
|
|
236
|
+
</Button>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
/>
|
|
240
|
+
</Form.Item>
|
|
241
|
+
|
|
242
|
+
{/* 都道府県 */}
|
|
243
|
+
<Form.Item
|
|
244
|
+
name={prefectureField}
|
|
245
|
+
label={getLabel(i18n, prefectureField, locale)}
|
|
246
|
+
rules={getRule(prefectureField)}
|
|
247
|
+
required={isRequired(prefectureField)}
|
|
248
|
+
>
|
|
249
|
+
<Select
|
|
250
|
+
placeholder={getPlaceholder(i18n, prefectureField, locale)}
|
|
251
|
+
options={options}
|
|
252
|
+
style={{ width: 200 }}
|
|
253
|
+
showSearch
|
|
254
|
+
optionFilterProp="label"
|
|
255
|
+
/>
|
|
256
|
+
</Form.Item>
|
|
257
|
+
|
|
258
|
+
{/* 市区町村 */}
|
|
259
|
+
<Form.Item
|
|
260
|
+
name={address1Field}
|
|
261
|
+
label={getLabel(i18n, address1Field, locale)}
|
|
262
|
+
rules={getRule(address1Field)}
|
|
263
|
+
required={isRequired(address1Field)}
|
|
264
|
+
>
|
|
265
|
+
<Input placeholder={getPlaceholder(i18n, address1Field, locale)} />
|
|
266
|
+
</Form.Item>
|
|
267
|
+
|
|
268
|
+
{/* 番地 */}
|
|
269
|
+
<Form.Item
|
|
270
|
+
name={address2Field}
|
|
271
|
+
label={getLabel(i18n, address2Field, locale)}
|
|
272
|
+
rules={getRule(address2Field)}
|
|
273
|
+
required={isRequired(address2Field)}
|
|
274
|
+
>
|
|
275
|
+
<Input placeholder={getPlaceholder(i18n, address2Field, locale)} />
|
|
276
|
+
</Form.Item>
|
|
277
|
+
|
|
278
|
+
{/* 建物名・部屋番号 */}
|
|
279
|
+
<Form.Item
|
|
280
|
+
name={address3Field}
|
|
281
|
+
label={getLabel(i18n, address3Field, locale)}
|
|
282
|
+
rules={getRule(address3Field)}
|
|
283
|
+
required={isRequired(address3Field)}
|
|
284
|
+
>
|
|
285
|
+
<Input placeholder={getPlaceholder(i18n, address3Field, locale)} />
|
|
286
|
+
</Form.Item>
|
|
287
|
+
</>
|
|
288
|
+
);
|
|
289
|
+
}
|