@prisma-next/sql-contract-ts 0.3.0-pr.99.5 → 0.3.0
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/LICENSE +201 -0
- package/README.md +206 -73
- package/dist/config-types.d.mts +8 -0
- package/dist/config-types.d.mts.map +1 -0
- package/dist/config-types.mjs +14 -0
- package/dist/config-types.mjs.map +1 -0
- package/dist/contract-builder.d.mts +769 -0
- package/dist/contract-builder.d.mts.map +1 -0
- package/dist/contract-builder.mjs +1288 -0
- package/dist/contract-builder.mjs.map +1 -0
- package/package.json +20 -17
- package/schemas/data-contract-sql-v1.json +189 -23
- package/src/authoring-helper-runtime.ts +139 -0
- package/src/authoring-type-utils.ts +168 -0
- package/src/build-contract.ts +463 -0
- package/src/composed-authoring-helpers.ts +256 -0
- package/src/config-types.ts +11 -0
- package/src/contract-builder.ts +232 -551
- package/src/contract-definition.ts +103 -0
- package/src/contract-dsl.ts +1492 -0
- package/src/contract-lowering.ts +703 -0
- package/src/contract-types.ts +534 -0
- package/src/contract-warnings.ts +242 -0
- package/src/exports/config-types.ts +2 -0
- package/src/exports/contract-builder.ts +23 -2
- package/dist/chunk-HTNUNGA2.js +0 -346
- package/dist/chunk-HTNUNGA2.js.map +0 -1
- package/dist/contract-builder.d.ts +0 -101
- package/dist/contract-builder.d.ts.map +0 -1
- package/dist/contract.d.ts +0 -50
- package/dist/contract.d.ts.map +0 -1
- package/dist/exports/contract-builder.d.ts +0 -3
- package/dist/exports/contract-builder.d.ts.map +0 -1
- package/dist/exports/contract-builder.js +0 -231
- package/dist/exports/contract-builder.js.map +0 -1
- package/dist/exports/contract.d.ts +0 -2
- package/dist/exports/contract.d.ts.map +0 -1
- package/dist/exports/contract.js +0 -9
- package/dist/exports/contract.js.map +0 -1
- package/src/contract.ts +0 -582
- package/src/exports/contract.ts +0 -1
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthoringArgumentDescriptor,
|
|
3
|
+
AuthoringFieldNamespace,
|
|
4
|
+
AuthoringTypeConstructorDescriptor,
|
|
5
|
+
AuthoringTypeNamespace,
|
|
6
|
+
} from '@prisma-next/framework-components/authoring';
|
|
7
|
+
import {
|
|
8
|
+
isAuthoringFieldPresetDescriptor,
|
|
9
|
+
isAuthoringTypeConstructorDescriptor,
|
|
10
|
+
} from '@prisma-next/framework-components/authoring';
|
|
11
|
+
import type {
|
|
12
|
+
ExtensionPackRef,
|
|
13
|
+
FamilyPackRef,
|
|
14
|
+
TargetPackRef,
|
|
15
|
+
} from '@prisma-next/framework-components/components';
|
|
16
|
+
import {
|
|
17
|
+
createFieldHelpersFromNamespace,
|
|
18
|
+
createFieldPresetHelper,
|
|
19
|
+
createTypeHelpersFromNamespace,
|
|
20
|
+
} from './authoring-helper-runtime';
|
|
21
|
+
import type {
|
|
22
|
+
FieldHelpersFromNamespace,
|
|
23
|
+
ResolveTemplateValue,
|
|
24
|
+
TupleFromArgumentDescriptors,
|
|
25
|
+
UnionToIntersection,
|
|
26
|
+
} from './authoring-type-utils';
|
|
27
|
+
import { buildFieldPreset, field, model, rel } from './contract-dsl';
|
|
28
|
+
|
|
29
|
+
type ExtractTypeNamespaceFromPack<Pack> = Pack extends {
|
|
30
|
+
readonly authoring?: { readonly type?: infer Namespace extends AuthoringTypeNamespace };
|
|
31
|
+
}
|
|
32
|
+
? Namespace
|
|
33
|
+
: Record<never, never>;
|
|
34
|
+
|
|
35
|
+
type ExtractFieldNamespaceFromPack<Pack> = Pack extends {
|
|
36
|
+
readonly authoring?: { readonly field?: infer Namespace extends AuthoringFieldNamespace };
|
|
37
|
+
}
|
|
38
|
+
? Namespace
|
|
39
|
+
: Record<never, never>;
|
|
40
|
+
|
|
41
|
+
type MergeExtensionTypeNamespaces<ExtensionPacks> =
|
|
42
|
+
ExtensionPacks extends Record<string, unknown>
|
|
43
|
+
? keyof ExtensionPacks extends never
|
|
44
|
+
? Record<never, never>
|
|
45
|
+
: UnionToIntersection<
|
|
46
|
+
{
|
|
47
|
+
[K in keyof ExtensionPacks]: ExtractTypeNamespaceFromPack<ExtensionPacks[K]>;
|
|
48
|
+
}[keyof ExtensionPacks]
|
|
49
|
+
>
|
|
50
|
+
: Record<never, never>;
|
|
51
|
+
|
|
52
|
+
type MergeExtensionFieldNamespaces<ExtensionPacks> =
|
|
53
|
+
ExtensionPacks extends Record<string, unknown>
|
|
54
|
+
? keyof ExtensionPacks extends never
|
|
55
|
+
? Record<never, never>
|
|
56
|
+
: UnionToIntersection<
|
|
57
|
+
{
|
|
58
|
+
[K in keyof ExtensionPacks]: ExtractFieldNamespaceFromPack<ExtensionPacks[K]>;
|
|
59
|
+
}[keyof ExtensionPacks]
|
|
60
|
+
>
|
|
61
|
+
: Record<never, never>;
|
|
62
|
+
|
|
63
|
+
type StorageTypeFromDescriptor<
|
|
64
|
+
Descriptor extends AuthoringTypeConstructorDescriptor,
|
|
65
|
+
Args extends readonly unknown[],
|
|
66
|
+
> = {
|
|
67
|
+
readonly codecId: ResolveTemplateValue<Descriptor['output']['codecId'], Args>;
|
|
68
|
+
readonly nativeType: ResolveTemplateValue<Descriptor['output']['nativeType'], Args>;
|
|
69
|
+
} & (Descriptor['output'] extends {
|
|
70
|
+
readonly typeParams: infer TypeParams extends Record<string, unknown>;
|
|
71
|
+
}
|
|
72
|
+
? {
|
|
73
|
+
readonly typeParams: ResolveTemplateValue<TypeParams, Args>;
|
|
74
|
+
}
|
|
75
|
+
: Record<never, never>);
|
|
76
|
+
|
|
77
|
+
type TypeHelperFunction<Descriptor extends AuthoringTypeConstructorDescriptor> =
|
|
78
|
+
Descriptor extends { readonly args: infer Args extends readonly AuthoringArgumentDescriptor[] }
|
|
79
|
+
? <const Params extends TupleFromArgumentDescriptors<Args>>(
|
|
80
|
+
...args: Params
|
|
81
|
+
) => StorageTypeFromDescriptor<Descriptor, Params>
|
|
82
|
+
: () => StorageTypeFromDescriptor<Descriptor, readonly []>;
|
|
83
|
+
|
|
84
|
+
type TypeHelpersFromNamespace<Namespace> = {
|
|
85
|
+
readonly [K in keyof Namespace]: Namespace[K] extends AuthoringTypeConstructorDescriptor
|
|
86
|
+
? TypeHelperFunction<Namespace[K]>
|
|
87
|
+
: Namespace[K] extends Record<string, unknown>
|
|
88
|
+
? TypeHelpersFromNamespace<Namespace[K]>
|
|
89
|
+
: never;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
type CoreFieldHelpers = Pick<typeof field, 'column' | 'generated' | 'namedType'>;
|
|
93
|
+
|
|
94
|
+
export type ComposedAuthoringHelpers<
|
|
95
|
+
Family extends FamilyPackRef<string>,
|
|
96
|
+
Target extends TargetPackRef<'sql', string>,
|
|
97
|
+
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
98
|
+
> = {
|
|
99
|
+
readonly field: CoreFieldHelpers &
|
|
100
|
+
FieldHelpersFromNamespace<
|
|
101
|
+
ExtractFieldNamespaceFromPack<Family> &
|
|
102
|
+
ExtractFieldNamespaceFromPack<Target> &
|
|
103
|
+
MergeExtensionFieldNamespaces<ExtensionPacks>
|
|
104
|
+
>;
|
|
105
|
+
readonly model: typeof model;
|
|
106
|
+
readonly rel: typeof rel;
|
|
107
|
+
readonly type: TypeHelpersFromNamespace<
|
|
108
|
+
ExtractTypeNamespaceFromPack<Family> &
|
|
109
|
+
ExtractTypeNamespaceFromPack<Target> &
|
|
110
|
+
MergeExtensionTypeNamespaces<ExtensionPacks>
|
|
111
|
+
>;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
function extractTypeNamespace<Pack>(pack: Pack): ExtractTypeNamespaceFromPack<Pack> {
|
|
115
|
+
return ((pack as { readonly authoring?: { readonly type?: unknown } }).authoring?.type ??
|
|
116
|
+
{}) as ExtractTypeNamespaceFromPack<Pack>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function extractFieldNamespace<Pack>(pack: Pack): ExtractFieldNamespaceFromPack<Pack> {
|
|
120
|
+
return ((pack as { readonly authoring?: { readonly field?: unknown } }).authoring?.field ??
|
|
121
|
+
{}) as ExtractFieldNamespaceFromPack<Pack>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function mergeHelperNamespaces(
|
|
125
|
+
target: Record<string, unknown>,
|
|
126
|
+
source: Record<string, unknown>,
|
|
127
|
+
path: readonly string[],
|
|
128
|
+
leafGuard: (value: unknown) => boolean,
|
|
129
|
+
label: string,
|
|
130
|
+
): void {
|
|
131
|
+
const assertSafePath = (currentPath: readonly string[]) => {
|
|
132
|
+
const blockedSegment = currentPath.find(
|
|
133
|
+
(segment) => segment === '__proto__' || segment === 'constructor' || segment === 'prototype',
|
|
134
|
+
);
|
|
135
|
+
if (blockedSegment) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`Invalid authoring ${label} helper "${currentPath.join('.')}". Helper path segments must not use "${blockedSegment}".`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
143
|
+
const currentPath = [...path, key];
|
|
144
|
+
assertSafePath(currentPath);
|
|
145
|
+
const hasExistingValue = Object.hasOwn(target, key);
|
|
146
|
+
const existingValue = hasExistingValue ? target[key] : undefined;
|
|
147
|
+
|
|
148
|
+
if (!hasExistingValue) {
|
|
149
|
+
target[key] = sourceValue;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const existingIsLeaf = leafGuard(existingValue);
|
|
154
|
+
const sourceIsLeaf = leafGuard(sourceValue);
|
|
155
|
+
|
|
156
|
+
if (existingIsLeaf || sourceIsLeaf) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Duplicate authoring ${label} helper "${currentPath.join('.')}". Helper names must be unique across composed packs.`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
mergeHelperNamespaces(
|
|
163
|
+
existingValue as Record<string, unknown>,
|
|
164
|
+
sourceValue as Record<string, unknown>,
|
|
165
|
+
currentPath,
|
|
166
|
+
leafGuard,
|
|
167
|
+
label,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
type AuthoringComponent = {
|
|
173
|
+
readonly authoring?: { readonly type?: unknown; readonly field?: unknown };
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
function composeTypeNamespace(components: readonly AuthoringComponent[]): AuthoringTypeNamespace {
|
|
177
|
+
const merged: Record<string, unknown> = {};
|
|
178
|
+
for (const component of components) {
|
|
179
|
+
const ns = extractTypeNamespace(component);
|
|
180
|
+
if (Object.keys(ns).length > 0) {
|
|
181
|
+
mergeHelperNamespaces(merged, ns, [], isAuthoringTypeConstructorDescriptor, 'type');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return merged as AuthoringTypeNamespace;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function composeFieldNamespace(components: readonly AuthoringComponent[]): AuthoringFieldNamespace {
|
|
188
|
+
const merged: Record<string, unknown> = {};
|
|
189
|
+
for (const component of components) {
|
|
190
|
+
const ns = extractFieldNamespace(component);
|
|
191
|
+
if (Object.keys(ns).length > 0) {
|
|
192
|
+
mergeHelperNamespaces(merged, ns, [], isAuthoringFieldPresetDescriptor, 'field');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return merged as AuthoringFieldNamespace;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function createComposedFieldHelpers(
|
|
199
|
+
components: readonly AuthoringComponent[],
|
|
200
|
+
): CoreFieldHelpers & Record<string, unknown> {
|
|
201
|
+
const helperNamespace = createFieldHelpersFromNamespace(
|
|
202
|
+
composeFieldNamespace(components),
|
|
203
|
+
({ helperPath, descriptor }) =>
|
|
204
|
+
createFieldPresetHelper({
|
|
205
|
+
helperPath,
|
|
206
|
+
descriptor,
|
|
207
|
+
build: ({ args, namedConstraintOptions }) =>
|
|
208
|
+
buildFieldPreset(descriptor, args, namedConstraintOptions),
|
|
209
|
+
}),
|
|
210
|
+
);
|
|
211
|
+
const coreFieldHelpers = {
|
|
212
|
+
column: field.column,
|
|
213
|
+
generated: field.generated,
|
|
214
|
+
namedType: field.namedType,
|
|
215
|
+
} satisfies CoreFieldHelpers;
|
|
216
|
+
|
|
217
|
+
const coreHelperNames = new Set(Object.keys(coreFieldHelpers));
|
|
218
|
+
for (const helperName of Object.keys(helperNamespace)) {
|
|
219
|
+
if (coreHelperNames.has(helperName)) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
`Duplicate authoring field helper "${helperName}". Core field helpers reserve that name.`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
...coreFieldHelpers,
|
|
228
|
+
...helperNamespace,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function createComposedAuthoringHelpers<
|
|
233
|
+
Family extends FamilyPackRef<string>,
|
|
234
|
+
Target extends TargetPackRef<'sql', string>,
|
|
235
|
+
ExtensionPacks extends Record<string, ExtensionPackRef<'sql', string>> | undefined,
|
|
236
|
+
>(options: {
|
|
237
|
+
readonly family: Family;
|
|
238
|
+
readonly target: Target;
|
|
239
|
+
readonly extensionPacks?: ExtensionPacks;
|
|
240
|
+
}): ComposedAuthoringHelpers<Family, Target, ExtensionPacks> {
|
|
241
|
+
const extensionValues: readonly ExtensionPackRef<'sql', string>[] = Object.values(
|
|
242
|
+
(options.extensionPacks ?? {}) as Record<string, ExtensionPackRef<'sql', string>>,
|
|
243
|
+
);
|
|
244
|
+
const components: readonly AuthoringComponent[] = [
|
|
245
|
+
options.family,
|
|
246
|
+
options.target,
|
|
247
|
+
...extensionValues,
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
field: createComposedFieldHelpers(components),
|
|
252
|
+
model,
|
|
253
|
+
rel,
|
|
254
|
+
type: createTypeHelpersFromNamespace(composeTypeNamespace(components)),
|
|
255
|
+
} as ComposedAuthoringHelpers<Family, Target, ExtensionPacks>;
|
|
256
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContractConfig } from '@prisma-next/config/config-types';
|
|
2
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
3
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
4
|
+
import { ok } from '@prisma-next/utils/result';
|
|
5
|
+
|
|
6
|
+
export function typescriptContract(contract: Contract, output?: string): ContractConfig {
|
|
7
|
+
return {
|
|
8
|
+
source: async (_context) => ok(contract),
|
|
9
|
+
...ifDefined('output', output),
|
|
10
|
+
};
|
|
11
|
+
}
|