@prisma/cli 3.0.0-dev.88.1 → 3.0.0-dev.91.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,376 +0,0 @@
1
- import { readBunPackageJson } from "./bun-project.js";
2
- import { sourceRootLineage } from "@prisma/compute-sdk/config";
3
- import { readFile, readdir, stat } from "node:fs/promises";
4
- import path from "node:path";
5
- import { exec } from "node:child_process";
6
- import { parseModule } from "magicast";
7
- //#region src/lib/app/preview-build-settings.ts
8
- /** Legacy build-settings file: no longer read or written, only detected for migration. */
9
- const PRISMA_APP_CONFIG_FILENAME = "prisma.app.json";
10
- /**
11
- * Detects a leftover `prisma.app.json`. The file is no longer used: one that
12
- * matches the effective settings is reported for deletion, one with custom
13
- * values must be migrated to the compute config so builds never silently
14
- * change.
15
- */
16
- async function detectLegacyBuildSettings(options) {
17
- const configPath = path.join(options.appPath, PRISMA_APP_CONFIG_FILENAME);
18
- let content;
19
- try {
20
- options.signal?.throwIfAborted();
21
- content = await readFile(configPath, {
22
- encoding: "utf8",
23
- signal: options.signal
24
- });
25
- } catch (error) {
26
- if (options.signal?.aborted) throw error;
27
- return { kind: "absent" };
28
- }
29
- let legacy;
30
- try {
31
- const parsed = JSON.parse(content);
32
- const buildCommand = parsed.buildCommand === null || typeof parsed.buildCommand === "string" ? typeof parsed.buildCommand === "string" ? parsed.buildCommand.trim() || null : null : void 0;
33
- const outputDirectory = typeof parsed.outputDirectory === "string" ? normalizeRelativePath(parsed.outputDirectory) : void 0;
34
- if (buildCommand === void 0 || !outputDirectory) return {
35
- kind: "invalid",
36
- configPath
37
- };
38
- legacy = {
39
- buildCommand,
40
- outputDirectory
41
- };
42
- } catch {
43
- return {
44
- kind: "invalid",
45
- configPath
46
- };
47
- }
48
- return legacy.buildCommand === options.effective.buildCommand && legacy.outputDirectory === options.effective.outputDirectory ? {
49
- kind: "matching",
50
- configPath
51
- } : {
52
- kind: "custom",
53
- configPath,
54
- ...legacy
55
- };
56
- }
57
- /** Resolves build settings purely from framework inference; nothing is read or written. */
58
- async function resolveInferredPreviewBuildSettings(options) {
59
- return {
60
- status: "inferred",
61
- configPath: null,
62
- relativeConfigPath: null,
63
- settings: await resolvePreviewBuildSettings(options)
64
- };
65
- }
66
- /**
67
- * Resolves build settings when the compute config owns them: configured
68
- * fields win, omitted fields fall back to framework defaults.
69
- */
70
- async function resolveConfiguredPreviewBuildSettings(options) {
71
- const configFilename = path.basename(options.configPath);
72
- const source = `set by ${configFilename}`;
73
- const fallback = options.configured.command === void 0 || options.configured.outputDirectory === void 0 ? await resolvePreviewBuildSettings(options) : null;
74
- return {
75
- status: "config",
76
- configPath: options.configPath,
77
- relativeConfigPath: configFilename,
78
- settings: {
79
- buildCommand: options.configured.command !== void 0 ? options.configured.command : fallback.buildCommand,
80
- buildCommandSource: options.configured.command !== void 0 ? source : fallback.buildCommandSource,
81
- outputDirectory: options.configured.outputDirectory ?? fallback.outputDirectory,
82
- outputDirectorySource: options.configured.outputDirectory !== void 0 ? source : fallback.outputDirectorySource
83
- }
84
- };
85
- }
86
- async function resolvePreviewBuildSettings(options) {
87
- switch (options.buildType) {
88
- case "nuxt": return {
89
- buildCommand: "nuxt build",
90
- buildCommandSource: "Nuxt default",
91
- outputDirectory: ".output",
92
- outputDirectorySource: "Nuxt output"
93
- };
94
- case "astro": return {
95
- buildCommand: "astro build",
96
- buildCommandSource: "Astro default",
97
- outputDirectory: "dist",
98
- outputDirectorySource: "Astro output"
99
- };
100
- case "nextjs": {
101
- const packageJson = await readBunPackageJson(options.appPath, options.signal);
102
- const buildCommand = await resolveFrameworkBuildCommand(options.appPath, packageJson, {
103
- command: "next build",
104
- source: "Next.js default",
105
- signal: options.signal
106
- });
107
- const outputRoot = await resolveNextOutputRoot(options.appPath, options.signal);
108
- return {
109
- buildCommand: buildCommand.command,
110
- buildCommandSource: buildCommand.source,
111
- outputDirectory: joinPosix(outputRoot, "standalone"),
112
- outputDirectorySource: outputRoot === ".next" ? "Next.js output" : "next.config distDir"
113
- };
114
- }
115
- case "tanstack-start": {
116
- const packageJson = await readBunPackageJson(options.appPath, options.signal);
117
- const buildCommand = await resolveFrameworkBuildCommand(options.appPath, packageJson, {
118
- command: "vite build",
119
- source: "TanStack Start default",
120
- signal: options.signal
121
- });
122
- return {
123
- buildCommand: buildCommand.command,
124
- buildCommandSource: buildCommand.source,
125
- outputDirectory: ".output",
126
- outputDirectorySource: "TanStack Start output"
127
- };
128
- }
129
- case "bun": {
130
- const packageJson = await readBunPackageJson(options.appPath, options.signal);
131
- const buildCommand = await resolveFrameworkBuildCommand(options.appPath, packageJson, {
132
- command: null,
133
- source: null,
134
- signal: options.signal
135
- });
136
- return {
137
- buildCommand: buildCommand.command,
138
- buildCommandSource: buildCommand.source,
139
- outputDirectory: ".",
140
- outputDirectorySource: "app root"
141
- };
142
- }
143
- }
144
- }
145
- async function hasRootFile(appPath, filenames, signal) {
146
- let entries;
147
- try {
148
- signal?.throwIfAborted();
149
- entries = await readdir(appPath);
150
- signal?.throwIfAborted();
151
- } catch (error) {
152
- if (signal?.aborted) throw error;
153
- return false;
154
- }
155
- return entries.some((entry) => filenames.includes(entry));
156
- }
157
- function hasPackageDependency(packageJson, dependencyName) {
158
- return hasAnyPackageDependency(packageJson, [dependencyName]);
159
- }
160
- function hasAnyPackageDependency(packageJson, dependencyNames) {
161
- if (!packageJson) return false;
162
- return [packageJson.dependencies, packageJson.devDependencies].some((group) => {
163
- if (!group || typeof group !== "object") return false;
164
- return dependencyNames.some((dependencyName) => dependencyName in group);
165
- });
166
- }
167
- async function resolveFrameworkBuildCommand(appPath, packageJson, fallback) {
168
- const buildScript = readBuildScript(packageJson);
169
- if (buildScript) {
170
- const packageManager = await resolvePackageManager(appPath, packageJson, fallback.signal);
171
- if (!packageManager) return {
172
- command: buildScript,
173
- source: "package.json scripts.build"
174
- };
175
- return {
176
- command: `${packageManager} run build`,
177
- source: "package.json scripts.build"
178
- };
179
- }
180
- return {
181
- command: fallback.command,
182
- source: fallback.source
183
- };
184
- }
185
- function readBuildScript(packageJson) {
186
- if (!packageJson?.scripts || typeof packageJson.scripts !== "object") return null;
187
- const scripts = packageJson.scripts;
188
- if (typeof scripts.build !== "string") return null;
189
- const buildScript = scripts.build.trim();
190
- return buildScript.length > 0 ? buildScript : null;
191
- }
192
- async function resolvePackageManager(appPath, packageJson, signal) {
193
- for (const directory of await sourceRootLineage(appPath, signal)) {
194
- const fromPackageManager = packageManagerFromPackageJson((directory === path.resolve(appPath) ? packageJson : await readBunPackageJson(directory, signal))?.packageManager);
195
- if (fromPackageManager) return fromPackageManager;
196
- if (await pathExists(path.join(directory, "bun.lock"), signal) || await pathExists(path.join(directory, "bun.lockb"), signal)) return "bun";
197
- if (await pathExists(path.join(directory, "pnpm-lock.yaml"), signal)) return "pnpm";
198
- if (await pathExists(path.join(directory, "yarn.lock"), signal)) return "yarn";
199
- if (await pathExists(path.join(directory, "package-lock.json"), signal)) return "npm";
200
- }
201
- }
202
- function packageManagerFromPackageJson(value) {
203
- if (typeof value !== "string") return null;
204
- const name = value.split("@")[0];
205
- return name === "bun" || name === "pnpm" || name === "yarn" || name === "npm" ? name : null;
206
- }
207
- async function runResolvedBuildCommand(appPath, settings, failurePrefix, signal) {
208
- if (!settings.buildCommand) return;
209
- const binDirs = (await sourceRootLineage(appPath, signal)).map((directory) => path.join(directory, "node_modules", ".bin"));
210
- await execBuildCommand(settings.buildCommand, appPath, binDirs, failurePrefix, signal);
211
- }
212
- function execBuildCommand(command, cwd, binDirs, failurePrefix, signal) {
213
- return new Promise((resolve, reject) => {
214
- const child = exec(command, {
215
- cwd,
216
- env: {
217
- ...process.env,
218
- PATH: [...binDirs, process.env.PATH].filter(Boolean).join(path.delimiter)
219
- },
220
- maxBuffer: 10 * 1024 * 1024,
221
- signal
222
- }, (error, stdout, stderr) => {
223
- if (error) {
224
- const output = [stderr.trim(), stdout.trim()].filter(Boolean).join("\n");
225
- reject(/* @__PURE__ */ new Error(`${failurePrefix} failed:\n${output || error.message}`));
226
- return;
227
- }
228
- resolve();
229
- });
230
- if (signal?.aborted) child.kill();
231
- });
232
- }
233
- async function resolveNextOutputRoot(appPath, signal) {
234
- return (await readNextConfig(appPath, signal)).distDir ?? ".next";
235
- }
236
- async function readNextConfig(appPath, signal) {
237
- for (const fileName of NEXT_CONFIG_FILENAMES) {
238
- const filePath = path.join(appPath, fileName);
239
- let content;
240
- try {
241
- content = await readFile(filePath, {
242
- encoding: "utf8",
243
- signal
244
- });
245
- } catch (error) {
246
- if (error.code === "ENOENT") continue;
247
- throw error;
248
- }
249
- return readStaticNextConfig(content);
250
- }
251
- return {};
252
- }
253
- const NEXT_CONFIG_FILENAMES = [
254
- "next.config.js",
255
- "next.config.mjs",
256
- "next.config.ts",
257
- "next.config.mts"
258
- ];
259
- function readStaticNextConfig(content) {
260
- try {
261
- const program = asAstNode(parseModule(content).$ast);
262
- const bindings = program ? collectStaticBindings(program) : /* @__PURE__ */ new Map();
263
- const configObject = program ? findExportedConfigObject(program, bindings) : null;
264
- if (!configObject) return {};
265
- const rawDistDir = readStaticStringProperty(configObject, "distDir");
266
- const output = readStaticStringProperty(configObject, "output");
267
- return {
268
- distDir: rawDistDir ? normalizeRelativePath(rawDistDir) : void 0,
269
- output: output === "standalone" || output === "export" ? output : void 0
270
- };
271
- } catch {
272
- return {};
273
- }
274
- }
275
- function joinPosix(...parts) {
276
- return parts.join("/").replace(/\/+/g, "/");
277
- }
278
- function nextOutputRootFromStandaloneDirectory(outputDirectory) {
279
- const normalized = outputDirectory.replace(/\/+$/g, "");
280
- if (normalized === "standalone") return ".";
281
- if (normalized.endsWith("/standalone")) {
282
- const outputRoot = normalized.slice(0, -11);
283
- return outputRoot.length > 0 ? outputRoot : ".";
284
- }
285
- const dirname = path.posix.dirname(normalized);
286
- return dirname === "." ? "." : dirname;
287
- }
288
- function asAstNode(value) {
289
- if (!value || typeof value !== "object") return null;
290
- return typeof value.type === "string" ? value : null;
291
- }
292
- function astNodes(value) {
293
- if (!Array.isArray(value)) return [];
294
- return value.map(asAstNode).filter((node) => Boolean(node));
295
- }
296
- function collectStaticBindings(program) {
297
- const bindings = /* @__PURE__ */ new Map();
298
- for (const statement of astNodes(program.body)) {
299
- if (statement.type !== "VariableDeclaration") continue;
300
- for (const declaration of astNodes(statement.declarations)) {
301
- const id = asAstNode(declaration.id);
302
- const init = asAstNode(declaration.init);
303
- if (id?.type === "Identifier" && typeof id.name === "string" && init) bindings.set(id.name, init);
304
- }
305
- }
306
- return bindings;
307
- }
308
- function findExportedConfigObject(program, bindings) {
309
- for (const statement of astNodes(program.body)) {
310
- if (statement.type === "ExportDefaultDeclaration") return resolveConfigObject(statement.declaration, bindings);
311
- if (statement.type !== "ExpressionStatement") continue;
312
- const expression = asAstNode(statement.expression);
313
- if (expression?.type !== "AssignmentExpression" || expression.operator !== "=") continue;
314
- if (isModuleExports(expression.left)) return resolveConfigObject(expression.right, bindings);
315
- }
316
- return null;
317
- }
318
- function resolveConfigObject(value, bindings, depth = 0) {
319
- if (depth > 4) return null;
320
- const node = unwrapStaticExpression(asAstNode(value));
321
- if (!node) return null;
322
- if (node.type === "ObjectExpression") return node;
323
- if (node.type === "Identifier" && typeof node.name === "string") return resolveConfigObject(bindings.get(node.name), bindings, depth + 1);
324
- if (node.type === "CallExpression") return resolveConfigObject(astNodes(node.arguments)[0], bindings, depth + 1);
325
- return null;
326
- }
327
- function unwrapStaticExpression(node) {
328
- let current = node;
329
- while (current?.type === "TSAsExpression" || current?.type === "TSSatisfiesExpression" || current?.type === "TSNonNullExpression") current = asAstNode(current.expression);
330
- return current;
331
- }
332
- function isModuleExports(value) {
333
- const node = asAstNode(value);
334
- if (node?.type !== "MemberExpression" || node.computed === true) return false;
335
- const object = asAstNode(node.object);
336
- const property = asAstNode(node.property);
337
- return object?.type === "Identifier" && object.name === "module" && property?.type === "Identifier" && property.name === "exports";
338
- }
339
- function readStaticStringProperty(objectExpression, propertyName) {
340
- for (const property of astNodes(objectExpression.properties)) {
341
- if (property.type !== "ObjectProperty" || property.computed === true) continue;
342
- if (propertyKeyName(property.key) !== propertyName) continue;
343
- const value = unwrapStaticExpression(asAstNode(property.value));
344
- if (value?.type === "StringLiteral" && typeof value.value === "string") {
345
- const trimmed = value.value.trim();
346
- return trimmed.length > 0 ? trimmed : void 0;
347
- }
348
- }
349
- }
350
- function propertyKeyName(value) {
351
- const key = asAstNode(value);
352
- if (key?.type === "Identifier" && typeof key.name === "string") return key.name;
353
- if (key?.type === "StringLiteral" && typeof key.value === "string") return key.value;
354
- }
355
- function normalizeRelativePath(value) {
356
- const raw = value.trim().replace(/\\/g, "/");
357
- if (raw.length === 0 || raw.split("/").includes("..")) return;
358
- if (/^[A-Za-z]:/.test(raw)) return;
359
- const normalized = path.posix.normalize(raw);
360
- const segments = normalized.split("/");
361
- if (path.win32.isAbsolute(value) || path.posix.isAbsolute(normalized) || segments.includes("..")) return;
362
- return normalized === "." ? "." : normalized;
363
- }
364
- async function pathExists(targetPath, signal) {
365
- try {
366
- signal?.throwIfAborted();
367
- await stat(targetPath);
368
- signal?.throwIfAborted();
369
- return true;
370
- } catch (error) {
371
- if (signal?.aborted) throw error;
372
- return false;
373
- }
374
- }
375
- //#endregion
376
- export { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, hasAnyPackageDependency, hasPackageDependency, hasRootFile, joinPosix, nextOutputRootFromStandaloneDirectory, resolveConfiguredPreviewBuildSettings, resolveInferredPreviewBuildSettings, resolvePreviewBuildSettings, runResolvedBuildCommand };