prisma-laravel-migrate 3.1.2 → 3.1.4
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/dist/cli/cli.js +105 -67
- package/dist/cli/migrator.index.js +25 -7
- package/dist/cli/models.index.js +33 -7
- package/dist/cli/ts.index.js +98 -46
- package/dist/index.js +81 -44
- package/package.json +1 -1
package/dist/cli/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
3
|
+
import fs7, { readFile } from 'fs/promises';
|
|
4
4
|
import path13, { resolve, extname, dirname } from 'path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
6
6
|
import fs, { existsSync, readdirSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
@@ -9,8 +9,8 @@ import { Minimatch } from 'minimatch';
|
|
|
9
9
|
import * as diff3 from 'node-diff3';
|
|
10
10
|
import * as prettier from 'prettier';
|
|
11
11
|
import * as prettierPhp from '@prettier/plugin-php';
|
|
12
|
-
import * as dmf2 from '@prisma/internals';
|
|
13
12
|
import { spawn } from 'child_process';
|
|
13
|
+
import * as dmf from '@prisma/internals';
|
|
14
14
|
|
|
15
15
|
function nearestPkgType(fromPath) {
|
|
16
16
|
try {
|
|
@@ -378,16 +378,18 @@ var listFrom = (doc, tag) => {
|
|
|
378
378
|
return cleaned;
|
|
379
379
|
};
|
|
380
380
|
var FOLDER = "prisma-laravel-migrate";
|
|
381
|
-
function getStubPath(pathString) {
|
|
381
|
+
function getStubPath(pathString, folder) {
|
|
382
382
|
const __filename = fileURLToPath(import.meta.url);
|
|
383
383
|
const __dirname = path13.dirname(__filename);
|
|
384
|
+
const __file = folder ?? FOLDER;
|
|
384
385
|
const normalised = pathString.replace(/\\/g, "/");
|
|
385
386
|
const dir = __dirname.replace(/\\/g, "/");
|
|
386
|
-
const idx = dir.lastIndexOf(
|
|
387
|
+
const idx = dir.lastIndexOf(__file);
|
|
387
388
|
if (idx === -1) {
|
|
389
|
+
if (!folder) return getStubPath(pathString, "prisma-to-laravel-migration");
|
|
388
390
|
return path13.resolve(process.cwd(), normalised);
|
|
389
391
|
}
|
|
390
|
-
const baseDir = dir.slice(0, idx +
|
|
392
|
+
const baseDir = dir.slice(0, idx + __file.length);
|
|
391
393
|
return path13.join(baseDir, "stubs", normalised);
|
|
392
394
|
}
|
|
393
395
|
|
|
@@ -2634,6 +2636,22 @@ var TsPrinter = class {
|
|
|
2634
2636
|
// ---------------------------------------------------------------------------
|
|
2635
2637
|
// IMPORTS
|
|
2636
2638
|
// ---------------------------------------------------------------------------
|
|
2639
|
+
normalizeTsImports(imports) {
|
|
2640
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2641
|
+
for (const imp of imports) {
|
|
2642
|
+
if (!imp.from) continue;
|
|
2643
|
+
const set = grouped.get(imp.from) ?? /* @__PURE__ */ new Set();
|
|
2644
|
+
for (const t of imp.types ?? []) {
|
|
2645
|
+
if (!t) continue;
|
|
2646
|
+
set.add(t);
|
|
2647
|
+
}
|
|
2648
|
+
grouped.set(imp.from, set);
|
|
2649
|
+
}
|
|
2650
|
+
return Array.from(grouped.entries()).map(([from, set]) => ({
|
|
2651
|
+
from,
|
|
2652
|
+
types: Array.from(set).sort()
|
|
2653
|
+
})).sort((a, b) => a.from.localeCompare(b.from));
|
|
2654
|
+
}
|
|
2637
2655
|
/**
|
|
2638
2656
|
* Render import statements for a node that has an `imports` property:
|
|
2639
2657
|
* node.imports?: { from: string; types: string[] }[];
|
|
@@ -2643,26 +2661,55 @@ var TsPrinter = class {
|
|
|
2643
2661
|
renderImports(node) {
|
|
2644
2662
|
const imports = node.imports ?? [];
|
|
2645
2663
|
if (!imports.length) return "";
|
|
2646
|
-
return imports.map((i) => {
|
|
2664
|
+
return this.normalizeTsImports(imports).map((i) => {
|
|
2647
2665
|
const names = i.types.join(", ");
|
|
2648
2666
|
return `import { ${names} } from ${JSON.stringify(i.from)};`;
|
|
2649
2667
|
}).join("\n");
|
|
2650
2668
|
}
|
|
2651
2669
|
/**
|
|
2652
|
-
|
|
2653
|
-
|
|
2670
|
+
* Merge & dedupe imports from multiple model contexts.
|
|
2671
|
+
*
|
|
2672
|
+
* We re-parse the per-model import lines into TsImport objects so that
|
|
2673
|
+
* `normalizeTsImports` can group everything by `from` and merge type lists.
|
|
2674
|
+
*/
|
|
2654
2675
|
collectImports(ctxs) {
|
|
2655
|
-
const
|
|
2676
|
+
const collected = [];
|
|
2677
|
+
const importRe = /^import\s*\{\s*([^}]+)\}\s*from\s*(['"])([^'"]+)\2;?$/;
|
|
2656
2678
|
for (const ctx of ctxs) {
|
|
2657
2679
|
const raw = (ctx.imports || "").replace(/\r\n/g, "\n");
|
|
2658
2680
|
if (!raw.trim()) continue;
|
|
2659
2681
|
for (const line of raw.split("\n")) {
|
|
2660
2682
|
const trimmed = line.trim();
|
|
2661
2683
|
if (!trimmed) continue;
|
|
2662
|
-
|
|
2684
|
+
const m = importRe.exec(trimmed);
|
|
2685
|
+
if (!m) {
|
|
2686
|
+
if (trimmed.startsWith("import ")) {
|
|
2687
|
+
collected.push({
|
|
2688
|
+
from: trimmed,
|
|
2689
|
+
// sentinel; will emit as-is below
|
|
2690
|
+
types: []
|
|
2691
|
+
// no types
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2694
|
+
continue;
|
|
2695
|
+
}
|
|
2696
|
+
const typeList = m[1].split(",").map((t) => t.trim()).filter(Boolean);
|
|
2697
|
+
const from = m[3];
|
|
2698
|
+
collected.push({ from, types: typeList });
|
|
2663
2699
|
}
|
|
2664
2700
|
}
|
|
2665
|
-
|
|
2701
|
+
const rawLines = collected.filter((imp) => !imp.types?.length && imp.from.startsWith("import ")).map((imp) => imp.from);
|
|
2702
|
+
const structured = collected.filter(
|
|
2703
|
+
(imp) => imp.types && imp.types.length && !imp.from.startsWith("import ")
|
|
2704
|
+
);
|
|
2705
|
+
const normalized = this.normalizeTsImports(structured);
|
|
2706
|
+
const structuredLines = normalized.map(
|
|
2707
|
+
(i) => `import { ${i.types.join(", ")} } from ${JSON.stringify(i.from)};`
|
|
2708
|
+
);
|
|
2709
|
+
const allLines = Array.from(
|
|
2710
|
+
/* @__PURE__ */ new Set([...rawLines, ...structuredLines])
|
|
2711
|
+
);
|
|
2712
|
+
return allLines.join("\n");
|
|
2666
2713
|
}
|
|
2667
2714
|
// ---------------------------------------------------------------------------
|
|
2668
2715
|
// MODEL RENDERING (DEFAULT)
|
|
@@ -2881,22 +2928,6 @@ function indentBlock(text, indent = " ") {
|
|
|
2881
2928
|
function getDefaultTsOutDir(generator) {
|
|
2882
2929
|
return generator?.output?.value ?? "resources/ts/prisma";
|
|
2883
2930
|
}
|
|
2884
|
-
async function loadMergedDatamodel(schemaPrismaPath) {
|
|
2885
|
-
const schemaDir = path13.dirname(schemaPrismaPath);
|
|
2886
|
-
const entries = readdirSync(schemaDir).filter(
|
|
2887
|
-
(f) => f.endsWith(".prisma")
|
|
2888
|
-
);
|
|
2889
|
-
const order = [
|
|
2890
|
-
// schema.prisma first
|
|
2891
|
-
...entries.filter((f) => f === "schema.prisma"),
|
|
2892
|
-
// then the rest alphabetically
|
|
2893
|
-
...entries.filter((f) => f !== "schema.prisma").sort()
|
|
2894
|
-
];
|
|
2895
|
-
const chunks = await Promise.all(
|
|
2896
|
-
order.map((f) => fs8.readFile(path13.join(schemaDir, f), "utf-8"))
|
|
2897
|
-
);
|
|
2898
|
-
return chunks.join("\n\n");
|
|
2899
|
-
}
|
|
2900
2931
|
function hasModelSpecificTsStub(model, cfg) {
|
|
2901
2932
|
if (!cfg.stubDir) return false;
|
|
2902
2933
|
const key = model.tableName && typeof model.tableName === "string" ? model.tableName : model.name;
|
|
@@ -2912,17 +2943,13 @@ function hasModelSpecificTsStub(model, cfg) {
|
|
|
2912
2943
|
return path13.basename(stubPath) !== "index.stub";
|
|
2913
2944
|
}
|
|
2914
2945
|
async function generateTypesFromPrisma(options) {
|
|
2915
|
-
const { generator } = options;
|
|
2946
|
+
const { dmmf, generator } = options;
|
|
2916
2947
|
const raw = generator.config ?? {};
|
|
2917
|
-
const
|
|
2918
|
-
const schemaDir = path13.dirname(schemaPrismaPath);
|
|
2948
|
+
const schemaDir = path13.dirname(options.schemaPath);
|
|
2919
2949
|
const shared = await loadSharedConfig(schemaDir);
|
|
2920
2950
|
let groups = [];
|
|
2921
2951
|
if (raw["groups"]) {
|
|
2922
|
-
const groupsModulePath = path13.resolve(
|
|
2923
|
-
process.cwd(),
|
|
2924
|
-
raw["groups"]
|
|
2925
|
-
);
|
|
2952
|
+
const groupsModulePath = path13.resolve(process.cwd(), raw["groups"]);
|
|
2926
2953
|
const importedModule = await import(groupsModulePath);
|
|
2927
2954
|
const imported = importedModule.default ?? importedModule;
|
|
2928
2955
|
if (!Array.isArray(imported)) {
|
|
@@ -2933,14 +2960,14 @@ async function generateTypesFromPrisma(options) {
|
|
|
2933
2960
|
groups = imported;
|
|
2934
2961
|
}
|
|
2935
2962
|
const pick = (key, fallback) => (
|
|
2936
|
-
//
|
|
2963
|
+
// shared.ts section (if present)
|
|
2937
2964
|
shared.ts?.[key] ?? // shared root (if you keep ts props there)
|
|
2938
2965
|
shared[key] ?? // generator block config
|
|
2939
2966
|
raw[key] ?? // explicit fallback
|
|
2940
2967
|
fallback
|
|
2941
2968
|
);
|
|
2942
2969
|
const cfg = {
|
|
2943
|
-
//
|
|
2970
|
+
// Laravel-ish generator knobs
|
|
2944
2971
|
overwriteExisting: pick("overwriteExisting", true),
|
|
2945
2972
|
prettier: pick("prettier", false),
|
|
2946
2973
|
noEmit: pick("noEmit", false),
|
|
@@ -2952,6 +2979,11 @@ async function generateTypesFromPrisma(options) {
|
|
|
2952
2979
|
groups,
|
|
2953
2980
|
// TS-specific
|
|
2954
2981
|
outputDir: pick("outputDir") ?? getDefaultTsOutDir(generator),
|
|
2982
|
+
/**
|
|
2983
|
+
* declaration now only affects enums:
|
|
2984
|
+
* - true → enums.d.ts
|
|
2985
|
+
* - false → enums.ts
|
|
2986
|
+
*/
|
|
2955
2987
|
declaration: pick("declaration", false),
|
|
2956
2988
|
shape: pick("shape", "interface"),
|
|
2957
2989
|
scalarMap: pick("scalarMap"),
|
|
@@ -2959,7 +2991,9 @@ async function generateTypesFromPrisma(options) {
|
|
|
2959
2991
|
readonlyArrays: pick("readonlyArrays", false),
|
|
2960
2992
|
namePrefix: pick("namePrefix", ""),
|
|
2961
2993
|
nameSuffix: pick("nameSuffix", ""),
|
|
2962
|
-
moduleName: pick("moduleName", "database/prisma")
|
|
2994
|
+
moduleName: pick("moduleName", "database/prisma"),
|
|
2995
|
+
modelsFileName: pick("modelsFileName", "index"),
|
|
2996
|
+
enumsFileName: pick("enumsFileName", "enums")
|
|
2963
2997
|
};
|
|
2964
2998
|
const tsOutDir = path13.resolve(process.cwd(), cfg.outputDir);
|
|
2965
2999
|
if (!existsSync(tsOutDir)) {
|
|
@@ -2969,9 +3003,6 @@ async function generateTypesFromPrisma(options) {
|
|
|
2969
3003
|
global._config.ts = {
|
|
2970
3004
|
prettier: !!cfg.prettier
|
|
2971
3005
|
};
|
|
2972
|
-
const datamodel = await loadMergedDatamodel(schemaPrismaPath);
|
|
2973
|
-
const sdk = dmf2.default ?? dmf2;
|
|
2974
|
-
const { dmmf } = await sdk.getDMMF({ datamodel });
|
|
2975
3006
|
const tsGen = new PrismaToTypesGenerator(dmmf, cfg);
|
|
2976
3007
|
const {
|
|
2977
3008
|
models,
|
|
@@ -2992,11 +3023,15 @@ async function generateTypesFromPrisma(options) {
|
|
|
2992
3023
|
moduleName: cfg.moduleName,
|
|
2993
3024
|
shape: cfg.shape
|
|
2994
3025
|
});
|
|
2995
|
-
const
|
|
3026
|
+
const modelExt = ".d.ts";
|
|
3027
|
+
const enumExt = cfg.declaration ? ".d.ts" : ".ts";
|
|
2996
3028
|
if (enums.length) {
|
|
2997
3029
|
const enumsCode = printer.printEnums(enums);
|
|
2998
3030
|
if (enumsCode.trim()) {
|
|
2999
|
-
const enumsPath = path13.join(
|
|
3031
|
+
const enumsPath = path13.join(
|
|
3032
|
+
tsOutDir,
|
|
3033
|
+
`${cfg.enumsFileName ?? "enums"}${enumExt}`
|
|
3034
|
+
);
|
|
3000
3035
|
await writeWithMerge(
|
|
3001
3036
|
enumsPath,
|
|
3002
3037
|
enumsCode,
|
|
@@ -3016,7 +3051,10 @@ async function generateTypesFromPrisma(options) {
|
|
|
3016
3051
|
);
|
|
3017
3052
|
}
|
|
3018
3053
|
if (mainFile.trim()) {
|
|
3019
|
-
const mainPath = path13.join(
|
|
3054
|
+
const mainPath = path13.join(
|
|
3055
|
+
tsOutDir,
|
|
3056
|
+
`${cfg.modelsFileName ?? "index"}${modelExt}`
|
|
3057
|
+
);
|
|
3020
3058
|
await writeWithMerge(
|
|
3021
3059
|
mainPath,
|
|
3022
3060
|
mainFile,
|
|
@@ -3030,7 +3068,7 @@ async function generateTypesFromPrisma(options) {
|
|
|
3030
3068
|
const decoratedName = `${cfg.namePrefix ?? ""}${model.name}${cfg.nameSuffix ?? ""}`;
|
|
3031
3069
|
const filePath = path13.join(
|
|
3032
3070
|
tsOutDir,
|
|
3033
|
-
`${decoratedName}${
|
|
3071
|
+
`${decoratedName}${modelExt}`
|
|
3034
3072
|
);
|
|
3035
3073
|
await writeWithMerge(
|
|
3036
3074
|
filePath,
|
|
@@ -3041,18 +3079,18 @@ async function generateTypesFromPrisma(options) {
|
|
|
3041
3079
|
});
|
|
3042
3080
|
return { models, enums, config: cfg };
|
|
3043
3081
|
}
|
|
3044
|
-
async function
|
|
3082
|
+
async function loadMergedDatamodel(schemaPrismaPath) {
|
|
3045
3083
|
const schemaDir = path13.dirname(schemaPrismaPath);
|
|
3046
3084
|
const entries = readdirSync(schemaDir).filter((f) => f.endsWith(".prisma"));
|
|
3047
3085
|
const order = [
|
|
3048
3086
|
...entries.filter((f) => f === "schema.prisma"),
|
|
3049
3087
|
...entries.filter((f) => f !== "schema.prisma").sort()
|
|
3050
3088
|
];
|
|
3051
|
-
const chunks = await Promise.all(order.map((f) =>
|
|
3089
|
+
const chunks = await Promise.all(order.map((f) => fs7.readFile(path13.join(schemaDir, f), "utf-8")));
|
|
3052
3090
|
return chunks.join("\n\n");
|
|
3053
3091
|
}
|
|
3054
3092
|
async function getLaravelGeneratorConfigs(datamodel) {
|
|
3055
|
-
const sdk =
|
|
3093
|
+
const sdk = dmf.default ?? dmf;
|
|
3056
3094
|
const { generators } = await sdk.getConfig({ datamodel });
|
|
3057
3095
|
const findCfg = (provider) => (generators ?? []).find((g) => (g.provider?.value ?? "") === provider)?.config ?? {};
|
|
3058
3096
|
const migCfg = findCfg("prisma-laravel-migrations");
|
|
@@ -3073,9 +3111,9 @@ async function runGenerators(configPath, skipPrismaGenerate = false) {
|
|
|
3073
3111
|
throw new Error(`Schema not found: ${schemaPrismaPath}`);
|
|
3074
3112
|
}
|
|
3075
3113
|
const doRun = async () => {
|
|
3076
|
-
const datamodel = await
|
|
3114
|
+
const datamodel = await loadMergedDatamodel(schemaPrismaPath);
|
|
3077
3115
|
const { migCfg, modCfg, tsCfg } = await getLaravelGeneratorConfigs(datamodel);
|
|
3078
|
-
const sdk =
|
|
3116
|
+
const sdk = dmf.default ?? dmf;
|
|
3079
3117
|
const dmmf = await sdk.getDMMF({ datamodel });
|
|
3080
3118
|
const config = (conf) => {
|
|
3081
3119
|
return {
|
|
@@ -3133,7 +3171,7 @@ cli.command("init").description("Inject generators into schema.prisma and scaffo
|
|
|
3133
3171
|
const stubDirRel = "./" + path13.relative(process.cwd(), userStubs).replace(/\\/g, "/");
|
|
3134
3172
|
const __dirname = path13.dirname(fileURLToPath(import.meta.url));
|
|
3135
3173
|
const pkgStubs = path13.resolve(__dirname, "../../stubs");
|
|
3136
|
-
let schema = await
|
|
3174
|
+
let schema = await fs7.readFile(schemaPath, "utf-8");
|
|
3137
3175
|
const hasGenBlock = (name) => new RegExp(`generator\\s+${name}\\s*\\{`).test(schema);
|
|
3138
3176
|
const hasMigrationsGen = hasGenBlock("migrations");
|
|
3139
3177
|
const hasModelsGen = hasGenBlock("models");
|
|
@@ -3159,24 +3197,24 @@ generator types {
|
|
|
3159
3197
|
`;
|
|
3160
3198
|
console.log("\u27A1\uFE0F Added types generator");
|
|
3161
3199
|
}
|
|
3162
|
-
await
|
|
3200
|
+
await fs7.writeFile(schemaPath, schema, "utf-8");
|
|
3163
3201
|
console.log(`\u2705 Updated ${schemaPath}`);
|
|
3164
3202
|
const stubTypes = ["migration", "model", "enum"];
|
|
3165
3203
|
for (const type of stubTypes) {
|
|
3166
3204
|
const targetDir = path13.join(userStubs, type);
|
|
3167
|
-
await
|
|
3205
|
+
await fs7.mkdir(targetDir, { recursive: true });
|
|
3168
3206
|
const src = path13.join(pkgStubs, `${type}.stub`);
|
|
3169
3207
|
const dst = path13.join(targetDir, "index.stub");
|
|
3170
3208
|
try {
|
|
3171
|
-
await
|
|
3209
|
+
await fs7.access(dst);
|
|
3172
3210
|
} catch {
|
|
3173
|
-
await
|
|
3211
|
+
await fs7.copyFile(src, dst);
|
|
3174
3212
|
console.log(`\u27A1\uFE0F Copied ${type}.stub \u2192 stubs/${type}/index.stub`);
|
|
3175
3213
|
}
|
|
3176
3214
|
}
|
|
3177
3215
|
const cfgPath = path13.join(schemaDir, "prisma-laravel.config.js");
|
|
3178
3216
|
try {
|
|
3179
|
-
await
|
|
3217
|
+
await fs7.access(cfgPath);
|
|
3180
3218
|
} catch {
|
|
3181
3219
|
const cfgTemplate = `
|
|
3182
3220
|
// prisma/prisma-laravel.config.js
|
|
@@ -3200,7 +3238,7 @@ module.exports = {
|
|
|
3200
3238
|
|
|
3201
3239
|
};
|
|
3202
3240
|
`;
|
|
3203
|
-
await
|
|
3241
|
+
await fs7.writeFile(cfgPath, cfgTemplate.trimStart(), "utf-8");
|
|
3204
3242
|
console.log("\u27A1\uFE0F Created prisma-laravel.config.js");
|
|
3205
3243
|
}
|
|
3206
3244
|
console.log("\u{1F389} Initialization complete!");
|
|
@@ -3244,14 +3282,14 @@ cli.command("customize").alias("c").description("Scaffold per-table stub files f
|
|
|
3244
3282
|
if (t === "enum") {
|
|
3245
3283
|
const dir = path13.join(stubRoot, "enum");
|
|
3246
3284
|
const idx = resolveStubIndex("enum");
|
|
3247
|
-
await
|
|
3285
|
+
await fs7.mkdir(dir, { recursive: true });
|
|
3248
3286
|
for (const name of bases) {
|
|
3249
3287
|
const dst = path13.join(dir, `${name}.stub`);
|
|
3250
3288
|
try {
|
|
3251
|
-
await
|
|
3289
|
+
await fs7.access(dst);
|
|
3252
3290
|
console.log(`\u{1F7E1} Skip enum/${name}.stub`);
|
|
3253
3291
|
} catch {
|
|
3254
|
-
await
|
|
3292
|
+
await fs7.copyFile(idx, dst);
|
|
3255
3293
|
console.log(`\u2705 Created enum/${name}.stub`);
|
|
3256
3294
|
}
|
|
3257
3295
|
}
|
|
@@ -3260,14 +3298,14 @@ cli.command("customize").alias("c").description("Scaffold per-table stub files f
|
|
|
3260
3298
|
if (t === "ts") {
|
|
3261
3299
|
const dir = path13.join(stubRoot, "ts");
|
|
3262
3300
|
const idx = resolveStubIndex("ts");
|
|
3263
|
-
await
|
|
3301
|
+
await fs7.mkdir(dir, { recursive: true });
|
|
3264
3302
|
for (const base of bases) {
|
|
3265
3303
|
const dst = path13.join(dir, `${base}.stub`);
|
|
3266
3304
|
try {
|
|
3267
|
-
await
|
|
3305
|
+
await fs7.access(dst);
|
|
3268
3306
|
console.log(`\u{1F7E1} Skip ts/${base}.stub`);
|
|
3269
3307
|
} catch {
|
|
3270
|
-
await
|
|
3308
|
+
await fs7.copyFile(idx, dst);
|
|
3271
3309
|
console.log(`\u2705 Created ts/${base}.stub`);
|
|
3272
3310
|
}
|
|
3273
3311
|
}
|
|
@@ -3276,14 +3314,14 @@ cli.command("customize").alias("c").description("Scaffold per-table stub files f
|
|
|
3276
3314
|
for (const kind of doBoth ? ["migration", "model"] : [t]) {
|
|
3277
3315
|
const dir = path13.join(stubRoot, kind);
|
|
3278
3316
|
const idx = resolveStubIndex(kind);
|
|
3279
|
-
await
|
|
3317
|
+
await fs7.mkdir(dir, { recursive: true });
|
|
3280
3318
|
for (const base of bases) {
|
|
3281
3319
|
const dst = path13.join(dir, `${base}.stub`);
|
|
3282
3320
|
try {
|
|
3283
|
-
await
|
|
3321
|
+
await fs7.access(dst);
|
|
3284
3322
|
console.log(`\u{1F7E1} Skip ${kind}/${base}.stub`);
|
|
3285
3323
|
} catch {
|
|
3286
|
-
await
|
|
3324
|
+
await fs7.copyFile(idx, dst);
|
|
3287
3325
|
console.log(`\u2705 Created ${kind}/${base}.stub`);
|
|
3288
3326
|
}
|
|
3289
3327
|
}
|
|
@@ -3456,7 +3494,7 @@ cli.command("clean").description(
|
|
|
3456
3494
|
const rmIfExists = async (p) => {
|
|
3457
3495
|
if (!p || !existsSync(p)) return false;
|
|
3458
3496
|
try {
|
|
3459
|
-
await
|
|
3497
|
+
await fs7.unlink(p);
|
|
3460
3498
|
return true;
|
|
3461
3499
|
} catch {
|
|
3462
3500
|
return false;
|
|
@@ -3496,7 +3534,7 @@ cli.command("clean").description(
|
|
|
3496
3534
|
}
|
|
3497
3535
|
if (allRemoved) {
|
|
3498
3536
|
try {
|
|
3499
|
-
await
|
|
3537
|
+
await fs7.rmdir(dir);
|
|
3500
3538
|
return true;
|
|
3501
3539
|
} catch {
|
|
3502
3540
|
return false;
|
|
@@ -289,16 +289,18 @@ var listFrom = (doc, tag) => {
|
|
|
289
289
|
return cleaned;
|
|
290
290
|
};
|
|
291
291
|
var FOLDER = "prisma-laravel-migrate";
|
|
292
|
-
function getStubPath(pathString) {
|
|
292
|
+
function getStubPath(pathString, folder) {
|
|
293
293
|
const __filename = fileURLToPath(import.meta.url);
|
|
294
294
|
const __dirname = path7.dirname(__filename);
|
|
295
|
+
const __file = folder ?? FOLDER;
|
|
295
296
|
const normalised = pathString.replace(/\\/g, "/");
|
|
296
297
|
const dir = __dirname.replace(/\\/g, "/");
|
|
297
|
-
const idx = dir.lastIndexOf(
|
|
298
|
+
const idx = dir.lastIndexOf(__file);
|
|
298
299
|
if (idx === -1) {
|
|
300
|
+
if (!folder) return getStubPath(pathString, "prisma-to-laravel-migration");
|
|
299
301
|
return path7.resolve(process.cwd(), normalised);
|
|
300
302
|
}
|
|
301
|
-
const baseDir = dir.slice(0, idx +
|
|
303
|
+
const baseDir = dir.slice(0, idx + __file.length);
|
|
302
304
|
return path7.join(baseDir, "stubs", normalised);
|
|
303
305
|
}
|
|
304
306
|
|
|
@@ -1270,10 +1272,26 @@ function formatLaravelTimestamp(date, seq, width) {
|
|
|
1270
1272
|
var { generatorHandler } = helperPkg;
|
|
1271
1273
|
generatorHandler({
|
|
1272
1274
|
onGenerate: generateLaravelSchema,
|
|
1273
|
-
onManifest
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1275
|
+
async onManifest(options) {
|
|
1276
|
+
const cfg = options.config ?? {};
|
|
1277
|
+
let migrationsOutput;
|
|
1278
|
+
migrationsOutput = cfg.outputDir;
|
|
1279
|
+
if (!migrationsOutput && options.sourceFilePath) {
|
|
1280
|
+
try {
|
|
1281
|
+
const schemaDir = path7.dirname(options.sourceFilePath);
|
|
1282
|
+
const shared = await loadSharedConfig(schemaDir);
|
|
1283
|
+
migrationsOutput = shared?.migrate?.outputDir ?? shared?.output?.migrations ?? void 0;
|
|
1284
|
+
} catch {
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (!migrationsOutput) {
|
|
1288
|
+
migrationsOutput = "database/migrations";
|
|
1289
|
+
}
|
|
1290
|
+
return {
|
|
1291
|
+
defaultOutput: migrationsOutput,
|
|
1292
|
+
prettyName: `Laravel Migration Schema (migrations \u2192 ${migrationsOutput})`
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1277
1295
|
});
|
|
1278
1296
|
//# sourceMappingURL=migrator.index.js.map
|
|
1279
1297
|
//# sourceMappingURL=migrator.index.js.map
|
package/dist/cli/models.index.js
CHANGED
|
@@ -126,16 +126,18 @@ var listFrom = (doc, tag) => {
|
|
|
126
126
|
return cleaned;
|
|
127
127
|
};
|
|
128
128
|
var FOLDER = "prisma-laravel-migrate";
|
|
129
|
-
function getStubPath(pathString) {
|
|
129
|
+
function getStubPath(pathString, folder) {
|
|
130
130
|
const __filename = fileURLToPath(import.meta.url);
|
|
131
131
|
const __dirname = path7.dirname(__filename);
|
|
132
|
+
const __file = folder ?? FOLDER;
|
|
132
133
|
const normalised = pathString.replace(/\\/g, "/");
|
|
133
134
|
const dir = __dirname.replace(/\\/g, "/");
|
|
134
|
-
const idx = dir.lastIndexOf(
|
|
135
|
+
const idx = dir.lastIndexOf(__file);
|
|
135
136
|
if (idx === -1) {
|
|
137
|
+
if (!folder) return getStubPath(pathString, "prisma-to-laravel-migration");
|
|
136
138
|
return path7.resolve(process.cwd(), normalised);
|
|
137
139
|
}
|
|
138
|
-
const baseDir = dir.slice(0, idx +
|
|
140
|
+
const baseDir = dir.slice(0, idx + __file.length);
|
|
139
141
|
return path7.join(baseDir, "stubs", normalised);
|
|
140
142
|
}
|
|
141
143
|
|
|
@@ -1340,10 +1342,34 @@ function getOutDir(generator) {
|
|
|
1340
1342
|
var { generatorHandler } = helperPkg;
|
|
1341
1343
|
generatorHandler({
|
|
1342
1344
|
onGenerate: generateLaravelModels,
|
|
1343
|
-
onManifest
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1345
|
+
async onManifest(options) {
|
|
1346
|
+
const cfg = options.config ?? {};
|
|
1347
|
+
let modelOutput = cfg.outputDir;
|
|
1348
|
+
let enumOutput;
|
|
1349
|
+
if (options.sourceFilePath) {
|
|
1350
|
+
try {
|
|
1351
|
+
const schemaDir = path7.dirname(options.sourceFilePath);
|
|
1352
|
+
const shared = await loadSharedConfig(schemaDir);
|
|
1353
|
+
if (!modelOutput) {
|
|
1354
|
+
modelOutput = shared?.modeler?.outputDir ?? shared?.output?.models ?? void 0;
|
|
1355
|
+
}
|
|
1356
|
+
enumOutput = shared?.modeler?.outputEnumDir ?? shared?.output?.enums ?? void 0;
|
|
1357
|
+
} catch {
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
if (!modelOutput) {
|
|
1361
|
+
modelOutput = "app/Models";
|
|
1362
|
+
}
|
|
1363
|
+
if (!enumOutput) {
|
|
1364
|
+
enumOutput = "app/Enums";
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
// Prisma can only use ONE path for the generator's output
|
|
1368
|
+
defaultOutput: modelOutput,
|
|
1369
|
+
// But we can loudly show BOTH model + enum destinations here
|
|
1370
|
+
prettyName: `Laravel Models & Enums (models \u2192 ${modelOutput}, enums \u2192 ${enumOutput})`
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1347
1373
|
});
|
|
1348
1374
|
//# sourceMappingURL=models.index.js.map
|
|
1349
1375
|
//# sourceMappingURL=models.index.js.map
|
package/dist/cli/ts.index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path7, { resolve, extname, dirname } from 'path';
|
|
3
|
-
import fs, { existsSync, mkdirSync,
|
|
4
|
-
import
|
|
5
|
-
import * as dmf from '@prisma/internals';
|
|
3
|
+
import fs, { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
4
|
+
import { readFile } from 'fs/promises';
|
|
6
5
|
import { createRequire } from 'module';
|
|
7
6
|
import { pathToFileURL } from 'url';
|
|
8
7
|
import { Minimatch } from 'minimatch';
|
|
@@ -481,6 +480,22 @@ var TsPrinter = class {
|
|
|
481
480
|
// ---------------------------------------------------------------------------
|
|
482
481
|
// IMPORTS
|
|
483
482
|
// ---------------------------------------------------------------------------
|
|
483
|
+
normalizeTsImports(imports) {
|
|
484
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
485
|
+
for (const imp of imports) {
|
|
486
|
+
if (!imp.from) continue;
|
|
487
|
+
const set = grouped.get(imp.from) ?? /* @__PURE__ */ new Set();
|
|
488
|
+
for (const t of imp.types ?? []) {
|
|
489
|
+
if (!t) continue;
|
|
490
|
+
set.add(t);
|
|
491
|
+
}
|
|
492
|
+
grouped.set(imp.from, set);
|
|
493
|
+
}
|
|
494
|
+
return Array.from(grouped.entries()).map(([from, set]) => ({
|
|
495
|
+
from,
|
|
496
|
+
types: Array.from(set).sort()
|
|
497
|
+
})).sort((a, b) => a.from.localeCompare(b.from));
|
|
498
|
+
}
|
|
484
499
|
/**
|
|
485
500
|
* Render import statements for a node that has an `imports` property:
|
|
486
501
|
* node.imports?: { from: string; types: string[] }[];
|
|
@@ -490,26 +505,55 @@ var TsPrinter = class {
|
|
|
490
505
|
renderImports(node) {
|
|
491
506
|
const imports = node.imports ?? [];
|
|
492
507
|
if (!imports.length) return "";
|
|
493
|
-
return imports.map((i) => {
|
|
508
|
+
return this.normalizeTsImports(imports).map((i) => {
|
|
494
509
|
const names = i.types.join(", ");
|
|
495
510
|
return `import { ${names} } from ${JSON.stringify(i.from)};`;
|
|
496
511
|
}).join("\n");
|
|
497
512
|
}
|
|
498
513
|
/**
|
|
499
|
-
|
|
500
|
-
|
|
514
|
+
* Merge & dedupe imports from multiple model contexts.
|
|
515
|
+
*
|
|
516
|
+
* We re-parse the per-model import lines into TsImport objects so that
|
|
517
|
+
* `normalizeTsImports` can group everything by `from` and merge type lists.
|
|
518
|
+
*/
|
|
501
519
|
collectImports(ctxs) {
|
|
502
|
-
const
|
|
520
|
+
const collected = [];
|
|
521
|
+
const importRe = /^import\s*\{\s*([^}]+)\}\s*from\s*(['"])([^'"]+)\2;?$/;
|
|
503
522
|
for (const ctx of ctxs) {
|
|
504
523
|
const raw = (ctx.imports || "").replace(/\r\n/g, "\n");
|
|
505
524
|
if (!raw.trim()) continue;
|
|
506
525
|
for (const line of raw.split("\n")) {
|
|
507
526
|
const trimmed = line.trim();
|
|
508
527
|
if (!trimmed) continue;
|
|
509
|
-
|
|
528
|
+
const m = importRe.exec(trimmed);
|
|
529
|
+
if (!m) {
|
|
530
|
+
if (trimmed.startsWith("import ")) {
|
|
531
|
+
collected.push({
|
|
532
|
+
from: trimmed,
|
|
533
|
+
// sentinel; will emit as-is below
|
|
534
|
+
types: []
|
|
535
|
+
// no types
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
const typeList = m[1].split(",").map((t) => t.trim()).filter(Boolean);
|
|
541
|
+
const from = m[3];
|
|
542
|
+
collected.push({ from, types: typeList });
|
|
510
543
|
}
|
|
511
544
|
}
|
|
512
|
-
|
|
545
|
+
const rawLines = collected.filter((imp) => !imp.types?.length && imp.from.startsWith("import ")).map((imp) => imp.from);
|
|
546
|
+
const structured = collected.filter(
|
|
547
|
+
(imp) => imp.types && imp.types.length && !imp.from.startsWith("import ")
|
|
548
|
+
);
|
|
549
|
+
const normalized = this.normalizeTsImports(structured);
|
|
550
|
+
const structuredLines = normalized.map(
|
|
551
|
+
(i) => `import { ${i.types.join(", ")} } from ${JSON.stringify(i.from)};`
|
|
552
|
+
);
|
|
553
|
+
const allLines = Array.from(
|
|
554
|
+
/* @__PURE__ */ new Set([...rawLines, ...structuredLines])
|
|
555
|
+
);
|
|
556
|
+
return allLines.join("\n");
|
|
513
557
|
}
|
|
514
558
|
// ---------------------------------------------------------------------------
|
|
515
559
|
// MODEL RENDERING (DEFAULT)
|
|
@@ -841,22 +885,6 @@ function safeUnlink(p) {
|
|
|
841
885
|
function getDefaultTsOutDir(generator) {
|
|
842
886
|
return generator?.output?.value ?? "resources/ts/prisma";
|
|
843
887
|
}
|
|
844
|
-
async function loadMergedDatamodel(schemaPrismaPath) {
|
|
845
|
-
const schemaDir = path7.dirname(schemaPrismaPath);
|
|
846
|
-
const entries = readdirSync(schemaDir).filter(
|
|
847
|
-
(f) => f.endsWith(".prisma")
|
|
848
|
-
);
|
|
849
|
-
const order = [
|
|
850
|
-
// schema.prisma first
|
|
851
|
-
...entries.filter((f) => f === "schema.prisma"),
|
|
852
|
-
// then the rest alphabetically
|
|
853
|
-
...entries.filter((f) => f !== "schema.prisma").sort()
|
|
854
|
-
];
|
|
855
|
-
const chunks = await Promise.all(
|
|
856
|
-
order.map((f) => fs4.readFile(path7.join(schemaDir, f), "utf-8"))
|
|
857
|
-
);
|
|
858
|
-
return chunks.join("\n\n");
|
|
859
|
-
}
|
|
860
888
|
function hasModelSpecificTsStub(model, cfg) {
|
|
861
889
|
if (!cfg.stubDir) return false;
|
|
862
890
|
const key = model.tableName && typeof model.tableName === "string" ? model.tableName : model.name;
|
|
@@ -872,17 +900,13 @@ function hasModelSpecificTsStub(model, cfg) {
|
|
|
872
900
|
return path7.basename(stubPath) !== "index.stub";
|
|
873
901
|
}
|
|
874
902
|
async function generateTypesFromPrisma(options) {
|
|
875
|
-
const { generator } = options;
|
|
903
|
+
const { dmmf, generator } = options;
|
|
876
904
|
const raw = generator.config ?? {};
|
|
877
|
-
const
|
|
878
|
-
const schemaDir = path7.dirname(schemaPrismaPath);
|
|
905
|
+
const schemaDir = path7.dirname(options.schemaPath);
|
|
879
906
|
const shared = await loadSharedConfig(schemaDir);
|
|
880
907
|
let groups = [];
|
|
881
908
|
if (raw["groups"]) {
|
|
882
|
-
const groupsModulePath = path7.resolve(
|
|
883
|
-
process.cwd(),
|
|
884
|
-
raw["groups"]
|
|
885
|
-
);
|
|
909
|
+
const groupsModulePath = path7.resolve(process.cwd(), raw["groups"]);
|
|
886
910
|
const importedModule = await import(groupsModulePath);
|
|
887
911
|
const imported = importedModule.default ?? importedModule;
|
|
888
912
|
if (!Array.isArray(imported)) {
|
|
@@ -893,14 +917,14 @@ async function generateTypesFromPrisma(options) {
|
|
|
893
917
|
groups = imported;
|
|
894
918
|
}
|
|
895
919
|
const pick = (key, fallback) => (
|
|
896
|
-
//
|
|
920
|
+
// shared.ts section (if present)
|
|
897
921
|
shared.ts?.[key] ?? // shared root (if you keep ts props there)
|
|
898
922
|
shared[key] ?? // generator block config
|
|
899
923
|
raw[key] ?? // explicit fallback
|
|
900
924
|
fallback
|
|
901
925
|
);
|
|
902
926
|
const cfg = {
|
|
903
|
-
//
|
|
927
|
+
// Laravel-ish generator knobs
|
|
904
928
|
overwriteExisting: pick("overwriteExisting", true),
|
|
905
929
|
prettier: pick("prettier", false),
|
|
906
930
|
noEmit: pick("noEmit", false),
|
|
@@ -912,6 +936,11 @@ async function generateTypesFromPrisma(options) {
|
|
|
912
936
|
groups,
|
|
913
937
|
// TS-specific
|
|
914
938
|
outputDir: pick("outputDir") ?? getDefaultTsOutDir(generator),
|
|
939
|
+
/**
|
|
940
|
+
* declaration now only affects enums:
|
|
941
|
+
* - true → enums.d.ts
|
|
942
|
+
* - false → enums.ts
|
|
943
|
+
*/
|
|
915
944
|
declaration: pick("declaration", false),
|
|
916
945
|
shape: pick("shape", "interface"),
|
|
917
946
|
scalarMap: pick("scalarMap"),
|
|
@@ -919,7 +948,9 @@ async function generateTypesFromPrisma(options) {
|
|
|
919
948
|
readonlyArrays: pick("readonlyArrays", false),
|
|
920
949
|
namePrefix: pick("namePrefix", ""),
|
|
921
950
|
nameSuffix: pick("nameSuffix", ""),
|
|
922
|
-
moduleName: pick("moduleName", "database/prisma")
|
|
951
|
+
moduleName: pick("moduleName", "database/prisma"),
|
|
952
|
+
modelsFileName: pick("modelsFileName", "index"),
|
|
953
|
+
enumsFileName: pick("enumsFileName", "enums")
|
|
923
954
|
};
|
|
924
955
|
const tsOutDir = path7.resolve(process.cwd(), cfg.outputDir);
|
|
925
956
|
if (!existsSync(tsOutDir)) {
|
|
@@ -929,9 +960,6 @@ async function generateTypesFromPrisma(options) {
|
|
|
929
960
|
global._config.ts = {
|
|
930
961
|
prettier: !!cfg.prettier
|
|
931
962
|
};
|
|
932
|
-
const datamodel = await loadMergedDatamodel(schemaPrismaPath);
|
|
933
|
-
const sdk = dmf.default ?? dmf;
|
|
934
|
-
const { dmmf } = await sdk.getDMMF({ datamodel });
|
|
935
963
|
const tsGen = new PrismaToTypesGenerator(dmmf, cfg);
|
|
936
964
|
const {
|
|
937
965
|
models,
|
|
@@ -952,11 +980,15 @@ async function generateTypesFromPrisma(options) {
|
|
|
952
980
|
moduleName: cfg.moduleName,
|
|
953
981
|
shape: cfg.shape
|
|
954
982
|
});
|
|
955
|
-
const
|
|
983
|
+
const modelExt = ".d.ts";
|
|
984
|
+
const enumExt = cfg.declaration ? ".d.ts" : ".ts";
|
|
956
985
|
if (enums.length) {
|
|
957
986
|
const enumsCode = printer.printEnums(enums);
|
|
958
987
|
if (enumsCode.trim()) {
|
|
959
|
-
const enumsPath = path7.join(
|
|
988
|
+
const enumsPath = path7.join(
|
|
989
|
+
tsOutDir,
|
|
990
|
+
`${cfg.enumsFileName ?? "enums"}${enumExt}`
|
|
991
|
+
);
|
|
960
992
|
await writeWithMerge(
|
|
961
993
|
enumsPath,
|
|
962
994
|
enumsCode,
|
|
@@ -976,7 +1008,10 @@ async function generateTypesFromPrisma(options) {
|
|
|
976
1008
|
);
|
|
977
1009
|
}
|
|
978
1010
|
if (mainFile.trim()) {
|
|
979
|
-
const mainPath = path7.join(
|
|
1011
|
+
const mainPath = path7.join(
|
|
1012
|
+
tsOutDir,
|
|
1013
|
+
`${cfg.modelsFileName ?? "index"}${modelExt}`
|
|
1014
|
+
);
|
|
980
1015
|
await writeWithMerge(
|
|
981
1016
|
mainPath,
|
|
982
1017
|
mainFile,
|
|
@@ -990,7 +1025,7 @@ async function generateTypesFromPrisma(options) {
|
|
|
990
1025
|
const decoratedName = `${cfg.namePrefix ?? ""}${model.name}${cfg.nameSuffix ?? ""}`;
|
|
991
1026
|
const filePath = path7.join(
|
|
992
1027
|
tsOutDir,
|
|
993
|
-
`${decoratedName}${
|
|
1028
|
+
`${decoratedName}${modelExt}`
|
|
994
1029
|
);
|
|
995
1030
|
await writeWithMerge(
|
|
996
1031
|
filePath,
|
|
@@ -1004,10 +1039,27 @@ async function generateTypesFromPrisma(options) {
|
|
|
1004
1039
|
var { generatorHandler } = helperPkg;
|
|
1005
1040
|
generatorHandler({
|
|
1006
1041
|
onGenerate: generateTypesFromPrisma,
|
|
1007
|
-
onManifest
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1042
|
+
async onManifest(options) {
|
|
1043
|
+
const cfg = options.config ?? {};
|
|
1044
|
+
let defaultOutput = cfg.outputDir;
|
|
1045
|
+
if (!defaultOutput && options.sourceFilePath) {
|
|
1046
|
+
try {
|
|
1047
|
+
const schemaDir = path7.dirname(options.sourceFilePath);
|
|
1048
|
+
const shared = await loadSharedConfig(schemaDir);
|
|
1049
|
+
if (shared && shared.ts) {
|
|
1050
|
+
defaultOutput = shared.ts.outputDir;
|
|
1051
|
+
}
|
|
1052
|
+
} catch {
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
if (!defaultOutput) {
|
|
1056
|
+
defaultOutput = "resources/js/types";
|
|
1057
|
+
}
|
|
1058
|
+
return {
|
|
1059
|
+
defaultOutput,
|
|
1060
|
+
prettyName: "Typescript declarations"
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1011
1063
|
});
|
|
1012
1064
|
//# sourceMappingURL=ts.index.js.map
|
|
1013
1065
|
//# sourceMappingURL=ts.index.js.map
|
package/dist/index.js
CHANGED
|
@@ -5,9 +5,8 @@ import { Minimatch } from 'minimatch';
|
|
|
5
5
|
import * as diff3 from 'node-diff3';
|
|
6
6
|
import * as prettier from 'prettier';
|
|
7
7
|
import * as prettierPhp from '@prettier/plugin-php';
|
|
8
|
-
import
|
|
8
|
+
import { readFile } from 'fs/promises';
|
|
9
9
|
import { createRequire } from 'module';
|
|
10
|
-
import * as dmf from '@prisma/internals';
|
|
11
10
|
|
|
12
11
|
// src/generator/modeler/relationship/template-builder.ts
|
|
13
12
|
var asArrayPhp = (xs) => `[${xs.map((x) => `'${x}'`).join(", ")}]`;
|
|
@@ -443,16 +442,18 @@ var listFrom = (doc, tag) => {
|
|
|
443
442
|
return cleaned;
|
|
444
443
|
};
|
|
445
444
|
var FOLDER = "prisma-laravel-migrate";
|
|
446
|
-
function getStubPath(pathString) {
|
|
445
|
+
function getStubPath(pathString, folder) {
|
|
447
446
|
const __filename = fileURLToPath(import.meta.url);
|
|
448
447
|
const __dirname = path9.dirname(__filename);
|
|
448
|
+
const __file = folder ?? FOLDER;
|
|
449
449
|
const normalised = pathString.replace(/\\/g, "/");
|
|
450
450
|
const dir = __dirname.replace(/\\/g, "/");
|
|
451
|
-
const idx = dir.lastIndexOf(
|
|
451
|
+
const idx = dir.lastIndexOf(__file);
|
|
452
452
|
if (idx === -1) {
|
|
453
|
+
if (!folder) return getStubPath(pathString, "prisma-to-laravel-migration");
|
|
453
454
|
return path9.resolve(process.cwd(), normalised);
|
|
454
455
|
}
|
|
455
|
-
const baseDir = dir.slice(0, idx +
|
|
456
|
+
const baseDir = dir.slice(0, idx + __file.length);
|
|
456
457
|
return path9.join(baseDir, "stubs", normalised);
|
|
457
458
|
}
|
|
458
459
|
|
|
@@ -2630,6 +2631,22 @@ var TsPrinter = class {
|
|
|
2630
2631
|
// ---------------------------------------------------------------------------
|
|
2631
2632
|
// IMPORTS
|
|
2632
2633
|
// ---------------------------------------------------------------------------
|
|
2634
|
+
normalizeTsImports(imports) {
|
|
2635
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2636
|
+
for (const imp of imports) {
|
|
2637
|
+
if (!imp.from) continue;
|
|
2638
|
+
const set = grouped.get(imp.from) ?? /* @__PURE__ */ new Set();
|
|
2639
|
+
for (const t of imp.types ?? []) {
|
|
2640
|
+
if (!t) continue;
|
|
2641
|
+
set.add(t);
|
|
2642
|
+
}
|
|
2643
|
+
grouped.set(imp.from, set);
|
|
2644
|
+
}
|
|
2645
|
+
return Array.from(grouped.entries()).map(([from, set]) => ({
|
|
2646
|
+
from,
|
|
2647
|
+
types: Array.from(set).sort()
|
|
2648
|
+
})).sort((a, b) => a.from.localeCompare(b.from));
|
|
2649
|
+
}
|
|
2633
2650
|
/**
|
|
2634
2651
|
* Render import statements for a node that has an `imports` property:
|
|
2635
2652
|
* node.imports?: { from: string; types: string[] }[];
|
|
@@ -2639,26 +2656,55 @@ var TsPrinter = class {
|
|
|
2639
2656
|
renderImports(node) {
|
|
2640
2657
|
const imports = node.imports ?? [];
|
|
2641
2658
|
if (!imports.length) return "";
|
|
2642
|
-
return imports.map((i) => {
|
|
2659
|
+
return this.normalizeTsImports(imports).map((i) => {
|
|
2643
2660
|
const names = i.types.join(", ");
|
|
2644
2661
|
return `import { ${names} } from ${JSON.stringify(i.from)};`;
|
|
2645
2662
|
}).join("\n");
|
|
2646
2663
|
}
|
|
2647
2664
|
/**
|
|
2648
|
-
|
|
2649
|
-
|
|
2665
|
+
* Merge & dedupe imports from multiple model contexts.
|
|
2666
|
+
*
|
|
2667
|
+
* We re-parse the per-model import lines into TsImport objects so that
|
|
2668
|
+
* `normalizeTsImports` can group everything by `from` and merge type lists.
|
|
2669
|
+
*/
|
|
2650
2670
|
collectImports(ctxs) {
|
|
2651
|
-
const
|
|
2671
|
+
const collected = [];
|
|
2672
|
+
const importRe = /^import\s*\{\s*([^}]+)\}\s*from\s*(['"])([^'"]+)\2;?$/;
|
|
2652
2673
|
for (const ctx of ctxs) {
|
|
2653
2674
|
const raw = (ctx.imports || "").replace(/\r\n/g, "\n");
|
|
2654
2675
|
if (!raw.trim()) continue;
|
|
2655
2676
|
for (const line of raw.split("\n")) {
|
|
2656
2677
|
const trimmed = line.trim();
|
|
2657
2678
|
if (!trimmed) continue;
|
|
2658
|
-
|
|
2679
|
+
const m = importRe.exec(trimmed);
|
|
2680
|
+
if (!m) {
|
|
2681
|
+
if (trimmed.startsWith("import ")) {
|
|
2682
|
+
collected.push({
|
|
2683
|
+
from: trimmed,
|
|
2684
|
+
// sentinel; will emit as-is below
|
|
2685
|
+
types: []
|
|
2686
|
+
// no types
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
continue;
|
|
2690
|
+
}
|
|
2691
|
+
const typeList = m[1].split(",").map((t) => t.trim()).filter(Boolean);
|
|
2692
|
+
const from = m[3];
|
|
2693
|
+
collected.push({ from, types: typeList });
|
|
2659
2694
|
}
|
|
2660
2695
|
}
|
|
2661
|
-
|
|
2696
|
+
const rawLines = collected.filter((imp) => !imp.types?.length && imp.from.startsWith("import ")).map((imp) => imp.from);
|
|
2697
|
+
const structured = collected.filter(
|
|
2698
|
+
(imp) => imp.types && imp.types.length && !imp.from.startsWith("import ")
|
|
2699
|
+
);
|
|
2700
|
+
const normalized = this.normalizeTsImports(structured);
|
|
2701
|
+
const structuredLines = normalized.map(
|
|
2702
|
+
(i) => `import { ${i.types.join(", ")} } from ${JSON.stringify(i.from)};`
|
|
2703
|
+
);
|
|
2704
|
+
const allLines = Array.from(
|
|
2705
|
+
/* @__PURE__ */ new Set([...rawLines, ...structuredLines])
|
|
2706
|
+
);
|
|
2707
|
+
return allLines.join("\n");
|
|
2662
2708
|
}
|
|
2663
2709
|
// ---------------------------------------------------------------------------
|
|
2664
2710
|
// MODEL RENDERING (DEFAULT)
|
|
@@ -2877,22 +2923,6 @@ function indentBlock(text, indent = " ") {
|
|
|
2877
2923
|
function getDefaultTsOutDir(generator) {
|
|
2878
2924
|
return generator?.output?.value ?? "resources/ts/prisma";
|
|
2879
2925
|
}
|
|
2880
|
-
async function loadMergedDatamodel(schemaPrismaPath) {
|
|
2881
|
-
const schemaDir = path9.dirname(schemaPrismaPath);
|
|
2882
|
-
const entries = readdirSync(schemaDir).filter(
|
|
2883
|
-
(f) => f.endsWith(".prisma")
|
|
2884
|
-
);
|
|
2885
|
-
const order = [
|
|
2886
|
-
// schema.prisma first
|
|
2887
|
-
...entries.filter((f) => f === "schema.prisma"),
|
|
2888
|
-
// then the rest alphabetically
|
|
2889
|
-
...entries.filter((f) => f !== "schema.prisma").sort()
|
|
2890
|
-
];
|
|
2891
|
-
const chunks = await Promise.all(
|
|
2892
|
-
order.map((f) => fs6.readFile(path9.join(schemaDir, f), "utf-8"))
|
|
2893
|
-
);
|
|
2894
|
-
return chunks.join("\n\n");
|
|
2895
|
-
}
|
|
2896
2926
|
function hasModelSpecificTsStub(model, cfg) {
|
|
2897
2927
|
if (!cfg.stubDir) return false;
|
|
2898
2928
|
const key = model.tableName && typeof model.tableName === "string" ? model.tableName : model.name;
|
|
@@ -2908,17 +2938,13 @@ function hasModelSpecificTsStub(model, cfg) {
|
|
|
2908
2938
|
return path9.basename(stubPath) !== "index.stub";
|
|
2909
2939
|
}
|
|
2910
2940
|
async function generateTypesFromPrisma(options) {
|
|
2911
|
-
const { generator } = options;
|
|
2941
|
+
const { dmmf, generator } = options;
|
|
2912
2942
|
const raw = generator.config ?? {};
|
|
2913
|
-
const
|
|
2914
|
-
const schemaDir = path9.dirname(schemaPrismaPath);
|
|
2943
|
+
const schemaDir = path9.dirname(options.schemaPath);
|
|
2915
2944
|
const shared = await loadSharedConfig(schemaDir);
|
|
2916
2945
|
let groups = [];
|
|
2917
2946
|
if (raw["groups"]) {
|
|
2918
|
-
const groupsModulePath = path9.resolve(
|
|
2919
|
-
process.cwd(),
|
|
2920
|
-
raw["groups"]
|
|
2921
|
-
);
|
|
2947
|
+
const groupsModulePath = path9.resolve(process.cwd(), raw["groups"]);
|
|
2922
2948
|
const importedModule = await import(groupsModulePath);
|
|
2923
2949
|
const imported = importedModule.default ?? importedModule;
|
|
2924
2950
|
if (!Array.isArray(imported)) {
|
|
@@ -2929,14 +2955,14 @@ async function generateTypesFromPrisma(options) {
|
|
|
2929
2955
|
groups = imported;
|
|
2930
2956
|
}
|
|
2931
2957
|
const pick = (key, fallback) => (
|
|
2932
|
-
//
|
|
2958
|
+
// shared.ts section (if present)
|
|
2933
2959
|
shared.ts?.[key] ?? // shared root (if you keep ts props there)
|
|
2934
2960
|
shared[key] ?? // generator block config
|
|
2935
2961
|
raw[key] ?? // explicit fallback
|
|
2936
2962
|
fallback
|
|
2937
2963
|
);
|
|
2938
2964
|
const cfg = {
|
|
2939
|
-
//
|
|
2965
|
+
// Laravel-ish generator knobs
|
|
2940
2966
|
overwriteExisting: pick("overwriteExisting", true),
|
|
2941
2967
|
prettier: pick("prettier", false),
|
|
2942
2968
|
noEmit: pick("noEmit", false),
|
|
@@ -2948,6 +2974,11 @@ async function generateTypesFromPrisma(options) {
|
|
|
2948
2974
|
groups,
|
|
2949
2975
|
// TS-specific
|
|
2950
2976
|
outputDir: pick("outputDir") ?? getDefaultTsOutDir(generator),
|
|
2977
|
+
/**
|
|
2978
|
+
* declaration now only affects enums:
|
|
2979
|
+
* - true → enums.d.ts
|
|
2980
|
+
* - false → enums.ts
|
|
2981
|
+
*/
|
|
2951
2982
|
declaration: pick("declaration", false),
|
|
2952
2983
|
shape: pick("shape", "interface"),
|
|
2953
2984
|
scalarMap: pick("scalarMap"),
|
|
@@ -2955,7 +2986,9 @@ async function generateTypesFromPrisma(options) {
|
|
|
2955
2986
|
readonlyArrays: pick("readonlyArrays", false),
|
|
2956
2987
|
namePrefix: pick("namePrefix", ""),
|
|
2957
2988
|
nameSuffix: pick("nameSuffix", ""),
|
|
2958
|
-
moduleName: pick("moduleName", "database/prisma")
|
|
2989
|
+
moduleName: pick("moduleName", "database/prisma"),
|
|
2990
|
+
modelsFileName: pick("modelsFileName", "index"),
|
|
2991
|
+
enumsFileName: pick("enumsFileName", "enums")
|
|
2959
2992
|
};
|
|
2960
2993
|
const tsOutDir = path9.resolve(process.cwd(), cfg.outputDir);
|
|
2961
2994
|
if (!existsSync(tsOutDir)) {
|
|
@@ -2965,9 +2998,6 @@ async function generateTypesFromPrisma(options) {
|
|
|
2965
2998
|
global._config.ts = {
|
|
2966
2999
|
prettier: !!cfg.prettier
|
|
2967
3000
|
};
|
|
2968
|
-
const datamodel = await loadMergedDatamodel(schemaPrismaPath);
|
|
2969
|
-
const sdk = dmf.default ?? dmf;
|
|
2970
|
-
const { dmmf } = await sdk.getDMMF({ datamodel });
|
|
2971
3001
|
const tsGen = new PrismaToTypesGenerator(dmmf, cfg);
|
|
2972
3002
|
const {
|
|
2973
3003
|
models,
|
|
@@ -2988,11 +3018,15 @@ async function generateTypesFromPrisma(options) {
|
|
|
2988
3018
|
moduleName: cfg.moduleName,
|
|
2989
3019
|
shape: cfg.shape
|
|
2990
3020
|
});
|
|
2991
|
-
const
|
|
3021
|
+
const modelExt = ".d.ts";
|
|
3022
|
+
const enumExt = cfg.declaration ? ".d.ts" : ".ts";
|
|
2992
3023
|
if (enums.length) {
|
|
2993
3024
|
const enumsCode = printer.printEnums(enums);
|
|
2994
3025
|
if (enumsCode.trim()) {
|
|
2995
|
-
const enumsPath = path9.join(
|
|
3026
|
+
const enumsPath = path9.join(
|
|
3027
|
+
tsOutDir,
|
|
3028
|
+
`${cfg.enumsFileName ?? "enums"}${enumExt}`
|
|
3029
|
+
);
|
|
2996
3030
|
await writeWithMerge(
|
|
2997
3031
|
enumsPath,
|
|
2998
3032
|
enumsCode,
|
|
@@ -3012,7 +3046,10 @@ async function generateTypesFromPrisma(options) {
|
|
|
3012
3046
|
);
|
|
3013
3047
|
}
|
|
3014
3048
|
if (mainFile.trim()) {
|
|
3015
|
-
const mainPath = path9.join(
|
|
3049
|
+
const mainPath = path9.join(
|
|
3050
|
+
tsOutDir,
|
|
3051
|
+
`${cfg.modelsFileName ?? "index"}${modelExt}`
|
|
3052
|
+
);
|
|
3016
3053
|
await writeWithMerge(
|
|
3017
3054
|
mainPath,
|
|
3018
3055
|
mainFile,
|
|
@@ -3026,7 +3063,7 @@ async function generateTypesFromPrisma(options) {
|
|
|
3026
3063
|
const decoratedName = `${cfg.namePrefix ?? ""}${model.name}${cfg.nameSuffix ?? ""}`;
|
|
3027
3064
|
const filePath = path9.join(
|
|
3028
3065
|
tsOutDir,
|
|
3029
|
-
`${decoratedName}${
|
|
3066
|
+
`${decoratedName}${modelExt}`
|
|
3030
3067
|
);
|
|
3031
3068
|
await writeWithMerge(
|
|
3032
3069
|
filePath,
|