sizuku 0.0.7 → 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 +96 -344
- 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 +18 -0
- package/dist/config/index.js +13 -0
- 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/config/index.d.ts +4 -4
- package/dist/generator/mermaid-er/config/index.js +4 -10
- package/dist/generator/mermaid-er/core/extract-relations.d.ts +1 -1
- package/dist/generator/mermaid-er/core/extract-relations.js +3 -6
- 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 +20 -0
- package/dist/generator/mermaid-er/generator/{generate-er-content.js → er-content.js} +3 -7
- package/dist/generator/mermaid-er/generator/index.d.ts +2 -0
- package/dist/generator/mermaid-er/generator/index.js +2 -0
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +12 -0
- package/dist/generator/mermaid-er/generator/{generate-relation-line.js → relation-line.js} +3 -6
- 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 +12 -5
- package/dist/generator/mermaid-er/index.js +30 -74
- package/dist/generator/mermaid-er/relationship/build-relation-line.js +3 -6
- package/dist/generator/mermaid-er/types.js +1 -0
- package/dist/generator/mermaid-er/validator/index.d.ts +8 -0
- package/dist/generator/mermaid-er/validator/index.js +71 -0
- package/dist/generator/mermaid-er/validator/is-relationship.d.ts +1 -1
- package/dist/generator/mermaid-er/validator/is-relationship.js +1 -4
- package/dist/generator/mermaid-er/validator/parse-relation-line.js +1 -4
- package/dist/generator/mermaid-er/validator/parse-table-info.d.ts +1 -7
- package/dist/generator/mermaid-er/validator/parse-table-info.js +69 -89
- package/dist/generator/mermaid-er/validator/remove-duplicate-relations.js +1 -4
- package/dist/generator/valibot/config/index.d.ts +2 -2
- package/dist/generator/valibot/config/index.js +6 -12
- package/dist/generator/valibot/core/extract-schema.d.ts +2 -5
- package/dist/generator/valibot/core/extract-schema.js +162 -81
- package/dist/generator/valibot/core.d.ts +5 -0
- package/dist/generator/valibot/core.js +39 -0
- package/dist/generator/valibot/generator/infer-input.d.ts +5 -0
- package/dist/generator/valibot/generator/infer-input.js +8 -0
- 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 +15 -0
- package/dist/generator/valibot/generator/valibot-code.js +16 -0
- package/dist/generator/valibot/generator/valibot.d.ts +14 -0
- package/dist/generator/valibot/generator/valibot.js +15 -0
- package/dist/generator/valibot/generator.d.ts +3 -0
- package/dist/generator/valibot/generator.js +14 -0
- package/dist/generator/valibot/index.d.ts +14 -3
- package/dist/generator/valibot/index.js +46 -73
- package/dist/generator/zod/config/index.d.ts +2 -2
- package/dist/generator/zod/config/index.js +6 -12
- package/dist/generator/zod/core/extract-schema.d.ts +1 -2
- package/dist/generator/zod/core/extract-schema.js +228 -81
- package/dist/generator/zod/core.d.ts +5 -0
- package/dist/generator/zod/core.js +39 -0
- package/dist/generator/zod/generator/infer.d.ts +5 -0
- package/dist/generator/zod/generator/infer.js +8 -0
- 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 +17 -0
- package/dist/generator/zod/generator/zod-code.js +18 -0
- package/dist/generator/zod/generator/zod.d.ts +16 -0
- package/dist/generator/zod/generator/zod.js +16 -0
- package/dist/generator/zod/generator.d.ts +3 -0
- package/dist/generator/zod/generator.js +14 -0
- package/dist/generator/zod/index.d.ts +15 -3
- package/dist/generator/zod/index.js +50 -73
- package/dist/index.d.ts +8 -0
- package/dist/index.js +71 -0
- package/dist/shared/config/index.d.ts +13 -0
- package/dist/{common → shared}/config/index.js +1 -4
- package/dist/shared/format/index.d.ts +15 -0
- package/dist/shared/format/index.js +24 -0
- package/dist/shared/fs/index.d.ts +7 -0
- package/dist/shared/fs/index.js +16 -0
- package/dist/shared/fsp/index.d.ts +27 -0
- package/dist/shared/fsp/index.js +38 -0
- package/dist/shared/generator/field-definitions.d.ts +12 -0
- package/dist/shared/generator/field-definitions.js +12 -0
- 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/types.js +1 -0
- package/dist/{common/text → shared/utils}/capitalize.js +1 -4
- package/dist/shared/utils/compose.d.ts +101 -0
- package/dist/shared/utils/compose.js +124 -0
- package/dist/shared/utils/file.d.ts +92 -0
- package/dist/shared/utils/file.js +177 -0
- package/dist/shared/utils/functional.d.ts +118 -0
- package/dist/shared/utils/functional.js +96 -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/{generator/zod/generator/generate-zod-code.d.ts → src/generator/zod/generator/zod-code.d.ts} +8 -3
- package/dist/src/generator/zod/generator/zod-code.js +18 -0
- package/dist/{generator/zod/generator/generate-zod-schema.d.ts → src/generator/zod/generator/zod.d.ts} +8 -4
- 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 +10 -13
- package/dist/common/config/index.d.ts +0 -13
- package/dist/common/format/index.d.ts +0 -1
- package/dist/common/format/index.js +0 -12
- package/dist/common/generator/generate-field-definitions.d.ts +0 -8
- package/dist/common/generator/generate-field-definitions.js +0 -16
- package/dist/common/helper/get-camel-case-schema-name-helper.d.ts +0 -7
- package/dist/common/helper/get-camel-case-schema-name-helper.js +0 -14
- package/dist/common/helper/get-pascal-case-schema-name-helper.d.ts +0 -8
- package/dist/common/helper/get-pascal-case-schema-name-helper.js +0 -15
- package/dist/common/helper/get-variable-name-helper.d.ts +0 -9
- package/dist/common/helper/get-variable-name-helper.js +0 -15
- package/dist/common/helper/get-variable-schema-name-helper.d.ts +0 -9
- package/dist/common/helper/get-variable-schema-name-helper.js +0 -17
- package/dist/common/text/decapitalize.d.ts +0 -17
- package/dist/common/text/decapitalize.js +0 -22
- package/dist/common/type/index.js +0 -2
- package/dist/generator/mermaid-er/generator/generate-er-content.d.ts +0 -9
- package/dist/generator/mermaid-er/generator/generate-relation-line.d.ts +0 -7
- package/dist/generator/mermaid-er/type/index.js +0 -2
- package/dist/generator/mermaid-er/validator/is-relation.d.ts +0 -7
- package/dist/generator/mermaid-er/validator/is-relation.js +0 -40
- package/dist/generator/valibot/generator/generate-valibot-code.d.ts +0 -11
- package/dist/generator/valibot/generator/generate-valibot-code.js +0 -21
- package/dist/generator/valibot/generator/generate-valibot-infer-input.d.ts +0 -9
- package/dist/generator/valibot/generator/generate-valibot-infer-input.js +0 -16
- package/dist/generator/valibot/generator/generate-valibot-schema.d.ts +0 -9
- package/dist/generator/valibot/generator/generate-valibot-schema.js +0 -16
- package/dist/generator/zod/generator/generate-z-infer.d.ts +0 -11
- package/dist/generator/zod/generator/generate-z-infer.js +0 -18
- package/dist/generator/zod/generator/generate-zod-code.js +0 -21
- package/dist/generator/zod/generator/generate-zod-schema.js +0 -17
- /package/dist/generator/mermaid-er/{type/index.d.ts → types.d.ts} +0 -0
- /package/dist/{common/type/index.d.ts → shared/types.d.ts} +0 -0
- /package/dist/{common/text → shared/utils}/capitalize.d.ts +0 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Project, SourceFile, Node, SyntaxKind, JSDocTagInfo } from 'ts-morph';
|
|
2
|
+
import { Result, err, ok } from 'neverthrow';
|
|
3
|
+
import { extractComment, parseZodTag, parseValibotTag, parseRelationTag, toPascalCase } from '../utils/string-utils.js';
|
|
4
|
+
import { validateTableName, validateColumnName, validateRelationType } from '../utils/validation-utils.js';
|
|
5
|
+
export const parseSchemaFile = (filePath) => {
|
|
6
|
+
try {
|
|
7
|
+
const project = new Project();
|
|
8
|
+
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
9
|
+
const tables = [];
|
|
10
|
+
const relations = [];
|
|
11
|
+
// テーブル定義を解析
|
|
12
|
+
const tableExports = sourceFile.getExportedDeclarations();
|
|
13
|
+
for (const [name, declarations] of tableExports) {
|
|
14
|
+
if (name === 'userRelations' || name === 'postRelations')
|
|
15
|
+
continue;
|
|
16
|
+
const declaration = declarations[0];
|
|
17
|
+
if (!declaration || !Node.isVariableDeclaration(declaration))
|
|
18
|
+
continue;
|
|
19
|
+
const initializer = declaration.getInitializer();
|
|
20
|
+
if (!initializer || !Node.isCallExpression(initializer))
|
|
21
|
+
continue;
|
|
22
|
+
const callName = initializer.getExpression().getText();
|
|
23
|
+
if (!callName.includes('Table'))
|
|
24
|
+
continue;
|
|
25
|
+
const tableName = initializer.getArguments()[0]?.getText().replace(/['"]/g, '');
|
|
26
|
+
if (!tableName || !validateTableName(tableName))
|
|
27
|
+
continue;
|
|
28
|
+
const columns = parseTableColumns(initializer);
|
|
29
|
+
if (columns.isErr())
|
|
30
|
+
return err(columns.error);
|
|
31
|
+
tables.push({
|
|
32
|
+
name: tableName,
|
|
33
|
+
columns: columns.value,
|
|
34
|
+
relations: []
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// リレーション定義を解析
|
|
38
|
+
const relationExports = sourceFile.getExportedDeclarations();
|
|
39
|
+
for (const [name, declarations] of relationExports) {
|
|
40
|
+
if (!name.includes('Relations'))
|
|
41
|
+
continue;
|
|
42
|
+
const declaration = declarations[0];
|
|
43
|
+
if (!declaration || !Node.isVariableDeclaration(declaration))
|
|
44
|
+
continue;
|
|
45
|
+
const initializer = declaration.getInitializer();
|
|
46
|
+
if (!initializer || !Node.isCallExpression(initializer))
|
|
47
|
+
continue;
|
|
48
|
+
const relation = parseRelation(initializer, tables.map(t => t.name));
|
|
49
|
+
if (relation.isOk()) {
|
|
50
|
+
relations.push(relation.value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// リレーションをテーブルに割り当て
|
|
54
|
+
for (const relation of relations) {
|
|
55
|
+
const sourceTable = tables.find(t => t.name === relation.sourceTable);
|
|
56
|
+
const targetTable = tables.find(t => t.name === relation.targetTable);
|
|
57
|
+
if (sourceTable) {
|
|
58
|
+
sourceTable.relations.push(relation);
|
|
59
|
+
}
|
|
60
|
+
if (targetTable) {
|
|
61
|
+
targetTable.relations.push(relation);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return ok({ tables });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return err(new Error(`Failed to parse schema file: ${error instanceof Error ? error.message : String(error)}`));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const parseTableColumns = (tableCall) => {
|
|
71
|
+
try {
|
|
72
|
+
const columns = [];
|
|
73
|
+
const objectLiteral = tableCall.getArguments()[1];
|
|
74
|
+
if (!objectLiteral || !Node.isObjectLiteralExpression(objectLiteral)) {
|
|
75
|
+
return err(new Error('Invalid table definition'));
|
|
76
|
+
}
|
|
77
|
+
const properties = objectLiteral.getProperties();
|
|
78
|
+
for (const property of properties) {
|
|
79
|
+
if (!Node.isPropertyAssignment(property))
|
|
80
|
+
continue;
|
|
81
|
+
const propertyName = property.getName();
|
|
82
|
+
if (!validateColumnName(propertyName))
|
|
83
|
+
continue;
|
|
84
|
+
const initializer = property.getInitializer();
|
|
85
|
+
if (!initializer || !Node.isCallExpression(initializer))
|
|
86
|
+
continue;
|
|
87
|
+
const column = parseColumnDefinition(propertyName, initializer, property);
|
|
88
|
+
if (column.isOk()) {
|
|
89
|
+
columns.push(column.value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return ok(columns);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return err(new Error(`Failed to parse table columns: ${error instanceof Error ? error.message : String(error)}`));
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const parseColumnDefinition = (name, columnCall, property) => {
|
|
99
|
+
try {
|
|
100
|
+
const callName = columnCall.getExpression().getText();
|
|
101
|
+
const args = columnCall.getArguments();
|
|
102
|
+
let type = 'unknown';
|
|
103
|
+
let length;
|
|
104
|
+
let isPrimary = false;
|
|
105
|
+
let isNullable = true;
|
|
106
|
+
// 型と長さを解析
|
|
107
|
+
if (callName.includes('varchar')) {
|
|
108
|
+
type = 'varchar';
|
|
109
|
+
if (args[1] && Node.isObjectLiteralExpression(args[1])) {
|
|
110
|
+
const lengthProp = args[1].getProperty('length');
|
|
111
|
+
if (lengthProp && Node.isPropertyAssignment(lengthProp)) {
|
|
112
|
+
const lengthValue = lengthProp.getInitializer();
|
|
113
|
+
if (lengthValue && Node.isNumericLiteral(lengthValue)) {
|
|
114
|
+
length = parseInt(lengthValue.getText());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (callName.includes('int')) {
|
|
120
|
+
type = 'int';
|
|
121
|
+
}
|
|
122
|
+
else if (callName.includes('text')) {
|
|
123
|
+
type = 'text';
|
|
124
|
+
}
|
|
125
|
+
// メソッドチェーンを解析
|
|
126
|
+
let currentCall = columnCall;
|
|
127
|
+
while (currentCall.getParent() && Node.isCallExpression(currentCall.getParent())) {
|
|
128
|
+
currentCall = currentCall.getParent();
|
|
129
|
+
const methodName = currentCall.getExpression().getText();
|
|
130
|
+
if (methodName.includes('primaryKey')) {
|
|
131
|
+
isPrimary = true;
|
|
132
|
+
}
|
|
133
|
+
else if (methodName.includes('notNull')) {
|
|
134
|
+
isNullable = false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// JSDocコメントを解析
|
|
138
|
+
const jsDoc = property.getJsDocs()[0];
|
|
139
|
+
const comment = jsDoc ? extractComment(jsDoc.getText()) : undefined;
|
|
140
|
+
let zodSchema;
|
|
141
|
+
let valibotSchema;
|
|
142
|
+
if (jsDoc) {
|
|
143
|
+
const tags = jsDoc.getTags();
|
|
144
|
+
for (const tag of tags) {
|
|
145
|
+
const tagName = tag.getTagName();
|
|
146
|
+
const tagText = tag.getText();
|
|
147
|
+
if (tagName === 'z') {
|
|
148
|
+
zodSchema = parseZodTag(tagText);
|
|
149
|
+
}
|
|
150
|
+
else if (tagName === 'v') {
|
|
151
|
+
valibotSchema = parseValibotTag(tagText);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return ok({
|
|
156
|
+
name,
|
|
157
|
+
type,
|
|
158
|
+
isPrimary,
|
|
159
|
+
isNullable,
|
|
160
|
+
length,
|
|
161
|
+
zodSchema,
|
|
162
|
+
valibotSchema,
|
|
163
|
+
comment
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return err(new Error(`Failed to parse column definition: ${error instanceof Error ? error.message : String(error)}`));
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const parseRelation = (relationCall, tableNames) => {
|
|
171
|
+
try {
|
|
172
|
+
// リレーションコメントを探す
|
|
173
|
+
const jsDoc = relationCall.getJsDocs()[0];
|
|
174
|
+
if (!jsDoc)
|
|
175
|
+
return err(new Error('No relation comment found'));
|
|
176
|
+
const relationText = parseRelationTag(jsDoc.getText());
|
|
177
|
+
const parts = relationText.split(' ');
|
|
178
|
+
if (parts.length < 4)
|
|
179
|
+
return err(new Error('Invalid relation format'));
|
|
180
|
+
const sourceTable = parts[0];
|
|
181
|
+
const sourceColumn = parts[1];
|
|
182
|
+
const targetTable = parts[2];
|
|
183
|
+
const targetColumn = parts[3];
|
|
184
|
+
const type = parts[4] || 'one-to-many';
|
|
185
|
+
if (!validateRelationType(type)) {
|
|
186
|
+
return err(new Error(`Invalid relation type: ${type}`));
|
|
187
|
+
}
|
|
188
|
+
if (!tableNames.includes(sourceTable) || !tableNames.includes(targetTable)) {
|
|
189
|
+
return err(new Error(`Table not found in relation: ${sourceTable} -> ${targetTable}`));
|
|
190
|
+
}
|
|
191
|
+
return ok({
|
|
192
|
+
sourceTable,
|
|
193
|
+
sourceColumn,
|
|
194
|
+
targetTable,
|
|
195
|
+
targetColumn,
|
|
196
|
+
type
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return err(new Error(`Failed to parse relation: ${error instanceof Error ? error.message : String(error)}`));
|
|
201
|
+
}
|
|
202
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CallExpression } from 'ts-morph';
|
|
2
|
+
import { Node } from 'ts-morph';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a schema extractor from customizable strategies.
|
|
5
|
+
*
|
|
6
|
+
* @param extractFieldsFromCall - Function to extract fields from a call expression (e.g. mysqlTable(...)).
|
|
7
|
+
* @param extractFieldFromProperty - Function to extract a single field from an object literal property.
|
|
8
|
+
* @returns A function that extracts a schema from a variable declaration node.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildSchemaExtractor(extractFieldsFromCall: (call: CallExpression, sourceText: string) => {
|
|
11
|
+
name: string;
|
|
12
|
+
definition: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}[], extractFieldFromProperty: (prop: Node, sourceText: string) => {
|
|
15
|
+
name: string;
|
|
16
|
+
definition: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
} | null): (declaration: Node, sourceText: string) => {
|
|
19
|
+
name: string;
|
|
20
|
+
fields: {
|
|
21
|
+
name: string;
|
|
22
|
+
definition: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
}[];
|
|
25
|
+
} | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { isRelationFunctionCall } from '../../shared/helper/is-relation-function.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a schema extractor from customizable strategies.
|
|
5
|
+
*
|
|
6
|
+
* @param extractFieldsFromCall - Function to extract fields from a call expression (e.g. mysqlTable(...)).
|
|
7
|
+
* @param extractFieldFromProperty - Function to extract a single field from an object literal property.
|
|
8
|
+
* @returns A function that extracts a schema from a variable declaration node.
|
|
9
|
+
*/
|
|
10
|
+
export function buildSchemaExtractor(extractFieldsFromCall, extractFieldFromProperty) {
|
|
11
|
+
return (declaration, sourceText) => {
|
|
12
|
+
if (!Node.isVariableDeclaration(declaration))
|
|
13
|
+
return null;
|
|
14
|
+
const name = declaration.getName();
|
|
15
|
+
if (!name)
|
|
16
|
+
return null;
|
|
17
|
+
const initializer = declaration.getInitializer();
|
|
18
|
+
if (Node.isCallExpression(initializer)) {
|
|
19
|
+
if (isRelationFunctionCall(initializer))
|
|
20
|
+
return null;
|
|
21
|
+
const fields = extractFieldsFromCall(initializer, sourceText);
|
|
22
|
+
return { name, fields };
|
|
23
|
+
}
|
|
24
|
+
if (Node.isObjectLiteralExpression(initializer)) {
|
|
25
|
+
const fields = initializer
|
|
26
|
+
.getProperties()
|
|
27
|
+
.map((prop) => extractFieldFromProperty(prop, sourceText))
|
|
28
|
+
.filter((field) => field !== null);
|
|
29
|
+
return { name, fields };
|
|
30
|
+
}
|
|
31
|
+
return { name, fields: [] };
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a field extractor function using a custom parseFieldComments implementation.
|
|
4
|
+
*
|
|
5
|
+
* @param parseFieldComments - A function that parses comment lines into { definition, description }
|
|
6
|
+
* @returns A property node extractor function.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createExtractFieldFromProperty(parseFieldComments: (commentLines: string[]) => {
|
|
9
|
+
definition: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}): (property: Node, sourceText: string) => {
|
|
12
|
+
name: string;
|
|
13
|
+
definition: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
} | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { extractFieldComments } from '../../shared/utils/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a field extractor function using a custom parseFieldComments implementation.
|
|
5
|
+
*
|
|
6
|
+
* @param parseFieldComments - A function that parses comment lines into { definition, description }
|
|
7
|
+
* @returns A property node extractor function.
|
|
8
|
+
*/
|
|
9
|
+
export function createExtractFieldFromProperty(parseFieldComments) {
|
|
10
|
+
return (property, sourceText) => {
|
|
11
|
+
if (!Node.isPropertyAssignment(property))
|
|
12
|
+
return null;
|
|
13
|
+
const name = property.getName();
|
|
14
|
+
if (!name)
|
|
15
|
+
return null;
|
|
16
|
+
const commentLines = extractFieldComments(sourceText, property.getStart());
|
|
17
|
+
const { definition, description } = parseFieldComments(commentLines);
|
|
18
|
+
return { name, definition, description };
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CallExpression, Node, ObjectLiteralExpression } from 'ts-morph';
|
|
2
|
+
export declare function createExtractFieldsFromCallExpression(extractFieldFromProperty: (property: Node, sourceText: string) => {
|
|
3
|
+
name: string;
|
|
4
|
+
definition: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
} | null, extractRelationFieldFromProperty: (property: Node, sourceText: string) => {
|
|
7
|
+
name: string;
|
|
8
|
+
definition: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
} | null, findObjectLiteralExpression: (expr: Node) => ObjectLiteralExpression | null, findObjectLiteralInArgs: (call: CallExpression, finder: (expr: Node) => ObjectLiteralExpression | null) => ObjectLiteralExpression | null, isRelationFunctionCall: (call: CallExpression) => boolean): (callExpr: CallExpression, sourceText: string) => {
|
|
11
|
+
name: string;
|
|
12
|
+
definition: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function createExtractFieldsFromCallExpression(extractFieldFromProperty, extractRelationFieldFromProperty, findObjectLiteralExpression, findObjectLiteralInArgs, isRelationFunctionCall) {
|
|
2
|
+
return (callExpr, sourceText) => {
|
|
3
|
+
const objectLiteral = findObjectLiteralInArgs(callExpr, findObjectLiteralExpression);
|
|
4
|
+
if (!objectLiteral)
|
|
5
|
+
return [];
|
|
6
|
+
const isRelation = isRelationFunctionCall(callExpr);
|
|
7
|
+
return objectLiteral
|
|
8
|
+
.getProperties()
|
|
9
|
+
.map((prop) => isRelation
|
|
10
|
+
? extractRelationFieldFromProperty(prop, sourceText)
|
|
11
|
+
: extractFieldFromProperty(prop, sourceText))
|
|
12
|
+
.filter((field) => field !== null);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
export declare const createExtractRelationFieldFromProperty: (parseFieldComments: (lines: string[]) => {
|
|
3
|
+
definition: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}, prefix: "v" | "z") => (property: Node, sourceText: string) => {
|
|
6
|
+
name: string;
|
|
7
|
+
fields: {
|
|
8
|
+
name: string;
|
|
9
|
+
definition: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}[];
|
|
12
|
+
}["fields"][0] | null;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Node } from 'ts-morph';
|
|
2
|
+
import { extractFieldComments, schemaName } from '../utils/index.js';
|
|
3
|
+
export const createExtractRelationFieldFromProperty = (parseFieldComments, prefix) => {
|
|
4
|
+
return (property, sourceText) => {
|
|
5
|
+
if (!Node.isPropertyAssignment(property))
|
|
6
|
+
return null;
|
|
7
|
+
const name = property.getName();
|
|
8
|
+
if (!name)
|
|
9
|
+
return null;
|
|
10
|
+
const init = property.getInitializer();
|
|
11
|
+
if (!Node.isCallExpression(init))
|
|
12
|
+
return { name, definition: '', description: undefined };
|
|
13
|
+
const expr = init.getExpression();
|
|
14
|
+
if (!Node.isIdentifier(expr))
|
|
15
|
+
return { name, definition: '', description: undefined };
|
|
16
|
+
const fnName = expr.getText();
|
|
17
|
+
const args = init.getArguments();
|
|
18
|
+
if (!(args.length && Node.isIdentifier(args[0]))) {
|
|
19
|
+
return { name, definition: '', description: undefined };
|
|
20
|
+
}
|
|
21
|
+
const refTable = args[0].getText();
|
|
22
|
+
const schema = schemaName(refTable);
|
|
23
|
+
const definition = fnName === 'many' ? `${prefix}.array(${schema})` : fnName === 'one' ? schema : '';
|
|
24
|
+
const { description } = parseFieldComments(extractFieldComments(sourceText, property.getStart()));
|
|
25
|
+
return { name, definition, description };
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported validation library types.
|
|
3
|
+
*/
|
|
4
|
+
export type ValidationLibrary = 'zod' | 'valibot';
|
|
5
|
+
/**
|
|
6
|
+
* Schema extraction result type containing table name and field definitions.
|
|
7
|
+
*/
|
|
8
|
+
export type SchemaExtractionResult = {
|
|
9
|
+
/** The name of the table/schema */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Optional base schema/table name (used for relations) */
|
|
12
|
+
baseName?: string;
|
|
13
|
+
/** Array of field definitions with name, validation definition, and description */
|
|
14
|
+
fields: {
|
|
15
|
+
/** Field name */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Validation definition (e.g., 'z.uuid()', 'v.pipe(v.string(), v.uuid())') */
|
|
18
|
+
definition: string;
|
|
19
|
+
/** Optional field description from comments */
|
|
20
|
+
description?: string;
|
|
21
|
+
}[];
|
|
22
|
+
/** Object type for schema generation ('strict' | 'loose' | undefined) */
|
|
23
|
+
objectType?: 'strict' | 'loose';
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Relation schema extraction result with required base name.
|
|
27
|
+
*/
|
|
28
|
+
export type RelationSchemaExtractionResult = {
|
|
29
|
+
name: string;
|
|
30
|
+
baseName: string;
|
|
31
|
+
fields: {
|
|
32
|
+
name: string;
|
|
33
|
+
definition: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
}[];
|
|
36
|
+
/** Object type for schema generation ('strict' | 'loose' | undefined) */
|
|
37
|
+
objectType?: 'strict' | 'loose';
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Extracts schemas from TypeScript source code using AST analysis.
|
|
41
|
+
*
|
|
42
|
+
* This function processes exported variable declarations to extract table schemas
|
|
43
|
+
* with their field definitions and comments. It supports both Zod and Valibot schema extraction.
|
|
44
|
+
*
|
|
45
|
+
* @param lines - Array of source code lines to process
|
|
46
|
+
* @param library - The validation library to extract schemas for ('zod' or 'valibot')
|
|
47
|
+
* @returns Array of extracted schemas with field definitions
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // For Zod schemas
|
|
52
|
+
* const zodSchemas = extractSchemas(sourceLines, 'zod')
|
|
53
|
+
*
|
|
54
|
+
* // For Valibot schemas
|
|
55
|
+
* const valibotSchemas = extractSchemas(sourceLines, 'valibot')
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function extractSchemas(lines: string[], library: ValidationLibrary): SchemaExtractionResult[];
|
|
59
|
+
/**
|
|
60
|
+
* Extracts Zod schemas from TypeScript source code using AST analysis.
|
|
61
|
+
*
|
|
62
|
+
* This function processes exported variable declarations to extract table schemas
|
|
63
|
+
* with their field definitions and comments. It automatically handles Zod schema extraction.
|
|
64
|
+
*
|
|
65
|
+
* @param lines - Array of source code lines to process
|
|
66
|
+
* @returns Array of extracted schemas with field definitions
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const schemas = extractZodSchemas(sourceLines)
|
|
71
|
+
* // Returns: [{ name: 'user', fields: [{ name: 'id', definition: 'z.uuid()', description: 'Primary key' }] }]
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function extractZodSchemas(lines: string[]): SchemaExtractionResult[];
|
|
75
|
+
/**
|
|
76
|
+
* Extracts Valibot schemas from TypeScript source code using AST analysis.
|
|
77
|
+
*
|
|
78
|
+
* This function processes exported variable declarations to extract table schemas
|
|
79
|
+
* with their field definitions and comments. It automatically handles Valibot schema extraction.
|
|
80
|
+
*
|
|
81
|
+
* @param lines - Array of source code lines to process
|
|
82
|
+
* @returns Array of extracted schemas with field definitions
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const schemas = extractValibotSchemas(sourceLines)
|
|
87
|
+
* // Returns: [{ name: 'user', fields: [{ name: 'id', definition: 'v.pipe(v.string(), v.uuid())', description: 'Primary key' }] }]
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function extractValibotSchemas(lines: string[]): SchemaExtractionResult[];
|
|
91
|
+
/**
|
|
92
|
+
* Extracts relation schemas from `relations(...)` declarations using AST analysis.
|
|
93
|
+
*
|
|
94
|
+
* This returns entries like `userRelations` and `postRelations` with fields
|
|
95
|
+
* resolved to either `z.array(OtherSchema)` / `v.array(OtherSchema)` or direct
|
|
96
|
+
* `OtherSchema` based on `many`/`one`.
|
|
97
|
+
*
|
|
98
|
+
* Note: Base table schemas are not included here; use `extractSchemas` for those.
|
|
99
|
+
*/
|
|
100
|
+
export declare function extractRelationSchemas(lines: string[], library: ValidationLibrary): RelationSchemaExtractionResult[];
|
|
101
|
+
/**
|
|
102
|
+
* Extracts relations from the given code.
|
|
103
|
+
*
|
|
104
|
+
* @param code - The code to extract relations from.
|
|
105
|
+
* @returns The extracted relations.
|
|
106
|
+
*/
|
|
107
|
+
export declare function extractRelations(code: string[]): {
|
|
108
|
+
fromModel: string;
|
|
109
|
+
toModel: string;
|
|
110
|
+
fromField: string;
|
|
111
|
+
toField: string;
|
|
112
|
+
type: string;
|
|
113
|
+
}[];
|
|
114
|
+
/**
|
|
115
|
+
* Parse relation line and extract components.
|
|
116
|
+
*
|
|
117
|
+
* @param line - The line to parse.
|
|
118
|
+
* @returns Parsed relation or null if not a relation line.
|
|
119
|
+
*/
|
|
120
|
+
export declare function parseRelationLine(line: string): {
|
|
121
|
+
fromModel: string;
|
|
122
|
+
toModel: string;
|
|
123
|
+
fromField: string;
|
|
124
|
+
toField: string;
|
|
125
|
+
type: string;
|
|
126
|
+
} | null;
|
|
127
|
+
/**
|
|
128
|
+
* Build a relation line from a string.
|
|
129
|
+
*
|
|
130
|
+
* @param input - The input string.
|
|
131
|
+
* @returns The built relation line.
|
|
132
|
+
*/
|
|
133
|
+
export declare function buildRelationLine(input: string): string;
|