hekireki 0.4.2 → 0.5.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 +180 -20
- package/dist/dbml-content-D3ioOw2D.js +151 -0
- package/dist/fsp-DYtOxLN_.js +68 -0
- package/dist/generator/arktype/index.d.ts +6 -0
- package/dist/generator/arktype/index.js +94 -0
- package/dist/generator/dbml/index.d.ts +6 -0
- package/dist/generator/dbml/index.js +49 -0
- package/dist/generator/ecto/index.d.ts +6 -3
- package/dist/generator/ecto/index.js +150 -13
- package/dist/generator/effect/index.d.ts +6 -0
- package/dist/generator/effect/index.js +94 -0
- package/dist/generator/mermaid-er/index.d.ts +6 -3
- package/dist/generator/mermaid-er/index.js +136 -21
- package/dist/generator/svg/index.d.ts +6 -0
- package/dist/generator/svg/index.js +74 -0
- package/dist/generator/valibot/index.d.ts +6 -3
- package/dist/generator/valibot/index.js +91 -45
- package/dist/generator/zod/index.d.ts +6 -3
- package/dist/generator/zod/index.js +98 -56
- package/dist/relations-CxeKj9KD.js +12 -0
- package/dist/utils-CXBzdZih.js +134 -0
- package/package.json +29 -17
- package/dist/generator/ecto/generator/ecto.d.ts +0 -3
- package/dist/generator/ecto/generator/ecto.js +0 -131
- package/dist/generator/ecto/utils/index.d.ts +0 -1
- package/dist/generator/ecto/utils/index.js +0 -1
- package/dist/generator/ecto/utils/prisma-type-to-ecto-type.d.ts +0 -1
- package/dist/generator/ecto/utils/prisma-type-to-ecto-type.js +0 -11
- package/dist/generator/mermaid-er/generator/er-content.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/er-content.js +0 -23
- package/dist/generator/mermaid-er/generator/index.d.ts +0 -4
- package/dist/generator/mermaid-er/generator/index.js +0 -4
- package/dist/generator/mermaid-er/generator/model-fields.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/model-fields.js +0 -25
- package/dist/generator/mermaid-er/generator/model-info.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/model-info.js +0 -10
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +0 -13
- package/dist/generator/mermaid-er/generator/relation-line.js +0 -14
- package/dist/generator/mermaid-er/helper/build-relation-line.d.ts +0 -9
- package/dist/generator/mermaid-er/helper/build-relation-line.js +0 -37
- package/dist/generator/mermaid-er/helper/extract-relations.d.ts +0 -8
- package/dist/generator/mermaid-er/helper/extract-relations.js +0 -22
- package/dist/generator/mermaid-er/utils/index.d.ts +0 -34
- package/dist/generator/mermaid-er/utils/index.js +0 -48
- package/dist/generator/valibot/generator/index.d.ts +0 -3
- package/dist/generator/valibot/generator/index.js +0 -3
- package/dist/generator/valibot/generator/schema.d.ts +0 -16
- package/dist/generator/valibot/generator/schema.js +0 -51
- package/dist/generator/valibot/generator/schemas.d.ts +0 -13
- package/dist/generator/valibot/generator/schemas.js +0 -17
- package/dist/generator/valibot/generator/valibot.d.ts +0 -9
- package/dist/generator/valibot/generator/valibot.js +0 -42
- package/dist/generator/valibot/utils/index.d.ts +0 -44
- package/dist/generator/valibot/utils/index.js +0 -75
- package/dist/generator/zod/generator/index.d.ts +0 -3
- package/dist/generator/zod/generator/index.js +0 -3
- package/dist/generator/zod/generator/schema.d.ts +0 -17
- package/dist/generator/zod/generator/schema.js +0 -38
- package/dist/generator/zod/generator/schemas.d.ts +0 -13
- package/dist/generator/zod/generator/schemas.js +0 -17
- package/dist/generator/zod/generator/zod.d.ts +0 -9
- package/dist/generator/zod/generator/zod.js +0 -47
- package/dist/generator/zod/utils/index.d.ts +0 -46
- package/dist/generator/zod/utils/index.js +0 -75
- package/dist/shared/format/index.d.ts +0 -1
- package/dist/shared/format/index.js +0 -9
- package/dist/shared/generator/index.d.ts +0 -11
- package/dist/shared/generator/index.js +0 -23
- package/dist/shared/helper/relations.d.ts +0 -7
- package/dist/shared/helper/relations.js +0 -5
- package/dist/shared/utils/index.d.ts +0 -61
- package/dist/shared/utils/index.js +0 -63
|
@@ -1,53 +1,99 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
2
|
+
import { a as getString, i as getBool, n as validationSchemas, o as fmt, r as parseDocumentWithoutAnnotations, t as schemaFromFields } from "../../utils-CXBzdZih.js";
|
|
3
|
+
import { n as writeFile, t as mkdir } from "../../fsp-DYtOxLN_.js";
|
|
4
|
+
import { t as collectRelationProps } from "../../relations-CxeKj9KD.js";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import pkg from "@prisma/generator-helper";
|
|
7
|
+
import { makePropertiesGenerator, makeValibotInfer, makeValidationExtractor } from "utils-lab";
|
|
8
|
+
|
|
9
|
+
//#region src/generator/valibot/generator/schema.ts
|
|
10
|
+
function buildValibotRelations(model, relProps, options) {
|
|
11
|
+
if (relProps.length === 0) return null;
|
|
12
|
+
const fields = `${` ...${model.name}Schema.entries,`}\n${relProps.map((r) => ` ${r.key}: ${r.isMany ? `v.array(${r.targetModel}Schema)` : `${r.targetModel}Schema`},`).join("\n")}`;
|
|
13
|
+
const typeLine = options?.includeType ? `\n\nexport type ${model.name}Relations = v.InferInput<typeof ${model.name}RelationsSchema>` : "";
|
|
14
|
+
return `export const ${model.name}RelationsSchema = v.object({\n${fields}\n})${typeLine}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate Valibot schema
|
|
18
|
+
* @param modelName - The name of the model
|
|
19
|
+
* @param fields - The fields of the model
|
|
20
|
+
* @returns The generated Valibot schema
|
|
21
|
+
*/
|
|
22
|
+
function schema(modelName, fields) {
|
|
23
|
+
return `export const ${modelName}Schema = v.object({\n${fields}\n})`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/generator/valibot/generator/schemas.ts
|
|
28
|
+
/**
|
|
29
|
+
* Creates Valibot schemas from model fields.
|
|
30
|
+
*
|
|
31
|
+
* @param modelFields - The fields of the model
|
|
32
|
+
* @param comment - Whether to include comments in the generated code
|
|
33
|
+
* @returns The generated Valibot schemas
|
|
34
|
+
*/
|
|
35
|
+
function schemas(modelFields, comment) {
|
|
36
|
+
return schemaFromFields(modelFields, comment, schema, makePropertiesGenerator("v"));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/generator/valibot/generator/valibot.ts
|
|
41
|
+
/**
|
|
42
|
+
* Creates Valibot schemas and types from models.
|
|
43
|
+
*
|
|
44
|
+
* @param models - The models to generate the Valibot schemas and types for
|
|
45
|
+
* @param type - Whether to generate types
|
|
46
|
+
* @param comment - Whether to include comments in the generated code
|
|
47
|
+
* @returns The generated Valibot schemas and types
|
|
48
|
+
*/
|
|
49
|
+
function valibot(models, type, comment) {
|
|
50
|
+
return validationSchemas(models, type, comment, {
|
|
51
|
+
importStatement: `import * as v from 'valibot'`,
|
|
52
|
+
annotationPrefix: "@v.",
|
|
53
|
+
parseDocument: parseDocumentWithoutAnnotations,
|
|
54
|
+
extractValidation: makeValidationExtractor("@v."),
|
|
55
|
+
inferType: makeValibotInfer,
|
|
56
|
+
schemas
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/generator/valibot/index.ts
|
|
9
62
|
const { generatorHandler } = pkg;
|
|
10
63
|
const buildRelationsOnly = (dmmf, includeType) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
isMany,
|
|
24
|
-
})), { includeType }))
|
|
25
|
-
.filter((code) => Boolean(code))
|
|
26
|
-
.join('\n\n');
|
|
64
|
+
const models = dmmf.datamodel.models;
|
|
65
|
+
const relIndex = collectRelationProps(models);
|
|
66
|
+
const relByModel = {};
|
|
67
|
+
for (const r of relIndex) {
|
|
68
|
+
const existing = relByModel[r.model] ?? [];
|
|
69
|
+
relByModel[r.model] = [...existing, r];
|
|
70
|
+
}
|
|
71
|
+
return models.map((model) => buildValibotRelations(model, (relByModel[model.name] ?? []).map(({ key, targetModel, isMany }) => ({
|
|
72
|
+
key,
|
|
73
|
+
targetModel,
|
|
74
|
+
isMany
|
|
75
|
+
})), { includeType })).filter((code) => Boolean(code)).join("\n\n");
|
|
27
76
|
};
|
|
28
|
-
const getString = (v, fallback) => typeof v === 'string' ? v : Array.isArray(v) ? (v[0] ?? fallback) : fallback;
|
|
29
|
-
const getBool = (v, fallback = false) => v === true || v === 'true' || (Array.isArray(v) && v[0] === 'true') ? true : fallback;
|
|
30
77
|
const emit = async (options, enableRelation) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
await fsp.mkdir(outDir, { recursive: true });
|
|
40
|
-
await fsp.writeFile(path.join(outDir, file), code, 'utf8');
|
|
78
|
+
const outDir = options.generator.output?.value ?? "./valibot";
|
|
79
|
+
const file = getString(options.generator.config?.file, "index.ts") ?? "index.ts";
|
|
80
|
+
const fmtResult = await fmt([valibot(options.dmmf.datamodel.models, getBool(options.generator.config?.type), getBool(options.generator.config?.comment)), enableRelation ? buildRelationsOnly(options.dmmf, getBool(options.generator.config?.type)) : ""].filter(Boolean).join("\n\n"));
|
|
81
|
+
if (!fmtResult.ok) throw new Error(`Format error: ${fmtResult.error}`);
|
|
82
|
+
const mkdirResult = await mkdir(outDir);
|
|
83
|
+
if (!mkdirResult.ok) throw new Error(`Failed to create directory: ${mkdirResult.error}`);
|
|
84
|
+
const writeResult = await writeFile(path.join(outDir, file), fmtResult.value);
|
|
85
|
+
if (!writeResult.ok) throw new Error(`Failed to write file: ${writeResult.error}`);
|
|
41
86
|
};
|
|
42
|
-
|
|
43
|
-
(Array.isArray(options.generator.config?.relation) &&
|
|
44
|
-
options.generator.config?.relation[0] === 'true'));
|
|
87
|
+
const onGenerate = (options) => emit(options, options.generator.config?.relation === "true" || Array.isArray(options.generator.config?.relation) && options.generator.config?.relation[0] === "true");
|
|
45
88
|
generatorHandler({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
89
|
+
onManifest() {
|
|
90
|
+
return {
|
|
91
|
+
defaultOutput: "./valibot/",
|
|
92
|
+
prettyName: "Hekireki-Valibot"
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
onGenerate
|
|
53
96
|
});
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
export { onGenerate };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { GeneratorOptions } from "@prisma/generator-helper";
|
|
2
|
+
|
|
3
|
+
//#region src/generator/zod/index.d.ts
|
|
4
|
+
declare const onGenerate: (options: GeneratorOptions) => Promise<void>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { onGenerate };
|
|
@@ -1,64 +1,106 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
|
|
2
|
+
import { a as getString, i as getBool, n as validationSchemas, o as fmt, r as parseDocumentWithoutAnnotations, t as schemaFromFields } from "../../utils-CXBzdZih.js";
|
|
3
|
+
import { n as writeFile, t as mkdir } from "../../fsp-DYtOxLN_.js";
|
|
4
|
+
import { t as collectRelationProps } from "../../relations-CxeKj9KD.js";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import pkg from "@prisma/generator-helper";
|
|
7
|
+
import { makePropertiesGenerator, makeValidationExtractor, makeZodInfer } from "utils-lab";
|
|
8
|
+
|
|
9
|
+
//#region src/generator/zod/generator/schema.ts
|
|
10
|
+
function buildZodRelations(model, relProps, options) {
|
|
11
|
+
if (relProps.length === 0) return null;
|
|
12
|
+
const fields = `${` ...${model.name}Schema.shape,`}\n${relProps.map((r) => ` ${r.key}: ${r.isMany ? `z.array(${r.targetModel}Schema)` : `${r.targetModel}Schema`},`).join("\n")}`;
|
|
13
|
+
const typeLine = options?.includeType ? `\n\nexport type ${model.name}Relations = z.infer<typeof ${model.name}RelationsSchema>` : "";
|
|
14
|
+
return `export const ${model.name}RelationsSchema = z.object({\n${fields}\n})${typeLine}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate Zod schema
|
|
18
|
+
* @param modelName - The name of the model
|
|
19
|
+
* @param fields - The fields of the model
|
|
20
|
+
* @param config - The configuration for the generator
|
|
21
|
+
* @returns The generated Zod schema
|
|
22
|
+
*/
|
|
23
|
+
function schema(modelName, fields) {
|
|
24
|
+
return `export const ${modelName}Schema = z.object({\n${fields}\n})`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/generator/zod/generator/schemas.ts
|
|
29
|
+
/**
|
|
30
|
+
* Creates Zod schemas from model fields.
|
|
31
|
+
*
|
|
32
|
+
* @param modelFields - The fields of the model
|
|
33
|
+
* @param comment - Whether to include comments in the generated code
|
|
34
|
+
* @returns The generated Zod schemas
|
|
35
|
+
*/
|
|
36
|
+
function schemas(modelFields, comment) {
|
|
37
|
+
return schemaFromFields(modelFields, comment, schema, makePropertiesGenerator("z"));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/generator/zod/generator/zod.ts
|
|
42
|
+
/**
|
|
43
|
+
* Creates Zod schemas and types from models.
|
|
44
|
+
*
|
|
45
|
+
* @param models - The models to generate the Zod schemas and types for
|
|
46
|
+
* @param type - Whether to generate types
|
|
47
|
+
* @param comment - Whether to include comments in the generated code
|
|
48
|
+
* @param zodVersion - The Zod version/variant to use
|
|
49
|
+
* @returns The generated Zod schemas and types
|
|
50
|
+
*/
|
|
51
|
+
function zod(models, type, comment, zodVersion) {
|
|
52
|
+
return validationSchemas(models, type, comment, {
|
|
53
|
+
importStatement: zodVersion === "mini" ? `import * as z from 'zod/mini'` : zodVersion === "@hono/zod-openapi" ? `import { z } from '@hono/zod-openapi'` : `import * as z from 'zod'`,
|
|
54
|
+
annotationPrefix: "@z.",
|
|
55
|
+
parseDocument: parseDocumentWithoutAnnotations,
|
|
56
|
+
extractValidation: makeValidationExtractor("@z."),
|
|
57
|
+
inferType: makeZodInfer,
|
|
58
|
+
schemas
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/generator/zod/index.ts
|
|
9
64
|
const { generatorHandler } = pkg;
|
|
10
65
|
const buildRelationsOnly = (dmmf, includeType) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return '';
|
|
28
|
-
const schema = buildZodRelations(model, relProps);
|
|
29
|
-
const typeLine = includeType
|
|
30
|
-
? `\n\nexport type ${model.name}Relations = z.infer<typeof ${model.name}RelationsSchema>`
|
|
31
|
-
: '';
|
|
32
|
-
return `${schema}${typeLine}`;
|
|
33
|
-
})
|
|
34
|
-
.filter(Boolean);
|
|
35
|
-
return blocks.join('\n\n');
|
|
66
|
+
const models = dmmf.datamodel.models;
|
|
67
|
+
const relIndex = collectRelationProps(models);
|
|
68
|
+
const relByModel = {};
|
|
69
|
+
for (const r of relIndex) {
|
|
70
|
+
const existing = relByModel[r.model] ?? [];
|
|
71
|
+
relByModel[r.model] = [...existing, r];
|
|
72
|
+
}
|
|
73
|
+
return models.map((model) => {
|
|
74
|
+
const relProps = (relByModel[model.name] ?? []).map(({ key, targetModel, isMany }) => ({
|
|
75
|
+
key,
|
|
76
|
+
targetModel,
|
|
77
|
+
isMany
|
|
78
|
+
}));
|
|
79
|
+
if (relProps.length === 0) return "";
|
|
80
|
+
return `${buildZodRelations(model, relProps)}${includeType ? `\n\nexport type ${model.name}Relations = z.infer<typeof ${model.name}RelationsSchema>` : ""}`;
|
|
81
|
+
}).filter(Boolean).join("\n\n");
|
|
36
82
|
};
|
|
37
|
-
const getString = (v, fallback) => typeof v === 'string' ? v : Array.isArray(v) ? (v[0] ?? fallback) : fallback;
|
|
38
|
-
const getBool = (v, fallback = false) => v === true || v === 'true' || (Array.isArray(v) && v[0] === 'true') ? true : fallback;
|
|
39
83
|
const emit = async (options, enableRelation) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const code = await fmt(full);
|
|
50
|
-
await fsp.mkdir(outDir, { recursive: true });
|
|
51
|
-
await fsp.writeFile(path.join(outDir, file), code, 'utf8');
|
|
84
|
+
const outDir = options.generator.output?.value ?? "./zod";
|
|
85
|
+
const file = getString(options.generator.config?.file, "index.ts") ?? "index.ts";
|
|
86
|
+
const zodVersion = getString(options.generator.config?.zod, "v4");
|
|
87
|
+
const fmtResult = await fmt([zod(options.dmmf.datamodel.models, getBool(options.generator.config?.type), getBool(options.generator.config?.comment), zodVersion), enableRelation ? buildRelationsOnly(options.dmmf, getBool(options.generator.config?.type)) : ""].filter(Boolean).join("\n\n"));
|
|
88
|
+
if (!fmtResult.ok) throw new Error(`Format error: ${fmtResult.error}`);
|
|
89
|
+
const mkdirResult = await mkdir(outDir);
|
|
90
|
+
if (!mkdirResult.ok) throw new Error(`Failed to create directory: ${mkdirResult.error}`);
|
|
91
|
+
const writeResult = await writeFile(path.join(outDir, file), fmtResult.value);
|
|
92
|
+
if (!writeResult.ok) throw new Error(`Failed to write file: ${writeResult.error}`);
|
|
52
93
|
};
|
|
53
|
-
|
|
54
|
-
(Array.isArray(options.generator.config?.relation) &&
|
|
55
|
-
options.generator.config?.relation[0] === 'true'));
|
|
94
|
+
const onGenerate = (options) => emit(options, options.generator.config?.relation === "true" || Array.isArray(options.generator.config?.relation) && options.generator.config?.relation[0] === "true");
|
|
56
95
|
generatorHandler({
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
96
|
+
onManifest() {
|
|
97
|
+
return {
|
|
98
|
+
defaultOutput: "./zod/",
|
|
99
|
+
prettyName: "Hekireki-Zod"
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
onGenerate
|
|
64
103
|
});
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
export { onGenerate };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/shared/helper/relations.ts
|
|
2
|
+
function collectRelationProps(models) {
|
|
3
|
+
return models.flatMap((m) => m.fields.filter((f) => f.kind === "object").map((f) => ({
|
|
4
|
+
model: m.name,
|
|
5
|
+
key: f.name,
|
|
6
|
+
targetModel: f.type,
|
|
7
|
+
isMany: f.isList
|
|
8
|
+
})));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { collectRelationProps as t };
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { format } from "oxfmt";
|
|
3
|
+
|
|
4
|
+
//#region src/shared/format/index.ts
|
|
5
|
+
async function fmt(input) {
|
|
6
|
+
const { code, errors } = await format("<stdin>.ts", input, {
|
|
7
|
+
printWidth: 100,
|
|
8
|
+
singleQuote: true,
|
|
9
|
+
semi: false
|
|
10
|
+
});
|
|
11
|
+
if (errors.length > 0) return {
|
|
12
|
+
ok: false,
|
|
13
|
+
error: errors.map((e) => e.message).join("\n")
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
ok: true,
|
|
17
|
+
value: code
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/shared/generator/index.ts
|
|
23
|
+
/**
|
|
24
|
+
* Extract a string value from generator config.
|
|
25
|
+
* Handles both single string and array of strings.
|
|
26
|
+
*/
|
|
27
|
+
const getString = (v, fallback) => typeof v === "string" ? v : Array.isArray(v) ? v[0] ?? fallback : fallback;
|
|
28
|
+
/**
|
|
29
|
+
* Extract a boolean value from generator config.
|
|
30
|
+
* Accepts true, 'true', or ['true'] as truthy values.
|
|
31
|
+
*/
|
|
32
|
+
const getBool = (v, fallback = false) => v === true || v === "true" || Array.isArray(v) && v[0] === "true" ? true : fallback;
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/shared/helper/document-parser.ts
|
|
36
|
+
/**
|
|
37
|
+
* All annotation prefixes used by hekireki generators.
|
|
38
|
+
*/
|
|
39
|
+
const ANNOTATION_PREFIXES = [
|
|
40
|
+
"@z.",
|
|
41
|
+
"@v.",
|
|
42
|
+
"@a.",
|
|
43
|
+
"@e."
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Parse documentation and filter out all annotation lines.
|
|
47
|
+
* This ensures that annotations from other libraries don't appear in comments.
|
|
48
|
+
*
|
|
49
|
+
* @param documentation - The documentation string from Prisma field
|
|
50
|
+
* @returns Array of comment lines without any annotations
|
|
51
|
+
*/
|
|
52
|
+
function parseDocumentWithoutAnnotations(documentation) {
|
|
53
|
+
if (!documentation) return [];
|
|
54
|
+
return documentation.split("\n").map((line) => line.trim()).filter((line) => {
|
|
55
|
+
return !ANNOTATION_PREFIXES.some((prefix) => line.startsWith(prefix));
|
|
56
|
+
}).filter((line) => line.length > 0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/shared/utils/index.ts
|
|
61
|
+
/**
|
|
62
|
+
* Group valid fields by their model name.
|
|
63
|
+
*
|
|
64
|
+
* @param validFields - An array of field objects with validation metadata.
|
|
65
|
+
* @returns An object mapping each model name to its corresponding array of fields.
|
|
66
|
+
*/
|
|
67
|
+
function groupByModel(validFields) {
|
|
68
|
+
const grouped = {};
|
|
69
|
+
for (const field of validFields) {
|
|
70
|
+
if (!grouped[field.modelName]) grouped[field.modelName] = [];
|
|
71
|
+
grouped[field.modelName] = [...grouped[field.modelName], field];
|
|
72
|
+
}
|
|
73
|
+
return grouped;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Extract fields with validation from a nested array of model fields.
|
|
77
|
+
*
|
|
78
|
+
* @param modelFields - A nested array of model field definitions.
|
|
79
|
+
* @returns A flat array of fields that include a non-null `validation` property.
|
|
80
|
+
*/
|
|
81
|
+
function isFields(modelFields) {
|
|
82
|
+
return modelFields.flat().filter((field) => field.validation !== null);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates schema from model fields.
|
|
86
|
+
*
|
|
87
|
+
* @param modelFields - The list of model fields with metadata.
|
|
88
|
+
* @param comment - Whether to include documentation comments.
|
|
89
|
+
* @param schemaBuilder - Function to build the schema from modelName and fields.
|
|
90
|
+
* @returns The generated schema string.
|
|
91
|
+
*/
|
|
92
|
+
function schemaFromFields(modelFields, comment, schemaBuilder, propertiesGenerator) {
|
|
93
|
+
const modelName = modelFields[0].modelName;
|
|
94
|
+
const modelDoc = modelFields[0].documentation || "";
|
|
95
|
+
const fields = propertiesGenerator(modelFields, comment);
|
|
96
|
+
if (!(modelDoc || !comment)) return schemaBuilder(modelName, fields);
|
|
97
|
+
return schemaBuilder(modelName, fields);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates validation schemas for models.
|
|
101
|
+
*
|
|
102
|
+
* @param models - The models to generate schemas for
|
|
103
|
+
* @param type - Whether to generate types
|
|
104
|
+
* @param comment - Whether to include comments
|
|
105
|
+
* @param config - Configuration for the specific library
|
|
106
|
+
* @returns The generated schemas and types
|
|
107
|
+
*/
|
|
108
|
+
function validationSchemas(models, type, comment, config) {
|
|
109
|
+
const modelFields = models.map((model) => ({
|
|
110
|
+
documentation: model.documentation ?? "",
|
|
111
|
+
name: model.name,
|
|
112
|
+
fields: model.fields
|
|
113
|
+
})).map((model) => {
|
|
114
|
+
return model.fields.map((field) => ({
|
|
115
|
+
documentation: model.documentation,
|
|
116
|
+
modelName: model.name,
|
|
117
|
+
fieldName: field.name,
|
|
118
|
+
comment: config.parseDocument(field.documentation),
|
|
119
|
+
validation: config.extractValidation(field.documentation)
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
const schemaResults = Object.values(groupByModel(isFields(modelFields))).map((fields) => ({
|
|
123
|
+
schema: config.schemas(fields, comment),
|
|
124
|
+
inferType: type ? config.inferType(fields[0].modelName) : ""
|
|
125
|
+
}));
|
|
126
|
+
return [
|
|
127
|
+
config.importStatement,
|
|
128
|
+
"",
|
|
129
|
+
schemaResults.flatMap(({ schema, inferType }) => [schema, inferType].filter(Boolean)).join("\n\n")
|
|
130
|
+
].join("\n");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { getString as a, getBool as i, validationSchemas as n, fmt as o, parseDocumentWithoutAnnotations as r, schemaFromFields as t };
|
package/package.json
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hekireki",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"description": "Hekireki is a tool that generates validation schemas for Zod and
|
|
6
|
+
"description": "Hekireki is a tool that generates validation schemas for Zod, Valibot, ArkType, and Effect Schema, as well as ER diagrams and DBML, from Prisma schemas annotated with comments.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"prisma",
|
|
9
9
|
"zod",
|
|
10
10
|
"valibot",
|
|
11
|
+
"arktype",
|
|
12
|
+
"effect",
|
|
11
13
|
"mermaid",
|
|
12
|
-
"ecto"
|
|
14
|
+
"ecto",
|
|
15
|
+
"dbml"
|
|
13
16
|
],
|
|
14
17
|
"homepage": "https://github.com/nakita628/hekireki",
|
|
15
18
|
"publishConfig": {
|
|
@@ -22,8 +25,6 @@
|
|
|
22
25
|
"bugs": {
|
|
23
26
|
"url": "https://github.com/nakita628/hekireki/issues"
|
|
24
27
|
},
|
|
25
|
-
"main": "dist/index.js",
|
|
26
|
-
"types": "dist/index.d.ts",
|
|
27
28
|
"files": [
|
|
28
29
|
"dist"
|
|
29
30
|
],
|
|
@@ -31,29 +32,40 @@
|
|
|
31
32
|
"hekireki-zod": "dist/generator/zod/index.js",
|
|
32
33
|
"hekireki-valibot": "dist/generator/valibot/index.js",
|
|
33
34
|
"hekireki-mermaid-er": "dist/generator/mermaid-er/index.js",
|
|
34
|
-
"hekireki-ecto": "dist/generator/ecto/index.js"
|
|
35
|
+
"hekireki-ecto": "dist/generator/ecto/index.js",
|
|
36
|
+
"hekireki-arktype": "dist/generator/arktype/index.js",
|
|
37
|
+
"hekireki-effect": "dist/generator/effect/index.js",
|
|
38
|
+
"hekireki-dbml": "dist/generator/dbml/index.js",
|
|
39
|
+
"hekireki-svg": "dist/generator/svg/index.js"
|
|
35
40
|
},
|
|
36
41
|
"scripts": {
|
|
37
42
|
"generate": "prisma generate",
|
|
38
43
|
"deps": "rm -rf node_modules && pnpm install",
|
|
39
|
-
"build": "
|
|
44
|
+
"build": "tsdown",
|
|
40
45
|
"typecheck": "tsc --noEmit",
|
|
41
46
|
"test": "vitest run",
|
|
42
47
|
"coverage": "vitest run --coverage",
|
|
43
48
|
"release": "npm pkg fix && pnpm build && npm publish"
|
|
44
49
|
},
|
|
45
50
|
"dependencies": {
|
|
46
|
-
"@prisma/generator-helper": "^
|
|
47
|
-
"
|
|
51
|
+
"@prisma/generator-helper": "^7.0.1",
|
|
52
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
53
|
+
"@softwaretechnik/dbml-renderer": "^1.0.31",
|
|
54
|
+
"oxfmt": "^0.27.0",
|
|
55
|
+
"utils-lab": "^0.0.2"
|
|
48
56
|
},
|
|
49
57
|
"devDependencies": {
|
|
50
|
-
"@prisma/client": "^
|
|
51
|
-
"@types/node": "^
|
|
52
|
-
"@
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
+
"@prisma/client": "^7.0.1",
|
|
59
|
+
"@types/node": "^24.10.1",
|
|
60
|
+
"@typescript/native-preview": "7.0.0-dev.20260130.1",
|
|
61
|
+
"@vitest/coverage-v8": "^4.0.14",
|
|
62
|
+
"arktype": "^2.1.29",
|
|
63
|
+
"effect": "^3.19.15",
|
|
64
|
+
"prisma": "^7.0.1",
|
|
65
|
+
"tsdown": "^0.20.1",
|
|
66
|
+
"tsx": "^4.20.6",
|
|
67
|
+
"valibot": "1.2.0",
|
|
68
|
+
"vitest": "^4.0.14",
|
|
69
|
+
"zod": "^4.1.13"
|
|
58
70
|
}
|
|
59
71
|
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { DMMF } from '@prisma/generator-helper';
|
|
2
|
-
export declare function ectoSchemas(models: readonly DMMF.Model[], app: string | string[]): string;
|
|
3
|
-
export declare function writeEctoSchemasToFiles(models: readonly DMMF.Model[], app: string | string[], outDir: string): Promise<void>;
|