hekireki 0.7.1 โ†’ 0.7.2

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 CHANGED
@@ -2,20 +2,31 @@
2
2
 
3
3
  # Hekireki
4
4
 
5
- **[Hekireki](https://www.npmjs.com/package/hekireki)** is a tool that generates validation schemas for Zod, Valibot, ArkType, Effect Schema, TypeBox, and AJV (JSON Schema), as well as [Drizzle ORM](https://orm.drizzle.team/) schemas and ER diagrams, from [Prisma](https://www.prisma.io/) schemas annotated with comments.
5
+ **[Hekireki](https://www.npmjs.com/package/hekireki)** is a tool that generates validation schemas, ORM models, and ER diagrams from [Prisma](https://www.prisma.io/) schemas โ€” supporting TypeScript, Python, Go, Rust, and Elixir.
6
6
 
7
7
  ## Features
8
8
 
9
+ ### TypeScript Validation Libraries
10
+
9
11
  - ๐Ÿ’Ž Automatically generates [Zod](https://zod.dev/) schemas from your Prisma schema
10
12
  - ๐Ÿค– Automatically generates [Valibot](https://valibot.dev/) schemas from your Prisma schema
11
13
  - ๐Ÿน Automatically generates [ArkType](https://arktype.io/) schemas from your Prisma schema
12
14
  - โšก Automatically generates [Effect Schema](https://effect.website/docs/schema/introduction/) from your Prisma schema
13
15
  - ๐Ÿ“ฆ Automatically generates [TypeBox](https://github.com/sinclairzx81/typebox) schemas from your Prisma schema
14
16
  - ๐Ÿ“‹ Automatically generates [AJV](https://ajv.js.org/)-compatible JSON Schema objects from your Prisma schema
17
+
18
+ ### ORM / Schema Generation (Multi-Language)
19
+
15
20
  - ๐Ÿ—„๏ธ Automatically generates [Drizzle ORM](https://orm.drizzle.team/) table schemas and relations from your Prisma schema
21
+ - ๐Ÿ Automatically generates [SQLAlchemy](https://www.sqlalchemy.org/) models (Python) โ€” with `Mapped[T]` type hints, relationships, enums, composite keys, and index support
22
+ - ๐Ÿน Automatically generates [GORM](https://gorm.io/) models (Go) โ€” with struct tags, JSON tags, relationships, enums, composite keys, and index support
23
+ - ๐Ÿฆ€ Automatically generates [Sea-ORM](https://www.sea-ql.org/SeaORM/) entities (Rust) โ€” with `DeriveEntityModel`, relations, enums, serde support, and `rename_all`
24
+ - ๐Ÿงช Generates [Ecto](https://hexdocs.pm/ecto/Ecto.Schema.html) schemas (Elixir) โ€” with associations (`belongs_to`, `has_many`, `has_one`), composite primary keys, `@type t` typespecs, array fields, `@@map`/`@map` support, and `@moduledoc`
25
+
26
+ ### Diagrams & Documentation
27
+
16
28
  - ๐Ÿ“Š Creates [Mermaid](https://mermaid.js.org/) ER diagrams with PK/FK markers
17
29
  - ๐Ÿ“ Generates [DBML](https://dbml.dbdiagram.io/) (Database Markup Language) files and **PNG** ER diagrams via [dbml-renderer](https://github.com/softwaretechnik-berlin/dbml-renderer) โ€” output format is determined by the file extension (`.dbml` or `.png`)
18
- - ๐Ÿงช Generates [Ecto](https://hexdocs.pm/ecto/Ecto.Schema.html) schemas for Elixir projects โ€” with associations (`belongs_to`, `has_many`, `has_one`), composite primary keys, `@type t` typespecs, array fields, `@@map`/`@map` support, and `@moduledoc`
19
30
 
20
31
  ## Installation
21
32
 
@@ -82,6 +93,23 @@ generator Hekireki-Drizzle {
82
93
  provider = "hekireki-drizzle"
83
94
  }
84
95
 
96
+ generator Hekireki-SQLAlchemy {
97
+ provider = "hekireki-sqlalchemy"
98
+ output = "./sqlalchemy"
99
+ }
100
+
101
+ generator Hekireki-GORM {
102
+ provider = "hekireki-gorm"
103
+ output = "./gorm"
104
+ package = "model"
105
+ }
106
+
107
+ generator Hekireki-SeaORM {
108
+ provider = "hekireki-sea-orm"
109
+ output = "./sea_orm"
110
+ renameAll = "camelCase"
111
+ }
112
+
85
113
  generator Hekireki-Ecto {
86
114
  provider = "hekireki-ecto"
87
115
  output = "./ecto"
@@ -520,6 +548,91 @@ defmodule DBSchema.Post do
520
548
  end
521
549
  ```
522
550
 
551
+ ### SQLAlchemy
552
+
553
+ ```python
554
+ from sqlalchemy import ForeignKey
555
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
556
+
557
+
558
+ class Base(DeclarativeBase):
559
+ pass
560
+
561
+
562
+ class User(Base):
563
+ __tablename__ = "user"
564
+
565
+ id: Mapped[str] = mapped_column(primary_key=True)
566
+ name: Mapped[str]
567
+
568
+ posts: Mapped[list["Post"]] = relationship(back_populates="user")
569
+
570
+
571
+ class Post(Base):
572
+ __tablename__ = "post"
573
+
574
+ id: Mapped[str] = mapped_column(primary_key=True)
575
+ title: Mapped[str]
576
+ content: Mapped[str]
577
+ user_id: Mapped[str] = mapped_column(ForeignKey("user.id"))
578
+
579
+ user: Mapped["User"] = relationship(back_populates="posts")
580
+ ```
581
+
582
+ ### GORM
583
+
584
+ ```go
585
+ package model
586
+
587
+ type User struct {
588
+ ID string `gorm:"column:id;primaryKey;type:char(36)" json:"id"`
589
+ Name string `gorm:"column:name;not null" json:"name"`
590
+ Posts []Post `gorm:"foreignKey:UserID"`
591
+ }
592
+
593
+ type Post struct {
594
+ ID string `gorm:"column:id;primaryKey;type:char(36)" json:"id"`
595
+ Title string `gorm:"column:title;not null" json:"title"`
596
+ Content string `gorm:"column:content;not null" json:"content"`
597
+ UserID string `gorm:"column:user_id;not null" json:"user_id"`
598
+ User User
599
+ }
600
+ ```
601
+
602
+ ### Sea-ORM
603
+
604
+ Each model is output as a separate `.rs` file with `mod.rs` and `prelude.rs`, following Sea-ORM conventions.
605
+
606
+ **user.rs:**
607
+
608
+ ```rust
609
+ use sea_orm::entity::prelude::*;
610
+ use serde::{Deserialize, Serialize};
611
+
612
+ #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
613
+ #[serde(rename_all = "camelCase")]
614
+ #[sea_orm(table_name = "user")]
615
+ pub struct Model {
616
+ #[sea_orm(primary_key, auto_increment = false)]
617
+ pub id: String,
618
+ pub name: String,
619
+ }
620
+
621
+ #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
622
+ pub enum Relation {
623
+ #[sea_orm(has_many = "super::post::Entity")]
624
+ Posts,
625
+ }
626
+
627
+ impl Related<super::post::Entity> for Entity {
628
+ fn to() -> RelationDef {
629
+ Relation::Posts.def()
630
+ }
631
+ }
632
+
633
+ impl ActiveModelBehavior for ActiveModel {}
634
+ ```
635
+
523
636
  ### DBML
524
637
 
525
638
  ```dbml
@@ -634,7 +747,27 @@ generator Hekireki-ER {
634
747
  output = "./mermaid-er" // Output path (default: ./mermaid-er/ER.md)
635
748
  }
636
749
 
637
- // Ecto Generator
750
+ // SQLAlchemy Generator (Python)
751
+ generator Hekireki-SQLAlchemy {
752
+ provider = "hekireki-sqlalchemy"
753
+ output = "./sqlalchemy" // Output path (default: ./sqlalchemy/models.py)
754
+ }
755
+
756
+ // GORM Generator (Go)
757
+ generator Hekireki-GORM {
758
+ provider = "hekireki-gorm"
759
+ output = "./gorm" // Output path (default: ./gorm/models.go)
760
+ package = "model" // Go package name (default: model)
761
+ }
762
+
763
+ // Sea-ORM Generator (Rust)
764
+ generator Hekireki-SeaORM {
765
+ provider = "hekireki-sea-orm"
766
+ output = "./sea_orm" // Output directory for .rs files
767
+ renameAll = "camelCase" // #[serde(rename_all = "...")] attribute (optional)
768
+ }
769
+
770
+ // Ecto Generator (Elixir)
638
771
  generator Hekireki-Ecto {
639
772
  provider = "hekireki-ecto"
640
773
  output = "./ecto" // Output directory (default: ./ecto/)
@@ -0,0 +1,6 @@
1
+ import { GeneratorOptions } from "@prisma/generator-helper";
2
+
3
+ //#region src/generator/gorm/index.d.ts
4
+ declare function main(options: GeneratorOptions): Promise<void>;
5
+ //#endregion
6
+ export { main };
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env node
2
+ import { d as mkdir, f as writeFile, n as getString, o as makeSnakeCase } from "../../utils-COHZyQue.js";
3
+ import path, { dirname } from "node:path";
4
+ import pkg from "@prisma/generator-helper";
5
+
6
+ //#region src/helper/gorm.ts
7
+ const PRISMA_TO_GO = {
8
+ String: "string",
9
+ Int: "int",
10
+ BigInt: "int64",
11
+ Float: "float64",
12
+ Decimal: "float64",
13
+ Boolean: "bool",
14
+ DateTime: "time.Time",
15
+ Json: "datatypes.JSON",
16
+ Bytes: "[]byte"
17
+ };
18
+ function prismaTypeToGoType(type, isRequired) {
19
+ const base = PRISMA_TO_GO[type] ?? "string";
20
+ if (!isRequired && base !== "[]byte" && base !== "datatypes.JSON") return `*${base}`;
21
+ return base;
22
+ }
23
+ function resolveNativeType(field) {
24
+ if (!field.nativeType) return null;
25
+ const [nativeName, nativeArgs] = field.nativeType;
26
+ const args = nativeArgs ?? [];
27
+ switch (nativeName) {
28
+ case "VarChar":
29
+ case "Char": return args.length > 0 ? `varchar(${args[0]})` : null;
30
+ case "Text":
31
+ case "MediumText":
32
+ case "LongText":
33
+ case "TinyText": return "text";
34
+ case "SmallInt":
35
+ case "TinyInt": return "smallint";
36
+ case "MediumInt": return "mediumint";
37
+ case "DoublePrecision":
38
+ case "Double":
39
+ case "Real": return "double precision";
40
+ case "Decimal":
41
+ case "Money": return args.length >= 2 ? `decimal(${args[0]},${args[1]})` : "decimal";
42
+ case "Uuid": return "char(36)";
43
+ case "Timestamp":
44
+ case "Timestamptz": return "timestamp";
45
+ case "Date": return "date";
46
+ case "Time":
47
+ case "Timetz": return "time";
48
+ case "JsonB": return "jsonb";
49
+ case "Xml": return "xml";
50
+ default: return null;
51
+ }
52
+ }
53
+ function getAssociations(model, allModels) {
54
+ const belongsTo = [];
55
+ const hasMany = [];
56
+ const hasOne = [];
57
+ const manyToMany = [];
58
+ for (const field of model.fields) {
59
+ if (field.kind !== "object") continue;
60
+ if (field.relationFromFields && field.relationFromFields.length > 0) belongsTo.push({
61
+ name: field.name,
62
+ targetModel: field.type,
63
+ foreignKey: field.relationFromFields[0],
64
+ references: field.relationToFields?.[0] ?? "id"
65
+ });
66
+ else if (field.isList) {
67
+ const targetModel = allModels.find((m) => m.name === field.type);
68
+ if (!targetModel) continue;
69
+ if (targetModel.fields.find((f) => f.relationName === field.relationName && f.kind === "object")?.isList) manyToMany.push({
70
+ name: field.name,
71
+ targetModel: field.type,
72
+ relationName: field.relationName ?? `${model.name}To${field.type}`
73
+ });
74
+ else {
75
+ const fkField = targetModel.fields.find((f) => f.relationName === field.relationName && f.relationFromFields && f.relationFromFields.length > 0);
76
+ const foreignKey = fkField?.relationFromFields?.[0];
77
+ if (!foreignKey) continue;
78
+ const references = fkField?.relationToFields?.[0] ?? "id";
79
+ hasMany.push({
80
+ name: field.name,
81
+ targetModel: field.type,
82
+ foreignKey,
83
+ references,
84
+ isList: true
85
+ });
86
+ }
87
+ } else {
88
+ const targetModel = allModels.find((m) => m.name === field.type);
89
+ if (!targetModel) continue;
90
+ const fkField = targetModel.fields.find((f) => f.relationName === field.relationName && f.relationFromFields && f.relationFromFields.length > 0);
91
+ const foreignKey = fkField?.relationFromFields?.[0];
92
+ if (!foreignKey) continue;
93
+ const references = fkField?.relationToFields?.[0] ?? "id";
94
+ hasOne.push({
95
+ name: field.name,
96
+ targetModel: field.type,
97
+ foreignKey,
98
+ references,
99
+ isList: false
100
+ });
101
+ }
102
+ }
103
+ return {
104
+ belongsTo,
105
+ hasMany,
106
+ hasOne,
107
+ manyToMany
108
+ };
109
+ }
110
+ function isFunctionDefault(def) {
111
+ return def !== null && typeof def === "object" && "name" in def;
112
+ }
113
+ function isAutoincrement(field) {
114
+ return isFunctionDefault(field.default) && field.default.name === "autoincrement";
115
+ }
116
+ function formatGoDefault(def) {
117
+ if (def === void 0 || def === null) return null;
118
+ if (typeof def === "boolean") return def ? "true" : "false";
119
+ if (typeof def === "number") return String(def);
120
+ if (typeof def === "string") return def;
121
+ return null;
122
+ }
123
+ function buildGormTags(field, isPk, isCompositePk, compositeIndexTags) {
124
+ const columnName = field.dbName ?? makeSnakeCase(field.name);
125
+ const parts = [`column:${columnName}`];
126
+ if (isPk) {
127
+ parts.push("primaryKey");
128
+ if (isAutoincrement(field)) parts.push("autoIncrement");
129
+ if (isFunctionDefault(field.default) && field.default.name === "uuid") parts.push("type:char(36)");
130
+ }
131
+ if (field.isUnique) parts.push("uniqueIndex");
132
+ for (const tag of compositeIndexTags) parts.push(tag);
133
+ const nativeType = resolveNativeType(field);
134
+ if (nativeType && !isPk) parts.push(`type:${nativeType}`);
135
+ else if (nativeType && isPk && !isFunctionDefault(field.default)) parts.push(`type:${nativeType}`);
136
+ else if (nativeType && isPk && isFunctionDefault(field.default) && field.default.name !== "uuid") parts.push(`type:${nativeType}`);
137
+ if (!isPk || isCompositePk) if (field.type === "DateTime" && isFunctionDefault(field.default) && field.default.name === "now") parts.push("autoCreateTime");
138
+ else if (field.isUpdatedAt) {} else {
139
+ const defaultVal = formatGoDefault(field.default);
140
+ if (defaultVal !== null) parts.push(`default:${defaultVal}`);
141
+ }
142
+ else if (isPk && !isCompositePk) {
143
+ if (field.type === "DateTime" && isFunctionDefault(field.default) && field.default.name === "now") parts.push("autoCreateTime");
144
+ }
145
+ if (field.isUpdatedAt) parts.push("autoUpdateTime");
146
+ if (field.isRequired && !isPk) parts.push("not null");
147
+ return `\`gorm:"${parts.join(";")}" json:"${columnName}"\``;
148
+ }
149
+ function collectCompositeIndexTags(model, indexes) {
150
+ const tagMap = /* @__PURE__ */ new Map();
151
+ const addTag = (fieldName, tag) => {
152
+ const existing = tagMap.get(fieldName) ?? [];
153
+ existing.push(tag);
154
+ tagMap.set(fieldName, existing);
155
+ };
156
+ for (const fields of model.uniqueFields) {
157
+ if (fields.length <= 1) continue;
158
+ const idxName = `idx_${fields.map((f) => {
159
+ return model.fields.find((mf) => mf.name === f)?.dbName ?? makeSnakeCase(f);
160
+ }).join("_")}_unique`;
161
+ for (const f of fields) addTag(f, `uniqueIndex:${idxName}`);
162
+ }
163
+ for (const idx of indexes) {
164
+ if (idx.model !== model.name) continue;
165
+ if (idx.type !== "normal" && idx.type !== "fulltext") continue;
166
+ const idxName = idx.dbName ?? idx.name ?? `idx_${idx.fields.map((f) => makeSnakeCase(f.name)).join("_")}`;
167
+ for (const f of idx.fields) addTag(f.name, `index:${idxName}`);
168
+ }
169
+ return tagMap;
170
+ }
171
+ const GO_INITIALISMS = new Set([
172
+ "acl",
173
+ "api",
174
+ "ascii",
175
+ "cpu",
176
+ "css",
177
+ "dns",
178
+ "eof",
179
+ "guid",
180
+ "html",
181
+ "http",
182
+ "https",
183
+ "id",
184
+ "ip",
185
+ "json",
186
+ "lhs",
187
+ "qps",
188
+ "ram",
189
+ "rhs",
190
+ "rpc",
191
+ "sla",
192
+ "smtp",
193
+ "sql",
194
+ "ssh",
195
+ "tcp",
196
+ "tls",
197
+ "ttl",
198
+ "udp",
199
+ "ui",
200
+ "uid",
201
+ "uri",
202
+ "url",
203
+ "utf8",
204
+ "uuid",
205
+ "vm",
206
+ "xml",
207
+ "xmpp",
208
+ "xsrf",
209
+ "xss"
210
+ ]);
211
+ /**
212
+ * Split a camelCase/PascalCase name into words, applying Go initialism rules.
213
+ * e.g. "userId" -> ["User", "ID"], "avatarUrl" -> ["Avatar", "URL"],
214
+ * "ipAddress" -> ["IP", "Address"], "createdAt" -> ["Created", "At"]
215
+ */
216
+ function splitGoWords(name) {
217
+ const parts = name.replace(/([a-z0-9])([A-Z])/g, "$1\0$2").split("\0");
218
+ const result = [];
219
+ let i = 0;
220
+ while (i < parts.length) {
221
+ const lower = parts[i].toLowerCase();
222
+ if (GO_INITIALISMS.has(lower)) {
223
+ result.push(lower.toUpperCase());
224
+ i++;
225
+ continue;
226
+ }
227
+ result.push(parts[i].charAt(0).toUpperCase() + parts[i].slice(1));
228
+ i++;
229
+ }
230
+ return result;
231
+ }
232
+ function goFieldName(name) {
233
+ return splitGoWords(name).join("");
234
+ }
235
+ function generateStructField(field, isPk, isCompositePk, compositeIndexTags, _enumNames) {
236
+ const fieldName = goFieldName(field.name);
237
+ let goType;
238
+ if (field.kind === "enum") goType = field.isRequired ? "string" : "*string";
239
+ else goType = prismaTypeToGoType(field.type, field.isRequired);
240
+ const tag = buildGormTags(field, isPk, isCompositePk, compositeIndexTags);
241
+ const tagStr = tag ? ` ${tag}` : "";
242
+ return `\t${fieldName} ${goType}${tagStr}`;
243
+ }
244
+ function needsReferencesTag(references) {
245
+ return references !== "id";
246
+ }
247
+ function buildRelationTag(parts) {
248
+ return `\`gorm:"${parts.join(";")}"\``;
249
+ }
250
+ function generateRelationFields(model, associations) {
251
+ const lines = [];
252
+ for (const assoc of associations.belongsTo) {
253
+ const fieldName = goFieldName(assoc.name);
254
+ const fkFieldName = goFieldName(assoc.foreignKey);
255
+ const refsFieldName = goFieldName(assoc.references);
256
+ const isAmbiguous = fieldName !== assoc.targetModel || associations.belongsTo.filter((a) => a.targetModel === assoc.targetModel).length > 1;
257
+ const tagParts = [];
258
+ if (isAmbiguous) tagParts.push(`foreignKey:${fkFieldName}`);
259
+ if (needsReferencesTag(assoc.references)) tagParts.push(`references:${refsFieldName}`);
260
+ if (tagParts.length > 0) lines.push(`\t${fieldName} ${assoc.targetModel} ${buildRelationTag(tagParts)}`);
261
+ else lines.push(`\t${fieldName} ${assoc.targetModel}`);
262
+ }
263
+ for (const assoc of associations.hasMany) {
264
+ const tagParts = [`foreignKey:${goFieldName(assoc.foreignKey)}`];
265
+ if (needsReferencesTag(assoc.references)) tagParts.push(`references:${goFieldName(assoc.references)}`);
266
+ lines.push(`\t${goFieldName(assoc.name)} []${assoc.targetModel} ${buildRelationTag(tagParts)}`);
267
+ }
268
+ for (const assoc of associations.hasOne) {
269
+ const tagParts = [`foreignKey:${goFieldName(assoc.foreignKey)}`];
270
+ if (needsReferencesTag(assoc.references)) tagParts.push(`references:${goFieldName(assoc.references)}`);
271
+ lines.push(`\t${goFieldName(assoc.name)} ${assoc.targetModel} ${buildRelationTag(tagParts)}`);
272
+ }
273
+ for (const assoc of associations.manyToMany) {
274
+ const [leftName, rightName] = model.name < assoc.targetModel ? [model.name, assoc.targetModel] : [assoc.targetModel, model.name];
275
+ const joinTable = `_${leftName}To${rightName}`;
276
+ lines.push(`\t${goFieldName(assoc.name)} []${assoc.targetModel} \`gorm:"many2many:${joinTable};"\``);
277
+ }
278
+ return lines;
279
+ }
280
+ function generateModelStruct(model, allModels, enums, indexes) {
281
+ const idField = model.fields.find((f) => f.isId);
282
+ const compositePkFieldNames = new Set(model.primaryKey?.fields ?? []);
283
+ const isCompositePk = !idField && compositePkFieldNames.size > 0;
284
+ if (!(idField || isCompositePk)) return null;
285
+ const associations = getAssociations(model, allModels);
286
+ const enumNames = new Set((enums ?? []).map((e) => e.name));
287
+ const compositeTagMap = collectCompositeIndexTags(model, indexes);
288
+ const tableName = model.dbName ?? makeSnakeCase(model.name);
289
+ const fieldLines = model.fields.filter((f) => f.kind !== "object").map((field) => {
290
+ return generateStructField(field, field.isId || compositePkFieldNames.has(field.name), isCompositePk, compositeTagMap.get(field.name) ?? [], enumNames);
291
+ });
292
+ const relationLines = generateRelationFields(model, associations);
293
+ const lines = [
294
+ `type ${model.name} struct {`,
295
+ ...fieldLines,
296
+ ...relationLines.length > 0 ? relationLines : [],
297
+ "}"
298
+ ];
299
+ if (tableName !== makeSnakeCase(model.name)) {
300
+ lines.push("");
301
+ lines.push(`func (${model.name}) TableName() string {`);
302
+ lines.push(`\treturn "${tableName}"`);
303
+ lines.push("}");
304
+ }
305
+ return lines.join("\n");
306
+ }
307
+ function collectImports(models) {
308
+ const imports = [];
309
+ const needsTime = models.some((m) => m.fields.some((f) => f.kind !== "object" && f.type === "DateTime"));
310
+ const needsDatatypes = models.some((m) => m.fields.some((f) => f.kind !== "object" && f.type === "Json"));
311
+ if (needsTime) imports.push("\"time\"");
312
+ if (needsDatatypes) imports.push("\"gorm.io/datatypes\"");
313
+ return imports;
314
+ }
315
+ function generateGormModels(models, enums, indexes, packageName = "model") {
316
+ const idx = indexes ?? [];
317
+ const modelBodies = models.map((model) => generateModelStruct(model, models, enums, idx)).filter((body) => body !== null);
318
+ const imports = collectImports(models);
319
+ const lines = [`package ${packageName}`];
320
+ if (imports.length > 0) {
321
+ lines.push("");
322
+ if (imports.length === 1) lines.push(`import ${imports[0]}`);
323
+ else {
324
+ lines.push("import (");
325
+ for (const imp of imports) lines.push(`\t${imp}`);
326
+ lines.push(")");
327
+ }
328
+ }
329
+ lines.push("");
330
+ lines.push(modelBodies.join("\n\n"));
331
+ lines.push("");
332
+ return lines.join("\n");
333
+ }
334
+ async function writeGormFile(models, outPath, enums, indexes, packageName = "model") {
335
+ const mkdirResult = await mkdir(dirname(outPath));
336
+ if (!mkdirResult.ok) return mkdirResult;
337
+ const writeResult = await writeFile(outPath, generateGormModels(models, enums, indexes, packageName));
338
+ if (!writeResult.ok) return writeResult;
339
+ console.log(`wrote ${outPath}`);
340
+ return {
341
+ ok: true,
342
+ value: void 0
343
+ };
344
+ }
345
+
346
+ //#endregion
347
+ //#region src/generator/gorm/index.ts
348
+ const { generatorHandler } = pkg;
349
+ async function main(options) {
350
+ if (!(options.generator.isCustomOutput && options.generator.output?.value)) throw new Error("output is required for Hekireki-GORM. Please specify output in your generator config.");
351
+ const output = options.generator.output.value;
352
+ const resolved = path.extname(output) ? output : path.join(output, "models.go");
353
+ const packageName = getString(options.generator.config.package, "model");
354
+ const enums = options.dmmf.datamodel.enums;
355
+ const indexes = options.dmmf.datamodel.indexes;
356
+ const result = await writeGormFile(options.dmmf.datamodel.models, resolved, enums, indexes, packageName);
357
+ if (!result.ok) throw new Error(`Failed to write GORM models: ${result.error}`);
358
+ }
359
+ generatorHandler({
360
+ onManifest() {
361
+ return {
362
+ defaultOutput: ".",
363
+ prettyName: "Hekireki-GORM"
364
+ };
365
+ },
366
+ onGenerate: main
367
+ });
368
+
369
+ //#endregion
370
+ export { main };
@@ -0,0 +1,6 @@
1
+ import { GeneratorOptions } from "@prisma/generator-helper";
2
+
3
+ //#region src/generator/sea-orm/index.d.ts
4
+ declare function main(options: GeneratorOptions): Promise<void>;
5
+ //#endregion
6
+ export { main };