sizuku 0.3.2 → 0.4.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 +103 -0
- package/dist/config/index.d.mts +58 -0
- package/dist/config/index.mjs +95 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +1615 -0
- package/package.json +31 -17
- package/dist/cli/main.d.ts +0 -10
- package/dist/cli/main.js +0 -61
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -51
- package/dist/config/index.d.ts +0 -27
- package/dist/config/index.js +0 -85
- package/dist/config/loader.d.ts +0 -19
- package/dist/config/loader.js +0 -30
- package/dist/generator/engine.d.ts +0 -3
- package/dist/generator/engine.js +0 -63
- package/dist/generator/mermaid-er/config/index.d.ts +0 -10
- package/dist/generator/mermaid-er/config/index.js +0 -12
- package/dist/generator/mermaid-er/core/extract-relations.d.ts +0 -8
- package/dist/generator/mermaid-er/core/extract-relations.js +0 -17
- package/dist/generator/mermaid-er/core.d.ts +0 -6
- package/dist/generator/mermaid-er/core.js +0 -54
- package/dist/generator/mermaid-er/generator/er-content.d.ts +0 -20
- package/dist/generator/mermaid-er/generator/er-content.js +0 -23
- package/dist/generator/mermaid-er/generator/index.d.ts +0 -2
- package/dist/generator/mermaid-er/generator/index.js +0 -2
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +0 -12
- package/dist/generator/mermaid-er/generator/relation-line.js +0 -13
- package/dist/generator/mermaid-er/generator.d.ts +0 -3
- package/dist/generator/mermaid-er/generator.js +0 -14
- package/dist/generator/mermaid-er/index.d.ts +0 -12
- package/dist/generator/mermaid-er/index.js +0 -33
- package/dist/generator/mermaid-er/relationship/build-relation-line.d.ts +0 -14
- package/dist/generator/mermaid-er/relationship/build-relation-line.js +0 -34
- package/dist/generator/mermaid-er/types.d.ts +0 -21
- package/dist/generator/mermaid-er/types.js +0 -1
- package/dist/generator/mermaid-er/validator/index.d.ts +0 -8
- package/dist/generator/mermaid-er/validator/index.js +0 -74
- package/dist/generator/mermaid-er/validator/is-relationship.d.ts +0 -7
- package/dist/generator/mermaid-er/validator/is-relationship.js +0 -8
- package/dist/generator/mermaid-er/validator/parse-relation-line.d.ts +0 -12
- package/dist/generator/mermaid-er/validator/parse-relation-line.js +0 -20
- package/dist/generator/mermaid-er/validator/parse-table-info.d.ts +0 -2
- package/dist/generator/mermaid-er/validator/parse-table-info.js +0 -71
- package/dist/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +0 -7
- package/dist/generator/mermaid-er/validator/remove-duplicate-relations.js +0 -9
- package/dist/generator/valibot/config/index.d.ts +0 -7
- package/dist/generator/valibot/config/index.js +0 -13
- package/dist/generator/valibot/core/extract-schema.d.ts +0 -5
- package/dist/generator/valibot/core/extract-schema.js +0 -173
- package/dist/generator/valibot/core.d.ts +0 -5
- package/dist/generator/valibot/core.js +0 -39
- package/dist/generator/valibot/generator/infer-input.d.ts +0 -5
- package/dist/generator/valibot/generator/infer-input.js +0 -8
- package/dist/generator/valibot/generator/relation-valibot-code.d.ts +0 -13
- package/dist/generator/valibot/generator/relation-valibot-code.js +0 -19
- package/dist/generator/valibot/generator/valibot-code.d.ts +0 -15
- package/dist/generator/valibot/generator/valibot-code.js +0 -16
- package/dist/generator/valibot/generator/valibot.d.ts +0 -14
- package/dist/generator/valibot/generator/valibot.js +0 -15
- package/dist/generator/valibot/generator.d.ts +0 -3
- package/dist/generator/valibot/generator.js +0 -14
- package/dist/generator/valibot/index.d.ts +0 -14
- package/dist/generator/valibot/index.js +0 -50
- package/dist/generator/zod/config/index.d.ts +0 -8
- package/dist/generator/zod/config/index.js +0 -14
- package/dist/generator/zod/core/extract-schema.d.ts +0 -7
- package/dist/generator/zod/core/extract-schema.js +0 -243
- package/dist/generator/zod/core.d.ts +0 -5
- package/dist/generator/zod/core.js +0 -39
- package/dist/generator/zod/generator/infer.d.ts +0 -5
- package/dist/generator/zod/generator/infer.js +0 -8
- package/dist/generator/zod/generator/relation-zod-code.d.ts +0 -13
- package/dist/generator/zod/generator/relation-zod-code.js +0 -19
- package/dist/generator/zod/generator/zod-code.d.ts +0 -17
- package/dist/generator/zod/generator/zod-code.js +0 -18
- package/dist/generator/zod/generator/zod.d.ts +0 -16
- package/dist/generator/zod/generator/zod.js +0 -16
- package/dist/generator/zod/generator.d.ts +0 -3
- package/dist/generator/zod/generator.js +0 -14
- package/dist/generator/zod/index.d.ts +0 -15
- package/dist/generator/zod/index.js +0 -54
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -73
- package/dist/shared/config/index.d.ts +0 -13
- package/dist/shared/config/index.js +0 -10
- package/dist/shared/format/index.d.ts +0 -13
- package/dist/shared/format/index.js +0 -24
- package/dist/shared/fs/index.d.ts +0 -7
- package/dist/shared/fs/index.js +0 -16
- package/dist/shared/fsp/index.d.ts +0 -27
- package/dist/shared/fsp/index.js +0 -38
- package/dist/shared/generator/field-definitions.d.ts +0 -12
- package/dist/shared/generator/field-definitions.js +0 -12
- package/dist/shared/helper/ast-parser.d.ts +0 -3
- package/dist/shared/helper/ast-parser.js +0 -202
- package/dist/shared/helper/build-schema-extractor.d.ts +0 -25
- package/dist/shared/helper/build-schema-extractor.js +0 -33
- package/dist/shared/helper/create-extract-field-from-property.d.ts +0 -15
- package/dist/shared/helper/create-extract-field-from-property.js +0 -20
- package/dist/shared/helper/create-extract-fields-from-call-expression.d.ts +0 -14
- package/dist/shared/helper/create-extract-fields-from-call-expression.js +0 -14
- package/dist/shared/helper/create-extract-relation-field-from-property.d.ts +0 -12
- package/dist/shared/helper/create-extract-relation-field-from-property.js +0 -27
- package/dist/shared/helper/extract-schemas.d.ts +0 -133
- package/dist/shared/helper/extract-schemas.js +0 -445
- package/dist/shared/helper/file-writer.d.ts +0 -3
- package/dist/shared/helper/file-writer.js +0 -25
- package/dist/shared/helper/find-object-literal-expression.d.ts +0 -12
- package/dist/shared/helper/find-object-literal-expression.js +0 -31
- package/dist/shared/helper/find-object-literalIn-args.d.ts +0 -2
- package/dist/shared/helper/find-object-literalIn-args.js +0 -8
- package/dist/shared/helper/is-relation-function.d.ts +0 -10
- package/dist/shared/helper/is-relation-function.js +0 -16
- package/dist/shared/types.d.ts +0 -9
- package/dist/shared/types.js +0 -1
- package/dist/shared/utils/capitalize.d.ts +0 -18
- package/dist/shared/utils/capitalize.js +0 -20
- package/dist/shared/utils/compose.d.ts +0 -101
- package/dist/shared/utils/compose.js +0 -124
- package/dist/shared/utils/file.d.ts +0 -92
- package/dist/shared/utils/file.js +0 -177
- package/dist/shared/utils/functional.d.ts +0 -118
- package/dist/shared/utils/functional.js +0 -96
- package/dist/shared/utils/index.d.ts +0 -20
- package/dist/shared/utils/index.js +0 -48
- package/dist/shared/utils/string-utils.d.ts +0 -8
- package/dist/shared/utils/string-utils.js +0 -28
- package/dist/shared/utils/types.d.ts +0 -32
- package/dist/shared/utils/types.js +0 -2
- package/dist/shared/utils/validation-utils.d.ts +0 -8
- package/dist/shared/utils/validation-utils.js +0 -25
- package/dist/src/config/index.d.ts +0 -18
- package/dist/src/config/index.js +0 -13
- package/dist/src/generator/mermaid-er/core/extract-relations.d.ts +0 -8
- package/dist/src/generator/mermaid-er/core/extract-relations.js +0 -12
- package/dist/src/generator/mermaid-er/generator/er-content.d.ts +0 -9
- package/dist/src/generator/mermaid-er/generator/er-content.js +0 -25
- package/dist/src/generator/mermaid-er/generator/index.d.ts +0 -2
- package/dist/src/generator/mermaid-er/generator/index.js +0 -2
- package/dist/src/generator/mermaid-er/generator/relation-line.d.ts +0 -8
- package/dist/src/generator/mermaid-er/generator/relation-line.js +0 -14
- package/dist/src/generator/mermaid-er/index.d.ts +0 -6
- package/dist/src/generator/mermaid-er/index.js +0 -16
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.d.ts +0 -15
- package/dist/src/generator/mermaid-er/relationship/build-relation-line.js +0 -35
- package/dist/src/generator/mermaid-er/types.d.ts +0 -21
- package/dist/src/generator/mermaid-er/types.js +0 -1
- package/dist/src/generator/mermaid-er/validator/index.d.ts +0 -4
- package/dist/src/generator/mermaid-er/validator/index.js +0 -4
- package/dist/src/generator/mermaid-er/validator/is-relationship.d.ts +0 -8
- package/dist/src/generator/mermaid-er/validator/is-relationship.js +0 -9
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.d.ts +0 -13
- package/dist/src/generator/mermaid-er/validator/parse-relation-line.js +0 -21
- package/dist/src/generator/mermaid-er/validator/parse-table-info.d.ts +0 -8
- package/dist/src/generator/mermaid-er/validator/parse-table-info.js +0 -91
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.d.ts +0 -7
- package/dist/src/generator/mermaid-er/validator/remove-duplicate-relations.js +0 -9
- package/dist/src/generator/valibot/generator/infer-input.d.ts +0 -5
- package/dist/src/generator/valibot/generator/infer-input.js +0 -8
- package/dist/src/generator/valibot/generator/valibot-code.d.ts +0 -14
- package/dist/src/generator/valibot/generator/valibot-code.js +0 -16
- package/dist/src/generator/valibot/generator/valibot.d.ts +0 -13
- package/dist/src/generator/valibot/generator/valibot.js +0 -11
- package/dist/src/generator/valibot/index.d.ts +0 -9
- package/dist/src/generator/valibot/index.js +0 -34
- package/dist/src/generator/zod/generator/infer.d.ts +0 -5
- package/dist/src/generator/zod/generator/infer.js +0 -8
- package/dist/src/generator/zod/generator/zod-code.d.ts +0 -16
- package/dist/src/generator/zod/generator/zod-code.js +0 -18
- package/dist/src/generator/zod/generator/zod.d.ts +0 -15
- package/dist/src/generator/zod/generator/zod.js +0 -12
- package/dist/src/generator/zod/index.d.ts +0 -10
- package/dist/src/generator/zod/index.js +0 -40
- package/dist/src/index.d.ts +0 -10
- package/dist/src/index.js +0 -35
- package/dist/src/shared/format/index.d.ts +0 -2
- package/dist/src/shared/format/index.js +0 -10
- package/dist/src/shared/fs/index.d.ts +0 -2
- package/dist/src/shared/fs/index.js +0 -10
- package/dist/src/shared/fsp/index.d.ts +0 -3
- package/dist/src/shared/fsp/index.js +0 -8
- package/dist/src/shared/generator/field-definitions.d.ts +0 -12
- package/dist/src/shared/generator/field-definitions.js +0 -12
- package/dist/src/shared/helper/build-schema-extractor.d.ts +0 -25
- package/dist/src/shared/helper/build-schema-extractor.js +0 -33
- package/dist/src/shared/helper/create-extract-field-from-property.d.ts +0 -15
- package/dist/src/shared/helper/create-extract-field-from-property.js +0 -20
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.d.ts +0 -14
- package/dist/src/shared/helper/create-extract-fields-from-call-expression.js +0 -14
- package/dist/src/shared/helper/create-extract-relation-field-from-property.d.ts +0 -12
- package/dist/src/shared/helper/create-extract-relation-field-from-property.js +0 -27
- package/dist/src/shared/helper/extract-schemas.d.ts +0 -16
- package/dist/src/shared/helper/extract-schemas.js +0 -19
- package/dist/src/shared/helper/find-object-literal-expression.d.ts +0 -12
- package/dist/src/shared/helper/find-object-literal-expression.js +0 -31
- package/dist/src/shared/helper/find-object-literalIn-args.d.ts +0 -2
- package/dist/src/shared/helper/find-object-literalIn-args.js +0 -8
- package/dist/src/shared/helper/is-relation-function.d.ts +0 -10
- package/dist/src/shared/helper/is-relation-function.js +0 -16
- package/dist/src/shared/utils/index.d.ts +0 -33
- package/dist/src/shared/utils/index.js +0 -61
- package/dist/utils/index.d.ts +0 -144
- package/dist/utils/index.js +0 -250
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Result, err, ok } from 'neverthrow';
|
|
2
|
-
import { generateMermaidER } from './core.js';
|
|
3
|
-
export const generateMermaidERDiagram = (schema) => {
|
|
4
|
-
try {
|
|
5
|
-
if (schema.tables.length === 0) {
|
|
6
|
-
return err(new Error('No tables found in schema'));
|
|
7
|
-
}
|
|
8
|
-
const mermaidContent = generateMermaidER(schema.tables);
|
|
9
|
-
return ok(mermaidContent);
|
|
10
|
-
}
|
|
11
|
-
catch (error) {
|
|
12
|
-
return err(new Error(`Failed to generate Mermaid ER diagram: ${error instanceof Error ? error.message : String(error)}`));
|
|
13
|
-
}
|
|
14
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate Mermaid ER diagram
|
|
3
|
-
* @param code - The code to generate Mermaid ER diagram from
|
|
4
|
-
* @param output - The output file path
|
|
5
|
-
*/
|
|
6
|
-
export declare function sizukuMermaidER(code: string[], output: string): Promise<{
|
|
7
|
-
ok: true;
|
|
8
|
-
value: undefined;
|
|
9
|
-
} | {
|
|
10
|
-
ok: false;
|
|
11
|
-
error: string;
|
|
12
|
-
}>;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir, writeFile } from '../../shared/fsp/index.js';
|
|
3
|
-
import { extractRelations } from '../../shared/helper/extract-schemas.js';
|
|
4
|
-
import { erContent } from './generator/index.js';
|
|
5
|
-
import { parseTableInfo } from './validator/index.js';
|
|
6
|
-
/**
|
|
7
|
-
* Generate Mermaid ER diagram
|
|
8
|
-
* @param code - The code to generate Mermaid ER diagram from
|
|
9
|
-
* @param output - The output file path
|
|
10
|
-
*/
|
|
11
|
-
export async function sizukuMermaidER(code, output) {
|
|
12
|
-
const tables = parseTableInfo(code);
|
|
13
|
-
const relations = extractRelations(code);
|
|
14
|
-
const ERContent = erContent(relations, tables);
|
|
15
|
-
const mkdirResult = await mkdir(path.dirname(output));
|
|
16
|
-
if (!mkdirResult.ok) {
|
|
17
|
-
return {
|
|
18
|
-
ok: false,
|
|
19
|
-
error: mkdirResult.error,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const writeFileResult = await writeFile(output, ERContent);
|
|
23
|
-
if (!writeFileResult.ok) {
|
|
24
|
-
return {
|
|
25
|
-
ok: false,
|
|
26
|
-
error: writeFileResult.error,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
ok: true,
|
|
31
|
-
value: undefined,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
declare const RELATIONSHIPS: {
|
|
2
|
-
readonly 'zero-one': "|o";
|
|
3
|
-
readonly one: "||";
|
|
4
|
-
readonly 'zero-many': "}o";
|
|
5
|
-
readonly many: "}|";
|
|
6
|
-
};
|
|
7
|
-
export type Relationship = keyof typeof RELATIONSHIPS;
|
|
8
|
-
/**
|
|
9
|
-
* Builds a relationship line for mermaid from a string.
|
|
10
|
-
* @param { string } input
|
|
11
|
-
* @returns { string }
|
|
12
|
-
*/
|
|
13
|
-
export declare function buildRelationLine(input: string): string;
|
|
14
|
-
export {};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { isRelationship } from '../validator/is-relationship.js';
|
|
2
|
-
const RELATIONSHIPS = {
|
|
3
|
-
'zero-one': '|o',
|
|
4
|
-
one: '||',
|
|
5
|
-
'zero-many': '}o',
|
|
6
|
-
many: '}|',
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Builds a relationship line for mermaid from a string.
|
|
10
|
-
* @param { string } input
|
|
11
|
-
* @returns { string }
|
|
12
|
-
*/
|
|
13
|
-
export function buildRelationLine(input) {
|
|
14
|
-
const parts = input.split('-to-');
|
|
15
|
-
if (parts.length !== 2) {
|
|
16
|
-
throw new Error(`Invalid input format: ${input}`);
|
|
17
|
-
}
|
|
18
|
-
const [toRaw, optionalFlag] = parts[1].includes('-optional')
|
|
19
|
-
? [parts[1].replace('-optional', ''), 'optional']
|
|
20
|
-
: [parts[1], ''];
|
|
21
|
-
const from = parts[0];
|
|
22
|
-
const to = toRaw;
|
|
23
|
-
const isOptional = optionalFlag === 'optional';
|
|
24
|
-
if (!(isRelationship(from) && isRelationship(to))) {
|
|
25
|
-
throw new Error(`Invalid relationship string: ${input}`);
|
|
26
|
-
}
|
|
27
|
-
const fromSymbol = RELATIONSHIPS[from];
|
|
28
|
-
const toSymbol = RELATIONSHIPS[to];
|
|
29
|
-
if (!(fromSymbol && toSymbol)) {
|
|
30
|
-
throw new Error(`Invalid relationship string: ${input}`);
|
|
31
|
-
}
|
|
32
|
-
const connector = isOptional ? '..' : '--';
|
|
33
|
-
return `${fromSymbol}${connector}${toSymbol}`;
|
|
34
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export type Relation = {
|
|
2
|
-
fromModel: string;
|
|
3
|
-
toModel: string;
|
|
4
|
-
fromField: string;
|
|
5
|
-
toField: string;
|
|
6
|
-
type: string;
|
|
7
|
-
};
|
|
8
|
-
export type ERContent = readonly string[];
|
|
9
|
-
export type TableInfo = {
|
|
10
|
-
name: string;
|
|
11
|
-
fields: {
|
|
12
|
-
type: string;
|
|
13
|
-
name: string;
|
|
14
|
-
description: string | null;
|
|
15
|
-
}[];
|
|
16
|
-
};
|
|
17
|
-
export type AccumulatorType = {
|
|
18
|
-
tables: TableInfo[];
|
|
19
|
-
currentTable: TableInfo | null;
|
|
20
|
-
currentDescription: string;
|
|
21
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Node, Project } from 'ts-morph';
|
|
2
|
-
const baseBuilderName = (expr) => {
|
|
3
|
-
if (Node.isIdentifier(expr))
|
|
4
|
-
return expr.getText();
|
|
5
|
-
if (Node.isCallExpression(expr) || Node.isPropertyAccessExpression(expr))
|
|
6
|
-
return baseBuilderName(expr.getExpression());
|
|
7
|
-
return '';
|
|
8
|
-
};
|
|
9
|
-
const isFieldInfo = (v) => v !== null;
|
|
10
|
-
export function parseTableInfo(code) {
|
|
11
|
-
const source = code.join('\n');
|
|
12
|
-
const file = new Project({ useInMemoryFileSystem: true }).createSourceFile('temp.ts', source);
|
|
13
|
-
return file
|
|
14
|
-
.getVariableStatements()
|
|
15
|
-
.filter((stmt) => stmt.isExported())
|
|
16
|
-
.flatMap((stmt) => {
|
|
17
|
-
const decl = stmt.getDeclarations()[0];
|
|
18
|
-
if (!Node.isVariableDeclaration(decl))
|
|
19
|
-
return [];
|
|
20
|
-
const varName = decl.getName();
|
|
21
|
-
if (varName.toLowerCase().includes('relation'))
|
|
22
|
-
return [];
|
|
23
|
-
const init = decl.getInitializer();
|
|
24
|
-
if (!(init && Node.isCallExpression(init)))
|
|
25
|
-
return [];
|
|
26
|
-
const callee = init.getExpression().getText();
|
|
27
|
-
if (!callee.endsWith('Table') || callee === 'relations')
|
|
28
|
-
return [];
|
|
29
|
-
const objLit = init.getArguments()[1];
|
|
30
|
-
if (!(objLit && Node.isObjectLiteralExpression(objLit)))
|
|
31
|
-
return [];
|
|
32
|
-
const fields = objLit
|
|
33
|
-
.getProperties()
|
|
34
|
-
.filter(Node.isPropertyAssignment)
|
|
35
|
-
.map((prop) => {
|
|
36
|
-
const keyNode = prop.getNameNode();
|
|
37
|
-
if (!Node.isIdentifier(keyNode))
|
|
38
|
-
return null;
|
|
39
|
-
const fieldName = keyNode.getText();
|
|
40
|
-
const initExpr = prop.getInitializer();
|
|
41
|
-
if (!(initExpr && Node.isCallExpression(initExpr)))
|
|
42
|
-
return null;
|
|
43
|
-
const fieldType = baseBuilderName(initExpr);
|
|
44
|
-
const initText = initExpr.getText();
|
|
45
|
-
const lineIdx = prop.getStartLineNumber() - 1;
|
|
46
|
-
// Find the immediate comment above this field
|
|
47
|
-
const immediateComment = code
|
|
48
|
-
.slice(0, lineIdx)
|
|
49
|
-
.reverse()
|
|
50
|
-
.find((line) => {
|
|
51
|
-
const t = line.trim();
|
|
52
|
-
return (t.startsWith('///') &&
|
|
53
|
-
!t.includes('@z.') &&
|
|
54
|
-
!t.includes('@v.') &&
|
|
55
|
-
!t.includes('@relation'));
|
|
56
|
-
})
|
|
57
|
-
?.replace(/^\s*\/\/\/\s*/, '') ?? '';
|
|
58
|
-
const prefix = initText.includes('.primaryKey()')
|
|
59
|
-
? '(PK) '
|
|
60
|
-
: initText.includes('.references(')
|
|
61
|
-
? '(FK) '
|
|
62
|
-
: '';
|
|
63
|
-
// Only include description if there's a comment
|
|
64
|
-
const description = immediateComment ? `${prefix}${immediateComment}`.trim() : null;
|
|
65
|
-
return {
|
|
66
|
-
name: fieldName,
|
|
67
|
-
type: fieldType,
|
|
68
|
-
description,
|
|
69
|
-
};
|
|
70
|
-
})
|
|
71
|
-
.filter(isFieldInfo);
|
|
72
|
-
return [{ name: varName, fields }];
|
|
73
|
-
});
|
|
74
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parse a relation line
|
|
3
|
-
* @param line - The line to parse
|
|
4
|
-
* @returns The parsed relation
|
|
5
|
-
*/
|
|
6
|
-
export declare function parseRelationLine(line: string): {
|
|
7
|
-
fromModel: string;
|
|
8
|
-
fromField: string;
|
|
9
|
-
toModel: string;
|
|
10
|
-
toField: string;
|
|
11
|
-
type: string;
|
|
12
|
-
} | null;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parse a relation line
|
|
3
|
-
* @param line - The line to parse
|
|
4
|
-
* @returns The parsed relation
|
|
5
|
-
*/
|
|
6
|
-
export function parseRelationLine(line) {
|
|
7
|
-
// @relation <fromModel>.<fromField> <toModel>.<toField> <relationType>
|
|
8
|
-
const relationMatch = line.match(/@relation\s+(\w+)\.(\w+)\s+(\w+)\.(\w+)\s+(\w+-to-\w+)/);
|
|
9
|
-
if (relationMatch) {
|
|
10
|
-
const [_, fromModel, fromField, toModel, toField, type] = relationMatch;
|
|
11
|
-
return {
|
|
12
|
-
fromModel,
|
|
13
|
-
fromField,
|
|
14
|
-
toModel,
|
|
15
|
-
toField,
|
|
16
|
-
type,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { Node, Project } from 'ts-morph';
|
|
2
|
-
const baseBuilderName = (expr) => {
|
|
3
|
-
if (Node.isIdentifier(expr))
|
|
4
|
-
return expr.getText();
|
|
5
|
-
if (Node.isCallExpression(expr) || Node.isPropertyAccessExpression(expr))
|
|
6
|
-
return baseBuilderName(expr.getExpression());
|
|
7
|
-
return '';
|
|
8
|
-
};
|
|
9
|
-
const isFieldInfo = (v) => v !== null;
|
|
10
|
-
export function parseTableInfo(code) {
|
|
11
|
-
const source = code.join('\n');
|
|
12
|
-
const file = new Project({ useInMemoryFileSystem: true }).createSourceFile('temp.ts', source);
|
|
13
|
-
return file
|
|
14
|
-
.getVariableStatements()
|
|
15
|
-
.filter((stmt) => stmt.isExported())
|
|
16
|
-
.flatMap((stmt) => {
|
|
17
|
-
const decl = stmt.getDeclarations()[0];
|
|
18
|
-
if (!Node.isVariableDeclaration(decl))
|
|
19
|
-
return [];
|
|
20
|
-
const varName = decl.getName();
|
|
21
|
-
if (varName.toLowerCase().includes('relation'))
|
|
22
|
-
return [];
|
|
23
|
-
const init = decl.getInitializer();
|
|
24
|
-
if (!(init && Node.isCallExpression(init)))
|
|
25
|
-
return [];
|
|
26
|
-
const callee = init.getExpression().getText();
|
|
27
|
-
if (!callee.endsWith('Table') || callee === 'relations')
|
|
28
|
-
return [];
|
|
29
|
-
const objLit = init.getArguments()[1];
|
|
30
|
-
if (!(objLit && Node.isObjectLiteralExpression(objLit)))
|
|
31
|
-
return [];
|
|
32
|
-
const fields = objLit
|
|
33
|
-
.getProperties()
|
|
34
|
-
.filter(Node.isPropertyAssignment)
|
|
35
|
-
.map((prop) => {
|
|
36
|
-
const keyNode = prop.getNameNode();
|
|
37
|
-
if (!Node.isIdentifier(keyNode))
|
|
38
|
-
return null;
|
|
39
|
-
const fieldName = keyNode.getText();
|
|
40
|
-
const initExpr = prop.getInitializer();
|
|
41
|
-
if (!(initExpr && Node.isCallExpression(initExpr)))
|
|
42
|
-
return null;
|
|
43
|
-
const fieldType = baseBuilderName(initExpr);
|
|
44
|
-
const initText = initExpr.getText();
|
|
45
|
-
const lineIdx = prop.getStartLineNumber() - 1;
|
|
46
|
-
const baseDesc = code
|
|
47
|
-
.slice(0, lineIdx)
|
|
48
|
-
.reverse()
|
|
49
|
-
.find((line) => {
|
|
50
|
-
const t = line.trim();
|
|
51
|
-
return (t.startsWith('///') &&
|
|
52
|
-
!t.includes('@z.') &&
|
|
53
|
-
!t.includes('@v.') &&
|
|
54
|
-
!t.includes('@relation'));
|
|
55
|
-
})
|
|
56
|
-
?.replace(/^\s*\/\/\/\s*/, '') ?? '';
|
|
57
|
-
const prefix = initText.includes('.primaryKey()')
|
|
58
|
-
? '(PK) '
|
|
59
|
-
: initText.includes('.references(')
|
|
60
|
-
? '(FK) '
|
|
61
|
-
: '';
|
|
62
|
-
return {
|
|
63
|
-
name: fieldName,
|
|
64
|
-
type: fieldType,
|
|
65
|
-
description: `${prefix}${baseDesc}`.trim(),
|
|
66
|
-
};
|
|
67
|
-
})
|
|
68
|
-
.filter(isFieldInfo);
|
|
69
|
-
return [{ name: varName, fields }];
|
|
70
|
-
});
|
|
71
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remove duplicate relations
|
|
3
|
-
* @function removeDuplicateRelations
|
|
4
|
-
* @param relations - The relations to remove duplicates from
|
|
5
|
-
* @returns The relations without duplicates
|
|
6
|
-
*/
|
|
7
|
-
export declare function removeDuplicateRelations(relations: readonly string[]): readonly string[];
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remove duplicate relations
|
|
3
|
-
* @function removeDuplicateRelations
|
|
4
|
-
* @param relations - The relations to remove duplicates from
|
|
5
|
-
* @returns The relations without duplicates
|
|
6
|
-
*/
|
|
7
|
-
export function removeDuplicateRelations(relations) {
|
|
8
|
-
return [...new Set(relations)];
|
|
9
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import { DEFAULT_CONFIG } from '../../../shared/config/index.js';
|
|
3
|
-
/**
|
|
4
|
-
* Loads the configuration from the `sizuku.json` file or returns the default configuration.
|
|
5
|
-
*
|
|
6
|
-
* @returns The configuration object.
|
|
7
|
-
*/
|
|
8
|
-
export function getConfig() {
|
|
9
|
-
const config = fs.existsSync('sizuku-valibot.json')
|
|
10
|
-
? { ...DEFAULT_CONFIG, ...JSON.parse(fs.readFileSync('sizuku-valibot.json', 'utf-8')) }
|
|
11
|
-
: DEFAULT_CONFIG;
|
|
12
|
-
return config;
|
|
13
|
-
}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { Node, Project } from 'ts-morph';
|
|
2
|
-
/**
|
|
3
|
-
* Check if the comment line is metadata (Zod / Valibot / relation helper)
|
|
4
|
-
*/
|
|
5
|
-
const isMetadataComment = (text) => {
|
|
6
|
-
return text.includes('@z.') || text.includes('@v.') || text.includes('@relation.');
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Collect consecutive `///` comment lines that appear immediately above a field.
|
|
10
|
-
*/
|
|
11
|
-
const extractFieldComments = (sourceText, fieldStartPos) => {
|
|
12
|
-
const beforeField = sourceText.substring(0, fieldStartPos);
|
|
13
|
-
const lines = beforeField.split('\n');
|
|
14
|
-
return lines
|
|
15
|
-
.map((line) => line.trim())
|
|
16
|
-
.reverse()
|
|
17
|
-
.reduce((acc, line) => {
|
|
18
|
-
if (acc.stop)
|
|
19
|
-
return acc;
|
|
20
|
-
if (line.startsWith('///')) {
|
|
21
|
-
return { commentLines: [line, ...acc.commentLines], stop: false };
|
|
22
|
-
}
|
|
23
|
-
if (line === '')
|
|
24
|
-
return acc;
|
|
25
|
-
return { commentLines: acc.commentLines, stop: true };
|
|
26
|
-
}, { commentLines: [], stop: false }).commentLines;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Parse the collected comment lines -> { valibotDefinition, description }
|
|
30
|
-
*/
|
|
31
|
-
const parseFieldComments = (commentLines) => {
|
|
32
|
-
const cleaned = commentLines.map((l) => l.replace(/^\/\/\/\s*/, '').trim()).filter(Boolean);
|
|
33
|
-
const valibotDefinition = cleaned.find((l) => l.startsWith('@v.'))?.replace(/^@/, '') ?? '';
|
|
34
|
-
const descriptionLines = cleaned.filter((l) => !isMetadataComment(l));
|
|
35
|
-
const description = descriptionLines.length ? descriptionLines.join(' ') : undefined;
|
|
36
|
-
return { valibotDefinition, description };
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Convert table name to Schema name (e.g. `user` -> `UserSchema`)
|
|
40
|
-
*/
|
|
41
|
-
const toSchemaName = (table) => `${table.charAt(0).toUpperCase() + table.slice(1)}Schema`;
|
|
42
|
-
/**
|
|
43
|
-
* Extract an ordinary column field.
|
|
44
|
-
*/
|
|
45
|
-
const extractFieldFromProperty = (property, sourceText) => {
|
|
46
|
-
if (!Node.isPropertyAssignment(property))
|
|
47
|
-
return null;
|
|
48
|
-
const name = property.getName();
|
|
49
|
-
if (!name)
|
|
50
|
-
return null;
|
|
51
|
-
const commentLines = extractFieldComments(sourceText, property.getStart());
|
|
52
|
-
const { valibotDefinition, description } = parseFieldComments(commentLines);
|
|
53
|
-
return { name, definition: valibotDefinition, description };
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Extract a relation field (many / one) and infer Valibot schema.
|
|
57
|
-
*/
|
|
58
|
-
const extractRelationFieldFromProperty = (property, sourceText) => {
|
|
59
|
-
if (!Node.isPropertyAssignment(property))
|
|
60
|
-
return null;
|
|
61
|
-
const name = property.getName();
|
|
62
|
-
if (!name)
|
|
63
|
-
return null;
|
|
64
|
-
const init = property.getInitializer();
|
|
65
|
-
if (!Node.isCallExpression(init))
|
|
66
|
-
return { name, definition: '', description: undefined };
|
|
67
|
-
const expr = init.getExpression();
|
|
68
|
-
if (!Node.isIdentifier(expr))
|
|
69
|
-
return { name, definition: '', description: undefined };
|
|
70
|
-
const fnName = expr.getText();
|
|
71
|
-
const args = init.getArguments();
|
|
72
|
-
if (!(args.length && Node.isIdentifier(args[0])))
|
|
73
|
-
return { name, definition: '', description: undefined };
|
|
74
|
-
const refTable = args[0].getText();
|
|
75
|
-
const schemaName = toSchemaName(refTable);
|
|
76
|
-
const definition = fnName === 'many' ? `v.array(${schemaName})` : fnName === 'one' ? schemaName : '';
|
|
77
|
-
const commentLines = extractFieldComments(sourceText, property.getStart());
|
|
78
|
-
const { description } = parseFieldComments(commentLines);
|
|
79
|
-
return { name, definition, description };
|
|
80
|
-
};
|
|
81
|
-
/** Utility: unwrap arrow / paren / etc. until ObjectLiteralExpression or null */
|
|
82
|
-
const extractObjectLiteralFromExpression = (expr) => {
|
|
83
|
-
if (Node.isObjectLiteralExpression(expr))
|
|
84
|
-
return expr;
|
|
85
|
-
if (Node.isParenthesizedExpression(expr))
|
|
86
|
-
return extractObjectLiteralFromExpression(expr.getExpression());
|
|
87
|
-
if (Node.isArrowFunction(expr)) {
|
|
88
|
-
const body = expr.getBody();
|
|
89
|
-
if (Node.isObjectLiteralExpression(body))
|
|
90
|
-
return body;
|
|
91
|
-
if (Node.isParenthesizedExpression(body))
|
|
92
|
-
return extractObjectLiteralFromExpression(body.getExpression());
|
|
93
|
-
if (Node.isBlock(body)) {
|
|
94
|
-
const ret = body.getStatements().find(Node.isReturnStatement);
|
|
95
|
-
if (ret && Node.isReturnStatement(ret)) {
|
|
96
|
-
const re = ret.getExpression();
|
|
97
|
-
return re && Node.isObjectLiteralExpression(re) ? re : null;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
};
|
|
103
|
-
/** find the first object literal among call expression arguments */
|
|
104
|
-
const findObjectLiteralInArgs = (call) => {
|
|
105
|
-
for (const arg of call.getArguments()) {
|
|
106
|
-
const obj = extractObjectLiteralFromExpression(arg);
|
|
107
|
-
if (obj)
|
|
108
|
-
return obj;
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
};
|
|
112
|
-
/** recognise `relations()` / `somethingRelation*` helpers */
|
|
113
|
-
const isRelationFunction = (call) => {
|
|
114
|
-
const expr = call.getExpression();
|
|
115
|
-
return (Node.isIdentifier(expr) &&
|
|
116
|
-
(expr.getText() === 'relations' || expr.getText().includes('relation')));
|
|
117
|
-
};
|
|
118
|
-
/** extract fields from mysqlTable / relations call expression */
|
|
119
|
-
const extractFieldsFromCallExpression = (call, sourceText) => {
|
|
120
|
-
const obj = findObjectLiteralInArgs(call);
|
|
121
|
-
if (!obj)
|
|
122
|
-
return [];
|
|
123
|
-
const relation = isRelationFunction(call);
|
|
124
|
-
return obj
|
|
125
|
-
.getProperties()
|
|
126
|
-
.map((p) => relation
|
|
127
|
-
? extractRelationFieldFromProperty(p, sourceText)
|
|
128
|
-
: extractFieldFromProperty(p, sourceText))
|
|
129
|
-
.filter((f) => f !== null);
|
|
130
|
-
};
|
|
131
|
-
/** extract a single schema from variable declaration */
|
|
132
|
-
const extractSchemaFromDeclaration = (decl, sourceText) => {
|
|
133
|
-
if (!Node.isVariableDeclaration(decl))
|
|
134
|
-
return null;
|
|
135
|
-
const name = decl.getName();
|
|
136
|
-
if (!name)
|
|
137
|
-
return null;
|
|
138
|
-
const init = decl.getInitializer();
|
|
139
|
-
// Handle call expressions (mysqlTable, relations, etc.)
|
|
140
|
-
if (Node.isCallExpression(init)) {
|
|
141
|
-
// ⛔ Skip relation helper exports (userRelations / postRelations ...)
|
|
142
|
-
if (isRelationFunction(init))
|
|
143
|
-
return null;
|
|
144
|
-
const fields = extractFieldsFromCallExpression(init, sourceText);
|
|
145
|
-
return { name, fields };
|
|
146
|
-
}
|
|
147
|
-
// Direct object literal export
|
|
148
|
-
if (Node.isObjectLiteralExpression(init)) {
|
|
149
|
-
const fields = init
|
|
150
|
-
.getProperties()
|
|
151
|
-
.map((p) => extractFieldFromProperty(p, sourceText))
|
|
152
|
-
.filter((f) => f !== null);
|
|
153
|
-
return { name, fields };
|
|
154
|
-
}
|
|
155
|
-
return { name, fields: [] };
|
|
156
|
-
};
|
|
157
|
-
/**
|
|
158
|
-
* Public API: extract schemas from code lines
|
|
159
|
-
*/
|
|
160
|
-
export function extractSchemas(lines) {
|
|
161
|
-
const project = new Project({
|
|
162
|
-
useInMemoryFileSystem: true,
|
|
163
|
-
compilerOptions: { allowJs: true, skipLibCheck: true },
|
|
164
|
-
});
|
|
165
|
-
const file = project.createSourceFile('temp.ts', lines.join('\n'));
|
|
166
|
-
const fullText = file.getFullText();
|
|
167
|
-
return file
|
|
168
|
-
.getVariableStatements()
|
|
169
|
-
.filter((s) => s.hasExportKeyword())
|
|
170
|
-
.flatMap((s) => s.getDeclarations())
|
|
171
|
-
.map((d) => extractSchemaFromDeclaration(d, fullText))
|
|
172
|
-
.filter((s) => s !== null);
|
|
173
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { TableInfo, ColumnInfo } from '../../shared/utils/types.js';
|
|
2
|
-
export declare const generateValibotSchema: (table: TableInfo) => string;
|
|
3
|
-
export declare const generateValibotProperty: (column: ColumnInfo) => string;
|
|
4
|
-
export declare const generateDefaultValibotSchema: (column: ColumnInfo) => string;
|
|
5
|
-
export declare const generateValibotFile: (tables: TableInfo[]) => string;
|
|
@@ -1,39 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
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;
|