hekireki 0.6.3 โ†’ 0.7.1

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,7 +2,7 @@
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, and Effect 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 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.
6
6
 
7
7
  ## Features
8
8
 
@@ -10,11 +10,12 @@
10
10
  - ๐Ÿค– Automatically generates [Valibot](https://valibot.dev/) schemas from your Prisma schema
11
11
  - ๐Ÿน Automatically generates [ArkType](https://arktype.io/) schemas from your Prisma schema
12
12
  - โšก Automatically generates [Effect Schema](https://effect.website/docs/schema/introduction/) from your Prisma schema
13
+ - ๐Ÿ“ฆ Automatically generates [TypeBox](https://github.com/sinclairzx81/typebox) schemas from your Prisma schema
14
+ - ๐Ÿ“‹ Automatically generates [AJV](https://ajv.js.org/)-compatible JSON Schema objects from your Prisma schema
13
15
  - ๐Ÿ—„๏ธ Automatically generates [Drizzle ORM](https://orm.drizzle.team/) table schemas and relations from your Prisma schema
14
16
  - ๐Ÿ“Š Creates [Mermaid](https://mermaid.js.org/) ER diagrams with PK/FK markers
15
17
  - ๐Ÿ“ 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`)
16
- - ๐Ÿงช Generates [Ecto](https://hexdocs.pm/ecto/Ecto.Schema.html) schemas for Elixir projects
17
- โš ๏ธ Foreign key constraints are **not** included โ€” manage relationships in your application logic
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`
18
19
 
19
20
  ## Installation
20
21
 
@@ -63,6 +64,20 @@ generator Hekireki-Effect {
63
64
  relation = true
64
65
  }
65
66
 
67
+ generator Hekireki-TypeBox {
68
+ provider = "hekireki-typebox"
69
+ type = true
70
+ comment = true
71
+ relation = true
72
+ }
73
+
74
+ generator Hekireki-AJV {
75
+ provider = "hekireki-ajv"
76
+ type = true
77
+ comment = true
78
+ relation = true
79
+ }
80
+
66
81
  generator Hekireki-Drizzle {
67
82
  provider = "hekireki-drizzle"
68
83
  }
@@ -89,12 +104,16 @@ model User {
89
104
  /// @v.pipe(v.string(), v.uuid())
90
105
  /// @a."string.uuid"
91
106
  /// @e.Schema.UUID
107
+ /// @t.Type.String({ format: 'uuid' })
108
+ /// @j.{ type: 'string' as const, format: 'uuid' as const }
92
109
  id String @id @default(uuid())
93
110
  /// Display name
94
111
  /// @z.string().min(1).max(50)
95
112
  /// @v.pipe(v.string(), v.minLength(1), v.maxLength(50))
96
113
  /// @a."1 <= string <= 50"
97
114
  /// @e.Schema.String.pipe(Schema.minLength(1), Schema.maxLength(50))
115
+ /// @t.Type.String({ minLength: 1, maxLength: 50 })
116
+ /// @j.{ type: 'string' as const, minLength: 1, maxLength: 50 }
98
117
  name String
99
118
  /// One-to-many relation to Post
100
119
  posts Post[]
@@ -106,24 +125,32 @@ model Post {
106
125
  /// @v.pipe(v.string(), v.uuid())
107
126
  /// @a."string.uuid"
108
127
  /// @e.Schema.UUID
128
+ /// @t.Type.String({ format: 'uuid' })
129
+ /// @j.{ type: 'string' as const, format: 'uuid' as const }
109
130
  id String @id @default(uuid())
110
131
  /// Article title
111
132
  /// @z.string().min(1).max(100)
112
133
  /// @v.pipe(v.string(), v.minLength(1), v.maxLength(100))
113
134
  /// @a."1 <= string <= 100"
114
135
  /// @e.Schema.String.pipe(Schema.minLength(1), Schema.maxLength(100))
136
+ /// @t.Type.String({ minLength: 1, maxLength: 100 })
137
+ /// @j.{ type: 'string' as const, minLength: 1, maxLength: 100 }
115
138
  title String
116
139
  /// Body content (no length limit)
117
140
  /// @z.string()
118
141
  /// @v.string()
119
142
  /// @a."string"
120
143
  /// @e.Schema.String
144
+ /// @t.Type.String()
145
+ /// @j.{ type: 'string' as const }
121
146
  content String
122
147
  /// Foreign key referencing User.id
123
148
  /// @z.uuid()
124
149
  /// @v.pipe(v.string(), v.uuid())
125
150
  /// @a."string.uuid"
126
151
  /// @e.Schema.UUID
152
+ /// @t.Type.String({ format: 'uuid' })
153
+ /// @j.{ type: 'string' as const, format: 'uuid' as const }
127
154
  userId String
128
155
  /// Prisma relation definition
129
156
  user User @relation(fields: [userId], references: [id])
@@ -296,6 +323,108 @@ export const PostSchema = Schema.Struct({
296
323
  export type Post = Schema.Schema.Type<typeof PostSchema>
297
324
  ```
298
325
 
326
+ ### TypeBox
327
+
328
+ ```ts
329
+ import { type Static, Type } from '@sinclair/typebox'
330
+
331
+ export const UserSchema = Type.Object({
332
+ /** Primary key */
333
+ id: Type.String({ format: 'uuid' }),
334
+ /** Display name */
335
+ name: Type.String({ minLength: 1, maxLength: 50 }),
336
+ })
337
+
338
+ export type User = Static<typeof UserSchema>
339
+
340
+ export const PostSchema = Type.Object({
341
+ /** Primary key */
342
+ id: Type.String({ format: 'uuid' }),
343
+ /** Article title */
344
+ title: Type.String({ minLength: 1, maxLength: 100 }),
345
+ /** Body content (no length limit) */
346
+ content: Type.String(),
347
+ /** Foreign key referencing User.id */
348
+ userId: Type.String({ format: 'uuid' }),
349
+ })
350
+
351
+ export type Post = Static<typeof PostSchema>
352
+
353
+ export const UserRelationsSchema = Type.Object({
354
+ ...UserSchema.properties,
355
+ posts: Type.Array(PostSchema),
356
+ })
357
+
358
+ export type UserRelations = Static<typeof UserRelationsSchema>
359
+
360
+ export const PostRelationsSchema = Type.Object({
361
+ ...PostSchema.properties,
362
+ user: UserSchema,
363
+ })
364
+
365
+ export type PostRelations = Static<typeof PostRelationsSchema>
366
+ ```
367
+
368
+ ### AJV (JSON Schema)
369
+
370
+ ```ts
371
+ import type { FromSchema } from 'json-schema-to-ts'
372
+
373
+ export const UserSchema = {
374
+ type: 'object' as const,
375
+ properties: {
376
+ /** Primary key */
377
+ id: { type: 'string' as const, format: 'uuid' as const },
378
+ /** Display name */
379
+ name: { type: 'string' as const, minLength: 1, maxLength: 50 },
380
+ },
381
+ required: ['id', 'name'] as const,
382
+ additionalProperties: false,
383
+ } as const
384
+
385
+ export type User = FromSchema<typeof UserSchema>
386
+
387
+ export const PostSchema = {
388
+ type: 'object' as const,
389
+ properties: {
390
+ /** Primary key */
391
+ id: { type: 'string' as const, format: 'uuid' as const },
392
+ /** Article title */
393
+ title: { type: 'string' as const, minLength: 1, maxLength: 100 },
394
+ /** Body content (no length limit) */
395
+ content: { type: 'string' as const },
396
+ /** Foreign key referencing User.id */
397
+ userId: { type: 'string' as const, format: 'uuid' as const },
398
+ },
399
+ required: ['id', 'title', 'content', 'userId'] as const,
400
+ additionalProperties: false,
401
+ } as const
402
+
403
+ export type Post = FromSchema<typeof PostSchema>
404
+
405
+ export const UserRelationsSchema = {
406
+ type: 'object' as const,
407
+ properties: {
408
+ ...UserSchema.properties,
409
+ posts: { type: 'array' as const, items: PostSchema },
410
+ },
411
+ additionalProperties: false,
412
+ } as const
413
+
414
+ export type UserRelations = FromSchema<typeof UserRelationsSchema>
415
+
416
+ export const PostRelationsSchema = {
417
+ type: 'object' as const,
418
+ properties: {
419
+ ...PostSchema.properties,
420
+ user: UserSchema,
421
+ },
422
+ additionalProperties: false,
423
+ } as const
424
+
425
+ export type PostRelations = FromSchema<typeof PostRelationsSchema>
426
+ ```
427
+
299
428
  ### Drizzle
300
429
 
301
430
  ```ts
@@ -344,19 +473,25 @@ erDiagram
344
473
 
345
474
  ### Ecto
346
475
 
476
+ Each model is output as a separate `.ex` file (1 model = 1 file), following Elixir conventions.
477
+
347
478
  ```elixir
348
479
  defmodule DBSchema.User do
349
480
  use Ecto.Schema
481
+ @moduledoc false
350
482
 
351
483
  @primary_key {:id, :binary_id, autogenerate: true}
484
+ @foreign_key_type :binary_id
352
485
 
353
486
  @type t :: %__MODULE__{
354
487
  id: Ecto.UUID.t(),
355
- name: String.t()
488
+ name: String.t(),
489
+ posts: [DBSchema.Post.t()]
356
490
  }
357
491
 
358
492
  schema "user" do
359
493
  field(:name, :string)
494
+ has_many(:posts, DBSchema.Post, foreign_key: :user_id)
360
495
  end
361
496
  end
362
497
  ```
@@ -364,20 +499,23 @@ end
364
499
  ```elixir
365
500
  defmodule DBSchema.Post do
366
501
  use Ecto.Schema
502
+ @moduledoc false
367
503
 
368
504
  @primary_key {:id, :binary_id, autogenerate: true}
505
+ @foreign_key_type :binary_id
369
506
 
370
507
  @type t :: %__MODULE__{
371
508
  id: Ecto.UUID.t(),
372
509
  title: String.t(),
373
510
  content: String.t(),
374
- userId: String.t()
511
+ user: DBSchema.User.t() | nil
375
512
  }
376
513
 
377
514
  schema "post" do
378
515
  field(:title, :string)
379
516
  field(:content, :string)
380
- field(:userId, :string)
517
+ field(:user_id, :binary_id, source: :userId)
518
+ belongs_to(:user, DBSchema.User, foreign_key: :user_id, define_field: false)
381
519
  end
382
520
  end
383
521
  ```
@@ -466,6 +604,24 @@ generator Hekireki-Effect {
466
604
  relation = true // Generate relation schemas (default: false)
467
605
  }
468
606
 
607
+ // TypeBox Generator
608
+ generator Hekireki-TypeBox {
609
+ provider = "hekireki-typebox"
610
+ output = "./typebox" // Output path (default: ./typebox/index.ts)
611
+ type = true // Generate TypeScript types (default: false)
612
+ comment = true // Include schema documentation (default: false)
613
+ relation = true // Generate relation schemas (default: false)
614
+ }
615
+
616
+ // AJV (JSON Schema) Generator
617
+ generator Hekireki-AJV {
618
+ provider = "hekireki-ajv"
619
+ output = "./ajv" // Output path (default: ./ajv/index.ts)
620
+ type = true // Generate TypeScript types (default: false)
621
+ comment = true // Include schema documentation (default: false)
622
+ relation = true // Generate relation schemas (default: false)
623
+ }
624
+
469
625
  // Drizzle ORM Schema Generator
470
626
  generator Hekireki-Drizzle {
471
627
  provider = "hekireki-drizzle"
@@ -0,0 +1,6 @@
1
+ import { GeneratorOptions } from "@prisma/generator-helper";
2
+
3
+ //#region src/generator/ajv/index.d.ts
4
+ declare function main(options: GeneratorOptions): Promise<void>;
5
+ //#endregion
6
+ export { main };
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ import { t as fmt } from "../../format-CzXgkLDe.js";
3
+ import { c as parseDocumentWithoutAnnotations, d as mkdir, f as writeFile, s as makeValidationExtractor, t as getBool } from "../../utils-COHZyQue.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-ChsFqlYX.js";
5
+ import path from "node:path";
6
+ import pkg from "@prisma/generator-helper";
7
+
8
+ //#region src/helper/ajv.ts
9
+ function makeAjvInfer(modelName) {
10
+ return `export type ${modelName} = FromSchema<typeof ${modelName}Schema>`;
11
+ }
12
+ function makeAjvEnumExpression(values) {
13
+ return `{ enum: [${values.map((v) => `'${v}'`).join(", ")}] as const }`;
14
+ }
15
+ const PRISMA_TO_AJV = {
16
+ String: "{ type: 'string' as const }",
17
+ Int: "{ type: 'integer' as const }",
18
+ Float: "{ type: 'number' as const }",
19
+ Boolean: "{ type: 'boolean' as const }",
20
+ DateTime: "{ type: 'string' as const, format: 'date-time' as const }",
21
+ BigInt: "{ type: 'integer' as const }",
22
+ Decimal: "{ type: 'number' as const }",
23
+ Json: "{}",
24
+ Bytes: "{ type: 'string' as const }"
25
+ };
26
+ function makeAjvSchemas(modelFields, comment) {
27
+ const modelName = modelFields[0].modelName;
28
+ const properties = modelFields.map((field) => {
29
+ return `${comment && field.comment.length > 0 ? `${field.comment.map((c) => ` /** ${c} */`).join("\n")}\n` : ""} ${field.fieldName}: ${field.validation ?? "{ type: 'unknown' as const }"},`;
30
+ }).join("\n");
31
+ const requiredFields = modelFields.filter((f) => f.isRequired).map((f) => f.fieldName);
32
+ return `export const ${modelName}Schema = {\n type: 'object' as const,\n properties: {\n${properties}\n },${requiredFields.length > 0 ? `\n required: [${requiredFields.map((f) => `'${f}'`).join(", ")}] as const,` : ""}\n additionalProperties: false,\n} as const`;
33
+ }
34
+ function makeAjvRelations(model, relProps, options) {
35
+ if (relProps.length === 0) return null;
36
+ const base = ` ...${model.name}Schema.properties,`;
37
+ const rels = relProps.map((r) => ` ${r.key}: ${r.isMany ? `{ type: 'array' as const, items: ${r.targetModel}Schema }` : `${r.targetModel}Schema`},`).join("\n");
38
+ const typeLine = options?.includeType ? `\n\nexport type ${model.name}Relations = FromSchema<typeof ${model.name}RelationsSchema>` : "";
39
+ return `export const ${model.name}RelationsSchema = {\n type: 'object' as const,\n properties: {\n${base}\n${rels}\n },\n additionalProperties: false,\n} as const${typeLine}`;
40
+ }
41
+ function ajv(models, type, comment, enums) {
42
+ return validationSchemas(models, type, comment, {
43
+ importStatement: type ? `import type { FromSchema } from 'json-schema-to-ts'` : "",
44
+ annotationPrefix: "@j.",
45
+ parseDocument: parseDocumentWithoutAnnotations,
46
+ extractValidation: makeValidationExtractor("@j."),
47
+ inferType: makeAjvInfer,
48
+ schemas: makeAjvSchemas,
49
+ typeMapping: PRISMA_TO_AJV,
50
+ enums,
51
+ formatEnum: makeAjvEnumExpression
52
+ });
53
+ }
54
+
55
+ //#endregion
56
+ //#region src/generator/ajv/index.ts
57
+ const { generatorHandler } = pkg;
58
+ async function main(options) {
59
+ if (!(options.generator.isCustomOutput && options.generator.output?.value)) throw new Error("output is required for Hekireki-AJV. Please specify output in your generator config.");
60
+ const output = options.generator.output.value;
61
+ const resolved = path.extname(output) ? {
62
+ dir: path.dirname(output),
63
+ file: output
64
+ } : {
65
+ dir: output,
66
+ file: path.join(output, "index.ts")
67
+ };
68
+ const enableRelation = getBool(options.generator.config?.relation);
69
+ const fmtResult = await fmt([ajv(options.dmmf.datamodel.models, getBool(options.generator.config?.type), getBool(options.generator.config?.comment), options.dmmf.datamodel.enums), enableRelation ? makeRelationsOnly(options.dmmf, getBool(options.generator.config?.type), makeAjvRelations) : ""].filter(Boolean).join("\n\n"));
70
+ if (!fmtResult.ok) throw new Error(`Format error: ${fmtResult.error}`);
71
+ const mkdirResult = await mkdir(resolved.dir);
72
+ if (!mkdirResult.ok) throw new Error(`Failed to create directory: ${mkdirResult.error}`);
73
+ const writeResult = await writeFile(resolved.file, fmtResult.value);
74
+ if (!writeResult.ok) throw new Error(`Failed to write file: ${writeResult.error}`);
75
+ }
76
+ generatorHandler({
77
+ onManifest() {
78
+ return {
79
+ defaultOutput: ".",
80
+ prettyName: "Hekireki-AJV"
81
+ };
82
+ },
83
+ onGenerate: main
84
+ });
85
+
86
+ //#endregion
87
+ export { main };
@@ -1,11 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-CzXgkLDe.js";
3
- import { N as mkdir, O as parseDocumentWithoutAnnotations, P as writeFile, a as getBool, d as makeArktypeProperties, f as makeArktypeSchema, j as schemaFromFields, l as makeArktypeEnumExpression, u as makeArktypeInfer, w as makeValidationExtractor } from "../../utils-bU9015ai.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-DKvlcO1B.js";
3
+ import { c as parseDocumentWithoutAnnotations, d as mkdir, f as writeFile, l as schemaFromFields, s as makeValidationExtractor, t as getBool } from "../../utils-COHZyQue.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-ChsFqlYX.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
8
8
  //#region src/helper/arktype.ts
9
+ function makeArktypeInfer(modelName) {
10
+ return `export type ${modelName} = typeof ${modelName}Schema.infer`;
11
+ }
12
+ function makeArktypeSchema(modelName, fields) {
13
+ return `export const ${modelName}Schema = type({\n${fields}\n})`;
14
+ }
15
+ function makeArktypeProperties(fields, comment) {
16
+ return fields.map((field) => {
17
+ return `${comment && field.comment.length > 0 ? `${field.comment.map((c) => ` /** ${c} */`).join("\n")}\n` : ""} ${field.fieldName}: ${field.validation ?? "\"unknown\""},`;
18
+ }).join("\n");
19
+ }
20
+ function makeArktypeEnumExpression(values) {
21
+ return `"${values.map((v) => `'${v}'`).join(" | ")}"`;
22
+ }
9
23
  const PRISMA_TO_ARKTYPE = {
10
24
  String: "\"string\"",
11
25
  Int: "\"number\"",
@@ -53,7 +67,7 @@ async function main(options) {
53
67
  dir: output,
54
68
  file: path.join(output, "index.ts")
55
69
  };
56
- const enableRelation = options.generator.config?.relation === "true" || Array.isArray(options.generator.config?.relation) && options.generator.config?.relation[0] === "true";
70
+ const enableRelation = getBool(options.generator.config?.relation);
57
71
  const fmtResult = await fmt([arktype(options.dmmf.datamodel.models, getBool(options.generator.config?.type), getBool(options.generator.config?.comment), options.dmmf.datamodel.enums), enableRelation ? makeRelationsOnly(options.dmmf, getBool(options.generator.config?.type), makeArktypeRelations) : ""].filter(Boolean).join("\n\n"));
58
72
  if (!fmtResult.ok) throw new Error(`Format error: ${fmtResult.error}`);
59
73
  const mkdirResult = await mkdir(resolved.dir);
@@ -1,11 +1,30 @@
1
1
  #!/usr/bin/env node
2
- import { F as writeFileBinary, M as stripAnnotations, N as mkdir, P as writeFile, _ as makeEnum, i as formatConstraints, o as getString, r as escapeNote, t as combineKeys, y as makeRefName } from "../../utils-bU9015ai.js";
2
+ import { d as mkdir, f as writeFile, n as getString, p as writeFileBinary, u as stripAnnotations } from "../../utils-COHZyQue.js";
3
3
  import path from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
  import { Resvg } from "@resvg/resvg-js";
6
6
  import { run } from "@softwaretechnik/dbml-renderer";
7
7
 
8
8
  //#region src/helper/dbml.ts
9
+ function escapeNote(str) {
10
+ return str.replace(/'/g, "\\'");
11
+ }
12
+ function formatConstraints(constraints) {
13
+ return constraints.length > 0 ? ` [${constraints.join(", ")}]` : "";
14
+ }
15
+ function makeEnum(enumDef) {
16
+ return [
17
+ `Enum ${enumDef.name} {`,
18
+ ...enumDef.values.map((v) => ` ${v}`),
19
+ "}"
20
+ ].join("\n");
21
+ }
22
+ function makeRefName(ref) {
23
+ return ref.name ?? `${ref.fromTable}_${ref.fromColumn}_${ref.toTable}_${ref.toColumn}_fk`;
24
+ }
25
+ function combineKeys(keys) {
26
+ return keys.length > 1 ? `(${keys.join(", ")})` : keys[0];
27
+ }
9
28
  function quote(value) {
10
29
  return `'${escapeNote(value)}'`;
11
30
  }
@@ -34,43 +53,37 @@ function makePrismaColumn(column) {
34
53
  ].filter((c) => Boolean(c));
35
54
  return ` ${column.name} ${column.type}${formatConstraints(constraints)}`;
36
55
  }
37
- function resolveFieldType(field, models, mapToDbSchema) {
38
- const baseType = mapToDbSchema ? models.find((m) => m.name === field.type)?.dbName ?? field.type : field.type;
39
- return field.isList && !field.relationName ? `${baseType}[]` : baseType;
40
- }
41
- function resolveDefaultValue(field) {
42
- const defaultDef = field.default;
43
- if (defaultDef?.name === "autoincrement") return void 0;
44
- if (defaultDef?.name === "now") return "`now()`";
45
- if (field.hasDefaultValue && typeof field.default !== "object") return field.type === "String" || field.type === "Json" || field.kind === "enum" ? `'${field.default}'` : String(field.default);
46
- }
47
56
  function toDBMLColumn(field, models, mapToDbSchema) {
48
57
  const defaultDef = field.default;
58
+ const baseType = mapToDbSchema ? models.find((m) => m.name === field.type)?.dbName ?? field.type : field.type;
59
+ const type = field.isList && !field.relationName ? `${baseType}[]` : baseType;
60
+ const defaultValue = (() => {
61
+ if (defaultDef?.name === "autoincrement") return void 0;
62
+ if (defaultDef?.name === "now") return "`now()`";
63
+ if (field.hasDefaultValue && typeof field.default !== "object") return field.type === "String" || field.type === "Json" || field.kind === "enum" ? `'${field.default}'` : String(field.default);
64
+ })();
49
65
  return {
50
66
  name: field.name,
51
- type: resolveFieldType(field, models, mapToDbSchema),
67
+ type,
52
68
  isPrimaryKey: field.isId,
53
69
  isIncrement: defaultDef?.name === "autoincrement",
54
70
  isUnique: field.isUnique,
55
71
  isNotNull: field.isRequired && !field.isId,
56
- defaultValue: resolveDefaultValue(field),
72
+ defaultValue,
57
73
  note: stripAnnotations(field.documentation)
58
74
  };
59
75
  }
60
- function makeTableIndexes(model) {
61
- return [...model.primaryKey?.fields && model.primaryKey.fields.length > 0 ? [{
62
- columns: model.primaryKey.fields,
63
- isPrimaryKey: true
64
- }] : [], ...model.uniqueFields.filter((c) => c.length > 1).map((c) => ({
65
- columns: c,
66
- isUnique: true
67
- }))];
68
- }
69
76
  function makeTables(models, mapToDbSchema = false) {
70
77
  return models.map((model) => {
71
78
  const modelName = mapToDbSchema && model.dbName ? model.dbName : model.name;
72
79
  const columnLines = model.fields.map((field) => toDBMLColumn(field, models, mapToDbSchema)).map(makePrismaColumn).join("\n");
73
- const indexes = makeTableIndexes(model);
80
+ const indexes = [...model.primaryKey?.fields && model.primaryKey.fields.length > 0 ? [{
81
+ columns: model.primaryKey.fields,
82
+ isPrimaryKey: true
83
+ }] : [], ...model.uniqueFields.filter((c) => c.length > 1).map((c) => ({
84
+ columns: c,
85
+ isUnique: true
86
+ }))];
74
87
  const indexBlock = indexes.length > 0 ? `\n\n indexes {\n${indexes.map(makeIndex).join("\n")}\n }` : "";
75
88
  const strippedNote = stripAnnotations(model.documentation);
76
89
  return `Table ${modelName} {\n${columnLines}${indexBlock}${strippedNote ? `\n\n Note: ${quote(escapeNote(strippedNote))}` : ""}\n}`;
@@ -84,14 +97,11 @@ function makeEnums(enums) {
84
97
  });
85
98
  });
86
99
  }
87
- function getRelationOperator(models, from, to) {
88
- return (models.find((m) => m.name === to)?.fields.find((f) => f.type === from))?.isList ? ">" : "-";
89
- }
90
100
  function makeRelations(models, mapToDbSchema = false) {
91
101
  return models.flatMap((model) => model.fields.filter((field) => field.relationName && field.relationToFields?.length && field.relationFromFields?.length).map((field) => {
92
102
  const relationFrom = model.name;
93
103
  const relationTo = field.type;
94
- const operator = getRelationOperator(models, relationFrom, relationTo);
104
+ const operator = (models.find((m) => m.name === relationTo)?.fields.find((f) => f.type === relationFrom))?.isList ? ">" : "-";
95
105
  const relationFromName = mapToDbSchema && model.dbName ? model.dbName : model.name;
96
106
  const relatedModel = models.find((m) => m.name === relationTo);
97
107
  const relationToName = mapToDbSchema && relatedModel?.dbName ? relatedModel.dbName : relationTo;
@@ -118,25 +128,25 @@ function dbmlContent(datamodel, mapToDbSchema = false) {
118
128
  ...refs
119
129
  ].join("\n\n");
120
130
  }
121
- const makeDbmlFile = async (outputDir, content, fileName) => {
131
+ async function makeDbmlFile(outputDir, content, fileName) {
122
132
  const writeResult = await writeFile(`${outputDir}/${fileName}`, content);
123
133
  if (!writeResult.ok) return {
124
134
  ok: false,
125
135
  error: `Failed to write DBML: ${writeResult.error}`
126
136
  };
127
137
  return { ok: true };
128
- };
129
- const makePng = async (outputDir, dbml, fileName) => {
138
+ }
139
+ async function makePng(outputDir, dbml, fileName) {
130
140
  return makePngFile(`${outputDir}/${fileName}`, dbml);
131
- };
132
- const makePngFile = async (outputPath, dbml) => {
141
+ }
142
+ async function makePngFile(outputPath, dbml) {
133
143
  const writeResult = await writeFileBinary(outputPath, new Resvg(run(dbml, "svg"), { font: { loadSystemFonts: true } }).render().asPng());
134
144
  if (!writeResult.ok) return {
135
145
  ok: false,
136
146
  error: `Failed to write PNG: ${writeResult.error}`
137
147
  };
138
148
  return { ok: true };
139
- };
149
+ }
140
150
 
141
151
  //#endregion
142
152
  //#region src/generator/dbml/index.ts
@@ -1,19 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-CzXgkLDe.js";
3
- import { N as mkdir, P as writeFile, b as makeSnakeCase } from "../../utils-bU9015ai.js";
3
+ import { d as mkdir, f as writeFile, o as makeSnakeCase } from "../../utils-COHZyQue.js";
4
4
  import path from "node:path";
5
5
  import pkg from "@prisma/generator-helper";
6
6
 
7
7
  //#region src/helper/drizzle.ts
8
- function resolveProvider(provider) {
9
- switch (provider) {
10
- case "postgresql":
11
- case "cockroachdb": return "postgresql";
12
- case "mysql": return "mysql";
13
- case "sqlite": return "sqlite";
14
- default: throw new Error(`Unsupported provider: ${provider}`);
15
- }
16
- }
17
8
  const PG_SCALAR_MAP = {
18
9
  String: "text()",
19
10
  Int: "integer()",
@@ -140,13 +131,6 @@ function toCamelCase(name) {
140
131
  function isFieldDefault(v) {
141
132
  return typeof v === "object" && v !== null && "name" in v;
142
133
  }
143
- function insertColName(expr, colName) {
144
- const parenIdx = expr.indexOf("(");
145
- if (parenIdx === -1) return expr;
146
- const fnName = expr.slice(0, parenIdx);
147
- const rest = expr.slice(parenIdx + 1);
148
- return rest === ")" ? `${fnName}('${colName}')` : `${fnName}('${colName}', ${rest}`;
149
- }
150
134
  function resolveScalarType(field, provider) {
151
135
  if (field.nativeType && provider !== "sqlite") {
152
136
  const [nativeName, nativeArgs] = field.nativeType;
@@ -179,7 +163,11 @@ function makeColumnExpr(field, provider, imports, enums) {
179
163
  const baseExpr = resolveScalarType(field, provider);
180
164
  const fnName = baseExpr.match(/^(\w+)/)?.[1];
181
165
  if (fnName) imports.addCore(fnName);
182
- return insertColName(baseExpr, colName);
166
+ const parenIdx = baseExpr.indexOf("(");
167
+ if (parenIdx === -1) return baseExpr;
168
+ const baseFnName = baseExpr.slice(0, parenIdx);
169
+ const rest = baseExpr.slice(parenIdx + 1);
170
+ return rest === ")" ? `${baseFnName}('${colName}')` : `${baseFnName}('${colName}', ${rest}`;
183
171
  }
184
172
  function makeDefaultChain(dflt, fieldType, provider, imports) {
185
173
  if (dflt === void 0 || dflt === null) return "";
@@ -228,9 +216,6 @@ function makeColumn(field, model, provider, imports, enums) {
228
216
  ].join("");
229
217
  return `${field.name}: ${colExpr}${chain}`;
230
218
  }
231
- function makeEnums() {
232
- return [];
233
- }
234
219
  function makeCompositeConstraints(model, imports, indexes) {
235
220
  const pkLine = model.primaryKey ? (() => {
236
221
  imports.addCore("primaryKey");
@@ -291,9 +276,16 @@ function makeRelations(models, imports) {
291
276
  });
292
277
  }
293
278
  function drizzleSchema(datamodel, provider, indexes) {
294
- const db = resolveProvider(provider);
279
+ const db = (() => {
280
+ switch (provider) {
281
+ case "postgresql":
282
+ case "cockroachdb": return "postgresql";
283
+ case "mysql": return "mysql";
284
+ case "sqlite": return "sqlite";
285
+ default: throw new Error(`Unsupported provider: ${provider}`);
286
+ }
287
+ })();
295
288
  const imports = new ImportTracker(db);
296
- const enumLines = makeEnums();
297
289
  const tableLines = datamodel.models.map((model) => makeTable(model, db, imports, datamodel.enums, indexes));
298
290
  const relationsLines = makeRelations(datamodel.models, imports);
299
291
  const tableLinesWithGap = tableLines.flatMap((line, i) => i < tableLines.length - 1 ? [line, ""] : [line]);
@@ -301,7 +293,6 @@ function drizzleSchema(datamodel, provider, indexes) {
301
293
  return [
302
294
  imports.generate(),
303
295
  "",
304
- ...enumLines.length > 0 ? [...enumLines, ""] : [],
305
296
  ...tableLinesWithGap,
306
297
  ...relationsLinesWithGap.length > 0 ? ["", ...relationsLinesWithGap] : []
307
298
  ].join("\n");