@prisma-next/cli 0.5.0-dev.11 → 0.5.0-dev.12
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 +37 -3
- package/dist/cli.mjs +7 -14
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-faKQqcix.mjs → client-enZIahga.mjs} +5 -5
- package/dist/{client-faKQqcix.mjs.map → client-enZIahga.mjs.map} +1 -1
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +2 -7
- package/dist/commands/contract-infer.mjs +2 -8
- package/dist/commands/db-init.mjs +7 -8
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +5 -8
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +6 -7
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +7 -8
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +8 -9
- package/dist/commands/db-verify.mjs.map +1 -1
- package/dist/commands/migration-apply.mjs +6 -7
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +6 -6
- package/dist/commands/migration-plan.mjs +7 -7
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +3 -3
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +5 -5
- package/dist/commands/migration-status.mjs +2 -7
- package/dist/{config-loader-C25b63rJ.mjs → config-loader-ih8ViDb_.mjs} +2 -2
- package/dist/{config-loader-C25b63rJ.mjs.map → config-loader-ih8ViDb_.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/contract-emit-DWtGQYCD.mjs +150 -0
- package/dist/contract-emit-DWtGQYCD.mjs.map +1 -0
- package/dist/contract-emit-LjzCoicC.mjs +4 -0
- package/dist/contract-emit-RZBWzkop.mjs +329 -0
- package/dist/contract-emit-RZBWzkop.mjs.map +1 -0
- package/dist/{contract-enrichment-CAOELa-H.mjs → contract-enrichment-4Ptgw3Pe.mjs} +1 -1
- package/dist/{contract-enrichment-CAOELa-H.mjs.map → contract-enrichment-4Ptgw3Pe.mjs.map} +1 -1
- package/dist/{contract-infer-BgnsSkGp.mjs → contract-infer-BjzkcwQt.mjs} +5 -5
- package/dist/{contract-infer-BgnsSkGp.mjs.map → contract-infer-BjzkcwQt.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +41 -16
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +5 -7
- package/dist/exports/index.mjs +3 -8
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{extract-operation-statements-DsFfxXVZ.mjs → extract-operation-statements-CU-Pp4-N.mjs} +2 -2
- package/dist/{extract-operation-statements-DsFfxXVZ.mjs.map → extract-operation-statements-CU-Pp4-N.mjs.map} +1 -1
- package/dist/{extract-sql-ddl-D9UbZDyz.mjs → extract-sql-ddl-Bm0Mm0IT.mjs} +1 -1
- package/dist/{extract-sql-ddl-D9UbZDyz.mjs.map → extract-sql-ddl-Bm0Mm0IT.mjs.map} +1 -1
- package/dist/{framework-components-C6el-5x_.mjs → framework-components-Bgcre3Z6.mjs} +1 -1
- package/dist/{framework-components-C6el-5x_.mjs.map → framework-components-Bgcre3Z6.mjs.map} +1 -1
- package/dist/{init-jf33mNQ6.mjs → init-BKgjxw6r.mjs} +5 -5
- package/dist/{init-jf33mNQ6.mjs.map → init-BKgjxw6r.mjs.map} +1 -1
- package/dist/{inspect-live-schema-yCu0JT0I.mjs → inspect-live-schema-QklSDLt_.mjs} +5 -5
- package/dist/{inspect-live-schema-yCu0JT0I.mjs.map → inspect-live-schema-QklSDLt_.mjs.map} +1 -1
- package/dist/migration-cli.mjs +2 -2
- package/dist/{migration-command-scaffold-B8HAEGhQ.mjs → migration-command-scaffold-BfloSWPZ.mjs} +6 -6
- package/dist/{migration-command-scaffold-B8HAEGhQ.mjs.map → migration-command-scaffold-BfloSWPZ.mjs.map} +1 -1
- package/dist/{migration-status-8QUxCJHE.mjs → migration-status-C5VYA5r9.mjs} +7 -7
- package/dist/{migration-status-8QUxCJHE.mjs.map → migration-status-C5VYA5r9.mjs.map} +1 -1
- package/dist/{migrations-CKRMAKka.mjs → migrations-CSaDHNpB.mjs} +2 -2
- package/dist/{migrations-CKRMAKka.mjs.map → migrations-CSaDHNpB.mjs.map} +1 -1
- package/dist/{output-BpcQrnnq.mjs → output-BiO7kt87.mjs} +1 -1
- package/dist/{output-BpcQrnnq.mjs.map → output-BiO7kt87.mjs.map} +1 -1
- package/dist/{progress-adapter-DvQWB1nK.mjs → progress-adapter-DgRGldpT.mjs} +1 -1
- package/dist/{progress-adapter-DvQWB1nK.mjs.map → progress-adapter-DgRGldpT.mjs.map} +1 -1
- package/dist/{result-handler-CuhZ3kNu.mjs → result-handler-BmVh8AeV.mjs} +4 -4
- package/dist/{result-handler-CuhZ3kNu.mjs.map → result-handler-BmVh8AeV.mjs.map} +1 -1
- package/dist/{terminal-ui-C3ZLwQxK.mjs → terminal-ui-u2YgKghu.mjs} +1 -1
- package/dist/{terminal-ui-C3ZLwQxK.mjs.map → terminal-ui-u2YgKghu.mjs.map} +1 -1
- package/dist/{verify-Bkycc-Tf.mjs → verify-BumcH6Ry.mjs} +2 -2
- package/dist/{verify-Bkycc-Tf.mjs.map → verify-BumcH6Ry.mjs.map} +1 -1
- package/package.json +16 -16
- package/src/commands/contract-emit.ts +67 -163
- package/src/control-api/operations/contract-emit.ts +198 -115
- package/src/control-api/types.ts +22 -3
- package/src/exports/control-api.ts +2 -1
- package/src/utils/emit-queue.ts +26 -0
- package/src/utils/publish-contract-artifact-pair.ts +134 -0
- package/dist/contract-emit-B9wkchud.mjs +0 -6
- package/dist/contract-emit-Cf3fjDL6.mjs +0 -195
- package/dist/contract-emit-Cf3fjDL6.mjs.map +0 -1
- package/dist/contract-emit-PeB96eHy.mjs +0 -122
- package/dist/contract-emit-PeB96eHy.mjs.map +0 -1
- package/dist/validate-contract-deps-B_Cs29TL.mjs +0 -37
- package/dist/validate-contract-deps-B_Cs29TL.mjs.map +0 -1
- /package/dist/{cli-errors-D2NPMaxW.d.mts → cli-errors-BJLUczXT.d.mts} +0 -0
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { t as loadConfig } from "./config-loader-C25b63rJ.mjs";
|
|
2
|
-
import { _ as errorUnexpected$1, a as errorContractValidationFailed, m as errorRuntime, t as CliStructuredError$1 } from "./cli-errors-By1iVE3z.mjs";
|
|
3
|
-
import { t as createControlClient } from "./client-faKQqcix.mjs";
|
|
4
|
-
import { s as isVerbose, t as TerminalUI } from "./terminal-ui-C3ZLwQxK.mjs";
|
|
5
|
-
import { _ as formatStyledHeader, d as setCommandExamples, m as parseGlobalFlags, n as addGlobalOptions, t as handleResult, u as setCommandDescriptions, v as formatSuccessMessage } from "./result-handler-CuhZ3kNu.mjs";
|
|
6
|
-
import { t as createProgressAdapter } from "./progress-adapter-DvQWB1nK.mjs";
|
|
7
|
-
import { Command } from "commander";
|
|
8
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
10
|
-
import { errorContractConfigMissing } from "@prisma-next/errors/control";
|
|
11
|
-
import { notOk, ok } from "@prisma-next/utils/result";
|
|
12
|
-
import { dirname, relative, resolve } from "pathe";
|
|
13
|
-
import { ifDefined } from "@prisma-next/utils/defined";
|
|
14
|
-
|
|
15
|
-
//#region src/utils/formatters/emit.ts
|
|
16
|
-
/**
|
|
17
|
-
* Formats human-readable output for contract emit.
|
|
18
|
-
*/
|
|
19
|
-
function formatEmitOutput(result, flags) {
|
|
20
|
-
if (flags.quiet) return "";
|
|
21
|
-
const lines = [];
|
|
22
|
-
const jsonPath = relative(process.cwd(), result.files.json);
|
|
23
|
-
const dtsPath = relative(process.cwd(), result.files.dts);
|
|
24
|
-
lines.push(`✔ Emitted contract.json → ${jsonPath}`);
|
|
25
|
-
lines.push(`✔ Emitted contract.d.ts → ${dtsPath}`);
|
|
26
|
-
lines.push(` storageHash: ${result.storageHash}`);
|
|
27
|
-
if (result.executionHash) lines.push(` executionHash: ${result.executionHash}`);
|
|
28
|
-
if (result.profileHash) lines.push(` profileHash: ${result.profileHash}`);
|
|
29
|
-
if (isVerbose(flags, 1)) lines.push(` Total time: ${result.timings.total}ms`);
|
|
30
|
-
return lines.join("\n");
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Formats JSON output for contract emit.
|
|
34
|
-
*/
|
|
35
|
-
function formatEmitJson(result) {
|
|
36
|
-
const output = {
|
|
37
|
-
ok: true,
|
|
38
|
-
storageHash: result.storageHash,
|
|
39
|
-
...ifDefined("executionHash", result.executionHash),
|
|
40
|
-
...result.profileHash ? { profileHash: result.profileHash } : {},
|
|
41
|
-
outDir: result.outDir,
|
|
42
|
-
files: result.files,
|
|
43
|
-
timings: result.timings
|
|
44
|
-
};
|
|
45
|
-
return JSON.stringify(output, null, 2);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
//#endregion
|
|
49
|
-
//#region src/commands/contract-emit.ts
|
|
50
|
-
function mapDiagnosticsToIssues(failure) {
|
|
51
|
-
return (failure.diagnostics?.diagnostics ?? []).map((diagnostic) => {
|
|
52
|
-
const location = diagnostic.sourceId && diagnostic.span ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})` : diagnostic.sourceId ? ` (${diagnostic.sourceId})` : "";
|
|
53
|
-
return {
|
|
54
|
-
kind: diagnostic.code,
|
|
55
|
-
message: `${diagnostic.message}${location}`
|
|
56
|
-
};
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Maps an EmitFailure to a CliStructuredError for consistent error handling.
|
|
61
|
-
*/
|
|
62
|
-
function mapEmitFailure(failure, context) {
|
|
63
|
-
if (failure.code === "CONTRACT_SOURCE_INVALID") {
|
|
64
|
-
const issues = mapDiagnosticsToIssues(failure);
|
|
65
|
-
return errorRuntime(failure.summary, {
|
|
66
|
-
why: failure.why ?? "Contract source provider failed",
|
|
67
|
-
fix: "Check your contract source provider in prisma-next.config.ts and ensure it returns Result<Contract, Diagnostics>",
|
|
68
|
-
...issues.length > 0 ? { meta: { issues } } : {}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
if (failure.code === "CONTRACT_VALIDATION_FAILED") return errorContractValidationFailed(failure.why ?? "Contract validation failed while emitting", context?.configPath ? { where: { path: context.configPath } } : void 0);
|
|
72
|
-
if (failure.code === "EMIT_FAILED") return errorRuntime(failure.summary, {
|
|
73
|
-
why: failure.why ?? "Failed to emit contract",
|
|
74
|
-
fix: "Check your contract configuration and ensure the source is valid"
|
|
75
|
-
});
|
|
76
|
-
const exhaustive = failure.code;
|
|
77
|
-
throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Executes the contract emit command and returns a structured Result.
|
|
81
|
-
*/
|
|
82
|
-
async function executeContractEmitCommand(options, flags, ui, startTime) {
|
|
83
|
-
let config;
|
|
84
|
-
try {
|
|
85
|
-
config = await loadConfig(options.config);
|
|
86
|
-
} catch (error) {
|
|
87
|
-
if (error instanceof CliStructuredError$1) return notOk(error);
|
|
88
|
-
return notOk(errorUnexpected$1(error instanceof Error ? error.message : String(error), { why: "Failed to load config" }));
|
|
89
|
-
}
|
|
90
|
-
const configPath = options.config ? relative(process.cwd(), resolve(options.config)) : "prisma-next.config.ts";
|
|
91
|
-
if (!config.contract) return notOk(errorContractConfigMissing({ why: "Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }" }));
|
|
92
|
-
const contractConfig = config.contract;
|
|
93
|
-
if (!contractConfig.output) return notOk(errorContractConfigMissing({ why: "Contract config must have output path. This should not happen if defineConfig() was used." }));
|
|
94
|
-
let outputPaths;
|
|
95
|
-
try {
|
|
96
|
-
outputPaths = getEmittedArtifactPaths(contractConfig.output);
|
|
97
|
-
} catch (error) {
|
|
98
|
-
return notOk(errorContractConfigMissing({ why: error instanceof Error ? error.message : String(error) }));
|
|
99
|
-
}
|
|
100
|
-
const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = outputPaths;
|
|
101
|
-
if (!flags.json && !flags.quiet) {
|
|
102
|
-
const contractPath = relative(process.cwd(), outputJsonPath);
|
|
103
|
-
const typesPath = relative(process.cwd(), outputDtsPath);
|
|
104
|
-
const header = formatStyledHeader({
|
|
105
|
-
command: "contract emit",
|
|
106
|
-
description: "Emit your contract artifacts",
|
|
107
|
-
url: "https://pris.ly/contract-emit",
|
|
108
|
-
details: [
|
|
109
|
-
{
|
|
110
|
-
label: "config",
|
|
111
|
-
value: configPath
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
label: "contract",
|
|
115
|
-
value: contractPath
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
label: "types",
|
|
119
|
-
value: typesPath
|
|
120
|
-
}
|
|
121
|
-
],
|
|
122
|
-
flags
|
|
123
|
-
});
|
|
124
|
-
ui.stderr(header);
|
|
125
|
-
}
|
|
126
|
-
const client = createControlClient({
|
|
127
|
-
family: config.family,
|
|
128
|
-
target: config.target,
|
|
129
|
-
adapter: config.adapter,
|
|
130
|
-
extensionPacks: config.extensionPacks ?? []
|
|
131
|
-
});
|
|
132
|
-
const onProgress = createProgressAdapter({
|
|
133
|
-
ui,
|
|
134
|
-
flags
|
|
135
|
-
});
|
|
136
|
-
try {
|
|
137
|
-
const result = await client.emit({
|
|
138
|
-
contractConfig: {
|
|
139
|
-
source: contractConfig.source,
|
|
140
|
-
output: outputJsonPath
|
|
141
|
-
},
|
|
142
|
-
onProgress
|
|
143
|
-
});
|
|
144
|
-
if (!result.ok) return notOk(mapEmitFailure(result.failure, { configPath }));
|
|
145
|
-
mkdirSync(dirname(outputJsonPath), { recursive: true });
|
|
146
|
-
mkdirSync(dirname(outputDtsPath), { recursive: true });
|
|
147
|
-
writeFileSync(outputJsonPath, result.value.contractJson, "utf-8");
|
|
148
|
-
writeFileSync(outputDtsPath, result.value.contractDts, "utf-8");
|
|
149
|
-
const { validateContractDeps } = await import("./validate-contract-deps-B_Cs29TL.mjs");
|
|
150
|
-
const depsValidation = validateContractDeps(result.value.contractDts, dirname(outputDtsPath));
|
|
151
|
-
if (depsValidation.warning) ui.warn(depsValidation.warning);
|
|
152
|
-
return ok({
|
|
153
|
-
storageHash: result.value.storageHash,
|
|
154
|
-
...result.value.executionHash ? { executionHash: result.value.executionHash } : {},
|
|
155
|
-
profileHash: result.value.profileHash,
|
|
156
|
-
outDir: dirname(outputJsonPath),
|
|
157
|
-
files: {
|
|
158
|
-
json: outputJsonPath,
|
|
159
|
-
dts: outputDtsPath
|
|
160
|
-
},
|
|
161
|
-
timings: { total: Date.now() - startTime }
|
|
162
|
-
});
|
|
163
|
-
} catch (error) {
|
|
164
|
-
if (CliStructuredError$1.is(error)) return notOk(error);
|
|
165
|
-
return notOk(errorUnexpected$1("Unexpected error during contract emit", { why: error instanceof Error ? error.message : String(error) }));
|
|
166
|
-
} finally {
|
|
167
|
-
await client.close();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
function createContractEmitCommand() {
|
|
171
|
-
const command = new Command("emit");
|
|
172
|
-
setCommandDescriptions(command, "Emit your contract artifacts", "Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\ncontract.d.ts. The contract.json contains the canonical contract structure, and\ncontract.d.ts provides TypeScript types for type-safe query building.");
|
|
173
|
-
setCommandExamples(command, ["prisma-next contract emit", "prisma-next contract emit --config ./custom-config.ts"]);
|
|
174
|
-
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
175
|
-
const flags = parseGlobalFlags(options);
|
|
176
|
-
const ui = new TerminalUI({
|
|
177
|
-
color: flags.color,
|
|
178
|
-
interactive: flags.interactive
|
|
179
|
-
});
|
|
180
|
-
const exitCode = handleResult(await executeContractEmitCommand(options, flags, ui, Date.now()), flags, ui, (emitResult) => {
|
|
181
|
-
if (flags.json) ui.output(formatEmitJson(emitResult));
|
|
182
|
-
else {
|
|
183
|
-
const output = formatEmitOutput(emitResult, flags);
|
|
184
|
-
if (output) ui.log(output);
|
|
185
|
-
if (!flags.quiet) ui.success(formatSuccessMessage(flags));
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
process.exit(exitCode);
|
|
189
|
-
});
|
|
190
|
-
return command;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
//#endregion
|
|
194
|
-
export { createContractEmitCommand as t };
|
|
195
|
-
//# sourceMappingURL=contract-emit-Cf3fjDL6.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-emit-Cf3fjDL6.mjs","names":["lines: string[]","exhaustive: never","config: Awaited<ReturnType<typeof loadConfig>>","CliStructuredError","errorUnexpected","outputPaths: ReturnType<typeof getEmittedArtifactPaths>"],"sources":["../src/utils/formatters/emit.ts","../src/commands/contract-emit.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { relative } from 'pathe';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { isVerbose } from './helpers';\n\n// EmitContractResult type for CLI output formatting (includes file paths)\nexport interface EmitContractResult {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n readonly outDir: string;\n readonly files: {\n readonly json: string;\n readonly dts: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for contract emit.\n */\nexport function formatEmitOutput(result: EmitContractResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n // Convert absolute paths to relative paths from cwd\n const jsonPath = relative(process.cwd(), result.files.json);\n const dtsPath = relative(process.cwd(), result.files.dts);\n\n lines.push(`✔ Emitted contract.json → ${jsonPath}`);\n lines.push(`✔ Emitted contract.d.ts → ${dtsPath}`);\n lines.push(` storageHash: ${result.storageHash}`);\n if (result.executionHash) {\n lines.push(` executionHash: ${result.executionHash}`);\n }\n if (result.profileHash) {\n lines.push(` profileHash: ${result.profileHash}`);\n }\n if (isVerbose(flags, 1)) {\n lines.push(` Total time: ${result.timings.total}ms`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for contract emit.\n */\nexport function formatEmitJson(result: EmitContractResult): string {\n const output = {\n ok: true,\n storageHash: result.storageHash,\n ...ifDefined('executionHash', result.executionHash),\n ...(result.profileHash ? { profileHash: result.profileHash } : {}),\n outDir: result.outDir,\n files: result.files,\n timings: result.timings,\n };\n\n return JSON.stringify(output, null, 2);\n}\n","import { mkdirSync, writeFileSync } from 'node:fs';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { errorContractConfigMissing } from '@prisma-next/errors/control';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { EmitFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorRuntime,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport {\n type EmitContractResult,\n formatEmitJson,\n formatEmitOutput,\n} from '../utils/formatters/emit';\nimport { formatStyledHeader, formatSuccessMessage } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface ContractEmitOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nfunction mapDiagnosticsToIssues(\n failure: EmitFailure,\n): ReadonlyArray<{ kind: string; message: string }> {\n const diagnostics = failure.diagnostics?.diagnostics ?? [];\n return diagnostics.map((diagnostic) => {\n const location =\n diagnostic.sourceId && diagnostic.span\n ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})`\n : diagnostic.sourceId\n ? ` (${diagnostic.sourceId})`\n : '';\n return {\n kind: diagnostic.code,\n message: `${diagnostic.message}${location}`,\n };\n });\n}\n\n/**\n * Maps an EmitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapEmitFailure(\n failure: EmitFailure,\n context?: { readonly configPath?: string },\n): CliStructuredError {\n if (failure.code === 'CONTRACT_SOURCE_INVALID') {\n const issues = mapDiagnosticsToIssues(failure);\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Contract source provider failed',\n fix: 'Check your contract source provider in prisma-next.config.ts and ensure it returns Result<Contract, Diagnostics>',\n ...(issues.length > 0 ? { meta: { issues } } : {}),\n });\n }\n\n if (failure.code === 'CONTRACT_VALIDATION_FAILED') {\n return errorContractValidationFailed(\n failure.why ?? 'Contract validation failed while emitting',\n context?.configPath ? { where: { path: context.configPath } } : undefined,\n );\n }\n\n if (failure.code === 'EMIT_FAILED') {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Failed to emit contract',\n fix: 'Check your contract configuration and ensure the source is valid',\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the contract emit command and returns a structured Result.\n */\nasync function executeContractEmitCommand(\n options: ContractEmitOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<EmitContractResult, CliStructuredError>> {\n // Load config\n let config: Awaited<ReturnType<typeof loadConfig>>;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n // Convert thrown CliStructuredError to Result\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n // Resolve contract from config\n if (!config.contract) {\n return notOk(\n errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n }),\n );\n }\n\n // Contract config is already normalized by defineConfig() with defaults applied\n const contractConfig = config.contract;\n\n // Resolve artifact paths from config (already normalized by defineConfig() with defaults)\n if (!contractConfig.output) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n }),\n );\n }\n let outputPaths: ReturnType<typeof getEmittedArtifactPaths>;\n try {\n outputPaths = getEmittedArtifactPaths(contractConfig.output);\n } catch (error) {\n return notOk(\n errorContractConfigMissing({\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = outputPaths;\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const contractPath = relative(process.cwd(), outputJsonPath);\n const typesPath = relative(process.cwd(), outputDtsPath);\n const header = formatStyledHeader({\n command: 'contract emit',\n description: 'Emit your contract artifacts',\n url: 'https://pris.ly/contract-emit',\n details: [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'types', value: typesPath },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n // Create control client (no driver needed for emit)\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Call emit with progress callback\n const result = await client.emit({\n contractConfig: {\n source: contractConfig.source,\n output: outputJsonPath,\n },\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapEmitFailure(result.failure, { configPath }));\n }\n\n // Create directories if needed\n mkdirSync(dirname(outputJsonPath), { recursive: true });\n mkdirSync(dirname(outputDtsPath), { recursive: true });\n\n // Write the results to files\n writeFileSync(outputJsonPath, result.value.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, result.value.contractDts, 'utf-8');\n\n // Validate that contract.d.ts type imports are resolvable\n const { validateContractDeps } = await import('../utils/validate-contract-deps');\n const depsValidation = validateContractDeps(result.value.contractDts, dirname(outputDtsPath));\n if (depsValidation.warning) {\n ui.warn(depsValidation.warning);\n }\n\n // Convert success result to CLI output format\n const emitResult: EmitContractResult = {\n storageHash: result.value.storageHash,\n ...(result.value.executionHash ? { executionHash: result.value.executionHash } : {}),\n profileHash: result.value.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: { total: Date.now() - startTime },\n };\n\n return ok(emitResult);\n } catch (error) {\n // Use static type guard to work across module boundaries\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected('Unexpected error during contract emit', {\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Emit your contract artifacts',\n 'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\\n' +\n 'contract.d.ts. The contract.json contains the canonical contract structure, and\\n' +\n 'contract.d.ts provides TypeScript types for type-safe query building.',\n );\n setCommandExamples(command, [\n 'prisma-next contract emit',\n 'prisma-next contract emit --config ./custom-config.ts',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: ContractEmitOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await executeContractEmitCommand(options, flags, ui, startTime);\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, ui, (emitResult) => {\n if (flags.json) {\n ui.output(formatEmitJson(emitResult));\n } else {\n const output = formatEmitOutput(emitResult, flags);\n if (output) {\n ui.log(output);\n }\n if (!flags.quiet) {\n ui.success(formatSuccessMessage(flags));\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { t as loadConfig } from "./config-loader-C25b63rJ.mjs";
|
|
2
|
-
import { i as errorContractConfigMissing, m as errorRuntime } from "./cli-errors-By1iVE3z.mjs";
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "./framework-components-C6el-5x_.mjs";
|
|
4
|
-
import { t as enrichContract } from "./contract-enrichment-CAOELa-H.mjs";
|
|
5
|
-
import { emit, getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
6
|
-
import { dirname } from "pathe";
|
|
7
|
-
import { ifDefined } from "@prisma-next/utils/defined";
|
|
8
|
-
import { createControlStack } from "@prisma-next/framework-components/control";
|
|
9
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
10
|
-
import { abortable } from "@prisma-next/utils/abortable";
|
|
11
|
-
|
|
12
|
-
//#region src/control-api/operations/contract-emit.ts
|
|
13
|
-
function isRecord(value) {
|
|
14
|
-
return typeof value === "object" && value !== null;
|
|
15
|
-
}
|
|
16
|
-
function isAbortError(error) {
|
|
17
|
-
return isRecord(error) && typeof error["name"] === "string" && error["name"] === "AbortError";
|
|
18
|
-
}
|
|
19
|
-
function isProviderFailureLike(value) {
|
|
20
|
-
return isRecord(value) && typeof value["summary"] === "string" && Array.isArray(value["diagnostics"]);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Executes the contract emit operation.
|
|
24
|
-
*
|
|
25
|
-
* This is an offline operation that:
|
|
26
|
-
* 1. Loads the Prisma Next config from the specified path
|
|
27
|
-
* 2. Resolves the contract source from config
|
|
28
|
-
* 3. Creates a control plane stack and family instance
|
|
29
|
-
* 4. Emits contract artifacts (JSON and DTS)
|
|
30
|
-
* 5. Writes files to the paths specified in config
|
|
31
|
-
*
|
|
32
|
-
* Supports AbortSignal for cancellation, enabling "last change wins" behavior.
|
|
33
|
-
*
|
|
34
|
-
* @param options - Options including configPath and optional signal
|
|
35
|
-
* @returns File paths and hashes of emitted artifacts
|
|
36
|
-
* @throws If config loading fails, contract is invalid, or file I/O fails
|
|
37
|
-
* @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')
|
|
38
|
-
*/
|
|
39
|
-
async function executeContractEmit(options) {
|
|
40
|
-
const { configPath, signal = new AbortController().signal } = options;
|
|
41
|
-
const unlessAborted = abortable(signal);
|
|
42
|
-
const config = await unlessAborted(loadConfig(configPath));
|
|
43
|
-
if (!config.contract) throw errorContractConfigMissing({ why: "Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }" });
|
|
44
|
-
const contractConfig = config.contract;
|
|
45
|
-
if (!contractConfig.output) throw errorContractConfigMissing({ why: "Contract config must have output path. This should not happen if defineConfig() was used." });
|
|
46
|
-
if (typeof contractConfig.source?.load !== "function") throw errorContractConfigMissing({ why: "Contract config must include a valid source provider object" });
|
|
47
|
-
let outputPaths;
|
|
48
|
-
try {
|
|
49
|
-
outputPaths = getEmittedArtifactPaths(contractConfig.output);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
throw errorContractConfigMissing({ why: error instanceof Error ? error.message : String(error) });
|
|
52
|
-
}
|
|
53
|
-
const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = outputPaths;
|
|
54
|
-
const stack = createControlStack(config);
|
|
55
|
-
const sourceContext = {
|
|
56
|
-
composedExtensionPacks: stack.extensionPacks.map((p) => p.id),
|
|
57
|
-
scalarTypeDescriptors: stack.scalarTypeDescriptors,
|
|
58
|
-
authoringContributions: stack.authoringContributions,
|
|
59
|
-
codecLookup: stack.codecLookup,
|
|
60
|
-
controlMutationDefaults: stack.controlMutationDefaults,
|
|
61
|
-
resolvedInputs: contractConfig.source.inputs ?? []
|
|
62
|
-
};
|
|
63
|
-
let providerResult;
|
|
64
|
-
try {
|
|
65
|
-
providerResult = await unlessAborted(contractConfig.source.load(sourceContext));
|
|
66
|
-
} catch (error) {
|
|
67
|
-
if (signal.aborted || isAbortError(error)) throw error;
|
|
68
|
-
throw errorRuntime("Failed to resolve contract source", {
|
|
69
|
-
why: error instanceof Error ? error.message : String(error),
|
|
70
|
-
fix: "Ensure contract.source.load resolves to ok(Contract) or returns structured diagnostics."
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
if (!isRecord(providerResult) || typeof providerResult.ok !== "boolean") throw errorRuntime("Failed to resolve contract source", {
|
|
74
|
-
why: "Contract source provider returned malformed result shape.",
|
|
75
|
-
fix: "Ensure contract.source.load resolves to ok(Contract) or notOk({ summary, diagnostics })."
|
|
76
|
-
});
|
|
77
|
-
if (providerResult.ok && !("value" in providerResult)) throw errorRuntime("Failed to resolve contract source", {
|
|
78
|
-
why: "Contract source provider returned malformed success result: missing value.",
|
|
79
|
-
fix: "Ensure contract.source.load success payload is ok(Contract)."
|
|
80
|
-
});
|
|
81
|
-
if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) throw errorRuntime("Failed to resolve contract source", {
|
|
82
|
-
why: "Contract source provider returned malformed failure result: expected summary and diagnostics.",
|
|
83
|
-
fix: "Ensure contract.source.load failure payload is notOk({ summary, diagnostics, meta? })."
|
|
84
|
-
});
|
|
85
|
-
if (!providerResult.ok) throw errorRuntime("Failed to resolve contract source", {
|
|
86
|
-
why: providerResult.failure.summary,
|
|
87
|
-
fix: "Fix contract source diagnostics and return ok(Contract).",
|
|
88
|
-
meta: {
|
|
89
|
-
diagnostics: providerResult.failure.diagnostics,
|
|
90
|
-
...ifDefined("providerMeta", providerResult.failure.meta)
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
const familyInstance = config.family.create(stack);
|
|
94
|
-
const rawComponents = [
|
|
95
|
-
config.target,
|
|
96
|
-
config.adapter,
|
|
97
|
-
...config.extensionPacks ?? []
|
|
98
|
-
];
|
|
99
|
-
const frameworkComponents = assertFrameworkComponentsCompatible(config.family.familyId, config.target.targetId, rawComponents);
|
|
100
|
-
const enrichedIR = enrichContract(providerResult.value, frameworkComponents);
|
|
101
|
-
familyInstance.validateContract(enrichedIR);
|
|
102
|
-
const emitResult = await unlessAborted(emit(enrichedIR, stack, config.family.emission, { outputJsonPath }));
|
|
103
|
-
await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));
|
|
104
|
-
await unlessAborted(writeFile(outputJsonPath, emitResult.contractJson, "utf-8"));
|
|
105
|
-
await unlessAborted(writeFile(outputDtsPath, emitResult.contractDts, "utf-8"));
|
|
106
|
-
const { validateContractDeps } = await import("./validate-contract-deps-B_Cs29TL.mjs");
|
|
107
|
-
const depsValidation = validateContractDeps(emitResult.contractDts, dirname(outputDtsPath));
|
|
108
|
-
if (depsValidation.warning) process.stderr.write(`\n⚠ ${depsValidation.warning}\n`);
|
|
109
|
-
return {
|
|
110
|
-
storageHash: emitResult.storageHash,
|
|
111
|
-
...ifDefined("executionHash", emitResult.executionHash),
|
|
112
|
-
profileHash: emitResult.profileHash,
|
|
113
|
-
files: {
|
|
114
|
-
json: outputJsonPath,
|
|
115
|
-
dts: outputDtsPath
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
//#endregion
|
|
121
|
-
export { executeContractEmit as t };
|
|
122
|
-
//# sourceMappingURL=contract-emit-PeB96eHy.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-emit-PeB96eHy.mjs","names":["outputPaths: ReturnType<typeof getEmittedArtifactPaths>","providerResult: Awaited<ReturnType<typeof contractConfig.source.load>>"],"sources":["../src/control-api/operations/contract-emit.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { emit, getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { abortable } from '@prisma-next/utils/abortable';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { dirname } from 'pathe';\nimport { loadConfig } from '../../config-loader';\nimport { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';\nimport { assertFrameworkComponentsCompatible } from '../../utils/framework-components';\nimport { enrichContract } from '../contract-enrichment';\nimport type { ContractEmitOptions, ContractEmitResult } from '../types';\n\ninterface ProviderFailureLike {\n readonly summary: string;\n readonly diagnostics: readonly unknown[];\n readonly meta?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return isRecord(error) && typeof error['name'] === 'string' && error['name'] === 'AbortError';\n}\n\nfunction isProviderFailureLike(value: unknown): value is ProviderFailureLike {\n return (\n isRecord(value) && typeof value['summary'] === 'string' && Array.isArray(value['diagnostics'])\n );\n}\n\n/**\n * Executes the contract emit operation.\n *\n * This is an offline operation that:\n * 1. Loads the Prisma Next config from the specified path\n * 2. Resolves the contract source from config\n * 3. Creates a control plane stack and family instance\n * 4. Emits contract artifacts (JSON and DTS)\n * 5. Writes files to the paths specified in config\n *\n * Supports AbortSignal for cancellation, enabling \"last change wins\" behavior.\n *\n * @param options - Options including configPath and optional signal\n * @returns File paths and hashes of emitted artifacts\n * @throws If config loading fails, contract is invalid, or file I/O fails\n * @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')\n */\nexport async function executeContractEmit(\n options: ContractEmitOptions,\n): Promise<ContractEmitResult> {\n const { configPath, signal = new AbortController().signal } = options;\n const unlessAborted = abortable(signal);\n\n // Load config using the existing config loader\n const config = await unlessAborted(loadConfig(configPath));\n\n // Validate contract config is present\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n });\n }\n\n const contractConfig = config.contract;\n\n // Validate output path is present and ends with .json\n if (!contractConfig.output) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n });\n }\n\n // Validate source exists and is callable\n if (typeof contractConfig.source?.load !== 'function') {\n throw errorContractConfigMissing({\n why: 'Contract config must include a valid source provider object',\n });\n }\n\n let outputPaths: ReturnType<typeof getEmittedArtifactPaths>;\n try {\n outputPaths = getEmittedArtifactPaths(contractConfig.output);\n } catch (error) {\n throw errorContractConfigMissing({\n why: error instanceof Error ? error.message : String(error),\n });\n }\n const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = outputPaths;\n\n const stack = createControlStack(config);\n\n const sourceContext = {\n composedExtensionPacks: stack.extensionPacks.map((p) => p.id),\n scalarTypeDescriptors: stack.scalarTypeDescriptors,\n authoringContributions: stack.authoringContributions,\n codecLookup: stack.codecLookup,\n controlMutationDefaults: stack.controlMutationDefaults,\n resolvedInputs: contractConfig.source.inputs ?? [],\n };\n\n let providerResult: Awaited<ReturnType<typeof contractConfig.source.load>>;\n try {\n providerResult = await unlessAborted(contractConfig.source.load(sourceContext));\n } catch (error) {\n if (signal.aborted || isAbortError(error)) {\n throw error;\n }\n throw errorRuntime('Failed to resolve contract source', {\n why: error instanceof Error ? error.message : String(error),\n fix: 'Ensure contract.source.load resolves to ok(Contract) or returns structured diagnostics.',\n });\n }\n\n if (!isRecord(providerResult) || typeof providerResult.ok !== 'boolean') {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed result shape.',\n fix: 'Ensure contract.source.load resolves to ok(Contract) or notOk({ summary, diagnostics }).',\n });\n }\n\n if (providerResult.ok && !('value' in providerResult)) {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed success result: missing value.',\n fix: 'Ensure contract.source.load success payload is ok(Contract).',\n });\n }\n\n if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed failure result: expected summary and diagnostics.',\n fix: 'Ensure contract.source.load failure payload is notOk({ summary, diagnostics, meta? }).',\n });\n }\n\n if (!providerResult.ok) {\n throw errorRuntime('Failed to resolve contract source', {\n why: providerResult.failure.summary,\n fix: 'Fix contract source diagnostics and return ok(Contract).',\n meta: {\n diagnostics: providerResult.failure.diagnostics,\n ...ifDefined('providerMeta', providerResult.failure.meta),\n },\n });\n }\n\n const familyInstance = config.family.create(stack);\n\n const rawComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];\n const frameworkComponents = assertFrameworkComponentsCompatible(\n config.family.familyId,\n config.target.targetId,\n rawComponents,\n );\n const enrichedIR = enrichContract(providerResult.value as Contract, frameworkComponents);\n\n familyInstance.validateContract(enrichedIR);\n const emitResult = await unlessAborted(\n emit(enrichedIR, stack, config.family.emission, {\n outputJsonPath: outputJsonPath,\n }),\n );\n\n // Create directory if needed and write files (both colocated)\n await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));\n await unlessAborted(writeFile(outputJsonPath, emitResult.contractJson, 'utf-8'));\n await unlessAborted(writeFile(outputDtsPath, emitResult.contractDts, 'utf-8'));\n\n // Validate that contract.d.ts type imports are resolvable\n const { validateContractDeps } = await import('../../utils/validate-contract-deps');\n const depsValidation = validateContractDeps(emitResult.contractDts, dirname(outputDtsPath));\n if (depsValidation.warning) {\n process.stderr.write(`\\n⚠ ${depsValidation.warning}\\n`);\n }\n\n return {\n storageHash: emitResult.storageHash,\n ...ifDefined('executionHash', emitResult.executionHash),\n profileHash: emitResult.profileHash,\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
|
|
3
|
-
//#region src/utils/validate-contract-deps.ts
|
|
4
|
-
const IMPORT_PATTERN = /import\s+type\s+.*?\s+from\s+['"](@[^/]+\/[^/'"]+)/g;
|
|
5
|
-
function extractPackageSpecifiers(dtsContent) {
|
|
6
|
-
const packages = /* @__PURE__ */ new Set();
|
|
7
|
-
for (const match of dtsContent.matchAll(IMPORT_PATTERN)) {
|
|
8
|
-
const pkg = match[1];
|
|
9
|
-
if (pkg) packages.add(pkg);
|
|
10
|
-
}
|
|
11
|
-
return [...packages];
|
|
12
|
-
}
|
|
13
|
-
function validateContractDeps(dtsContent, projectRoot) {
|
|
14
|
-
const packages = extractPackageSpecifiers(dtsContent);
|
|
15
|
-
const resolve = createRequire(`${projectRoot}/package.json`);
|
|
16
|
-
const missing = [];
|
|
17
|
-
for (const pkg of packages) try {
|
|
18
|
-
resolve.resolve(`${pkg}/package.json`);
|
|
19
|
-
} catch {
|
|
20
|
-
missing.push(pkg);
|
|
21
|
-
}
|
|
22
|
-
if (missing.length === 0) return { missing };
|
|
23
|
-
return {
|
|
24
|
-
missing,
|
|
25
|
-
warning: [
|
|
26
|
-
"contract.d.ts imports types from packages that are not installed:",
|
|
27
|
-
missing.map((p) => ` - ${p}`).join("\n"),
|
|
28
|
-
"",
|
|
29
|
-
"Install them with your package manager:",
|
|
30
|
-
...missing.map((p) => ` ${p}`)
|
|
31
|
-
].join("\n")
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//#endregion
|
|
36
|
-
export { validateContractDeps };
|
|
37
|
-
//# sourceMappingURL=validate-contract-deps-B_Cs29TL.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validate-contract-deps-B_Cs29TL.mjs","names":["missing: string[]"],"sources":["../src/utils/validate-contract-deps.ts"],"sourcesContent":["import { createRequire } from 'node:module';\n\nconst IMPORT_PATTERN = /import\\s+type\\s+.*?\\s+from\\s+['\"](@[^/]+\\/[^/'\"]+)/g;\n\nexport function extractPackageSpecifiers(dtsContent: string): string[] {\n const packages = new Set<string>();\n for (const match of dtsContent.matchAll(IMPORT_PATTERN)) {\n const pkg = match[1];\n if (pkg) packages.add(pkg);\n }\n return [...packages];\n}\n\nexport interface ContractDepsValidation {\n readonly missing: readonly string[];\n readonly warning?: string;\n}\n\nexport function validateContractDeps(\n dtsContent: string,\n projectRoot: string,\n): ContractDepsValidation {\n const packages = extractPackageSpecifiers(dtsContent);\n const resolve = createRequire(`${projectRoot}/package.json`);\n\n const missing: string[] = [];\n for (const pkg of packages) {\n try {\n resolve.resolve(`${pkg}/package.json`);\n } catch {\n missing.push(pkg);\n }\n }\n\n if (missing.length === 0) {\n return { missing };\n }\n\n const list = missing.map((p) => ` - ${p}`).join('\\n');\n const warning = [\n 'contract.d.ts imports types from packages that are not installed:',\n list,\n '',\n 'Install them with your package manager:',\n ...missing.map((p) => ` ${p}`),\n ].join('\\n');\n\n return { missing, warning };\n}\n"],"mappings":";;;AAEA,MAAM,iBAAiB;AAEvB,SAAgB,yBAAyB,YAA8B;CACrE,MAAM,2BAAW,IAAI,KAAa;AAClC,MAAK,MAAM,SAAS,WAAW,SAAS,eAAe,EAAE;EACvD,MAAM,MAAM,MAAM;AAClB,MAAI,IAAK,UAAS,IAAI,IAAI;;AAE5B,QAAO,CAAC,GAAG,SAAS;;AAQtB,SAAgB,qBACd,YACA,aACwB;CACxB,MAAM,WAAW,yBAAyB,WAAW;CACrD,MAAM,UAAU,cAAc,GAAG,YAAY,eAAe;CAE5D,MAAMA,UAAoB,EAAE;AAC5B,MAAK,MAAM,OAAO,SAChB,KAAI;AACF,UAAQ,QAAQ,GAAG,IAAI,eAAe;SAChC;AACN,UAAQ,KAAK,IAAI;;AAIrB,KAAI,QAAQ,WAAW,EACrB,QAAO,EAAE,SAAS;AAYpB,QAAO;EAAE;EAAS,SARF;GACd;GAFW,QAAQ,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK;GAIpD;GACA;GACA,GAAG,QAAQ,KAAK,MAAM,KAAK,IAAI;GAChC,CAAC,KAAK,KAAK;EAEe"}
|
|
File without changes
|