sizuku 0.1.0 → 0.2.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/README.md +17 -11
- package/dist/cli/main.d.ts +10 -0
- package/dist/cli/main.js +61 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +51 -0
- package/dist/config/index.d.ts +1 -1
- package/dist/config/loader.d.ts +19 -0
- package/dist/config/loader.js +30 -0
- package/dist/generator/engine.d.ts +3 -0
- package/dist/generator/engine.js +63 -0
- package/dist/generator/mermaid-er/core.d.ts +6 -0
- package/dist/generator/mermaid-er/core.js +54 -0
- package/dist/generator/mermaid-er/generator/er-content.d.ts +14 -2
- package/dist/generator/mermaid-er/generator/index.d.ts +1 -1
- package/dist/generator/mermaid-er/generator/index.js +1 -1
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +7 -2
- package/dist/generator/mermaid-er/generator/relation-line.js +1 -1
- package/dist/generator/mermaid-er/generator.d.ts +3 -0
- package/dist/generator/mermaid-er/generator.js +14 -0
- package/dist/generator/mermaid-er/index.d.ts +7 -1
- package/dist/generator/mermaid-er/index.js +21 -4
- package/dist/generator/mermaid-er/validator/index.d.ts +8 -4
- package/dist/generator/mermaid-er/validator/index.js +71 -4
- package/dist/generator/mermaid-er/validator/parse-table-info.js +1 -1
- package/dist/generator/valibot/core.d.ts +5 -0
- package/dist/generator/valibot/core.js +39 -0
- package/dist/generator/valibot/generator/infer-input.js +1 -1
- package/dist/generator/valibot/generator/relation-valibot-code.d.ts +13 -0
- package/dist/generator/valibot/generator/relation-valibot-code.js +19 -0
- package/dist/generator/valibot/generator/valibot-code.d.ts +9 -2
- package/dist/generator/valibot/generator/valibot-code.js +1 -1
- package/dist/generator/valibot/generator/valibot.d.ts +9 -2
- package/dist/generator/valibot/generator/valibot.js +7 -3
- package/dist/generator/valibot/generator.d.ts +3 -0
- package/dist/generator/valibot/generator.js +14 -0
- package/dist/generator/valibot/index.d.ts +7 -2
- package/dist/generator/valibot/index.js +36 -8
- package/dist/generator/zod/core.d.ts +5 -0
- package/dist/generator/zod/core.js +39 -0
- package/dist/generator/zod/generator/infer.js +2 -2
- package/dist/generator/zod/generator/relation-zod-code.d.ts +13 -0
- package/dist/generator/zod/generator/relation-zod-code.js +19 -0
- package/dist/generator/zod/generator/zod-code.d.ts +9 -2
- package/dist/generator/zod/generator/zod-code.js +1 -1
- package/dist/generator/zod/generator/zod.d.ts +9 -2
- package/dist/generator/zod/generator/zod.js +7 -3
- package/dist/generator/zod/generator.d.ts +3 -0
- package/dist/generator/zod/generator.js +14 -0
- package/dist/generator/zod/index.d.ts +7 -2
- package/dist/generator/zod/index.js +40 -16
- package/dist/index.d.ts +7 -2
- package/dist/index.js +60 -43
- package/dist/shared/format/index.d.ts +15 -2
- package/dist/shared/format/index.js +22 -8
- package/dist/shared/fs/index.d.ts +7 -2
- package/dist/shared/fs/index.js +9 -3
- package/dist/shared/fsp/index.d.ts +27 -3
- package/dist/shared/fsp/index.js +35 -5
- package/dist/shared/generator/field-definitions.d.ts +8 -2
- package/dist/shared/helper/ast-parser.d.ts +3 -0
- package/dist/shared/helper/ast-parser.js +202 -0
- package/dist/shared/helper/build-schema-extractor.d.ts +25 -0
- package/dist/shared/helper/build-schema-extractor.js +33 -0
- package/dist/shared/helper/create-extract-field-from-property.d.ts +15 -0
- package/dist/shared/helper/create-extract-field-from-property.js +20 -0
- package/dist/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
- package/dist/shared/helper/create-extract-fields-from-call-expression.js +14 -0
- package/dist/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
- package/dist/shared/helper/create-extract-relation-field-from-property.js +27 -0
- package/dist/shared/helper/extract-schemas.d.ts +133 -0
- package/dist/shared/helper/extract-schemas.js +445 -0
- package/dist/shared/helper/file-writer.d.ts +3 -0
- package/dist/shared/helper/file-writer.js +25 -0
- package/dist/shared/helper/find-object-literal-expression.d.ts +12 -0
- package/dist/shared/helper/find-object-literal-expression.js +31 -0
- package/dist/shared/helper/find-object-literalIn-args.d.ts +2 -0
- package/dist/shared/helper/find-object-literalIn-args.js +8 -0
- package/dist/shared/helper/is-relation-function.d.ts +10 -0
- package/dist/shared/helper/is-relation-function.js +16 -0
- package/dist/shared/utils/index.d.ts +20 -0
- package/dist/shared/utils/index.js +48 -0
- package/dist/shared/utils/string-utils.d.ts +8 -0
- package/dist/shared/utils/string-utils.js +28 -0
- package/dist/shared/utils/types.d.ts +32 -0
- package/dist/shared/utils/types.js +2 -0
- package/dist/shared/utils/validation-utils.d.ts +8 -0
- package/dist/shared/utils/validation-utils.js +25 -0
- package/dist/src/config/index.d.ts +18 -0
- package/dist/src/config/index.js +13 -0
- package/dist/src/generator/mermaid-er/core/extract-relations.d.ts +8 -0
- package/dist/src/generator/mermaid-er/core/extract-relations.js +12 -0
- package/dist/src/generator/mermaid-er/generator/er-content.d.ts +9 -0
- package/dist/src/generator/mermaid-er/generator/er-content.js +25 -0
- package/dist/src/generator/mermaid-er/generator/index.d.ts +2 -0
- package/dist/src/generator/mermaid-er/generator/index.js +2 -0
- package/dist/src/generator/mermaid-er/generator/relation-line.d.ts +8 -0
- package/dist/src/generator/mermaid-er/generator/relation-line.js +14 -0
- package/dist/src/generator/mermaid-er/index.d.ts +6 -0
- package/dist/src/generator/mermaid-er/index.js +16 -0
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.d.ts +15 -0
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.js +35 -0
- package/dist/src/generator/mermaid-er/types.d.ts +21 -0
- package/dist/src/generator/mermaid-er/types.js +1 -0
- package/dist/src/generator/mermaid-er/validator/index.d.ts +4 -0
- package/dist/src/generator/mermaid-er/validator/index.js +4 -0
- package/dist/src/generator/mermaid-er/validator/is-relationship.d.ts +8 -0
- package/dist/src/generator/mermaid-er/validator/is-relationship.js +9 -0
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.d.ts +13 -0
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.js +21 -0
- package/dist/src/generator/mermaid-er/validator/parse-table-info.d.ts +8 -0
- package/dist/src/generator/mermaid-er/validator/parse-table-info.js +91 -0
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +7 -0
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.js +9 -0
- package/dist/src/generator/valibot/generator/infer-input.d.ts +5 -0
- package/dist/src/generator/valibot/generator/infer-input.js +8 -0
- package/dist/src/generator/valibot/generator/valibot-code.d.ts +14 -0
- package/dist/src/generator/valibot/generator/valibot-code.js +16 -0
- package/dist/src/generator/valibot/generator/valibot.d.ts +13 -0
- package/dist/src/generator/valibot/generator/valibot.js +11 -0
- package/dist/src/generator/valibot/index.d.ts +9 -0
- package/dist/src/generator/valibot/index.js +34 -0
- package/dist/src/generator/zod/generator/infer.d.ts +5 -0
- package/dist/src/generator/zod/generator/infer.js +8 -0
- package/dist/src/generator/zod/generator/zod-code.d.ts +16 -0
- package/dist/src/generator/zod/generator/zod-code.js +18 -0
- package/dist/src/generator/zod/generator/zod.d.ts +15 -0
- package/dist/src/generator/zod/generator/zod.js +12 -0
- package/dist/src/generator/zod/index.d.ts +10 -0
- package/dist/src/generator/zod/index.js +40 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +35 -0
- package/dist/src/shared/format/index.d.ts +2 -0
- package/dist/src/shared/format/index.js +10 -0
- package/dist/src/shared/fs/index.d.ts +2 -0
- package/dist/src/shared/fs/index.js +10 -0
- package/dist/src/shared/fsp/index.d.ts +3 -0
- package/dist/src/shared/fsp/index.js +8 -0
- package/dist/src/shared/generator/field-definitions.d.ts +12 -0
- package/dist/src/shared/generator/field-definitions.js +12 -0
- package/dist/src/shared/helper/build-schema-extractor.d.ts +25 -0
- package/dist/src/shared/helper/build-schema-extractor.js +33 -0
- package/dist/src/shared/helper/create-extract-field-from-property.d.ts +15 -0
- package/dist/src/shared/helper/create-extract-field-from-property.js +20 -0
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.d.ts +14 -0
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.js +14 -0
- package/dist/src/shared/helper/create-extract-relation-field-from-property.d.ts +12 -0
- package/dist/src/shared/helper/create-extract-relation-field-from-property.js +27 -0
- package/dist/src/shared/helper/extract-schemas.d.ts +16 -0
- package/dist/src/shared/helper/extract-schemas.js +19 -0
- package/dist/src/shared/helper/find-object-literal-expression.d.ts +12 -0
- package/dist/src/shared/helper/find-object-literal-expression.js +31 -0
- package/dist/src/shared/helper/find-object-literalIn-args.d.ts +2 -0
- package/dist/src/shared/helper/find-object-literalIn-args.js +8 -0
- package/dist/src/shared/helper/is-relation-function.d.ts +10 -0
- package/dist/src/shared/helper/is-relation-function.js +16 -0
- package/dist/src/shared/utils/index.d.ts +33 -0
- package/dist/src/shared/utils/index.js +61 -0
- package/dist/utils/index.d.ts +144 -0
- package/dist/utils/index.js +301 -0
- package/package.json +2 -6
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// 完全純粋なValibotスキーマ生成ユーティリティ - 外部import禁止
|
|
2
|
+
import { toPascalCase } from '../../shared/utils/string-utils.js';
|
|
3
|
+
export const generateValibotSchema = (table) => {
|
|
4
|
+
const schemaName = `${toPascalCase(table.name)}Schema`;
|
|
5
|
+
const typeName = toPascalCase(table.name);
|
|
6
|
+
const properties = table.columns.map(column => generateValibotProperty(column)).join('\n ');
|
|
7
|
+
return `export const ${schemaName} = v.object({
|
|
8
|
+
${properties}
|
|
9
|
+
})
|
|
10
|
+
export type ${typeName} = v.InferInput<typeof ${schemaName}>`;
|
|
11
|
+
};
|
|
12
|
+
export const generateValibotProperty = (column) => {
|
|
13
|
+
const comment = column.comment ? `/** ${column.comment} */\n ` : '';
|
|
14
|
+
const schema = column.valibotSchema || generateDefaultValibotSchema(column);
|
|
15
|
+
return `${comment}${column.name}: ${schema},`;
|
|
16
|
+
};
|
|
17
|
+
export const generateDefaultValibotSchema = (column) => {
|
|
18
|
+
if (column.type === 'varchar') {
|
|
19
|
+
if (column.length === 36) {
|
|
20
|
+
return 'v.pipe(v.string(), v.uuid())';
|
|
21
|
+
}
|
|
22
|
+
if (column.length) {
|
|
23
|
+
return `v.pipe(v.string(), v.maxLength(${column.length}))`;
|
|
24
|
+
}
|
|
25
|
+
return 'v.string()';
|
|
26
|
+
}
|
|
27
|
+
if (column.type === 'int') {
|
|
28
|
+
return 'v.pipe(v.number(), v.integer())';
|
|
29
|
+
}
|
|
30
|
+
if (column.type === 'text') {
|
|
31
|
+
return 'v.string()';
|
|
32
|
+
}
|
|
33
|
+
return 'v.unknown()';
|
|
34
|
+
};
|
|
35
|
+
export const generateValibotFile = (tables) => {
|
|
36
|
+
const imports = 'import * as v from \'valibot\'\n\n';
|
|
37
|
+
const schemas = tables.map(table => generateValibotSchema(table)).join('\n\n');
|
|
38
|
+
return imports + schemas;
|
|
39
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates Valibot relation schema code from a relation schema AST extraction.
|
|
3
|
+
*/
|
|
4
|
+
export declare function relationValibotCode(schema: {
|
|
5
|
+
name: string;
|
|
6
|
+
baseName: string;
|
|
7
|
+
fields: {
|
|
8
|
+
name: string;
|
|
9
|
+
definition: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}[];
|
|
12
|
+
objectType?: 'strict' | 'loose';
|
|
13
|
+
}, withType: boolean): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { capitalize, inferInput } from '../../../utils/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates Valibot relation schema code from a relation schema AST extraction.
|
|
4
|
+
*/
|
|
5
|
+
export function relationValibotCode(schema, withType) {
|
|
6
|
+
const base = schema.baseName;
|
|
7
|
+
const relName = `${schema.name}Schema`;
|
|
8
|
+
const baseSchema = `${capitalize(base)}Schema`;
|
|
9
|
+
const fields = schema.fields.map((f) => `${f.name}:${f.definition}`).join(',');
|
|
10
|
+
const objectType = schema.objectType === 'strict'
|
|
11
|
+
? 'strictObject'
|
|
12
|
+
: schema.objectType === 'loose'
|
|
13
|
+
? 'looseObject'
|
|
14
|
+
: 'object';
|
|
15
|
+
const obj = `\nexport const ${capitalize(relName)} = v.${objectType}({...${baseSchema}.entries,${fields}})`;
|
|
16
|
+
if (withType)
|
|
17
|
+
return `${obj}\n\n${inferInput(schema.name)}\n`;
|
|
18
|
+
return `${obj}`;
|
|
19
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import type { Schema } from '../../../shared/types.js';
|
|
2
1
|
/**
|
|
3
2
|
* @param schema
|
|
4
3
|
* @param comment
|
|
5
4
|
* @param type
|
|
6
5
|
* @returns
|
|
7
6
|
*/
|
|
8
|
-
export declare function valibotCode(schema:
|
|
7
|
+
export declare function valibotCode(schema: {
|
|
8
|
+
name: string;
|
|
9
|
+
fields: {
|
|
10
|
+
name: string;
|
|
11
|
+
definition: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
}[];
|
|
14
|
+
objectType?: 'strict' | 'loose';
|
|
15
|
+
}, comment: boolean, type: boolean): string;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import type { Schema } from '../../../shared/types.js';
|
|
2
1
|
/**
|
|
3
2
|
* @param schema
|
|
4
3
|
* @param config
|
|
5
4
|
* @returns
|
|
6
5
|
*/
|
|
7
|
-
export declare function valibot(schema:
|
|
6
|
+
export declare function valibot(schema: {
|
|
7
|
+
name: string;
|
|
8
|
+
fields: {
|
|
9
|
+
name: string;
|
|
10
|
+
definition: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
}[];
|
|
13
|
+
objectType?: 'strict' | 'loose';
|
|
14
|
+
}, comment: boolean): string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { capitalize } from '../../../
|
|
2
|
-
import { fieldDefinitions } from '../../../shared/generator/field-definitions.js';
|
|
1
|
+
import { capitalize, fieldDefinitions } from '../../../utils/index.js';
|
|
3
2
|
/**
|
|
4
3
|
* @param schema
|
|
5
4
|
* @param config
|
|
@@ -7,5 +6,10 @@ import { fieldDefinitions } from '../../../shared/generator/field-definitions.js
|
|
|
7
6
|
*/
|
|
8
7
|
export function valibot(schema, comment) {
|
|
9
8
|
const res = fieldDefinitions(schema, comment);
|
|
10
|
-
|
|
9
|
+
const objectType = schema.objectType === 'strict'
|
|
10
|
+
? 'strictObject'
|
|
11
|
+
: schema.objectType === 'loose'
|
|
12
|
+
? 'looseObject'
|
|
13
|
+
: 'object';
|
|
14
|
+
return `export const ${capitalize(schema.name)}Schema = v.${objectType}({${res}})`;
|
|
11
15
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Result, err, ok } from 'neverthrow';
|
|
2
|
+
import { generateValibotFile } from './core.js';
|
|
3
|
+
export const generateValibotSchemas = (schema) => {
|
|
4
|
+
try {
|
|
5
|
+
if (schema.tables.length === 0) {
|
|
6
|
+
return err(new Error('No tables found in schema'));
|
|
7
|
+
}
|
|
8
|
+
const valibotContent = generateValibotFile(schema.tables);
|
|
9
|
+
return ok(valibotContent);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return err(new Error(`Failed to generate Valibot schemas: ${error instanceof Error ? error.message : String(error)}`));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Result } from 'neverthrow';
|
|
2
1
|
/**
|
|
3
2
|
* Generate Valibot schema
|
|
4
3
|
* @param code - The code to generate Valibot schema from
|
|
@@ -6,4 +5,10 @@ import type { Result } from 'neverthrow';
|
|
|
6
5
|
* @param comment - Whether to include comments in the generated code
|
|
7
6
|
* @param type - Whether to include type information in the generated code
|
|
8
7
|
*/
|
|
9
|
-
export declare function sizukuValibot(code: string[], output: `${string}.ts`, comment?: boolean, type?: boolean): Promise<
|
|
8
|
+
export declare function sizukuValibot(code: string[], output: `${string}.ts`, comment?: boolean, type?: boolean, relations?: boolean): Promise<{
|
|
9
|
+
ok: true;
|
|
10
|
+
value: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: string;
|
|
14
|
+
}>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { extractSchemas } from './core/extract-schema.js';
|
|
3
|
-
import { valibotCode } from './generator/valibot-code.js';
|
|
4
2
|
import { fmt } from '../../shared/format/index.js';
|
|
5
3
|
import { mkdir, writeFile } from '../../shared/fsp/index.js';
|
|
4
|
+
import { extractRelationSchemas, extractSchemas } from '../../shared/helper/extract-schemas.js';
|
|
5
|
+
import { relationValibotCode } from './generator/relation-valibot-code.js';
|
|
6
|
+
import { valibotCode } from './generator/valibot-code.js';
|
|
6
7
|
/**
|
|
7
8
|
* Generate Valibot schema
|
|
8
9
|
* @param code - The code to generate Valibot schema from
|
|
@@ -10,13 +11,40 @@ import { mkdir, writeFile } from '../../shared/fsp/index.js';
|
|
|
10
11
|
* @param comment - Whether to include comments in the generated code
|
|
11
12
|
* @param type - Whether to include type information in the generated code
|
|
12
13
|
*/
|
|
13
|
-
export async function sizukuValibot(code, output, comment, type) {
|
|
14
|
+
export async function sizukuValibot(code, output, comment, type, relations) {
|
|
15
|
+
const baseSchemas = extractSchemas(code, 'valibot');
|
|
16
|
+
const relationSchemas = extractRelationSchemas(code, 'valibot');
|
|
14
17
|
const valibotGeneratedCode = [
|
|
15
|
-
|
|
18
|
+
"import * as v from 'valibot'",
|
|
16
19
|
'',
|
|
17
|
-
...
|
|
20
|
+
...baseSchemas.map((schema) => valibotCode(schema, comment ?? false, type ?? false)),
|
|
21
|
+
...(relations
|
|
22
|
+
? relationSchemas.map((schema) => relationValibotCode(schema, type ?? false))
|
|
23
|
+
: []),
|
|
18
24
|
].join('\n');
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const mkdirResult = await mkdir(path.dirname(output));
|
|
26
|
+
if (!mkdirResult.ok) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: mkdirResult.error,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const fmtResult = await fmt(valibotGeneratedCode);
|
|
33
|
+
if (!fmtResult.ok) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
error: fmtResult.error,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const writeFileResult = await writeFile(output, fmtResult.value);
|
|
40
|
+
if (!writeFileResult.ok) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: writeFileResult.error,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
value: undefined,
|
|
49
|
+
};
|
|
22
50
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TableInfo, ColumnInfo } from '../../shared/utils/types.js';
|
|
2
|
+
export declare const generateZodSchema: (table: TableInfo) => string;
|
|
3
|
+
export declare const generateZodProperty: (column: ColumnInfo) => string;
|
|
4
|
+
export declare const generateDefaultZodSchema: (column: ColumnInfo) => string;
|
|
5
|
+
export declare const generateZodFile: (tables: TableInfo[]) => string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// 完全純粋なZodスキーマ生成ユーティリティ - 外部import禁止
|
|
2
|
+
import { toPascalCase } from '../../shared/utils/string-utils.js';
|
|
3
|
+
export const generateZodSchema = (table) => {
|
|
4
|
+
const schemaName = `${toPascalCase(table.name)}Schema`;
|
|
5
|
+
const typeName = toPascalCase(table.name);
|
|
6
|
+
const properties = table.columns.map(column => generateZodProperty(column)).join('\n ');
|
|
7
|
+
return `export const ${schemaName} = z.object({
|
|
8
|
+
${properties}
|
|
9
|
+
})
|
|
10
|
+
export type ${typeName} = z.infer<typeof ${schemaName}>`;
|
|
11
|
+
};
|
|
12
|
+
export const generateZodProperty = (column) => {
|
|
13
|
+
const comment = column.comment ? `/** ${column.comment} */\n ` : '';
|
|
14
|
+
const schema = column.zodSchema || generateDefaultZodSchema(column);
|
|
15
|
+
return `${comment}${column.name}: ${schema},`;
|
|
16
|
+
};
|
|
17
|
+
export const generateDefaultZodSchema = (column) => {
|
|
18
|
+
if (column.type === 'varchar') {
|
|
19
|
+
if (column.length === 36) {
|
|
20
|
+
return 'z.uuid()';
|
|
21
|
+
}
|
|
22
|
+
if (column.length) {
|
|
23
|
+
return `z.string().max(${column.length})`;
|
|
24
|
+
}
|
|
25
|
+
return 'z.string()';
|
|
26
|
+
}
|
|
27
|
+
if (column.type === 'int') {
|
|
28
|
+
return 'z.number().int()';
|
|
29
|
+
}
|
|
30
|
+
if (column.type === 'text') {
|
|
31
|
+
return 'z.string()';
|
|
32
|
+
}
|
|
33
|
+
return 'z.unknown()';
|
|
34
|
+
};
|
|
35
|
+
export const generateZodFile = (tables) => {
|
|
36
|
+
const imports = 'import * as z from \'zod\'\n\n';
|
|
37
|
+
const schemas = tables.map(table => generateZodSchema(table)).join('\n\n');
|
|
38
|
+
return imports + schemas;
|
|
39
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { capitalize } from '../../../shared/utils/capitalize.js';
|
|
2
1
|
/**
|
|
3
2
|
* @param name
|
|
4
3
|
* @returns
|
|
5
4
|
*/
|
|
6
5
|
export function infer(name) {
|
|
7
|
-
|
|
6
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
7
|
+
return `export type ${capitalizedName} = z.infer<typeof ${capitalizedName}Schema>`;
|
|
8
8
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates Zod relation schema code from a relation schema AST extraction.
|
|
3
|
+
*/
|
|
4
|
+
export declare function relationZodCode(schema: {
|
|
5
|
+
name: string;
|
|
6
|
+
baseName: string;
|
|
7
|
+
fields: {
|
|
8
|
+
name: string;
|
|
9
|
+
definition: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}[];
|
|
12
|
+
objectType?: 'strict' | 'loose';
|
|
13
|
+
}, withType: boolean): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { capitalize, infer } from '../../../utils/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates Zod relation schema code from a relation schema AST extraction.
|
|
4
|
+
*/
|
|
5
|
+
export function relationZodCode(schema, withType) {
|
|
6
|
+
const base = schema.baseName;
|
|
7
|
+
const relName = `${schema.name}Schema`;
|
|
8
|
+
const baseSchema = `${capitalize(base)}Schema`;
|
|
9
|
+
const fields = schema.fields.map((f) => `${f.name}:${f.definition}`).join(',');
|
|
10
|
+
const objectType = schema.objectType === 'strict'
|
|
11
|
+
? 'strictObject'
|
|
12
|
+
: schema.objectType === 'loose'
|
|
13
|
+
? 'looseObject'
|
|
14
|
+
: 'object';
|
|
15
|
+
const obj = `\nexport const ${capitalize(relName)} = z.${objectType}({...${baseSchema}.shape,${fields}})`;
|
|
16
|
+
if (withType)
|
|
17
|
+
return `${obj}\n\n${infer(schema.name)}\n`;
|
|
18
|
+
return `${obj}`;
|
|
19
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Schema } from '../../../shared/types.js';
|
|
2
1
|
/**
|
|
3
2
|
* Generates Zod code for a given schema and config.
|
|
4
3
|
*
|
|
@@ -7,4 +6,12 @@ import type { Schema } from '../../../shared/types.js';
|
|
|
7
6
|
* @param config - The configuration for the code generation.
|
|
8
7
|
* @returns The generated Zod code.
|
|
9
8
|
*/
|
|
10
|
-
export declare function zodCode(schema:
|
|
9
|
+
export declare function zodCode(schema: {
|
|
10
|
+
name: string;
|
|
11
|
+
fields: {
|
|
12
|
+
name: string;
|
|
13
|
+
definition: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
}[];
|
|
16
|
+
objectType?: 'strict' | 'loose';
|
|
17
|
+
}, comment: boolean, type: boolean): string;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Schema } from '../../../shared/types.js';
|
|
2
1
|
/**
|
|
3
2
|
* Generates a Zod schema for a given schema and config.
|
|
4
3
|
*
|
|
@@ -6,4 +5,12 @@ import type { Schema } from '../../../shared/types.js';
|
|
|
6
5
|
* @param config - The configuration for the code generation.
|
|
7
6
|
* @returns The generated Zod schema.
|
|
8
7
|
*/
|
|
9
|
-
export declare function zod(schema:
|
|
8
|
+
export declare function zod(schema: {
|
|
9
|
+
name: string;
|
|
10
|
+
fields: {
|
|
11
|
+
name: string;
|
|
12
|
+
definition: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}[];
|
|
15
|
+
objectType?: 'strict' | 'loose';
|
|
16
|
+
}, comment: boolean): string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { fieldDefinitions } from '../../../
|
|
2
|
-
import { capitalize } from '../../../shared/utils/capitalize.js';
|
|
1
|
+
import { capitalize, fieldDefinitions } from '../../../utils/index.js';
|
|
3
2
|
/**
|
|
4
3
|
* Generates a Zod schema for a given schema and config.
|
|
5
4
|
*
|
|
@@ -8,5 +7,10 @@ import { capitalize } from '../../../shared/utils/capitalize.js';
|
|
|
8
7
|
* @returns The generated Zod schema.
|
|
9
8
|
*/
|
|
10
9
|
export function zod(schema, comment) {
|
|
11
|
-
|
|
10
|
+
const objectType = schema.objectType === 'strict'
|
|
11
|
+
? 'strictObject'
|
|
12
|
+
: schema.objectType === 'loose'
|
|
13
|
+
? 'looseObject'
|
|
14
|
+
: 'object';
|
|
15
|
+
return `export const ${capitalize(schema.name)}Schema = z.${objectType}({${fieldDefinitions(schema, comment)}})`;
|
|
12
16
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Result, err, ok } from 'neverthrow';
|
|
2
|
+
import { generateZodFile } from './core.js';
|
|
3
|
+
export const generateZodSchemas = (schema) => {
|
|
4
|
+
try {
|
|
5
|
+
if (schema.tables.length === 0) {
|
|
6
|
+
return err(new Error('No tables found in schema'));
|
|
7
|
+
}
|
|
8
|
+
const zodContent = generateZodFile(schema.tables);
|
|
9
|
+
return ok(zodContent);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return err(new Error(`Failed to generate Zod schemas: ${error instanceof Error ? error.message : String(error)}`));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Result } from 'neverthrow';
|
|
2
1
|
/**
|
|
3
2
|
* Generate Zod schema
|
|
4
3
|
* @param code - The code to generate Zod schema from
|
|
@@ -7,4 +6,10 @@ import type { Result } from 'neverthrow';
|
|
|
7
6
|
* @param type - Whether to include type information in the generated code
|
|
8
7
|
* @param zod - The Zod version to use
|
|
9
8
|
*/
|
|
10
|
-
export declare function sizukuZod(code: string[], output: `${string}.ts`, comment?: boolean, type?: boolean, zod?: 'v4' | '
|
|
9
|
+
export declare function sizukuZod(code: string[], output: `${string}.ts`, comment?: boolean, type?: boolean, zod?: 'v4' | 'mini' | '@hono/zod-openapi', relations?: boolean): Promise<{
|
|
10
|
+
ok: true;
|
|
11
|
+
value: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
ok: false;
|
|
14
|
+
error: string;
|
|
15
|
+
}>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { extractSchemas } from './core/extract-schema.js';
|
|
3
|
-
import { zodCode } from './generator/zod-code.js';
|
|
4
|
-
import { mkdir, writeFile } from '../../shared/fsp/index.js';
|
|
5
2
|
import { fmt } from '../../shared/format/index.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import { mkdir, writeFile } from '../../shared/fsp/index.js';
|
|
4
|
+
import { extractRelationSchemas, extractSchemas } from '../../shared/helper/extract-schemas.js';
|
|
5
|
+
import { relationZodCode } from './generator/relation-zod-code.js';
|
|
6
|
+
import { zodCode } from './generator/zod-code.js';
|
|
9
7
|
/**
|
|
10
8
|
* Generate Zod schema
|
|
11
9
|
* @param code - The code to generate Zod schema from
|
|
@@ -14,17 +12,43 @@ const ZOD_OPENAPI_HONO_IMPORT = `import { z } from '@hono/zod-openapi'`;
|
|
|
14
12
|
* @param type - Whether to include type information in the generated code
|
|
15
13
|
* @param zod - The Zod version to use
|
|
16
14
|
*/
|
|
17
|
-
export async function sizukuZod(code, output, comment, type, zod) {
|
|
15
|
+
export async function sizukuZod(code, output, comment, type, zod, relations) {
|
|
16
|
+
const importLine = zod === 'mini'
|
|
17
|
+
? `import * as z from 'zod/mini'`
|
|
18
|
+
: zod === '@hono/zod-openapi'
|
|
19
|
+
? `import { z } from '@hono/zod-openapi'`
|
|
20
|
+
: `import * as z from 'zod'`;
|
|
21
|
+
const baseSchemas = extractSchemas(code, 'zod');
|
|
22
|
+
const relationSchemas = extractRelationSchemas(code, 'zod');
|
|
18
23
|
const zodGeneratedCode = [
|
|
19
|
-
|
|
20
|
-
? ZODV4_MINI_IMPORT
|
|
21
|
-
: zod === '@hono/zod-openapi'
|
|
22
|
-
? ZOD_OPENAPI_HONO_IMPORT
|
|
23
|
-
: ZODV4_IMPORT,
|
|
24
|
+
importLine,
|
|
24
25
|
'',
|
|
25
|
-
...
|
|
26
|
+
...baseSchemas.map((schema) => zodCode(schema, comment ?? false, type ?? false)),
|
|
27
|
+
...(relations ? relationSchemas.map((schema) => relationZodCode(schema, type ?? false)) : []),
|
|
26
28
|
].join('\n');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const mkdirResult = await mkdir(path.dirname(output));
|
|
30
|
+
if (!mkdirResult.ok) {
|
|
31
|
+
return {
|
|
32
|
+
ok: false,
|
|
33
|
+
error: mkdirResult.error,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const fmtResult = await fmt(zodGeneratedCode);
|
|
37
|
+
if (!fmtResult.ok) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
error: fmtResult.error,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const writeFileResult = await writeFile(output, fmtResult.value);
|
|
44
|
+
if (!writeFileResult.ok) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: writeFileResult.error,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
value: undefined,
|
|
53
|
+
};
|
|
30
54
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { Config } from './config/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
export declare function main(config?: Config): Promise<{
|
|
3
|
+
ok: true;
|
|
4
|
+
value: string;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: string;
|
|
8
|
+
}>;
|
package/dist/index.js
CHANGED
|
@@ -1,54 +1,71 @@
|
|
|
1
|
+
// #!/usr/bin/env node
|
|
1
2
|
import { getConfig } from './config/index.js';
|
|
2
|
-
import { sizukuZod } from './generator/zod/index.js';
|
|
3
|
-
import { sizukuValibot } from './generator/valibot/index.js';
|
|
4
3
|
import { sizukuMermaidER } from './generator/mermaid-er/index.js';
|
|
4
|
+
import { sizukuValibot } from './generator/valibot/index.js';
|
|
5
|
+
import { sizukuZod } from './generator/zod/index.js';
|
|
5
6
|
import { readFileSync } from './shared/fs/index.js';
|
|
6
|
-
import { ok, err, ResultAsync } from 'neverthrow';
|
|
7
7
|
export async function main(config = getConfig()) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
8
|
+
if (!config.input) {
|
|
9
|
+
return {
|
|
10
|
+
ok: false,
|
|
11
|
+
error: 'input is not found',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const contentResult = readFileSync(config.input);
|
|
15
|
+
if (!contentResult.ok) {
|
|
16
|
+
return {
|
|
17
|
+
ok: false,
|
|
18
|
+
error: contentResult.error,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const content = contentResult.value;
|
|
22
|
+
const lines = content.split('\n');
|
|
23
|
+
const codeStart = lines.findIndex((line) => !line.trim().startsWith('import') && line.trim() !== '');
|
|
24
|
+
const code = lines.slice(codeStart);
|
|
25
|
+
const results = [];
|
|
26
|
+
/* zod */
|
|
27
|
+
if (config.zod?.output) {
|
|
28
|
+
const zodResult = await sizukuZod(code, config.zod.output, config.zod.comment, config.zod.type, config.zod.zod, true);
|
|
29
|
+
if (!zodResult.ok) {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
error: zodResult.error,
|
|
33
|
+
};
|
|
28
34
|
}
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
results.push(`Generated Zod schema at: ${config.zod?.output}`);
|
|
36
|
+
}
|
|
37
|
+
/* valibot */
|
|
38
|
+
if (config.valibot?.output) {
|
|
39
|
+
const valibotResult = await sizukuValibot(code, config.valibot.output, config.valibot.comment, config.valibot.type, true);
|
|
40
|
+
if (!valibotResult.ok) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: valibotResult.error,
|
|
44
|
+
};
|
|
37
45
|
}
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
results.push(`Generated Valibot schema at: ${config.valibot?.output}`);
|
|
47
|
+
}
|
|
48
|
+
/* mermaid */
|
|
49
|
+
if (config.mermaid?.output) {
|
|
50
|
+
const mermaidResult = await sizukuMermaidER(code, config.mermaid.output);
|
|
51
|
+
if (!mermaidResult.ok) {
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
error: mermaidResult.error,
|
|
55
|
+
};
|
|
45
56
|
}
|
|
46
|
-
|
|
47
|
-
}
|
|
57
|
+
results.push(`Generated Mermaid ER at: ${config.mermaid?.output}`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
value: results.join('\n'),
|
|
62
|
+
};
|
|
48
63
|
}
|
|
49
64
|
main().then((result) => {
|
|
50
|
-
if (
|
|
51
|
-
console.
|
|
52
|
-
|
|
65
|
+
if (result?.ok) {
|
|
66
|
+
console.log(result.value);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.error(result?.error);
|
|
53
70
|
}
|
|
54
71
|
});
|