prisma-laravel-migrate 3.0.4 → 3.0.6

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
@@ -1,8 +1,12 @@
1
1
  # Prisma Laravel Migrate
2
2
 
3
- A generator plugin that translates your **Prisma schema** into Laravel‑ready
4
- **Database Migrations**, **Eloquent Models**, and **Enum classes**.
5
- Built in strict TypeScript with fully‑customisable stubs, grouping, and smart merge updates.
3
+ A generator plugin that translates your **Prisma schema** into Laravel‑ready
4
+
5
+ * **Database Migrations**
6
+ * **Eloquent Models & PHP Enums**
7
+ * **TypeScript model & enum types**
8
+
9
+ Built in strict TypeScript with fully‑customisable stubs, grouping, smart merge updates, and an optional TS types generator.
6
10
 
7
11
  ---
8
12
 
@@ -14,7 +18,8 @@ npm install prisma-laravel-migrate --save-dev
14
18
  ```
15
19
 
16
20
  ---
17
- 🛠️ Configuration layers
21
+
22
+ ## 🛠️ Configuration layers
18
23
 
19
24
  The generators read options in **three tiers (highest → lowest)**:
20
25
 
@@ -43,54 +48,97 @@ module.exports = {
43
48
  output: {
44
49
  migrations: "database/migrations",
45
50
  models: "app/Models",
46
- enums: "app/Enums"
51
+ enums: "app/Enums",
47
52
  },
48
53
 
49
54
  /* -- per‑generator overrides ------------------------ */
50
55
  migrate: {
51
56
  groups: "./prisma/migrate-groups.js",
52
- rules : "./prisma/custom-rules.js"
57
+ rules : "./prisma/custom-rules.js",
53
58
  },
54
59
 
55
60
  modeler: {
56
61
  groups: [
57
- { stubFile: "audit.stub", tables: ["logs","audit_trails"] }
62
+ { stubFile: "audit.stub", tables: ["logs","audit_trails"] },
58
63
  ],
59
64
  outputEnumDir: "app/Enums",
60
65
  overwriteExisting: true,
61
- allowedPivotExtraFields: ["scope"]
62
- }
66
+ allowedPivotExtraFields: ["scope"],
67
+ // use awobaz/compoships for multi-column relations
68
+ awobaz: true,
69
+ },
70
+
71
+ /**
72
+ * NEW: TypeScript generator (models + enums → TS types)
73
+ */
74
+ types: {
75
+ // Where generated TS goes (default: "resources/ts/prisma")
76
+ outputDir: "resources/ts/prisma",
77
+
78
+ // Emit .d.ts instead of .ts when true
79
+ declaration: false,
80
+
81
+ // "interface" | "type" for model declarations
82
+ shape: "interface",
83
+
84
+ // Optional module wrapper for the main types file
85
+ // declare module "database/prisma" { ... }
86
+ moduleName: "database/prisma",
87
+
88
+ // Example scalar mapping overrides
89
+ scalarMap: {
90
+ // BigInt: "bigint",
91
+ // Decimal: "string",
92
+ // Json: "unknown",
93
+ },
94
+
95
+ // If true: nullable fields become optional properties
96
+ nullableAsOptional: false,
97
+
98
+ // If true: lists become ReadonlyArray<T>
99
+ readonlyArrays: false,
100
+
101
+ // Name decoration for interfaces/types
102
+ namePrefix: "",
103
+ nameSuffix: "",
104
+ },
63
105
  };
64
106
  ```
65
107
 
66
- >`Updated! I added a new section in the canvas—“Related Generator Options (Formatting & Compoships)”—covering:
67
- prettier (per-generator): what it does, defaults, config snippets, and a typings excerpt.
68
- modeler.awobaz: what enabling Compoships changes, config example, and a reminder to composer require it.`
108
+ > There is also a small section in the codebase labelled
109
+ > **“Related Generator Options (Formatting & Compoships)”** covering:
110
+ >
111
+ > * `prettier` (per‑generator): enables formatting via Prettier for
112
+ > PHP/TS outputs during merge.
113
+ > * `modeler.awobaz`: whether to emit Compoships‑aware relationships
114
+ > (requires `awobaz/compoships` in your Laravel app).
115
+
116
+ ---
69
117
 
70
118
  <details>
71
119
  <summary>Type reference</summary>
72
120
 
73
121
  ```ts
74
122
  export interface Rule {
75
- test(
76
- def: ColumnDefinition,
77
- allDefs: ColumnDefinition[],
78
- dmmf: DMMF.Document
79
- ): boolean;
80
- render(
81
- def: ColumnDefinition,
82
- allDefs: ColumnDefinition[],
83
- dmmf: DMMF.Document
84
- ): Render;
123
+ test(
124
+ def: ColumnDefinition,
125
+ allDefs: ColumnDefinition[],
126
+ dmmf: DMMF.Document,
127
+ ): boolean;
128
+ render(
129
+ def: ColumnDefinition,
130
+ allDefs: ColumnDefinition[],
131
+ dmmf: DMMF.Document,
132
+ ): Render;
85
133
  }
86
134
 
87
135
  /* ------------------------------------------------------------
88
136
  * Re-usable stub-group description
89
137
  * ---------------------------------------------------------- */
90
138
  export interface StubGroupConfig extends FlexibleStubGroup {
91
- /** Path relative to stubDir/<type>/ (e.g. "auth.stub") */
92
- stubFile: string;
93
- tables: string[]; // ["users","accounts",…] or enum names
139
+ /** Path relative to stubDir/<type>/ (e.g. "auth.stub") */
140
+ stubFile: string;
141
+ tables: string[]; // ["users","accounts",…] or enum names
94
142
  }
95
143
 
96
144
  /**
@@ -98,20 +146,20 @@ export interface StubGroupConfig extends FlexibleStubGroup {
98
146
  * Supply EITHER `tables` *or* (`include` / `exclude` / `pattern`).
99
147
  */
100
148
  interface FlexibleStubGroup {
101
- /** Path relative to stubDir/<type>/, e.g. "auth.stub" */
102
- stubFile: string;
149
+ /** Path relative to stubDir/<type>/, e.g. "auth.stub" */
150
+ stubFile: string;
103
151
 
104
- /** Old style - explicit white-list */
105
- tables?: string[];
152
+ /** Old style - explicit white-list */
153
+ tables?: string[];
106
154
 
107
- /** New style – include list ( '*' means “all tables” ) */
108
- include?: string[] | '*';
155
+ /** New style – include list ( '*' means “all tables” ) */
156
+ include?: string[] | '*';
109
157
 
110
- /** New style – blacklist applied after include / pattern */
111
- exclude?: string[];
158
+ /** New style – blacklist applied after include / pattern */
159
+ exclude?: string[];
112
160
 
113
- /** New style – RegExp OR minimatch glob(s) */
114
- pattern?: RegExp | string | Array<RegExp | string>;
161
+ /** New style – RegExp OR minimatch glob(s) */
162
+ pattern?: RegExp | string | Array<RegExp | string>;
115
163
  }
116
164
 
117
165
 
@@ -119,81 +167,124 @@ interface FlexibleStubGroup {
119
167
  * Per-generator overrides (migration / modeler)
120
168
  * ---------------------------------------------------------- */
121
169
  export interface LaravelGeneratorConfig {
122
- tablePrefix?: string;
123
- tableSuffix?: string;
124
-
125
- /** Override stubDir only for this generator */
126
- stubDir?: string;
127
-
128
- /** Where the generated PHP goes (overrides block) */
129
- outputDir?: string;
130
-
131
- overwriteExisting?: boolean;
132
- /** Allow formatting with prettier */
133
- prettier?: boolean;
134
- /**
135
- * Stub grouping:
136
- * • string – path to a JS module exporting StubGroupConfig[]
137
- * • array – the group definitions themselves
138
- */
139
- groups?: string | StubGroupConfig[];
140
-
141
- /** Skip file emission for *this* generator only */
142
- noEmit?: boolean;
143
-
144
- /**Default namespace for local imports */
145
- namespace?: "App\\"
170
+ tablePrefix?: string;
171
+ tableSuffix?: string;
172
+
173
+ /** Override stubDir only for this generator */
174
+ stubDir?: string;
175
+
176
+ /** Where the generated PHP goes (overrides block) */
177
+ outputDir?: string;
178
+
179
+ overwriteExisting?: boolean;
180
+ /** Allow formatting with prettier */
181
+ prettier?: boolean;
182
+ /**
183
+ * Stub grouping:
184
+ * • string – path to a JS module exporting StubGroupConfig[]
185
+ * • array – the group definitions themselves
186
+ */
187
+ groups?: string | StubGroupConfig[];
188
+
189
+ /** Skip file emission for *this* generator only */
190
+ noEmit?: boolean;
191
+
192
+ /** Default namespace for local imports */
193
+ namespace?: "App\\";
146
194
  }
147
195
 
148
196
  /* ------------------------------------------------------------
149
197
  * Top-level shared config (visible to all generators)
150
198
  * ---------------------------------------------------------- */
151
199
  export interface LaravelSharedConfig {
152
- /** Table name decoration */
153
- tablePrefix?: string;
154
- tableSuffix?: string;
155
-
156
- /** Default stub root (migration/, model/, enum/) */
157
- stubDir?: string;
158
-
159
- /** Global “don’t write files” switch */
160
- noEmit?: boolean;
161
-
162
- /** Override default output folders */
163
- output?: {
164
- migrations?: string;
165
- models?: string;
166
- enums?: string;
167
- };
168
-
169
- /** Per-generator fine-tuning */
170
- migrate?: Partial<MigratorConfigOverride>;
171
- modeler?: Partial<ModelConfigOverride>;
200
+ /** Table name decoration */
201
+ tablePrefix?: string;
202
+ tableSuffix?: string;
203
+
204
+ /** Default stub root (migration/, model/, enum/, ts/) */
205
+ stubDir?: string;
206
+
207
+ /** Global “don’t write files” switch */
208
+ noEmit?: boolean;
209
+
210
+ /** Override default output folders (PHP side) */
211
+ output?: {
212
+ migrations?: string;
213
+ models?: string;
214
+ enums?: string;
215
+ };
216
+
217
+ /** Per-generator fine-tuning */
218
+ migrate?: Partial<MigratorConfigOverride>;
219
+ modeler?: Partial<ModelConfigOverride>;
220
+
221
+ /** NEW: TypeScript generator overrides */
222
+ types?: Partial<TypesConfigOverride>;
172
223
  }
173
224
 
174
225
 
175
226
  /* --- Migrator-specific extra keys ---------------------------------------- */
176
227
  export interface MigratorConfigOverride extends LaravelGeneratorConfig {
177
- /**
178
- * Custom migration rules:
179
- * • string – path to JS module exporting Rule[]
180
- * • Rule[] – rules array inline
181
- */
182
- rules?: string | Rule[];
183
- stubPath?: string;
184
- defaultMaps?: DefaultMaps
228
+ /**
229
+ * Custom migration rules:
230
+ * • string – path to JS module exporting Rule[]
231
+ * • Rule[] – rules array inline
232
+ */
233
+ rules?: string | Rule[];
234
+ stubPath?: string;
235
+ defaultMaps?: DefaultMaps;
185
236
  }
186
237
 
187
238
 
188
239
  export interface ModelConfigOverride extends LaravelGeneratorConfig {
189
- modelStubPath?: string;
190
- enumStubPath?: string;
191
- /** Extra folder for enums (modeler only) */
192
- outputEnumDir?: string;
193
- /** use awobaz/compoships */
194
- awobaz?: boolean;
195
- /** Extra fields allowed on pivot models */
196
- allowedPivotExtraFields?: string[];
240
+ modelStubPath?: string;
241
+ enumStubPath?: string;
242
+ /** Extra folder for enums (modeler only) */
243
+ outputEnumDir?: string;
244
+ /** use awobaz/compoships */
245
+ awobaz?: boolean;
246
+ /** Extra fields allowed on pivot models */
247
+ allowedPivotExtraFields?: string[];
248
+ }
249
+
250
+ /* ------------------------------------------------------------
251
+ * TypeScript generator overrides
252
+ * ---------------------------------------------------------- */
253
+ export interface TypesConfigOverride extends LaravelGeneratorConfig {
254
+ /** Where generated TS types should be written, e.g. "resources/ts/prisma" */
255
+ outputDir?: string;
256
+
257
+ /** Emit `.d.ts` declaration files instead of `.ts` source files. */
258
+ declaration?: boolean; // default: false → .ts
259
+
260
+ /** Use `interface` or `type` for model declarations. */
261
+ shape?: "interface" | "type"; // default: "interface"
262
+
263
+ /**
264
+ * Map Prisma scalar types → TypeScript types.
265
+ * Keys are Prisma scalar names ("Int", "BigInt", "Decimal", "Json", "DateTime", etc.).
266
+ */
267
+ scalarMap?: Record<string, string>;
268
+
269
+ /** If true, nullable fields become optional: `foo?: string` instead of `foo: string | null`. */
270
+ nullableAsOptional?: boolean;
271
+
272
+ /** If true, lists are emitted as `ReadonlyArray<T>` instead of `T[]`. */
273
+ readonlyArrays?: boolean;
274
+
275
+ /** Optional name decoration for generated types/interfaces. */
276
+ namePrefix?: string;
277
+ nameSuffix?: string;
278
+
279
+ /**
280
+ * Optional root module/namespace hint.
281
+ * When set, the main types file is wrapped in:
282
+ * declare module "…" { ... }
283
+ */
284
+ moduleName?: string;
285
+
286
+ /** Where models should import enums from (default: "./enums"). */
287
+ enumImportFrom?: string;
197
288
  }
198
289
  ```
199
290
 
@@ -214,35 +305,47 @@ generator migrate {
214
305
  generator modeler {
215
306
  provider = "prisma-laravel-models"
216
307
  stubDir = "./prisma/stubs"
308
+ }
309
+
310
+ // NEW: TypeScript types generator
311
+ generator types {
312
+ provider = "prisma-laravel-types"
313
+ stubDir = "./prisma/stubs"
314
+ }
217
315
  ```
218
316
 
219
317
  ### Field Reference
220
318
 
221
- | Key | Notes |
222
- | ---------------------- | --------------------------------------------------------------------------------------------------------- |
223
- | `outputDir / output` | Destination folder (`outputDir` overrides `output`). |
224
- | `outputEnumDir` | (modeler) directory for generated enum classes. |
225
- | `stubDir` | Root stub folder (`migration/`, `model/`, `enum/`). |
226
- | `tablePrefix` | String prepended to every generated **physical** table name. |
227
- | `tableSuffix` | String appended to every generated **physical** table name. |
228
- | `groups` | JS module *or* inline array that maps stub files to table groups. |
229
- | `noEmit` | If `true`, generator parses and validates but **does not write** any files (dry-run / CI mode). |
319
+ | Key | Notes | |
320
+ | -------------------- | ----------------------------------------------------------------------------------------------- | ------ |
321
+ | `outputDir / output` | Destination folder (`outputDir` overrides `output`) — PHP and TS. | |
322
+ | `outputEnumDir` | (modeler) directory for generated PHP enum classes. | |
323
+ | `stubDir` | Root stub folder (`migration/`, `model/`, `enum/`, `ts/`). | |
324
+ | `tablePrefix` | String prepended to every generated **physical** table name. | |
325
+ | `tableSuffix` | String appended to every generated **physical** table name. | |
326
+ | `groups` | JS module *or* inline array that maps stub files to table/model/enum/TS groups. | |
327
+ | `noEmit` | If `true`, generator parses and validates but **does not write** any files (dry-run / CI mode). | |
328
+ | `prettier` | Per-generator toggle for formatting (PHP or TS) before 3‑way merge. | |
329
+ | `awobaz` | (modeler) Emit Compoships‑aware relationships; requires `awobaz/compoships`. | |
330
+ | `scalarMap` | (types) Map Prisma scalars → TS type names. | |
331
+ | `nullableAsOptional` | (types) Emit `foo?: T` for nullable fields instead of `foo: T | null`. |
332
+ | `readonlyArrays` | (types) Emit `ReadonlyArray<T>` instead of `T[]`. | |
333
+ | `moduleName` | (types) Wrap main types output in `declare module "…" {}`. | |
230
334
 
231
335
  ---
232
336
 
233
-
234
337
  ## 🔀 `groups` – Stub Grouping (v2)
235
338
 
236
- A **group** links one stub file to _many_ tables (or enums).
339
+ A **group** links one stub file to *many* tables (or enums / TS variants).
237
340
  From v2 you can keep the old **`tables: [...]`** list **or** use the new, more
238
341
  expressive selectors:
239
342
 
240
- | Key | Type / Example | Meaning |
241
- |--------------|----------------------------------------|--------------------------------------------------------------|
242
- | `tables` | `["users","accounts"]` | Classic explicit list – **exact names** only |
243
- | `include` | `["audit_*","logs"]` **or** `"*"` | White‑list using globs or `'*'` (all) |
244
- | `exclude` | `["*_archive","failed_jobs"]` | Black‑list applied *after* include / pattern |
245
- | `pattern` | `/^temp_/` or `"report_*"` | `RegExp` **or** glob(s) – match if **any** hits |
343
+ | Key | Type / Example | Meaning |
344
+ | --------- | --------------------------------- | ----------------------------------------------- |
345
+ | `tables` | `["users","accounts"]` | Classic explicit list – **exact names** only |
346
+ | `include` | `["audit_*","logs"]` **or** `"*"` | White‑list using globs or `'*'` (all) |
347
+ | `exclude` | `["*_archive","failed_jobs"]` | Black‑list applied *after* include / pattern |
348
+ | `pattern` | `/^temp_/` or `"report_*"` | `RegExp` **or** glob(s) – match if **any** hits |
246
349
 
247
350
  > Only one of **`tables`** **or** the new selector trio is required.
248
351
 
@@ -264,34 +367,36 @@ module.exports = [
264
367
  // 1. legacy explicit list
265
368
  {
266
369
  stubFile: "auth.stub", // stubs/migration/auth.stub
267
- tables: ["users","accounts","password_resets"]
370
+ tables: ["users","accounts","password_resets"],
268
371
  },
269
372
 
270
373
  // 2. regex + blacklist
271
374
  {
272
375
  stubFile: "audit.stub",
273
376
  pattern : /^audit_/,
274
- exclude : ["audit_archive"]
377
+ exclude : ["audit_archive"],
275
378
  },
276
379
 
277
380
  // 3. catch‑all
278
381
  {
279
382
  stubFile: "catch-all.stub",
280
383
  include : "*",
281
- exclude : ["failed_jobs","migrations"]
282
- }
384
+ exclude : ["failed_jobs","migrations"],
385
+ },
283
386
  ];
284
387
  ```
285
388
 
286
389
  ### Resolution order
287
390
 
288
- 1. **Table‑specific** — `stubs/<type>/<table>.stub`
289
- 2. **First matching group** (objects are checked top‑to‑bottom)
391
+ 1. **Table‑specific** — `stubs/<type>/<table>.stub`
392
+ 2. **First matching group** (objects are checked top‑to‑bottom)
290
393
  3. **Default** — `stubs/<type>/index.stub`
291
394
 
292
395
  > If a group’s `stubFile` does not exist it is skipped, so you may leave unused
293
396
  > groups in place without breaking the build.
294
397
 
398
+ ---
399
+
295
400
  ## 📁 Stub Folder Layout
296
401
 
297
402
  ```text
@@ -299,21 +404,26 @@ prisma/stubs/
299
404
  ├── migration/index.stub
300
405
  ├── model/index.stub
301
406
  ├── model/simple-model.stub
302
- └── enum/index.stub
407
+ ├── enum/index.stub
408
+ └── ts/index.stub
303
409
  ```
304
410
 
305
- Add table‑specific overrides at
306
- `stubs/<type>/<table>.stub` (e.g. `stubs/model/users.stub`).
411
+ Add table‑specific overrides at
412
+ `stubs/<type>/<table>.stub` (e.g. `stubs/model/users.stub`, `stubs/ts/Account.stub`).
413
+
414
+ * `migration/` and `model/` stubs are **PHP** template literals.
415
+ * `enum/` stubs are **PHP** enum templates.
416
+ * `ts/` stubs are **JavaScript template literals** evaluated by the TS printer.
307
417
 
308
418
  ---
309
419
 
310
420
  ## 🔧 CLI Commands
311
421
 
312
- | Command | Purpose |
313
- | --- | --- |
314
- | `init` | Inject generator blocks & scaffold stub folders |
315
- | `customize` | Create per-table stub overrides |
316
- | `gen` | Run `prisma generate` then Laravel generators |
422
+ | Command | Purpose |
423
+ | ----------- | -------------------------------------------------- |
424
+ | `init` | Inject generator blocks & scaffold stubs |
425
+ | `customize` | Create per-table stub overrides |
426
+ | `gen` | Run `prisma generate` then Laravel + TS generators |
317
427
 
318
428
  ### init
319
429
 
@@ -324,15 +434,18 @@ npx prisma-laravel-cli init --schema=prisma/schema.prisma
324
434
  ### customize
325
435
 
326
436
  ```bash
327
- npx prisma-laravel-cli customize -t migration,model -n users,accounts --force
437
+ npx prisma-laravel-cli customize \
438
+ -t migration,model,ts \
439
+ -n users,accounts \
440
+ --force
328
441
  ```
329
442
 
330
- | Flag | Description |
331
- | --- | --- |
332
- | `-t, --type` | **Required.** Stub types (`migration`, `model`, `enum`). `enum` may not mix. |
333
- | `-n, --names` | **Required.** Table or enum names (`users,accounts`). |
334
- | `--force` | Overwrite existing stub files. |
335
- | `--config` | Alternate CLI config path. |
443
+ | Flag | Description |
444
+ | ------------- | ---------------------------------------------------------------------------------------------- |
445
+ | `-t, --types` | **Required.** Stub types (`migration`, `model`, `enum`, `ts`). `enum` may not mix with others. |
446
+ | `-n, --names` | **Required.** Table or enum names (`users,accounts`). |
447
+ | `--force` | Overwrite existing stub files. |
448
+ | `--config` | Alternate CLI config path. |
336
449
 
337
450
  ### gen
338
451
 
@@ -346,17 +459,22 @@ npx prisma-laravel-cli gen --config=prisma/laravel.config.js --skipGenerate
346
459
 
347
460
  ```js
348
461
  module.exports = {
349
- migrator: {
462
+ migrate: {
350
463
  outputDir: "database/migrations",
351
464
  stubDir: "prisma/stubs",
352
- groups: "./prisma/group-stubs.js"
465
+ groups: "./prisma/group-stubs.js",
353
466
  },
354
467
  modeler: {
355
468
  outputDir: "app/Models",
356
469
  outputEnumDir: "app/Enums",
357
470
  stubDir: "prisma/stubs",
358
- groups: "./prisma/group-stubs.js"
359
- }
471
+ groups: "./prisma/group-stubs.js",
472
+ },
473
+ types: {
474
+ outputDir: "resources/ts/prisma",
475
+ stubDir: "prisma/stubs",
476
+ moduleName: "database/prisma",
477
+ },
360
478
  };
361
479
  ```
362
480
 
@@ -366,56 +484,67 @@ module.exports = {
366
484
 
367
485
  1. Generator builds a **full new file** from your schema & stubs.
368
486
  2. Performs a **git‑style 3‑way merge** (using `node-diff3`):
369
- - **base** = last generator output (`.prisma-laravel/backups/...`)
370
- - **ours** = file on disk (user edits)
371
- - **theirs** = freshly generated file
372
- 3. Non‑conflicting changes merge automatically; conflicts are wrapped with
373
- `<<<<<<<`, `=======`, `>>>>>>>`.
374
- 4. New `use …;` imports are merged, duplicates skipped.
487
+
488
+ * **base** = last generator output (`.prisma-laravel/backups/...`)
489
+ * **ours** = file on disk (user edits)
490
+ * **theirs** = freshly generated file
491
+ 3. Non‑conflicting changes merge automatically; conflicts are wrapped with
492
+ `<<<<<<<`, `=======`, `>>>>>>>`.
493
+ 4. New imports are merged, duplicates skipped.
375
494
  5. Baseline copy is updated in the backups folder.
376
495
 
496
+ The same merge pipeline is used for:
497
+
498
+ * PHP migrations (`type: "migrator"` in the diff writer),
499
+ * PHP models/enums (`type: "model"`),
500
+ * TypeScript outputs (`type: "ts"`, using the `typescript` Prettier parser).
501
+
377
502
  Delete the marker block **and** set `noEmit = true` to stop updates for a file.
378
503
 
379
504
  ---
380
505
 
381
506
  ## ✨ Stub Customisation Notes
382
507
 
383
- Stubs are **JavaScript template literals**. Escape \` and \${ } if you want them literally.
508
+ Stubs are **JavaScript template literals**. Escape ` and ${ } if you want them literally.
384
509
 
385
- > **Fully custom model stubs**
510
+ > **Fully custom model stubs**
386
511
  > If you remove the `${content}` placeholder **and** the marker block, the
387
- > generator leaves the file untouched.
512
+ > generator leaves the file untouched.
388
513
  > Keep the markers if you want automated updates but customised surroundings.
389
514
 
390
515
  ---
391
516
 
392
517
  ## 📑 Default Stub Templates
393
518
 
519
+ ### PHP Enum `index.stub`
520
+
394
521
  <details>
395
- <summary>Enum <code>index.stub</code></summary>
522
+ <summary>Enum <code>index.stub</code> (PHP)</summary>
396
523
 
397
524
  ```php
398
525
  <?php
399
526
 
400
- namespace App\\Enums;
527
+ namespace App\Enums;
401
528
 
402
529
  enum ${enumDef.name}: string
403
530
  {
404
- ${enumDef.values.map(v => ` case ${v} = '${v}';`).join('\\n')}
531
+ ${enumDef.values.map(v => ` case ${v} = '${v}';`).join('\n')}
405
532
  }
406
533
  ```
407
534
 
408
535
  </details>
409
536
 
537
+ ### PHP Migration `index.stub`
538
+
410
539
  <details>
411
540
  <summary>Migration <code>index.stub</code></summary>
412
541
 
413
542
  ```php
414
543
  <?php
415
544
 
416
- use Illuminate\\Database\\Migrations\\Migration;
417
- use Illuminate\\Database\\Schema\\Blueprint;
418
- use Illuminate\\Support\\Facades\\Schema;
545
+ use Illuminate\Database\Migrations\Migration;
546
+ use Illuminate\Database\Schema\Blueprint;
547
+ use Illuminate\Support\Facades\Schema;
419
548
 
420
549
  return new class extends Migration
421
550
  {
@@ -435,9 +564,35 @@ return new class extends Migration
435
564
 
436
565
  </details>
437
566
 
567
+ ### TypeScript module `index.stub`
568
+
569
+ <details>
570
+ <summary>TS <code>ts/index.stub</code> (module-level)</summary>
571
+
572
+ ```ts
573
+ ${imports}
574
+
575
+ ${body}
576
+ ```
577
+
578
+ * `imports` → merged import block for all non-stubbed models (including enums).
579
+ * `body` → full `declare module "…" { … }` wrapper generated by the TS printer.
580
+ * `content` (exposed to the stub function) is just the inner interfaces/types
581
+ without the `declare module` wrapper, if you need it for advanced patterns.
582
+
583
+ Per-model TS stubs under `stubs/ts/<Model>.stub` receive:
584
+
585
+ ```ts
586
+ (model, imports, content, body, moduleName) => string
587
+ ```
588
+
589
+ and are free to ignore or wrap the default `body` however they like.
590
+
591
+ </details>
592
+
438
593
  ---
439
594
 
440
- ## 🏗️ Complex Model Stub Example
595
+ ## 🏗️ Complex Model Stub Example (PHP)
441
596
 
442
597
  <details>
443
598
  <summary>Expand stub</summary>
@@ -445,11 +600,11 @@ return new class extends Migration
445
600
  ```php
446
601
  <?php
447
602
 
448
- namespace App\\Models;
603
+ namespace App\Models;
449
604
 
450
605
  ${model.imports}
451
- use Illuminate\\Database\\Eloquent\\Model;
452
- use Illuminate\\Database\\Eloquent\\Relations\\{ BelongsTo, HasMany, BelongsToMany };
606
+ use Illuminate\Database\Eloquent\Model;
607
+ use Illuminate\Database\Eloquent\Relations\{ BelongsTo, HasMany, BelongsToMany };
453
608
 
454
609
  class ${model.className} extends Model
455
610
  {
@@ -457,25 +612,25 @@ class ${model.className} extends Model
457
612
 
458
613
  /* Mass Assignment */
459
614
  protected $fillable = [
460
- ${model.properties.filter(p => p.fillable).map(p => ` '${p.name}',`).join('\\n')}
615
+ ${model.properties.filter(p => p.fillable).map(p => ` '${p.name}',`).join('\n')}
461
616
  ];
462
617
  protected $guarded = [
463
- ${(model.guarded ?? []).map(n => ` '${n}',`).join('\\n')}
618
+ ${(model.guarded ?? []).map(n => ` '${n}',`).join('\n')}
464
619
  ];
465
620
 
466
621
  /* Hidden & Casts */
467
622
  protected $hidden = [
468
- ${model.properties.filter(p => p.hidden).map(p => ` '${p.name}',`).join('\\n')}
623
+ ${model.properties.filter(p => p.hidden).map(p => ` '${p.name}',`).join('\n')}
469
624
  ];
470
625
  protected $casts = [
471
- ${model.properties.filter(p => p.cast).map(p => ` '${p.name}' => '${p.cast}',`).join('\\n')}
472
- ${model.properties.filter(p => p.enumRef).map(p => ` '${p.name}' => ${p.enumRef}::class,`).join('\\n')}
626
+ ${model.properties.filter(p => p.cast).map(p => ` '${p.name}' => '${p.cast}',`).join('\n')}
627
+ ${model.properties.filter(p => p.enumRef).map(p => ` '${p.name}' => ${p.enumRef}::class,`).join('\n')}
473
628
  ];
474
629
 
475
630
  /* Interfaces metadata */
476
631
  public array $interfaces = [
477
632
  ${Object.entries(model.interfaces).map(([k,i]) =>
478
- ` '${k}' => {${i.import ? ` import: '${i.import}',` : ''} type: '${i.type}' },`).join('\\n')}
633
+ ` '${k}' => {${i.import ? ` import: '${i.import}',` : ''} type: '${i.type}' },`).join('\n')}
479
634
  ];
480
635
  // This structure is useful for packages like fumeapp/modeltyper which
481
636
  // read interface metadata to build TypeScript helpers.
@@ -483,9 +638,9 @@ ${Object.entries(model.interfaces).map(([k,i]) =>
483
638
  /* Relationships */
484
639
  ${model.relations.map(r => {
485
640
  const args = [r.modelClass, r.foreignKey ? `'${r.foreignKey}'` : '', r.localKey ? `'${r.localKey}'` : ''].filter(Boolean).join(', ');
486
- return ` public function ${r.name}(): ${r.type.charAt(0).toUpperCase()+r.type.slice(1)}\\n {\\n return $this->${r.type}(${args});\\n }`;
487
- }).join('\\n\\n')}
488
- // Or
641
+ return ` public function ${r.name}(): ${r.type.charAt(0).toUpperCase()+r.type.slice(1)}\n {\n return $this->${r.type}(${args});\n }`;
642
+ }).join('\n\n')}
643
+ // Or
489
644
  ${relationships}
490
645
 
491
646
  ${content}
@@ -506,7 +661,6 @@ protected $casts = [
506
661
 
507
662
  ---
508
663
 
509
-
510
664
  ## 🧩 Custom Migration Rules
511
665
 
512
666
  Point the generator’s `rules` field to a JS file exporting an **array** of
@@ -543,7 +697,7 @@ module.exports = [
543
697
 
544
698
  **Rule execution order**
545
699
 
546
- 1. Built‑in rules
700
+ 1. Built‑in rules
547
701
  2. Custom rules (executed in array order)
548
702
 
549
703
  ---
@@ -568,7 +722,7 @@ export interface ColumnDefinition extends DMMF.Field {
568
722
  relationship?: {
569
723
  on: string;
570
724
  references?: string[];
571
- fields: string[]
725
+ fields: string[];
572
726
  onDelete?: string;
573
727
  onUpdate?: string;
574
728
  };
@@ -586,9 +740,8 @@ def.migrationType // mapped Laravel builder name
586
740
  def.isId
587
741
  ```
588
742
 
589
- 📝 **Prisma DMMF docs:**
590
- https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md
591
-
743
+ 📝 **Prisma DMMF docs:**
744
+ [https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md](https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md)
592
745
 
593
746
  ---
594
747
 
@@ -603,6 +756,13 @@ You can attach them either:
603
756
 
604
757
  > This document focuses on the **new & updated directives** and how they interact with existing ones like `@fillable`, `@hidden`, `@guarded`, `@cast{…}`, `@type{…}`, `@with`, `@trait:…`, `@extend:…`, `@implements:…`, `@observer:…`, `@factory:…`, `@touch{…}`, `@appends{…}`.
605
758
 
759
+ The same directives are visible to the **PHP generators** (migrator + modeler)
760
+ **and** to the **TS types generator**, which uses them to:
761
+
762
+ * apply `@type{…}` overrides for TS field types/imports,
763
+ * honour `@with` when deciding whether relation properties are optional, and
764
+ * strip directive noise from generated JSDoc/docblocks.
765
+
606
766
  ---
607
767
 
608
768
  ## What’s New
@@ -615,18 +775,21 @@ You can attach them either:
615
775
 
616
776
  ## Summary of Directives
617
777
 
618
- | Directive | Scope | Purpose |
619
- | ------------------------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------- |
620
- | `@fillable` | Field **or** `@fillable{...}` on model | Adds field(s) to `$fillable`. |
621
- | `@hidden` | Field **or** `@hidden{...}` on model | Adds field(s) to `$hidden`. |
622
- | `@guarded` | Field **or** `@guarded{...}` on model | Adds field(s) to `$guarded`. |
623
- | `@cast{…}` | Field | Adds a cast to `$casts`. |
624
- | `@type{ import:'…', type:'…' }` | Field | Exposes a PHP/interface type hint for downstream tooling. |
625
- | `@with` / `@with(a,b,…)` | Field / Model | Eager-load relations via `$with`. |
626
- | `@trait:…` `@extend:…` `@implements:…` `@observer:…` `@factory:…` `@touch{…}` `@appends{…}` | Model | Class customization & extras. |
627
- | **`@local` (new)** | **Relation Field** | **Skip generating that specific relation method** on the model. Replaces `@ignore`. |
628
- | **`@silent` (new)** | **Model / Enum** | **Do not emit files** for this entity (model + migration / enum). |
629
- | **`@morph(…)` (new)** | **Model** | Declare owner-side polymorphic relations; child-side `morphTo` is auto. |
778
+ | Directive | Scope | Purpose |
779
+ | ------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------- |
780
+ | `@fillable` | Field **or** `@fillable{}` on model | Adds field(s) to `$fillable`. |
781
+ | `@hidden` | Field **or** `@hidden{}` on model | Adds field(s) to `$hidden`. |
782
+ | `@guarded` | Field **or** `@guarded{}` on model | Adds field(s) to `$guarded`. |
783
+ | `@cast{…}` | Field | Adds a cast entry to `$casts`. |
784
+ | `@type{ import:'…', type:'…' }` | Field | Exposes a PHP/interface/TS type hint for downstream tooling. |
785
+ | `@with` / `@with(a,b,…)` | Field / Model | Marks relations to eager-load via `$with` and as non‑optional in TS types. |
786
+ | `@trait:…` `@extend:…` `@implements:…` `@observer:…` `@factory:…` `@touch{…}` `@appends{…}` | Model | Class customization & extras (traits, parents, observers, factories, touches, appends). |
787
+ | `@local` | Relation Field | Skip generating that **specific relation method** on the model. Replaces `@ignore`. |
788
+ | `@silent` | Model / Enum | Do **not** emit files for this entity (model + migration / enum). |
789
+ | `@morph(…)` | Model | Declare owner-side polymorphic relations; child-side `morphTo` is auto-detected. |
790
+ | `@pivot` / `@pivot(a,b,…)` | Pivot **model** and/or scalar **fields** | Explicitly mark extra pivot columns to include in generated `withPivot(…)` chains. |
791
+ | `@withTimestamps` | Pivot **model** / relation **field** | Instructs the generator to append `->withTimestamps()` on the relation definition. |
792
+ | `@pivotAlias(name)` | Pivot **model** | Sets the pivot attribute alias; generator should add `->as('name')` on the relation. |
630
793
 
631
794
  > **Syntax options**
632
795
  > • Inline: `balance Decimal /// @fillable @cast{decimal:2}`
@@ -643,10 +806,12 @@ You can attach them either:
643
806
  > `/// @touch{company,profile}`
644
807
  > `/// @appends{full_name,age}`
645
808
 
646
- > **Note:** Directives like `@fillable`, `@hidden`, `@guarded`, `@with`, `@touch`, and `@appends` now support **all of the following syntaxes**:
647
- > - `/// @fillable{name,balance}`
648
- > - `/// @fillable(name,balance)`
649
- > - `/// @fillable: name,balance`
809
+ > **Note:** Directives like `@fillable`, `@hidden`, `@guarded`, `@with`, `@touch`, and `@appends` support **all** of the following syntaxes:
810
+ >
811
+ > * `/// @fillable{name,balance}`
812
+ > * `/// @fillable(name,balance)`
813
+ > * `/// @fillable: name,balance`
814
+
650
815
  ---
651
816
 
652
817
  ## `@local` — Skip a Single Relation Method (replaces `@ignore`)
@@ -669,7 +834,7 @@ model Account {
669
834
  }
670
835
  ```
671
836
 
672
- **Effect:** the `user()` method is *not* written to `Account.php`. If scope includes Migrator, the migration also skips generating the FK/constraint. Other methods remain unaffected.
837
+ **Effect:** the `user()` method is *not* written to `Account.php`. If scope includes Migrator, the migration also skips generating the FK/constraint. Other methods remain unaffected. TS types still include the `user?: User | null` navigation property unless you override it with `@type`.
673
838
 
674
839
  ---
675
840
 
@@ -693,11 +858,10 @@ model AuditTrail {
693
858
  }
694
859
  ```
695
860
 
696
- **Effect:** no Eloquent model and/or no migration file are emitted for `AuditTrail` depending on the scope. For enums, no PHP enum is emitted.
861
+ **Effect:** no Eloquent model and/or no migration file are emitted for `AuditTrail` depending on the scope. For enums, no PHP enum is emitted. The TS generator can still expose types for `AuditTrail` if you wish (or you can add an additional TS-side filter later).
697
862
 
698
863
  ---
699
864
 
700
-
701
865
  ## Polymorphic Relations
702
866
 
703
867
  ### Auto-Detected Child Side: `morphTo`
@@ -713,6 +877,16 @@ public function commentable()
713
877
 
714
878
  No directive is required for `morphTo`.
715
879
 
880
+ On the TS side, the generator also detects these pairs and adds a
881
+ corresponding **appended property** like:
882
+
883
+ ```ts
884
+ commentable?: any;
885
+ ```
886
+
887
+ which you can refine via `@appends{commentable: Comment}` or project‑specific
888
+ TS overrides.
889
+
716
890
  ### Owner Side via `@morph(…)`
717
891
 
718
892
  Add one or more `@morph(...)` directives to the **owner model’s** docblock to generate Laravel morph methods. Parentheses and quotes inside `raw:"…"` are supported.
@@ -755,8 +929,8 @@ model User {
755
929
  /// Owner: Video → morphToMany(Tag::class, 'taggable', 'taggables')
756
930
  /// @morph(name: taggable, type: to many, model: Tag, table:"taggables")
757
931
  model Video {
758
- id Int @id @default(autoincrement())
759
- url String
932
+ id Int @id @default(autoincrement())
933
+ url String
760
934
  }
761
935
  ```
762
936
 
@@ -806,7 +980,7 @@ model Image {
806
980
  }
807
981
  ```
808
982
 
809
- **C) Polymorphic M\:N (`morphToMany` / `morphedByMany`)**
983
+ **C) Polymorphic M:N (`morphToMany` / `morphedByMany`)**
810
984
 
811
985
  ```prisma
812
986
  /// @morph(name: taggable, type: to many, model: Tag, table: "taggables")
@@ -860,64 +1034,53 @@ model Activity {
860
1034
  }
861
1035
  ```
862
1036
 
863
-
864
-
865
- #### Other Examples
1037
+ ---
866
1038
 
867
-
1039
+ ## Other Examples
868
1040
 
869
1041
  ```prisma
870
-
871
1042
  /// @fillable{name,balance}
872
1043
  /// @hidden{secretToken}
873
1044
  model Account {
874
-   id        Int      @id @default(autoincrement())
875
-   balance   Decimal  @default(0.0) /// @cast{decimal:2}
876
-   nickname  String   /// @fillable @hidden
877
-   profile   Json?    /// @type{ import:'@types/forms', type:'ProfileDTO' }
878
-   company   Company? @relation(fields:[companyId], references:[id]) /// @local
879
-
880
-   companyId Int?
881
-   posts     Post[]   /// @with
1045
+ id Int @id @default(autoincrement())
1046
+ balance Decimal @default(0.0) /// @cast{decimal:2}
1047
+ nickname String /// @fillable @hidden
1048
+ profile Json? /// @type{ import:'@types/forms', type:'ProfileDTO' }
1049
+ company Company? @relation(fields:[companyId], references:[id]) /// @local
1050
+
1051
+ companyId Int?
1052
+ posts Post[] /// @with
882
1053
  }
883
1054
 
884
-
885
-
886
1055
  /// @with(posts,comments)
887
-
888
1056
  model User {
889
-   id       Int      @id @default(autoincrement())
890
-   email    String
891
-   posts    Post[]
892
-   comments Comment[]
1057
+ id Int @id @default(autoincrement())
1058
+ email String
1059
+ posts Post[]
1060
+ comments Comment[]
893
1061
  }
894
-
895
1062
  ```
896
1063
 
897
- **Generated output**
1064
+ **Generated (PHP, simplified)**
898
1065
 
899
1066
  ```php
900
-
901
1067
  protected $fillable = ['name','balance','nickname'];
902
- protected $hidden   = ['secretToken','nickname'];
903
- protected $casts    = ['balance' => 'decimal:2'];
1068
+ protected $hidden = ['secretToken','nickname'];
1069
+ protected $casts = ['balance' => 'decimal:2'];
904
1070
 
905
1071
  public array $interfaces = [
906
-     'profile' => { import: '@types/forms', type: 'ProfileDTO' },
1072
+ 'profile' => { import: '@types/forms', type: 'ProfileDTO' },
907
1073
  ];
908
1074
 
909
1075
  protected $with = ['posts'];
910
-
911
1076
  ```
912
1077
 
913
- `@local` prevents the `company()` relation method.  
914
-
1078
+ `@local` prevents the `company()` relation method.
915
1079
  Combine multiple inline directives; they’re processed left‑to‑right.
916
1080
 
917
- #### Example: Combined Directives
1081
+ ### Example: Combined Directives
918
1082
 
919
1083
  ```prisma
920
-
921
1084
  /// @fillable{name,balance}
922
1085
  /// @hidden{secretToken}
923
1086
  /// @guarded{password,apiToken}
@@ -929,22 +1092,20 @@ Combine multiple inline directives; they’re processed left‑to‑right.
929
1092
  /// @touch{company}
930
1093
  /// @appends{full_name}
931
1094
  model User {
932
-   id        Int      @id @default(autoincrement())
933
-   email     String   @unique                      /// @hidden @fillable
934
-   password  String                                 /// @hidden @guarded
935
-   balance   Decimal @default(0.0) /// @cast{decimal:2}
936
-   profile   Json?    /// @type{ import:'@types/forms', type:'ProfileDTO' }
937
-   company   Company? @relation(fields:[companyId], references:[id]) /// @local
938
-   companyId Int?
939
-   posts     Post[]   /// @with
1095
+ id Int @id @default(autoincrement())
1096
+ email String @unique /// @hidden @fillable
1097
+ password String /// @hidden @guarded
1098
+ balance Decimal @default(0.0) /// @cast{decimal:2}
1099
+ profile Json? /// @type{ import:'@types/forms', type:'ProfileDTO' }
1100
+ company Company? @relation(fields:[companyId], references:[id]) /// @local
1101
+ companyId Int?
1102
+ posts Post[] /// @with
940
1103
  }
941
-
942
1104
  ```
943
1105
 
944
1106
  **Generated output (simplified)**
945
1107
 
946
1108
  ```php
947
-
948
1109
  use Illuminate\Auth\Authenticatable;
949
1110
  use Illuminate\Auth\User;
950
1111
  use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -953,47 +1114,51 @@ use App\Observers\UserObserver;
953
1114
 
954
1115
  class User extends User implements AuthenticatableContract
955
1116
  {
956
-     use HasFactory, Authenticatable;
957
-    
958
-     protected $fillable = ['name','balance','email'];
959
-     protected $hidden   = ['secretToken','password'];
960
-     protected $guarded  = ['password','apiToken'];
961
-     protected $casts    = ['balance' => 'decimal:2'];
962
-     protected $touches  = ['company'];
963
-     protected $appends  = ['full_name'];
964
-     protected static string $factory = UserFactory::class;
965
-
966
-     protected static function boot()
967
-     {
968
-         parent::boot();
969
-         static::observe(UserObserver::class);
970
-     }
971
-
972
-     public function getFullNameAttribute()
973
-     {
974
-         return $this->attributes['full_name'] ?? null;
975
-     }
976
-
977
-     public function posts()
978
-     {
979
-         return $this->hasMany(Post::class);
980
-     }
1117
+ use HasFactory, Authenticatable;
1118
+
1119
+ protected $fillable = ['name','balance','email'];
1120
+ protected $hidden = ['secretToken','password'];
1121
+ protected $guarded = ['password','apiToken'];
1122
+ protected $casts = ['balance' => 'decimal:2'];
1123
+ protected $touches = ['company'];
1124
+ protected $appends = ['full_name'];
1125
+ protected static string $factory = UserFactory::class;
1126
+
1127
+ protected static function boot()
1128
+ {
1129
+ parent::boot();
1130
+ static::observe(UserObserver::class);
1131
+ }
1132
+
1133
+ public function getFullNameAttribute()
1134
+ {
1135
+ return $this->attributes['full_name'] ?? null;
1136
+ }
1137
+
1138
+ public function posts()
1139
+ {
1140
+ return $this->hasMany(Post::class);
1141
+ }
981
1142
  }
982
1143
  ```
983
1144
 
984
1145
  ---
1146
+
985
1147
  ## Notes & Limitations
986
1148
 
987
1149
  * `@local` is **model-method only**; it does not change the migration. Use `@silent` to suppress a whole model/enum from emission.
988
1150
  * Laravel cannot express **composite pivot keys** directly inside `belongsToMany(...)`. If your schema uses composite pivot keys, consider generating a Pivot model or using query/Compoships patterns on the one-to-many sides.
989
1151
  * The generator keeps your edits safe via merge markers; conflicts will be surfaced with `<<<<<<<` sections for manual resolution.
1152
+ * TS types are generated from the **same DMMF + directives** as PHP. You can always override a single field type with `@type{…}`.
1153
+
990
1154
  ---
991
1155
 
992
1156
  ## 💡 Tips
993
1157
 
994
- - Combine `migration` & `model` in one customize command when table names align.
995
- - Use `noEmit: true` for dry‑runs or CI validation.
996
- - Escape template chars in stub files.
1158
+ * Combine `migration` & `model` & `ts` in one `customize` command when table names align.
1159
+ * Use `noEmit: true` for dry‑runs or CI validation.
1160
+ * Escape template chars in stub files.
1161
+ * Keep your Prisma schema as the single source of truth; everything else is generated.
997
1162
 
998
1163
  ---
999
1164
 
@@ -1005,6 +1170,7 @@ Use the library directly in a script or build tool instead of the CLI.
1005
1170
  import {
1006
1171
  generateLaravelSchema,
1007
1172
  generateLaravelModels,
1173
+ generateTypesFromPrisma,
1008
1174
  sortMigrations,
1009
1175
  } from 'prisma-laravel-migrate';
1010
1176
  import { readFileSync, writeFileSync } from 'fs';
@@ -1017,22 +1183,37 @@ import { getDMMF } from '@prisma/sdk';
1017
1183
  const dmmf = await getDMMF({ datamodel });
1018
1184
 
1019
1185
  /* 2. Run generators entirely in-memory */
1020
- const migrations = generateLaravelSchema({
1186
+ const migrations = await generateLaravelSchema({
1021
1187
  dmmf,
1022
1188
  schemaPath, // ← always pass this
1023
1189
  generator : { config: {} } as any,
1024
1190
  });
1025
1191
 
1026
- const { models, enums } = generateLaravelModels({
1192
+ const { models, enums } = await generateLaravelModels({
1027
1193
  dmmf,
1028
1194
  schemaPath,
1029
1195
  generator : { config: {} } as any,
1030
1196
  });
1031
1197
 
1198
+ const tsResult = await generateTypesFromPrisma({
1199
+ dmmf: dmmf as any,
1200
+ schemaPath,
1201
+ generator: {
1202
+ config: {
1203
+ // types-specific overrides
1204
+ moduleName: 'database/prisma',
1205
+ noEmit: true,
1206
+ },
1207
+ output: { value: 'resources/ts/prisma' },
1208
+ } as any,
1209
+ });
1210
+
1032
1211
  /* 3. Inspect or write output */
1033
1212
  sortMigrations(migrations).forEach(m => {
1034
1213
  writeFileSync(`./out/${m.tableName}.php`, m.statements.join('\n'), 'utf8');
1035
1214
  });
1215
+
1216
+ // tsResult.models / tsResult.enums contain TS model/enum definitions
1036
1217
  })();
1037
1218
  ```
1038
1219
 
@@ -1058,30 +1239,34 @@ generateLaravelSchema({
1058
1239
 
1059
1240
  ### Public exports
1060
1241
 
1061
- | Export | Purpose |
1062
- | -------------------------------- | --------------------------------------------------- |
1063
- | `generateLaravelSchema` | Build migration objects (and optionally write files)|
1064
- | `generateLaravelModels` | Build model + enum definitions |
1065
- | `sortMigrations` | Topologically sort migrations by FK dependencies |
1066
- | `Rule` | Type helper for custom migration shortcuts |
1067
- | _types_ (`column-definition-types`, `laravel-config`) | Full TypeScript typings |
1242
+ | Export | Purpose |
1243
+ | ----------------------------------------------------- | ------------------------------------------------------------- |
1244
+ | `generateLaravelSchema` | Build migration objects (and optionally write files) |
1245
+ | `generateLaravelModels` | Build PHP model + enum definitions |
1246
+ | `generateTypesFromPrisma` | Build TS model + enum definitions, with stub + module support |
1247
+ | `sortMigrations` | Topologically sort migrations by FK dependencies |
1248
+ | `Rule` | Type helper for custom migration shortcuts |
1249
+ | *types* (`column-definition-types`, `laravel-config`) | Full TypeScript typings |
1068
1250
 
1069
1251
  ```ts
1070
1252
  import {
1071
1253
  ColumnDefinition,
1072
1254
  LaravelSharedConfig,
1073
1255
  MigratorConfigOverride,
1256
+ ModelConfigOverride,
1257
+ TypesConfigOverride,
1074
1258
  } from 'prisma-laravel-migrate';
1075
1259
  ```
1076
1260
 
1077
- > **Heads-up:**
1078
- > `generateLaravelSchema` and `generateLaravelModels` **write files by default**
1079
- > (honouring the `outputDir` settings).
1261
+ > **Heads-up:**
1262
+ > `generateLaravelSchema`, `generateLaravelModels`, and `generateTypesFromPrisma`
1263
+ > **write files by default** (honouring their respective `outputDir` settings).
1080
1264
  > If you only want the in-memory objects—e.g. to capture the returned
1081
- > `migrations`, `models`, or `enums` arrays—set
1265
+ > `migrations`, `models`, `enums`, or TS `models`/`enums` arrays—set
1082
1266
  > `noEmit: true` in either
1083
1267
  >
1084
1268
  > * the per-call `generator.config` object:
1269
+ >
1085
1270
  > ```ts
1086
1271
  > generateLaravelSchema({
1087
1272
  > dmmf,
@@ -1090,18 +1275,20 @@ import {
1090
1275
  > });
1091
1276
  > ```
1092
1277
  > * **or** in `prisma/laravel.config.js`:
1278
+ >
1093
1279
  > ```js
1094
1280
  > module.exports = {
1095
1281
  > migrate: { noEmit: true },
1096
1282
  > modeler: { noEmit: true },
1283
+ > types: { noEmit: true },
1097
1284
  > };
1098
1285
  > ```
1286
+ >
1099
1287
  > This prevents any files from being created or overwritten while still
1100
1288
  > returning the fully-populated data structures for custom processing.
1101
1289
 
1102
1290
  ---
1103
1291
 
1104
-
1105
1292
  # Prisma → Laravel Migration Guide
1106
1293
 
1107
1294
  This document explains **how `prisma‑laravel‑migrate` converts your Prisma schema into
@@ -1115,21 +1302,21 @@ clean, idiomatic Laravel migrations.
1115
1302
  The generator first turns every Prisma (or native) scalar into the
1116
1303
  corresponding **Laravel schema builder method**.
1117
1304
 
1118
- | Native type | Laravel method |
1119
- |-------------|----------------|
1120
- | `Text` | `text()` |
1121
- | `VarChar` | `string()` |
1122
- | `Boolean` | `boolean()` |
1123
- | `TinyInt` | `tinyInteger()` |
1305
+ | Native type | Laravel method |
1306
+ | ---------------- | ---------------------- |
1307
+ | `Text` | `text()` |
1308
+ | `VarChar` | `string()` |
1309
+ | `Boolean` | `boolean()` |
1310
+ | `TinyInt` | `tinyInteger()` |
1124
1311
  | `UnsignedBigInt` | `unsignedBigInteger()` |
1125
- | `BigInt` | `bigInteger()` |
1126
- | `Decimal` | `decimal()` |
1127
- | `Double` | `double()` |
1128
- | `DateTime` | `timestamp()` |
1129
- | `Timestamptz` | `timestampsTz()` |
1130
- | `Json` | `json()` |
1131
- | `Uuid` | `uuid()` |
1132
- | `Inet` | `ipAddress()` |
1312
+ | `BigInt` | `bigInteger()` |
1313
+ | `Decimal` | `decimal()` |
1314
+ | `Double` | `double()` |
1315
+ | `DateTime` | `timestamp()` |
1316
+ | `Timestamptz` | `timestampsTz()` |
1317
+ | `Json` | `json()` |
1318
+ | `Uuid` | `uuid()` |
1319
+ | `Inet` | `ipAddress()` |
1133
1320
 
1134
1321
  *(See source `migrationTypes.ts` for the full mapping.)*
1135
1322
 
@@ -1140,17 +1327,17 @@ corresponding **Laravel schema builder method**.
1140
1327
  After basic mapping, each column is checked against a **rule set**
1141
1328
  so that common Laravel helper methods are used instead of verbose definitions.
1142
1329
 
1143
- | Rule | Condition in Prisma | Generated code |
1144
- |------|--------------------|----------------|
1145
- | **Primary ID** | `id BigInt @id @default(autoincrement())` | `$table->id();` |
1146
- | **Timestamps** | `created_at / updated_at` pair (`DateTime` or `Timestamp`) | `$table->timestamps();` |
1147
- | **TimestampsTz** | Same pair but `DateTimeTz` / tz‑aware types | `$table->timestampsTz();` |
1148
- | **Soft‑deletes** | `deleted_at DateTime` | `$table->softDeletes();` |
1149
- | **Soft‑deletesTz** | `deleted_at DateTimeTz` | `$table->softDeletesTz();` |
1150
- | **Remember token** | `remember_token String?` | `$table->rememberToken();` |
1151
- | **`foreignId`** | `<col>_id` + `@relation(...)` | `$table->foreignId('…')->constrained();` |
1152
- | **Morphs / NullableMorphs** | `<base>_id` & `<base>_type` combo | `$table->morphs('base');` / `$table->nullableMorphs('base');` |
1153
- | **UUID / ULID Morphs** | Same but with `Uuid` / `Ulid` id column | `$table->uuidMorphs()` & friends |
1330
+ | Rule | Condition in Prisma | Generated code |
1331
+ | --------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |
1332
+ | **Primary ID** | `id BigInt @id @default(autoincrement())` | `$table->id();` |
1333
+ | **Timestamps** | `created_at / updated_at` pair (`DateTime` or `Timestamp`) | `$table->timestamps();` |
1334
+ | **TimestampsTz** | Same pair but `DateTimeTz` / tz‑aware types | `$table->timestampsTz();` |
1335
+ | **Soft‑deletes** | `deleted_at DateTime` | `$table->softDeletes();` |
1336
+ | **Soft‑deletesTz** | `deleted_at DateTimeTz` | `$table->softDeletesTz();` |
1337
+ | **Remember token** | `remember_token String?` | `$table->rememberToken();` |
1338
+ | **`foreignId`** | `<col>_id` + `@relation(...)` | `$table->foreignId('…')->constrained();` |
1339
+ | **Morphs / NullableMorphs** | `<base>_id` & `<base>_type` combo | `$table->morphs('base');` / `$table->nullableMorphs('base');` |
1340
+ | **UUID / ULID Morphs** | Same but with `Uuid` / `Ulid` id column | `$table->uuidMorphs()` & friends |
1154
1341
 
1155
1342
  If a rule fires, both columns involved are marked *ignored* so the fallback
1156
1343
  builder doesn't emit them twice.
@@ -1180,7 +1367,7 @@ Foreign‑key references (`@relation`) then add a separate `$table->foreign()` c
1180
1367
  ```prisma
1181
1368
  model Post {
1182
1369
  id Int @id @default(autoincrement()) // ➜ $table->id()
1183
- title String
1370
+ title String
1184
1371
  body Text
1185
1372
  author_id Int
1186
1373
  author User @relation(fields:[author_id], references:[id])
@@ -1223,7 +1410,9 @@ $table->softDeletes();
1223
1410
  for shortcut rules; non‑standard names fall back to the generic builder.
1224
1411
  * Remember to run migrations **after** generating to ensure FK order is correct
1225
1412
  (the tool topologically sorts tables to avoid dependency loops).
1413
+
1226
1414
  ---
1415
+
1227
1416
  ### Custom `defaultMaps` for `formatDefault`
1228
1417
 
1229
1418
  You can override the built‑in `formatDefault()` logic without forking the package by
@@ -1264,14 +1453,15 @@ module.exports = {
1264
1453
  4. Keys are matched *case‑sensitive* to the Prisma default function
1265
1454
  (`uuid`, `cuid`, `sequence`, etc.).
1266
1455
 
1267
- > **Reference** – full list of Prisma `@@default()` helpers
1268
- > <https://www.prisma.io/docs/orm/reference/prisma-schema-reference#default>
1456
+ > **Reference** – full list of Prisma `@@default()` helpers
1457
+ > [https://www.prisma.io/docs/orm/reference/prisma-schema-reference#default](https://www.prisma.io/docs/orm/reference/prisma-schema-reference#default)
1458
+
1269
1459
  ---
1270
- Happy scaffolding! 🎉
1271
1460
 
1461
+ Happy scaffolding! 🎉
1272
1462
 
1273
1463
  ---
1274
1464
 
1275
1465
  ## 📜 License
1276
1466
 
1277
- MIT — Happy scaffolding! 🎉
1467
+ MIT — Happy scaffolding! 🎉