@prisma-next/config 0.4.0-dev.9 → 0.4.2
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 +13 -1
- package/dist/{config-types-BqPA4C22.d.mts → config-types-CK4a_UHR.d.mts} +12 -4
- package/dist/config-types-CK4a_UHR.d.mts.map +1 -0
- package/dist/config-types.d.mts +2 -2
- package/dist/config-types.mjs +19 -20
- package/dist/config-types.mjs.map +1 -1
- package/dist/config-validation.d.mts +1 -1
- package/dist/config-validation.d.mts.map +1 -1
- package/dist/config-validation.mjs +15 -3
- package/dist/config-validation.mjs.map +1 -1
- package/package.json +6 -6
- package/src/config-types.ts +22 -23
- package/src/config-validation.ts +45 -14
- package/src/contract-source-types.ts +7 -3
- package/src/exports/config-types.ts +1 -1
- package/dist/config-types-BqPA4C22.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ This package owns the shared config contract used by tooling and authoring packa
|
|
|
12
12
|
|
|
13
13
|
- `PrismaNextConfig` and `ContractConfig` types
|
|
14
14
|
- contract source provider + diagnostics protocol
|
|
15
|
+
- provider-declared input metadata for tooling integrations
|
|
15
16
|
- `defineConfig()` normalization/defaulting
|
|
16
17
|
- `validateConfig()` structural/runtime-shape validation
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ This package owns the shared config contract used by tooling and authoring packa
|
|
|
19
20
|
|
|
20
21
|
- Type-safe config composition for `family`, `target`, `adapter`, optional `driver`, and optional `extensionPacks` (`extensions` is rejected at runtime)
|
|
21
22
|
- Contract source provider protocol (`contract.source`) and diagnostics shape
|
|
23
|
+
- Tool-agnostic provider input metadata for build integrations via `contract.source.inputs`
|
|
22
24
|
- Pure config validation and normalization with no file system access
|
|
23
25
|
|
|
24
26
|
## Non-responsibilities
|
|
@@ -38,9 +40,19 @@ const config = defineConfig({
|
|
|
38
40
|
target: postgresTargetDescriptor,
|
|
39
41
|
adapter: postgresAdapterDescriptor,
|
|
40
42
|
contract: {
|
|
41
|
-
source:
|
|
43
|
+
source: {
|
|
44
|
+
inputs: ['./prisma/schema.prisma'],
|
|
45
|
+
load: async (_context) =>
|
|
46
|
+
/* Result<Contract, ContractSourceDiagnostics> */ null as never,
|
|
47
|
+
},
|
|
42
48
|
},
|
|
43
49
|
});
|
|
44
50
|
|
|
45
51
|
validateConfig(config);
|
|
46
52
|
```
|
|
53
|
+
|
|
54
|
+
Declare `source.inputs` only for source files that are not already covered by the config module
|
|
55
|
+
graph, such as PSL schema paths or TypeScript contract paths passed as strings. Do not include
|
|
56
|
+
emitted artifact paths derived from `contract.output` (for example `contract.json` or the
|
|
57
|
+
colocated `contract.d.ts`); the CLI loader resolves and validates those paths before emit/watch
|
|
58
|
+
commands run. Tooling should always treat the config module graph as watched by default.
|
|
@@ -36,8 +36,12 @@ interface ContractSourceContext {
|
|
|
36
36
|
readonly authoringContributions: AssembledAuthoringContributions;
|
|
37
37
|
readonly codecLookup: CodecLookup;
|
|
38
38
|
readonly controlMutationDefaults: ControlMutationDefaults;
|
|
39
|
+
readonly resolvedInputs: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
interface ContractSourceProvider {
|
|
42
|
+
readonly inputs?: readonly string[];
|
|
43
|
+
readonly load: (context: ContractSourceContext) => Promise<Result<Contract, ContractSourceDiagnostics>>;
|
|
39
44
|
}
|
|
40
|
-
type ContractSourceProvider = (context: ContractSourceContext) => Promise<Result<Contract, ContractSourceDiagnostics>>;
|
|
41
45
|
//#endregion
|
|
42
46
|
//#region src/config-types.d.ts
|
|
43
47
|
/**
|
|
@@ -55,6 +59,10 @@ interface ContractConfig {
|
|
|
55
59
|
*/
|
|
56
60
|
readonly output?: string;
|
|
57
61
|
}
|
|
62
|
+
declare const DEFAULT_CONTRACT_OUTPUT = "src/prisma/contract.json";
|
|
63
|
+
declare function normalizeContractConfig(contract: ContractConfig): ContractConfig & {
|
|
64
|
+
readonly output: string;
|
|
65
|
+
};
|
|
58
66
|
/**
|
|
59
67
|
* Configuration for Prisma Next CLI.
|
|
60
68
|
* Uses Control*Descriptor types for type-safe wiring with compile-time compatibility checks.
|
|
@@ -105,7 +113,7 @@ interface PrismaNextConfig<TFamilyId extends string = string, TTargetId extends
|
|
|
105
113
|
* Validates and normalizes the config using Arktype, then returns the normalized IR.
|
|
106
114
|
*
|
|
107
115
|
* Normalization:
|
|
108
|
-
* - contract.output defaults to
|
|
116
|
+
* - contract.output defaults to DEFAULT_CONTRACT_OUTPUT if missing
|
|
109
117
|
*
|
|
110
118
|
* @param config - Raw config input from user
|
|
111
119
|
* @returns Normalized config IR with defaults applied
|
|
@@ -113,5 +121,5 @@ interface PrismaNextConfig<TFamilyId extends string = string, TTargetId extends
|
|
|
113
121
|
*/
|
|
114
122
|
declare function defineConfig<TFamilyId extends string = string, TTargetId extends string = string>(config: PrismaNextConfig<TFamilyId, TTargetId>): PrismaNextConfig<TFamilyId, TTargetId>;
|
|
115
123
|
//#endregion
|
|
116
|
-
export {
|
|
117
|
-
//# sourceMappingURL=config-types-
|
|
124
|
+
export { normalizeContractConfig as a, ContractSourceDiagnosticPosition as c, ContractSourceProvider as d, defineConfig as i, ContractSourceDiagnosticSpan as l, DEFAULT_CONTRACT_OUTPUT as n, ContractSourceContext as o, PrismaNextConfig as r, ContractSourceDiagnostic as s, ContractConfig as t, ContractSourceDiagnostics as u };
|
|
125
|
+
//# sourceMappingURL=config-types-CK4a_UHR.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-types-CK4a_UHR.d.mts","names":[],"sources":["../src/contract-source-types.ts","../src/config-types.ts"],"sourcesContent":[],"mappings":";;;;;;UAQiB,gCAAA;;EAAA,SAAA,IAAA,EAAA,MAAA;EAMA,SAAA,MAAA,EAAA,MAAA;AAKjB;AAIkB,UATD,4BAAA,CASC;EAMS,SAAA,KAAA,EAdT,gCAcS;EAAT,SAAA,GAAA,EAbF,gCAaE;;AAGD,UAbA,wBAAA,CAayB;EAMzB,SAAA,IAAA,EAAA,MAAA;EAEiB,SAAA,OAAA,EAAA,MAAA;EACC,SAAA,QAAA,CAAA,EAAA,MAAA;EACX,SAAA,IAAA,CAAA,EAnBN,4BAmBM;EACY;;AAIpC;;;EAIgC,SAAA,IAAA,CAAA,EAtBd,QAsBc,CAtBL,MAsBK,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;;AAAzB,UAnBU,yBAAA,CAmBV;EAAO,SAAA,OAAA,EAAA,MAAA;iCAjBmB;kBACf;;ACfD,UDkBA,qBAAA,CCbE;EAQN,SAAA,sBAAuB,EAAA,SAAA,MAAA,EAAA;EAEpB,SAAA,qBAAuB,EDKL,WCJtB,CAAA,MAAA,EAAA,MACT,CAAA;EAec,SAAA,sBAAgB,EDXE,+BCWF;EAKU,SAAA,WAAA,EDfnB,WCemB;EAAxB,SAAA,uBAAA,EDdiB,uBCcjB;EACwB,SAAA,cAAA,EAAA,SAAA,MAAA,EAAA;;AAAxB,UDXF,sBAAA,CCWE;EAC0B,SAAA,MAAA,CAAA,EAAA,SAAA,MAAA,EAAA;EAAW,SAAA,IAAA,EAAA,CAAA,OAAA,EDT3C,qBCS2C,EAAA,GDRjD,OCQiD,CDRzC,MCQyC,CDRlC,QCQkC,EDRxB,yBCQwB,CAAA,CAAA;;;;AD7CxD;AAKA;;AAU2B,UCTV,cAAA,CDSU;EAAT;;AAGlB;AAMA;EAEkC,SAAA,MAAA,ECff,sBDee;EACC;;;;EAMlB,SAAA,MAAA,CAAA,EAAA,MAAA;;AAIK,cClBT,uBAAA,GDkBS,0BAAA;AAAU,iBChBhB,uBAAA,CDgBgB,QAAA,ECfpB,cDeoB,CAAA,ECd7B,cDc6B,GAAA;EAAjB,SAAA,MAAA,EAAA,MAAA;CAAR;;;;;AC/BP;AAaA;AAEA;AAiBA;AAK2C,UAL1B,gBAK0B,CAAA,kBAAA,MAAA,GAAA,MAAA,EAAA,kBAAA,MAAA,GAAA,MAAA,EAAA,cAAA,OAAA,CAAA,CAAA;EAAxB,SAAA,MAAA,EAAA,uBAAA,CAAwB,SAAxB,CAAA;EACwB,SAAA,MAAA,EAAxB,uBAAwB,CAAA,SAAA,EAAW,SAAX,CAAA;EAAW,SAAA,OAAA,EAClC,wBADkC,CACT,SADS,EACE,SADF,CAAA;EAAnC,SAAA,cAAA,CAAA,EAAA,SAEkB,0BAFlB,CAE6C,SAF7C,EAEwD,SAFxD,CAAA,EAAA;EAC0B;;;;;;EASzC,SAAA,MAAA,CAAA,EADgB,uBAChB,CAAA,SAAA,EACA,SADA,EAEA,qBAFA,CAEsB,SAFtB,EAEiC,SAFjC,CAAA,EAGA,WAHA,CAAA;EACA;;;;EAEA,SAAA,EAAA,CAAA,EAAA;IAJgB;;;;AA0EpB;IAC2B,SAAA,UAAA,CAAA,EA3DD,WA2DC;EAAW,CAAA;EAA5B;;;;EACS,SAAA,QAAA,CAAA,EAtDG,cAsDH;;;;;;;;;;;;;;;;;;;;iBAFH,2FACN,iBAAiB,WAAW,aACnC,iBAAiB,WAAW"}
|
package/dist/config-types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { type ContractConfig, type ContractSourceContext, type ContractSourceDiagnostic, type ContractSourceDiagnosticPosition, type ContractSourceDiagnosticSpan, type ContractSourceDiagnostics, type ContractSourceProvider, type PrismaNextConfig, defineConfig };
|
|
1
|
+
import { a as normalizeContractConfig, c as ContractSourceDiagnosticPosition, d as ContractSourceProvider, i as defineConfig, l as ContractSourceDiagnosticSpan, n as DEFAULT_CONTRACT_OUTPUT, o as ContractSourceContext, r as PrismaNextConfig, s as ContractSourceDiagnostic, t as ContractConfig, u as ContractSourceDiagnostics } from "./config-types-CK4a_UHR.mjs";
|
|
2
|
+
export { type ContractConfig, type ContractSourceContext, type ContractSourceDiagnostic, type ContractSourceDiagnosticPosition, type ContractSourceDiagnosticSpan, type ContractSourceDiagnostics, type ContractSourceProvider, DEFAULT_CONTRACT_OUTPUT, type PrismaNextConfig, defineConfig, normalizeContractConfig };
|
package/dist/config-types.mjs
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { type } from "arktype";
|
|
2
2
|
|
|
3
3
|
//#region src/config-types.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const DEFAULT_CONTRACT_OUTPUT = "src/prisma/contract.json";
|
|
5
|
+
function normalizeContractConfig(contract) {
|
|
6
|
+
return {
|
|
7
|
+
source: contract.source,
|
|
8
|
+
output: contract.output ?? DEFAULT_CONTRACT_OUTPUT
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const ContractSourceInputSchema = type("string");
|
|
12
|
+
const ContractSourceProviderSchema = type({
|
|
13
|
+
"inputs?": ContractSourceInputSchema.array(),
|
|
14
|
+
load: "Function"
|
|
15
|
+
});
|
|
9
16
|
const ContractConfigSchema = type({
|
|
10
|
-
source:
|
|
17
|
+
source: ContractSourceProviderSchema,
|
|
11
18
|
"output?": "string"
|
|
12
19
|
});
|
|
13
20
|
/**
|
|
@@ -30,7 +37,7 @@ const PrismaNextConfigSchema = type({
|
|
|
30
37
|
* Validates and normalizes the config using Arktype, then returns the normalized IR.
|
|
31
38
|
*
|
|
32
39
|
* Normalization:
|
|
33
|
-
* - contract.output defaults to
|
|
40
|
+
* - contract.output defaults to DEFAULT_CONTRACT_OUTPUT if missing
|
|
34
41
|
*
|
|
35
42
|
* @param config - Raw config input from user
|
|
36
43
|
* @returns Normalized config IR with defaults applied
|
|
@@ -42,21 +49,13 @@ function defineConfig(config) {
|
|
|
42
49
|
const messages = validated.map((p) => p.message).join("; ");
|
|
43
50
|
throw new Error(`Config validation failed: ${messages}`);
|
|
44
51
|
}
|
|
45
|
-
if (config.contract) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
source: config.contract.source,
|
|
50
|
-
output
|
|
51
|
-
};
|
|
52
|
-
return {
|
|
53
|
-
...config,
|
|
54
|
-
contract: normalizedContract
|
|
55
|
-
};
|
|
56
|
-
}
|
|
52
|
+
if (config.contract) return {
|
|
53
|
+
...config,
|
|
54
|
+
contract: normalizeContractConfig(config.contract)
|
|
55
|
+
};
|
|
57
56
|
return config;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
//#endregion
|
|
61
|
-
export { defineConfig };
|
|
60
|
+
export { DEFAULT_CONTRACT_OUTPUT, defineConfig, normalizeContractConfig };
|
|
62
61
|
//# sourceMappingURL=config-types.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-types.mjs","names":[
|
|
1
|
+
{"version":3,"file":"config-types.mjs","names":[],"sources":["../src/config-types.ts"],"sourcesContent":["import type {\n ControlAdapterDescriptor,\n ControlDriverDescriptor,\n ControlDriverInstance,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from '@prisma-next/framework-components/control';\nimport { type } from 'arktype';\nimport type { ContractSourceProvider } from './contract-source-types';\n\n/**\n * Type alias for CLI driver instances.\n * Uses string for both family and target IDs for maximum flexibility.\n */\nexport type CliDriver = ControlDriverInstance<string, string>;\n\n/**\n * Contract configuration specifying source and artifact locations.\n */\nexport interface ContractConfig {\n /**\n * Contract source provider. The provider is always async and must return\n * a Result containing either a Contract or structured diagnostics.\n */\n readonly source: ContractSourceProvider;\n /**\n * Path to contract.json artifact. Defaults to 'src/prisma/contract.json'.\n * The .d.ts types file will be colocated (e.g., contract.json -> contract.d.ts).\n */\n readonly output?: string;\n}\n\nexport const DEFAULT_CONTRACT_OUTPUT = 'src/prisma/contract.json';\n\nexport function normalizeContractConfig(\n contract: ContractConfig,\n): ContractConfig & { readonly output: string } {\n return {\n source: contract.source,\n output: contract.output ?? DEFAULT_CONTRACT_OUTPUT,\n };\n}\n\n/**\n * Configuration for Prisma Next CLI.\n * Uses Control*Descriptor types for type-safe wiring with compile-time compatibility checks.\n *\n * @template TFamilyId - The family ID (e.g., 'sql', 'document')\n * @template TTargetId - The target ID (e.g., 'postgres', 'mysql')\n * @template TConnection - The driver connection input type (defaults to `unknown` for config flexibility)\n */\nexport interface PrismaNextConfig<\n TFamilyId extends string = string,\n TTargetId extends string = string,\n TConnection = unknown,\n> {\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;\n readonly extensionPacks?: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];\n /**\n * Driver descriptor for DB-connected CLI commands.\n * Required for DB-connected commands (e.g., db verify).\n * Optional for commands that don't need database access (e.g., emit).\n * The driver's connection type matches the TConnection config parameter.\n */\n readonly driver?: ControlDriverDescriptor<\n TFamilyId,\n TTargetId,\n ControlDriverInstance<TFamilyId, TTargetId>,\n TConnection\n >;\n /**\n * Database connection configuration.\n * The connection type is driver-specific (e.g., URL string for Postgres).\n */\n readonly db?: {\n /**\n * Driver-specific connection input.\n * For Postgres: a connection string (URL).\n * For other drivers: may be a structured object.\n */\n readonly connection?: TConnection;\n };\n /**\n * Contract configuration. Specifies source and artifact locations.\n * Required for emit command; optional for other commands that only read artifacts.\n */\n readonly contract?: ContractConfig;\n /**\n * Migration configuration. Controls where on-disk migration packages are stored.\n */\n readonly migrations?: {\n /** Directory for migration packages, relative to config file. Defaults to 'migrations'. */\n readonly dir?: string;\n };\n}\n\nconst ContractSourceInputSchema = type('string');\n\nexport const ContractSourceProviderSchema = type({\n 'inputs?': ContractSourceInputSchema.array(),\n load: 'Function',\n});\n\nexport const ContractConfigSchema = type({\n source: ContractSourceProviderSchema,\n 'output?': 'string',\n});\n\n/**\n * Arktype schema for PrismaNextConfig validation.\n * Note: This validates structure only. Descriptor objects (family, target, adapter) are validated separately.\n */\nconst MigrationsConfigSchema = type({\n 'dir?': 'string',\n});\n\nconst PrismaNextConfigSchema = type({\n family: 'unknown', // ControlFamilyDescriptor - validated separately\n target: 'unknown', // ControlTargetDescriptor - validated separately\n adapter: 'unknown', // ControlAdapterDescriptor - validated separately\n 'extensionPacks?': 'unknown[]',\n 'driver?': 'unknown', // ControlDriverDescriptor - validated separately (optional)\n 'db?': 'unknown',\n 'contract?': ContractConfigSchema,\n 'migrations?': MigrationsConfigSchema,\n});\n\n/**\n * Helper function to define a Prisma Next config.\n * Validates and normalizes the config using Arktype, then returns the normalized IR.\n *\n * Normalization:\n * - contract.output defaults to DEFAULT_CONTRACT_OUTPUT if missing\n *\n * @param config - Raw config input from user\n * @returns Normalized config IR with defaults applied\n * @throws Error if config structure is invalid\n */\nexport function defineConfig<TFamilyId extends string = string, TTargetId extends string = string>(\n config: PrismaNextConfig<TFamilyId, TTargetId>,\n): PrismaNextConfig<TFamilyId, TTargetId> {\n // Validate structure using Arktype\n const validated = PrismaNextConfigSchema(config);\n if (validated instanceof type.errors) {\n const messages = validated.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Config validation failed: ${messages}`);\n }\n\n // Normalize contract config if present\n if (config.contract) {\n // Return normalized config\n return {\n ...config,\n contract: normalizeContractConfig(config.contract),\n };\n }\n\n // Return config as-is if no contract (preserve literal types)\n return config;\n}\n"],"mappings":";;;AAiCA,MAAa,0BAA0B;AAEvC,SAAgB,wBACd,UAC8C;AAC9C,QAAO;EACL,QAAQ,SAAS;EACjB,QAAQ,SAAS,UAAU;EAC5B;;AA0DH,MAAM,4BAA4B,KAAK,SAAS;AAEhD,MAAa,+BAA+B,KAAK;CAC/C,WAAW,0BAA0B,OAAO;CAC5C,MAAM;CACP,CAAC;AAEF,MAAa,uBAAuB,KAAK;CACvC,QAAQ;CACR,WAAW;CACZ,CAAC;;;;;AAMF,MAAM,yBAAyB,KAAK,EAClC,QAAQ,UACT,CAAC;AAEF,MAAM,yBAAyB,KAAK;CAClC,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,mBAAmB;CACnB,WAAW;CACX,OAAO;CACP,aAAa;CACb,eAAe;CAChB,CAAC;;;;;;;;;;;;AAaF,SAAgB,aACd,QACwC;CAExC,MAAM,YAAY,uBAAuB,OAAO;AAChD,KAAI,qBAAqB,KAAK,QAAQ;EACpC,MAAM,WAAW,UAAU,KAAK,MAA2B,EAAE,QAAQ,CAAC,KAAK,KAAK;AAChF,QAAM,IAAI,MAAM,6BAA6B,WAAW;;AAI1D,KAAI,OAAO,SAET,QAAO;EACL,GAAG;EACH,UAAU,wBAAwB,OAAO,SAAS;EACnD;AAIH,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-validation.d.mts","names":[],"sources":["../src/config-validation.ts","../src/errors.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"config-validation.d.mts","names":[],"sources":["../src/config-validation.ts","../src/errors.ts"],"sourcesContent":[],"mappings":";;;;;;AA0DA;;;;AC1DA;iBD0DgB,cAAA,qCAAmD;;;cC1DtD,qBAAA,SAA8B,KAAA;;;ED0D3B,WAAA,CAAA,KAAc,EAAA,MAAA,EAAA,GAAqC,CAAA,EAAA,MAAA"}
|
|
@@ -15,6 +15,20 @@ var ConfigValidationError = class extends Error {
|
|
|
15
15
|
function throwValidation(field, why) {
|
|
16
16
|
throw new ConfigValidationError(field, why);
|
|
17
17
|
}
|
|
18
|
+
function validateContractConfig(contract) {
|
|
19
|
+
if (!Object.hasOwn(contract, "source")) throwValidation("contract.source", "Config.contract.source is required when contract is provided");
|
|
20
|
+
const source = contract["source"];
|
|
21
|
+
if (!source || typeof source !== "object") throwValidation("contract.source", "Config.contract.source must be a provider object");
|
|
22
|
+
const sourceConfig = source;
|
|
23
|
+
const inputs = Object.hasOwn(sourceConfig, "inputs") ? sourceConfig["inputs"] : void 0;
|
|
24
|
+
if (inputs !== void 0) {
|
|
25
|
+
if (!Array.isArray(inputs)) throwValidation("contract.source.inputs", "Config.contract.source.inputs must be an array of strings when provided");
|
|
26
|
+
for (const input of inputs) if (typeof input !== "string") throwValidation("contract.source.inputs[]", "Config.contract.source.inputs must contain only strings");
|
|
27
|
+
}
|
|
28
|
+
if (!Object.hasOwn(sourceConfig, "load") || typeof sourceConfig["load"] !== "function") throwValidation("contract.source.load", "Config.contract.source.load must be a function");
|
|
29
|
+
const output = Object.hasOwn(contract, "output") ? contract["output"] : void 0;
|
|
30
|
+
if (output !== void 0 && typeof output !== "string") throwValidation("contract.output", "Config.contract.output must be a string when provided");
|
|
31
|
+
}
|
|
18
32
|
/**
|
|
19
33
|
* Validates that the config has the required structure.
|
|
20
34
|
* This is pure validation logic with no file I/O or CLI awareness.
|
|
@@ -84,9 +98,7 @@ function validateConfig(config) {
|
|
|
84
98
|
if (configObj["contract"] !== void 0) {
|
|
85
99
|
const contract = configObj["contract"];
|
|
86
100
|
if (!contract || typeof contract !== "object") throwValidation("contract", "Config.contract must be an object");
|
|
87
|
-
|
|
88
|
-
if (typeof contract["source"] !== "function") throwValidation("contract.source", "Config.contract.source must be a provider function");
|
|
89
|
-
if (contract["output"] !== void 0 && typeof contract["output"] !== "string") throwValidation("contract.output", "Config.contract.output must be a string when provided");
|
|
101
|
+
validateContractConfig(contract);
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
104
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-validation.mjs","names":[],"sources":["../src/errors.ts","../src/config-validation.ts"],"sourcesContent":["export class ConfigValidationError extends Error {\n readonly field: string;\n readonly why: string;\n\n constructor(field: string, why?: string) {\n super(why ?? `Config must have a \"${field}\" field`);\n this.name = 'ConfigValidationError';\n this.field = field;\n this.why = why ?? `Config must have a \"${field}\" field`;\n }\n}\n","import type { PrismaNextConfig } from './config-types';\nimport { ConfigValidationError } from './errors';\n\nfunction throwValidation(field: string, why?: string): never {\n throw new ConfigValidationError(field, why);\n}\n\n/**\n * Validates that the config has the required structure.\n * This is pure validation logic with no file I/O or CLI awareness.\n *\n * @param config - Config object to validate\n * @throws ConfigValidationError if config structure is invalid\n */\nexport function validateConfig(config: unknown): asserts config is PrismaNextConfig {\n if (!config || typeof config !== 'object') {\n throwValidation('object', 'Config must be an object');\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj['family']) {\n throwValidation('family');\n }\n\n if (!configObj['target']) {\n throwValidation('target');\n }\n\n if (!configObj['adapter']) {\n throwValidation('adapter');\n }\n\n // Validate family descriptor\n const family = configObj['family'] as Record<string, unknown>;\n if (family['kind'] !== 'family') {\n throwValidation('family.kind', 'Config.family must have kind: \"family\"');\n }\n if (typeof family['id'] !== 'string') {\n throwValidation('family.id', 'Config.family must have id: string');\n }\n if (typeof family['familyId'] !== 'string') {\n throwValidation('family.familyId', 'Config.family must have familyId: string');\n }\n if (typeof family['version'] !== 'string') {\n throwValidation('family.version', 'Config.family must have version: string');\n }\n if (!family['emission'] || typeof family['emission'] !== 'object') {\n throwValidation('family.emission', 'Config.family must have emission: EmissionSpi');\n }\n if (typeof family['create'] !== 'function') {\n throwValidation('family.create', 'Config.family must have create: function');\n }\n\n const familyId = family['familyId'] as string;\n\n // Validate target descriptor\n const target = configObj['target'] as Record<string, unknown>;\n if (target['kind'] !== 'target') {\n throwValidation('target.kind', 'Config.target must have kind: \"target\"');\n }\n if (typeof target['id'] !== 'string') {\n throwValidation('target.id', 'Config.target must have id: string');\n }\n if (typeof target['familyId'] !== 'string') {\n throwValidation('target.familyId', 'Config.target must have familyId: string');\n }\n if (typeof target['version'] !== 'string') {\n throwValidation('target.version', 'Config.target must have version: string');\n }\n if (target['familyId'] !== familyId) {\n throwValidation(\n 'target.familyId',\n `Config.target.familyId must match Config.family.familyId (expected: ${familyId}, got: ${target['familyId']})`,\n );\n }\n if (typeof target['targetId'] !== 'string') {\n throwValidation('target.targetId', 'Config.target must have targetId: string');\n }\n if (typeof target['create'] !== 'function') {\n throwValidation('target.create', 'Config.target must have create: function');\n }\n const expectedTargetId = target['targetId'] as string;\n\n // Validate adapter descriptor\n const adapter = configObj['adapter'] as Record<string, unknown>;\n if (adapter['kind'] !== 'adapter') {\n throwValidation('adapter.kind', 'Config.adapter must have kind: \"adapter\"');\n }\n if (typeof adapter['id'] !== 'string') {\n throwValidation('adapter.id', 'Config.adapter must have id: string');\n }\n if (typeof adapter['familyId'] !== 'string') {\n throwValidation('adapter.familyId', 'Config.adapter must have familyId: string');\n }\n if (typeof adapter['version'] !== 'string') {\n throwValidation('adapter.version', 'Config.adapter must have version: string');\n }\n if (adapter['familyId'] !== familyId) {\n throwValidation(\n 'adapter.familyId',\n `Config.adapter.familyId must match Config.family.familyId (expected: ${familyId}, got: ${adapter['familyId']})`,\n );\n }\n if (typeof adapter['targetId'] !== 'string') {\n throwValidation('adapter.targetId', 'Config.adapter must have targetId: string');\n }\n if (adapter['targetId'] !== expectedTargetId) {\n throwValidation(\n 'adapter.targetId',\n `Config.adapter.targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${adapter['targetId']})`,\n );\n }\n if (typeof adapter['create'] !== 'function') {\n throwValidation('adapter.create', 'Config.adapter must have create: function');\n }\n\n if (configObj['extensions'] !== undefined) {\n throwValidation('extensions', 'Config.extensions is not supported; use Config.extensionPacks');\n }\n\n // Validate extensionPacks array if present\n if (configObj['extensionPacks'] !== undefined) {\n if (!Array.isArray(configObj['extensionPacks'])) {\n throwValidation('extensionPacks', 'Config.extensionPacks must be an array');\n }\n for (const ext of configObj['extensionPacks']) {\n if (!ext || typeof ext !== 'object') {\n throwValidation(\n 'extensionPacks[]',\n 'Config.extensionPacks must contain ControlExtensionDescriptor objects',\n );\n }\n const extObj = ext as Record<string, unknown>;\n if (extObj['kind'] !== 'extension') {\n throwValidation(\n 'extensionPacks[].kind',\n 'Config.extensionPacks items must have kind: \"extension\"',\n );\n }\n if (typeof extObj['id'] !== 'string') {\n throwValidation('extensionPacks[].id', 'Config.extensionPacks items must have id: string');\n }\n if (typeof extObj['familyId'] !== 'string') {\n throwValidation(\n 'extensionPacks[].familyId',\n 'Config.extensionPacks items must have familyId: string',\n );\n }\n if (typeof extObj['version'] !== 'string') {\n throwValidation(\n 'extensionPacks[].version',\n 'Config.extensionPacks items must have version: string',\n );\n }\n if (extObj['familyId'] !== familyId) {\n throwValidation(\n 'extensionPacks[].familyId',\n `Config.extensionPacks[].familyId must match Config.family.familyId (expected: ${familyId}, got: ${extObj['familyId']})`,\n );\n }\n if (typeof extObj['targetId'] !== 'string') {\n throwValidation(\n 'extensionPacks[].targetId',\n 'Config.extensionPacks items must have targetId: string',\n );\n }\n if (extObj['targetId'] !== expectedTargetId) {\n throwValidation(\n 'extensionPacks[].targetId',\n `Config.extensionPacks[].targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${extObj['targetId']})`,\n );\n }\n if (typeof extObj['create'] !== 'function') {\n throwValidation(\n 'extensionPacks[].create',\n 'Config.extensionPacks items must have create: function',\n );\n }\n }\n }\n\n // Validate driver descriptor if present\n if (configObj['driver'] !== undefined) {\n const driver = configObj['driver'] as Record<string, unknown>;\n if (driver['kind'] !== 'driver') {\n throwValidation('driver.kind', 'Config.driver must have kind: \"driver\"');\n }\n if (typeof driver['id'] !== 'string') {\n throwValidation('driver.id', 'Config.driver must have id: string');\n }\n if (typeof driver['version'] !== 'string') {\n throwValidation('driver.version', 'Config.driver must have version: string');\n }\n if (typeof driver['familyId'] !== 'string') {\n throwValidation('driver.familyId', 'Config.driver must have familyId: string');\n }\n if (driver['familyId'] !== familyId) {\n throwValidation(\n 'driver.familyId',\n `Config.driver.familyId must match Config.family.familyId (expected: ${familyId}, got: ${driver['familyId']})`,\n );\n }\n if (typeof driver['targetId'] !== 'string') {\n throwValidation('driver.targetId', 'Config.driver must have targetId: string');\n }\n if (driver['targetId'] !== expectedTargetId) {\n throwValidation(\n 'driver.targetId',\n `Config.driver.targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${driver['targetId']})`,\n );\n }\n if (typeof driver['create'] !== 'function') {\n throwValidation('driver.create', 'Config.driver must have create: function');\n }\n }\n\n // Validate contract config if present (structure validation - defineConfig() handles normalization)\n if (configObj['contract'] !== undefined) {\n const contract = configObj['contract'] as Record<string, unknown>;\n if (!contract || typeof contract !== 'object') {\n throwValidation('contract', 'Config.contract must be an object');\n }\n if (!Object.hasOwn(contract, 'source')) {\n throwValidation(\n 'contract.source',\n 'Config.contract.source is required when contract is provided',\n );\n }\n\n if (typeof contract['source'] !== 'function') {\n throwValidation('contract.source', 'Config.contract.source must be a provider function');\n }\n\n if (contract['output'] !== undefined && typeof contract['output'] !== 'string') {\n throwValidation('contract.output', 'Config.contract.output must be a string when provided');\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config-validation.mjs","names":[],"sources":["../src/errors.ts","../src/config-validation.ts"],"sourcesContent":["export class ConfigValidationError extends Error {\n readonly field: string;\n readonly why: string;\n\n constructor(field: string, why?: string) {\n super(why ?? `Config must have a \"${field}\" field`);\n this.name = 'ConfigValidationError';\n this.field = field;\n this.why = why ?? `Config must have a \"${field}\" field`;\n }\n}\n","import type { PrismaNextConfig } from './config-types';\nimport { ConfigValidationError } from './errors';\n\nfunction throwValidation(field: string, why?: string): never {\n throw new ConfigValidationError(field, why);\n}\n\nfunction validateContractConfig(contract: Record<string, unknown>): void {\n if (!Object.hasOwn(contract, 'source')) {\n throwValidation(\n 'contract.source',\n 'Config.contract.source is required when contract is provided',\n );\n }\n\n const source = contract['source'];\n if (!source || typeof source !== 'object') {\n throwValidation('contract.source', 'Config.contract.source must be a provider object');\n }\n\n const sourceConfig = source as Record<string, unknown>;\n const inputs = Object.hasOwn(sourceConfig, 'inputs') ? sourceConfig['inputs'] : undefined;\n\n if (inputs !== undefined) {\n if (!Array.isArray(inputs)) {\n throwValidation(\n 'contract.source.inputs',\n 'Config.contract.source.inputs must be an array of strings when provided',\n );\n }\n\n for (const input of inputs) {\n if (typeof input !== 'string') {\n throwValidation(\n 'contract.source.inputs[]',\n 'Config.contract.source.inputs must contain only strings',\n );\n }\n }\n }\n\n if (!Object.hasOwn(sourceConfig, 'load') || typeof sourceConfig['load'] !== 'function') {\n throwValidation('contract.source.load', 'Config.contract.source.load must be a function');\n }\n\n const output = Object.hasOwn(contract, 'output') ? contract['output'] : undefined;\n if (output !== undefined && typeof output !== 'string') {\n throwValidation('contract.output', 'Config.contract.output must be a string when provided');\n }\n}\n\n/**\n * Validates that the config has the required structure.\n * This is pure validation logic with no file I/O or CLI awareness.\n *\n * @param config - Config object to validate\n * @throws ConfigValidationError if config structure is invalid\n */\nexport function validateConfig(config: unknown): asserts config is PrismaNextConfig {\n if (!config || typeof config !== 'object') {\n throwValidation('object', 'Config must be an object');\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj['family']) {\n throwValidation('family');\n }\n\n if (!configObj['target']) {\n throwValidation('target');\n }\n\n if (!configObj['adapter']) {\n throwValidation('adapter');\n }\n\n // Validate family descriptor\n const family = configObj['family'] as Record<string, unknown>;\n if (family['kind'] !== 'family') {\n throwValidation('family.kind', 'Config.family must have kind: \"family\"');\n }\n if (typeof family['id'] !== 'string') {\n throwValidation('family.id', 'Config.family must have id: string');\n }\n if (typeof family['familyId'] !== 'string') {\n throwValidation('family.familyId', 'Config.family must have familyId: string');\n }\n if (typeof family['version'] !== 'string') {\n throwValidation('family.version', 'Config.family must have version: string');\n }\n if (!family['emission'] || typeof family['emission'] !== 'object') {\n throwValidation('family.emission', 'Config.family must have emission: EmissionSpi');\n }\n if (typeof family['create'] !== 'function') {\n throwValidation('family.create', 'Config.family must have create: function');\n }\n\n const familyId = family['familyId'] as string;\n\n // Validate target descriptor\n const target = configObj['target'] as Record<string, unknown>;\n if (target['kind'] !== 'target') {\n throwValidation('target.kind', 'Config.target must have kind: \"target\"');\n }\n if (typeof target['id'] !== 'string') {\n throwValidation('target.id', 'Config.target must have id: string');\n }\n if (typeof target['familyId'] !== 'string') {\n throwValidation('target.familyId', 'Config.target must have familyId: string');\n }\n if (typeof target['version'] !== 'string') {\n throwValidation('target.version', 'Config.target must have version: string');\n }\n if (target['familyId'] !== familyId) {\n throwValidation(\n 'target.familyId',\n `Config.target.familyId must match Config.family.familyId (expected: ${familyId}, got: ${target['familyId']})`,\n );\n }\n if (typeof target['targetId'] !== 'string') {\n throwValidation('target.targetId', 'Config.target must have targetId: string');\n }\n if (typeof target['create'] !== 'function') {\n throwValidation('target.create', 'Config.target must have create: function');\n }\n const expectedTargetId = target['targetId'] as string;\n\n // Validate adapter descriptor\n const adapter = configObj['adapter'] as Record<string, unknown>;\n if (adapter['kind'] !== 'adapter') {\n throwValidation('adapter.kind', 'Config.adapter must have kind: \"adapter\"');\n }\n if (typeof adapter['id'] !== 'string') {\n throwValidation('adapter.id', 'Config.adapter must have id: string');\n }\n if (typeof adapter['familyId'] !== 'string') {\n throwValidation('adapter.familyId', 'Config.adapter must have familyId: string');\n }\n if (typeof adapter['version'] !== 'string') {\n throwValidation('adapter.version', 'Config.adapter must have version: string');\n }\n if (adapter['familyId'] !== familyId) {\n throwValidation(\n 'adapter.familyId',\n `Config.adapter.familyId must match Config.family.familyId (expected: ${familyId}, got: ${adapter['familyId']})`,\n );\n }\n if (typeof adapter['targetId'] !== 'string') {\n throwValidation('adapter.targetId', 'Config.adapter must have targetId: string');\n }\n if (adapter['targetId'] !== expectedTargetId) {\n throwValidation(\n 'adapter.targetId',\n `Config.adapter.targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${adapter['targetId']})`,\n );\n }\n if (typeof adapter['create'] !== 'function') {\n throwValidation('adapter.create', 'Config.adapter must have create: function');\n }\n\n if (configObj['extensions'] !== undefined) {\n throwValidation('extensions', 'Config.extensions is not supported; use Config.extensionPacks');\n }\n\n // Validate extensionPacks array if present\n if (configObj['extensionPacks'] !== undefined) {\n if (!Array.isArray(configObj['extensionPacks'])) {\n throwValidation('extensionPacks', 'Config.extensionPacks must be an array');\n }\n for (const ext of configObj['extensionPacks']) {\n if (!ext || typeof ext !== 'object') {\n throwValidation(\n 'extensionPacks[]',\n 'Config.extensionPacks must contain ControlExtensionDescriptor objects',\n );\n }\n const extObj = ext as Record<string, unknown>;\n if (extObj['kind'] !== 'extension') {\n throwValidation(\n 'extensionPacks[].kind',\n 'Config.extensionPacks items must have kind: \"extension\"',\n );\n }\n if (typeof extObj['id'] !== 'string') {\n throwValidation('extensionPacks[].id', 'Config.extensionPacks items must have id: string');\n }\n if (typeof extObj['familyId'] !== 'string') {\n throwValidation(\n 'extensionPacks[].familyId',\n 'Config.extensionPacks items must have familyId: string',\n );\n }\n if (typeof extObj['version'] !== 'string') {\n throwValidation(\n 'extensionPacks[].version',\n 'Config.extensionPacks items must have version: string',\n );\n }\n if (extObj['familyId'] !== familyId) {\n throwValidation(\n 'extensionPacks[].familyId',\n `Config.extensionPacks[].familyId must match Config.family.familyId (expected: ${familyId}, got: ${extObj['familyId']})`,\n );\n }\n if (typeof extObj['targetId'] !== 'string') {\n throwValidation(\n 'extensionPacks[].targetId',\n 'Config.extensionPacks items must have targetId: string',\n );\n }\n if (extObj['targetId'] !== expectedTargetId) {\n throwValidation(\n 'extensionPacks[].targetId',\n `Config.extensionPacks[].targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${extObj['targetId']})`,\n );\n }\n if (typeof extObj['create'] !== 'function') {\n throwValidation(\n 'extensionPacks[].create',\n 'Config.extensionPacks items must have create: function',\n );\n }\n }\n }\n\n // Validate driver descriptor if present\n if (configObj['driver'] !== undefined) {\n const driver = configObj['driver'] as Record<string, unknown>;\n if (driver['kind'] !== 'driver') {\n throwValidation('driver.kind', 'Config.driver must have kind: \"driver\"');\n }\n if (typeof driver['id'] !== 'string') {\n throwValidation('driver.id', 'Config.driver must have id: string');\n }\n if (typeof driver['version'] !== 'string') {\n throwValidation('driver.version', 'Config.driver must have version: string');\n }\n if (typeof driver['familyId'] !== 'string') {\n throwValidation('driver.familyId', 'Config.driver must have familyId: string');\n }\n if (driver['familyId'] !== familyId) {\n throwValidation(\n 'driver.familyId',\n `Config.driver.familyId must match Config.family.familyId (expected: ${familyId}, got: ${driver['familyId']})`,\n );\n }\n if (typeof driver['targetId'] !== 'string') {\n throwValidation('driver.targetId', 'Config.driver must have targetId: string');\n }\n if (driver['targetId'] !== expectedTargetId) {\n throwValidation(\n 'driver.targetId',\n `Config.driver.targetId must match Config.target.targetId (expected: ${expectedTargetId}, got: ${driver['targetId']})`,\n );\n }\n if (typeof driver['create'] !== 'function') {\n throwValidation('driver.create', 'Config.driver must have create: function');\n }\n }\n\n // Validate contract config if present (structure validation - defineConfig() handles normalization)\n if (configObj['contract'] !== undefined) {\n const contract = configObj['contract'] as Record<string, unknown>;\n if (!contract || typeof contract !== 'object') {\n throwValidation('contract', 'Config.contract must be an object');\n }\n validateContractConfig(contract);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/config",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Prisma Next config authoring types and validation",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"arktype": "^2.1.26",
|
|
9
|
-
"@prisma-next/framework-components": "0.4.
|
|
10
|
-
"@prisma-next/
|
|
11
|
-
"@prisma-next/
|
|
9
|
+
"@prisma-next/framework-components": "0.4.2",
|
|
10
|
+
"@prisma-next/utils": "0.4.2",
|
|
11
|
+
"@prisma-next/contract": "0.4.2"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"tsdown": "0.18.4",
|
|
15
15
|
"typescript": "5.9.3",
|
|
16
16
|
"vitest": "4.0.17",
|
|
17
|
-
"@prisma-next/
|
|
18
|
-
"@prisma-next/
|
|
17
|
+
"@prisma-next/tsdown": "0.0.0",
|
|
18
|
+
"@prisma-next/tsconfig": "0.0.0"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
package/src/config-types.ts
CHANGED
|
@@ -31,6 +31,17 @@ export interface ContractConfig {
|
|
|
31
31
|
readonly output?: string;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
export const DEFAULT_CONTRACT_OUTPUT = 'src/prisma/contract.json';
|
|
35
|
+
|
|
36
|
+
export function normalizeContractConfig(
|
|
37
|
+
contract: ContractConfig,
|
|
38
|
+
): ContractConfig & { readonly output: string } {
|
|
39
|
+
return {
|
|
40
|
+
source: contract.source,
|
|
41
|
+
output: contract.output ?? DEFAULT_CONTRACT_OUTPUT,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
/**
|
|
35
46
|
* Configuration for Prisma Next CLI.
|
|
36
47
|
* Uses Control*Descriptor types for type-safe wiring with compile-time compatibility checks.
|
|
@@ -86,13 +97,15 @@ export interface PrismaNextConfig<
|
|
|
86
97
|
};
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
100
|
+
const ContractSourceInputSchema = type('string');
|
|
101
|
+
|
|
102
|
+
export const ContractSourceProviderSchema = type({
|
|
103
|
+
'inputs?': ContractSourceInputSchema.array(),
|
|
104
|
+
load: 'Function',
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export const ContractConfigSchema = type({
|
|
108
|
+
source: ContractSourceProviderSchema,
|
|
96
109
|
'output?': 'string',
|
|
97
110
|
});
|
|
98
111
|
|
|
@@ -120,7 +133,7 @@ const PrismaNextConfigSchema = type({
|
|
|
120
133
|
* Validates and normalizes the config using Arktype, then returns the normalized IR.
|
|
121
134
|
*
|
|
122
135
|
* Normalization:
|
|
123
|
-
* - contract.output defaults to
|
|
136
|
+
* - contract.output defaults to DEFAULT_CONTRACT_OUTPUT if missing
|
|
124
137
|
*
|
|
125
138
|
* @param config - Raw config input from user
|
|
126
139
|
* @returns Normalized config IR with defaults applied
|
|
@@ -138,24 +151,10 @@ export function defineConfig<TFamilyId extends string = string, TTargetId extend
|
|
|
138
151
|
|
|
139
152
|
// Normalize contract config if present
|
|
140
153
|
if (config.contract) {
|
|
141
|
-
// Validate contract.source provider function shape at runtime.
|
|
142
|
-
const source = config.contract.source;
|
|
143
|
-
if (typeof source !== 'function') {
|
|
144
|
-
throw new Error('Config.contract.source must be a provider function');
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Apply defaults
|
|
148
|
-
const output = config.contract.output ?? 'src/prisma/contract.json';
|
|
149
|
-
|
|
150
|
-
const normalizedContract: ContractConfig = {
|
|
151
|
-
source: config.contract.source,
|
|
152
|
-
output,
|
|
153
|
-
};
|
|
154
|
-
|
|
155
154
|
// Return normalized config
|
|
156
155
|
return {
|
|
157
156
|
...config,
|
|
158
|
-
contract:
|
|
157
|
+
contract: normalizeContractConfig(config.contract),
|
|
159
158
|
};
|
|
160
159
|
}
|
|
161
160
|
|
package/src/config-validation.ts
CHANGED
|
@@ -5,6 +5,50 @@ function throwValidation(field: string, why?: string): never {
|
|
|
5
5
|
throw new ConfigValidationError(field, why);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
function validateContractConfig(contract: Record<string, unknown>): void {
|
|
9
|
+
if (!Object.hasOwn(contract, 'source')) {
|
|
10
|
+
throwValidation(
|
|
11
|
+
'contract.source',
|
|
12
|
+
'Config.contract.source is required when contract is provided',
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const source = contract['source'];
|
|
17
|
+
if (!source || typeof source !== 'object') {
|
|
18
|
+
throwValidation('contract.source', 'Config.contract.source must be a provider object');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sourceConfig = source as Record<string, unknown>;
|
|
22
|
+
const inputs = Object.hasOwn(sourceConfig, 'inputs') ? sourceConfig['inputs'] : undefined;
|
|
23
|
+
|
|
24
|
+
if (inputs !== undefined) {
|
|
25
|
+
if (!Array.isArray(inputs)) {
|
|
26
|
+
throwValidation(
|
|
27
|
+
'contract.source.inputs',
|
|
28
|
+
'Config.contract.source.inputs must be an array of strings when provided',
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const input of inputs) {
|
|
33
|
+
if (typeof input !== 'string') {
|
|
34
|
+
throwValidation(
|
|
35
|
+
'contract.source.inputs[]',
|
|
36
|
+
'Config.contract.source.inputs must contain only strings',
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!Object.hasOwn(sourceConfig, 'load') || typeof sourceConfig['load'] !== 'function') {
|
|
43
|
+
throwValidation('contract.source.load', 'Config.contract.source.load must be a function');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const output = Object.hasOwn(contract, 'output') ? contract['output'] : undefined;
|
|
47
|
+
if (output !== undefined && typeof output !== 'string') {
|
|
48
|
+
throwValidation('contract.output', 'Config.contract.output must be a string when provided');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
8
52
|
/**
|
|
9
53
|
* Validates that the config has the required structure.
|
|
10
54
|
* This is pure validation logic with no file I/O or CLI awareness.
|
|
@@ -221,19 +265,6 @@ export function validateConfig(config: unknown): asserts config is PrismaNextCon
|
|
|
221
265
|
if (!contract || typeof contract !== 'object') {
|
|
222
266
|
throwValidation('contract', 'Config.contract must be an object');
|
|
223
267
|
}
|
|
224
|
-
|
|
225
|
-
throwValidation(
|
|
226
|
-
'contract.source',
|
|
227
|
-
'Config.contract.source is required when contract is provided',
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (typeof contract['source'] !== 'function') {
|
|
232
|
-
throwValidation('contract.source', 'Config.contract.source must be a provider function');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (contract['output'] !== undefined && typeof contract['output'] !== 'string') {
|
|
236
|
-
throwValidation('contract.output', 'Config.contract.output must be a string when provided');
|
|
237
|
-
}
|
|
268
|
+
validateContractConfig(contract);
|
|
238
269
|
}
|
|
239
270
|
}
|
|
@@ -42,8 +42,12 @@ export interface ContractSourceContext {
|
|
|
42
42
|
readonly authoringContributions: AssembledAuthoringContributions;
|
|
43
43
|
readonly codecLookup: CodecLookup;
|
|
44
44
|
readonly controlMutationDefaults: ControlMutationDefaults;
|
|
45
|
+
readonly resolvedInputs: readonly string[];
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
export
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
export interface ContractSourceProvider {
|
|
49
|
+
readonly inputs?: readonly string[];
|
|
50
|
+
readonly load: (
|
|
51
|
+
context: ContractSourceContext,
|
|
52
|
+
) => Promise<Result<Contract, ContractSourceDiagnostics>>;
|
|
53
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ContractConfig, PrismaNextConfig } from '../config-types';
|
|
2
|
-
export { defineConfig } from '../config-types';
|
|
2
|
+
export { DEFAULT_CONTRACT_OUTPUT, defineConfig, normalizeContractConfig } from '../config-types';
|
|
3
3
|
export type {
|
|
4
4
|
ContractSourceContext,
|
|
5
5
|
ContractSourceDiagnostic,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-types-BqPA4C22.d.mts","names":[],"sources":["../src/contract-source-types.ts","../src/config-types.ts"],"sourcesContent":[],"mappings":";;;;;;UAQiB,gCAAA;;EAAA,SAAA,IAAA,EAAA,MAAA;EAMA,SAAA,MAAA,EAAA,MAAA;AAKjB;AAIkB,UATD,4BAAA,CASC;EAMS,SAAA,KAAA,EAdT,gCAcS;EAAT,SAAA,GAAA,EAbF,gCAaE;;AAGD,UAbA,wBAAA,CAayB;EAMzB,SAAA,IAAA,EAAA,MAAA;EAEiB,SAAA,OAAA,EAAA,MAAA;EACC,SAAA,QAAA,CAAA,EAAA,MAAA;EACX,SAAA,IAAA,CAAA,EAnBN,4BAmBM;EACY;;AAGpC;;;EAE8B,SAAA,IAAA,CAAA,EAnBZ,QAmBY,CAnBH,MAmBG,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;;AAAzB,UAhBY,yBAAA,CAgBZ;EAAO,SAAA,OAAA,EAAA,MAAA;iCAdqB;kBACf;;ACfD,UDkBA,qBAAA,CCbE;EAgBF,SAAA,sBAAgB,EAAA,SAAA,MAAA,EAAA;EAKU,SAAA,qBAAA,EDNT,WCMS,CAAA,MAAA,EAAA,MAAA,CAAA;EAAxB,SAAA,sBAAA,EDLgB,+BCKhB;EACwB,SAAA,WAAA,EDLnB,WCKmB;EAAW,SAAA,uBAAA,EDJlB,uBCIkB;;AACT,KDFjC,sBAAA,GCEiC,CAAA,OAAA,EDDlC,qBCCkC,EAAA,GDAxC,OCAwC,CDAhC,MCAgC,CDAzB,QCAyB,EDAf,yBCAe,CAAA,CAAA;;;ADlC7C;AAKA;;AAU2B,UCTV,cAAA,CDSU;EAAT;;AAGlB;AAMA;EAEkC,SAAA,MAAA,ECff,sBDee;EACC;;;;EAKvB,SAAA,MAAA,CAAA,EAAA,MAAA;;;;;;;;;;AC1BK,UAqBA,gBAhBE,CAAA,kBAAA,MAAsB,GAAA,MAAA,EAAA,kBAAA,MAAA,GAAA,MAAA,EAAA,cAAA,OAAA,CAAA,CAAA;EAgBxB,SAAA,MAAA,EAKE,uBALc,CAKU,SALV,CAAA;EAKU,SAAA,MAAA,EACxB,uBADwB,CACA,SADA,EACW,SADX,CAAA;EAAxB,SAAA,OAAA,EAEC,wBAFD,CAE0B,SAF1B,EAEqC,SAFrC,CAAA;EACwB,SAAA,cAAA,CAAA,EAAA,SAEN,0BAFM,CAEqB,SAFrB,EAEgC,SAFhC,CAAA,EAAA;EAAW;;;;;;EAEqB,SAAA,MAAA,CAAA,EAOvD,uBAPuD,CAQvE,SARuE,EASvE,SATuE,EAUvE,qBAVuE,CAUjD,SAViD,EAUtC,SAVsC,CAAA,EAWvE,WAXuE,CAAA;EAAtC;;;;EAUA,SAAA,EAAA,CAAA,EAAA;IAAjC;;;;;IAmBgC,SAAA,UAAA,CAAA,EANV,WAMU;EAkDpB,CAAA;EACW;;;;EACI,SAAA,QAAA,CAAA,EApDT,cAoDS;EAA5B;;;;;;;;;;;;;;;;;;;iBAFa,2FACN,iBAAiB,WAAW,aACnC,iBAAiB,WAAW"}
|