@prisma-next/sql-contract-psl 0.3.0-dev.71 → 0.4.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2343 @@
1
+ import { instantiateAuthoringTypeConstructor, isAuthoringTypeConstructorDescriptor, validateAuthoringHelperArguments } from "@prisma-next/framework-components/authoring";
2
+ import { buildSqlContractFromDefinition } from "@prisma-next/sql-contract-ts/contract-builder";
3
+ import { ifDefined } from "@prisma-next/utils/defined";
4
+ import { notOk, ok } from "@prisma-next/utils/result";
5
+ import { getPositionalArgument, parseQuotedStringLiteral } from "@prisma-next/psl-parser";
6
+ import { assertDefined, invariant } from "@prisma-next/utils/assertions";
7
+
8
+ //#region src/psl-attribute-parsing.ts
9
+ function lowerFirst(value) {
10
+ if (value.length === 0) return value;
11
+ return value[0]?.toLowerCase() + value.slice(1);
12
+ }
13
+ function getAttribute(attributes, name) {
14
+ return attributes?.find((attribute) => attribute.name === name);
15
+ }
16
+ function getNamedArgument(attribute, name) {
17
+ const entry = attribute.args.find((arg) => arg.kind === "named" && arg.name === name);
18
+ if (!entry || entry.kind !== "named") return;
19
+ return entry.value;
20
+ }
21
+ function getPositionalArgumentEntry(attribute, index = 0) {
22
+ const entry = attribute.args.filter((arg) => arg.kind === "positional")[index];
23
+ if (!entry || entry.kind !== "positional") return;
24
+ return {
25
+ value: entry.value,
26
+ span: entry.span
27
+ };
28
+ }
29
+ function unquoteStringLiteral(value) {
30
+ const trimmed = value.trim();
31
+ const match = trimmed.match(/^(['"])(.*)\1$/);
32
+ if (!match) return trimmed;
33
+ return match[2] ?? "";
34
+ }
35
+ function parseFieldList(value) {
36
+ const trimmed = value.trim();
37
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return;
38
+ return trimmed.slice(1, -1).split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
39
+ }
40
+ function parseMapName(input) {
41
+ if (!input.attribute) return input.defaultValue;
42
+ const value = getPositionalArgument(input.attribute);
43
+ if (!value) {
44
+ input.diagnostics.push({
45
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
46
+ message: `${input.entityLabel} @map requires a positional quoted string literal argument`,
47
+ sourceId: input.sourceId,
48
+ span: input.attribute.span
49
+ });
50
+ return input.defaultValue;
51
+ }
52
+ const parsed = parseQuotedStringLiteral(value);
53
+ if (parsed === void 0) {
54
+ input.diagnostics.push({
55
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
56
+ message: `${input.entityLabel} @map requires a positional quoted string literal argument`,
57
+ sourceId: input.sourceId,
58
+ span: input.attribute.span
59
+ });
60
+ return input.defaultValue;
61
+ }
62
+ return parsed;
63
+ }
64
+ function parseConstraintMapArgument(input) {
65
+ if (!input.attribute) return;
66
+ const raw = getNamedArgument(input.attribute, "map");
67
+ if (!raw) return;
68
+ const parsed = parseQuotedStringLiteral(raw);
69
+ if (parsed !== void 0) return parsed;
70
+ input.diagnostics.push({
71
+ code: input.code,
72
+ message: `${input.entityLabel} map argument must be a quoted string literal`,
73
+ sourceId: input.sourceId,
74
+ span: input.span
75
+ });
76
+ }
77
+ function getPositionalArguments(attribute) {
78
+ return attribute.args.filter((arg) => arg.kind === "positional").map((arg) => arg.kind === "positional" ? arg.value : "");
79
+ }
80
+ function pushInvalidAttributeArgument(input) {
81
+ input.diagnostics.push({
82
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
83
+ message: input.message,
84
+ sourceId: input.sourceId,
85
+ span: input.span
86
+ });
87
+ }
88
+ function parseOptionalSingleIntegerArgument(input) {
89
+ if (input.attribute.args.some((arg) => arg.kind === "named")) return pushInvalidAttributeArgument({
90
+ diagnostics: input.diagnostics,
91
+ sourceId: input.sourceId,
92
+ span: input.attribute.span,
93
+ message: `${input.entityLabel} @${input.attribute.name} accepts zero or one positional integer argument.`
94
+ });
95
+ const positionalArguments = getPositionalArguments(input.attribute);
96
+ if (positionalArguments.length > 1) return pushInvalidAttributeArgument({
97
+ diagnostics: input.diagnostics,
98
+ sourceId: input.sourceId,
99
+ span: input.attribute.span,
100
+ message: `${input.entityLabel} @${input.attribute.name} accepts zero or one positional integer argument.`
101
+ });
102
+ if (positionalArguments.length === 0) return null;
103
+ const parsed = Number(unquoteStringLiteral(positionalArguments[0] ?? ""));
104
+ if (!Number.isInteger(parsed) || parsed < input.minimum) return pushInvalidAttributeArgument({
105
+ diagnostics: input.diagnostics,
106
+ sourceId: input.sourceId,
107
+ span: input.attribute.span,
108
+ message: `${input.entityLabel} @${input.attribute.name} requires a ${input.valueLabel}.`
109
+ });
110
+ return parsed;
111
+ }
112
+ function parseOptionalNumericArguments(input) {
113
+ if (input.attribute.args.some((arg) => arg.kind === "named")) return pushInvalidAttributeArgument({
114
+ diagnostics: input.diagnostics,
115
+ sourceId: input.sourceId,
116
+ span: input.attribute.span,
117
+ message: `${input.entityLabel} @${input.attribute.name} accepts zero, one, or two positional integer arguments.`
118
+ });
119
+ const positionalArguments = getPositionalArguments(input.attribute);
120
+ if (positionalArguments.length > 2) return pushInvalidAttributeArgument({
121
+ diagnostics: input.diagnostics,
122
+ sourceId: input.sourceId,
123
+ span: input.attribute.span,
124
+ message: `${input.entityLabel} @${input.attribute.name} accepts zero, one, or two positional integer arguments.`
125
+ });
126
+ if (positionalArguments.length === 0) return null;
127
+ const precision = Number(unquoteStringLiteral(positionalArguments[0] ?? ""));
128
+ if (!Number.isInteger(precision) || precision < 1) return pushInvalidAttributeArgument({
129
+ diagnostics: input.diagnostics,
130
+ sourceId: input.sourceId,
131
+ span: input.attribute.span,
132
+ message: `${input.entityLabel} @${input.attribute.name} requires a positive integer precision.`
133
+ });
134
+ if (positionalArguments.length === 1) return { precision };
135
+ const scale = Number(unquoteStringLiteral(positionalArguments[1] ?? ""));
136
+ if (!Number.isInteger(scale) || scale < 0) return pushInvalidAttributeArgument({
137
+ diagnostics: input.diagnostics,
138
+ sourceId: input.sourceId,
139
+ span: input.attribute.span,
140
+ message: `${input.entityLabel} @${input.attribute.name} requires a non-negative integer scale.`
141
+ });
142
+ return {
143
+ precision,
144
+ scale
145
+ };
146
+ }
147
+ function parseAttributeFieldList(input) {
148
+ const raw = getNamedArgument(input.attribute, "fields") ?? getPositionalArgument(input.attribute);
149
+ if (!raw) {
150
+ input.diagnostics.push({
151
+ code: input.code,
152
+ message: `${input.messagePrefix} requires fields list argument`,
153
+ sourceId: input.sourceId,
154
+ span: input.attribute.span
155
+ });
156
+ return;
157
+ }
158
+ const fields = parseFieldList(raw);
159
+ if (!fields || fields.length === 0) {
160
+ input.diagnostics.push({
161
+ code: input.code,
162
+ message: `${input.messagePrefix} requires bracketed field list argument`,
163
+ sourceId: input.sourceId,
164
+ span: input.attribute.span
165
+ });
166
+ return;
167
+ }
168
+ return fields;
169
+ }
170
+ function mapFieldNamesToColumns(input) {
171
+ const columns = [];
172
+ for (const fieldName of input.fieldNames) {
173
+ const columnName = input.mapping.fieldColumns.get(fieldName);
174
+ if (!columnName) {
175
+ input.diagnostics.push({
176
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
177
+ message: `${input.contextLabel} references unknown field "${input.modelName}.${fieldName}"`,
178
+ sourceId: input.sourceId,
179
+ span: input.span
180
+ });
181
+ return;
182
+ }
183
+ columns.push(columnName);
184
+ }
185
+ return columns;
186
+ }
187
+
188
+ //#endregion
189
+ //#region src/default-function-registry.ts
190
+ function resolveSpanPositionFromBase(base, text, offset) {
191
+ const safeOffset = Math.min(Math.max(0, offset), text.length);
192
+ let line = base.start.line;
193
+ let column = base.start.column;
194
+ for (let index = 0; index < safeOffset; index += 1) {
195
+ const character = text[index] ?? "";
196
+ if (character === "\r") {
197
+ if (text[index + 1] === "\n" && index + 1 < safeOffset) index += 1;
198
+ line += 1;
199
+ column = 1;
200
+ continue;
201
+ }
202
+ if (character === "\n") {
203
+ line += 1;
204
+ column = 1;
205
+ continue;
206
+ }
207
+ column += 1;
208
+ }
209
+ return {
210
+ offset: base.start.offset + safeOffset,
211
+ line,
212
+ column
213
+ };
214
+ }
215
+ function createSpanFromBase(base, startOffset, endOffset, text) {
216
+ const safeStart = Math.max(0, Math.min(startOffset, text.length));
217
+ const safeEnd = Math.max(safeStart, Math.min(endOffset, text.length));
218
+ return {
219
+ start: resolveSpanPositionFromBase(base, text, safeStart),
220
+ end: resolveSpanPositionFromBase(base, text, safeEnd)
221
+ };
222
+ }
223
+ function splitTopLevelArgs(raw) {
224
+ if (raw.trim().length === 0) return [];
225
+ const parts = [];
226
+ let depthParen = 0;
227
+ let depthBracket = 0;
228
+ let quote = null;
229
+ let start = 0;
230
+ for (let index = 0; index < raw.length; index += 1) {
231
+ const character = raw[index] ?? "";
232
+ if (quote) {
233
+ if (character === quote && raw[index - 1] !== "\\") quote = null;
234
+ continue;
235
+ }
236
+ if (character === "\"" || character === "'") {
237
+ quote = character;
238
+ continue;
239
+ }
240
+ if (character === "(") {
241
+ depthParen += 1;
242
+ continue;
243
+ }
244
+ if (character === ")") {
245
+ depthParen = Math.max(0, depthParen - 1);
246
+ continue;
247
+ }
248
+ if (character === "[") {
249
+ depthBracket += 1;
250
+ continue;
251
+ }
252
+ if (character === "]") {
253
+ depthBracket = Math.max(0, depthBracket - 1);
254
+ continue;
255
+ }
256
+ if (character === "," && depthParen === 0 && depthBracket === 0) {
257
+ parts.push({
258
+ raw: raw.slice(start, index),
259
+ start,
260
+ end: index
261
+ });
262
+ start = index + 1;
263
+ }
264
+ }
265
+ parts.push({
266
+ raw: raw.slice(start),
267
+ start,
268
+ end: raw.length
269
+ });
270
+ return parts;
271
+ }
272
+ function parseDefaultFunctionCall(expression, expressionSpan) {
273
+ const trimmed = expression.trim();
274
+ const leadingWhitespace = expression.length - expression.trimStart().length;
275
+ const trailingWhitespace = expression.length - expression.trimEnd().length;
276
+ const contentEnd = expression.length - trailingWhitespace;
277
+ const openParen = trimmed.indexOf("(");
278
+ const closeParen = trimmed.lastIndexOf(")");
279
+ if (openParen <= 0 || closeParen !== trimmed.length - 1) return;
280
+ const functionName = trimmed.slice(0, openParen).trim();
281
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(functionName)) return;
282
+ const parts = splitTopLevelArgs(trimmed.slice(openParen + 1, closeParen));
283
+ const args = [];
284
+ for (const part of parts) {
285
+ const raw = part.raw.trim();
286
+ if (raw.length === 0) return;
287
+ const leadingPartWhitespace = part.raw.length - part.raw.trimStart().length;
288
+ const argStart = leadingWhitespace + openParen + 1 + part.start + leadingPartWhitespace;
289
+ const argEnd = argStart + raw.length;
290
+ args.push({
291
+ raw,
292
+ span: createSpanFromBase(expressionSpan, argStart, argEnd, expression)
293
+ });
294
+ }
295
+ return {
296
+ name: functionName,
297
+ raw: trimmed,
298
+ args,
299
+ span: createSpanFromBase(expressionSpan, leadingWhitespace, contentEnd, expression)
300
+ };
301
+ }
302
+ function formatSupportedFunctionList(registry) {
303
+ const signatures = Array.from(registry.entries()).sort(([a], [b]) => a.localeCompare(b)).flatMap(([functionName, entry]) => {
304
+ const usageSignatures = entry.usageSignatures?.filter((signature) => signature.length > 0);
305
+ return usageSignatures && usageSignatures.length > 0 ? usageSignatures : [`${functionName}()`];
306
+ });
307
+ return signatures.length > 0 ? signatures.join(", ") : "none";
308
+ }
309
+ function lowerDefaultFunctionWithRegistry(input) {
310
+ const entry = input.registry.get(input.call.name);
311
+ if (entry) return entry.lower({
312
+ call: input.call,
313
+ context: input.context
314
+ });
315
+ const supportedFunctionList = formatSupportedFunctionList(input.registry);
316
+ return {
317
+ ok: false,
318
+ diagnostic: {
319
+ code: "PSL_UNKNOWN_DEFAULT_FUNCTION",
320
+ message: `Default function "${input.call.name}" is not supported in SQL PSL provider v1. Supported functions: ${supportedFunctionList}.`,
321
+ sourceId: input.context.sourceId,
322
+ span: input.call.span
323
+ }
324
+ };
325
+ }
326
+
327
+ //#endregion
328
+ //#region src/psl-authoring-arguments.ts
329
+ const INVALID_AUTHORING_ARGUMENT = Symbol("invalidAuthoringArgument");
330
+ function isIdentifierStartCharacter(character) {
331
+ return character !== void 0 && /[A-Za-z_$]/.test(character);
332
+ }
333
+ function isIdentifierCharacter(character) {
334
+ return character !== void 0 && /[A-Za-z0-9_$]/.test(character);
335
+ }
336
+ function parseJsLikeLiteral(value) {
337
+ let index = 0;
338
+ function skipWhitespace() {
339
+ while (/\s/.test(value[index] ?? "")) index += 1;
340
+ }
341
+ function parseIdentifier() {
342
+ const first = value[index];
343
+ if (!isIdentifierStartCharacter(first)) return INVALID_AUTHORING_ARGUMENT;
344
+ let end = index + 1;
345
+ while (isIdentifierCharacter(value[end])) end += 1;
346
+ const identifier = value.slice(index, end);
347
+ index = end;
348
+ return identifier;
349
+ }
350
+ function parseString() {
351
+ const quote = value[index];
352
+ if (quote !== "\"" && quote !== "'") return INVALID_AUTHORING_ARGUMENT;
353
+ index += 1;
354
+ let result = "";
355
+ while (index < value.length) {
356
+ const character = value[index];
357
+ index += 1;
358
+ if (character === void 0) return INVALID_AUTHORING_ARGUMENT;
359
+ if (character === quote) return result;
360
+ if (character !== "\\") {
361
+ result += character;
362
+ continue;
363
+ }
364
+ const escaped = value[index];
365
+ index += 1;
366
+ if (escaped === void 0) return INVALID_AUTHORING_ARGUMENT;
367
+ switch (escaped) {
368
+ case "'":
369
+ case "\"":
370
+ case "\\":
371
+ case "/":
372
+ result += escaped;
373
+ break;
374
+ case "b":
375
+ result += "\b";
376
+ break;
377
+ case "f":
378
+ result += "\f";
379
+ break;
380
+ case "n":
381
+ result += "\n";
382
+ break;
383
+ case "r":
384
+ result += "\r";
385
+ break;
386
+ case "t":
387
+ result += " ";
388
+ break;
389
+ case "u": {
390
+ const hex = value.slice(index, index + 4);
391
+ if (!/^[0-9A-Fa-f]{4}$/.test(hex)) return INVALID_AUTHORING_ARGUMENT;
392
+ result += String.fromCharCode(Number.parseInt(hex, 16));
393
+ index += 4;
394
+ break;
395
+ }
396
+ default: return INVALID_AUTHORING_ARGUMENT;
397
+ }
398
+ }
399
+ return INVALID_AUTHORING_ARGUMENT;
400
+ }
401
+ function parseNumber() {
402
+ const raw = value.slice(index).match(/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0];
403
+ if (!raw) return INVALID_AUTHORING_ARGUMENT;
404
+ const parsed$1 = Number(raw);
405
+ if (!Number.isFinite(parsed$1)) return INVALID_AUTHORING_ARGUMENT;
406
+ index += raw.length;
407
+ return parsed$1;
408
+ }
409
+ function parseArray() {
410
+ if (value[index] !== "[") return INVALID_AUTHORING_ARGUMENT;
411
+ index += 1;
412
+ const result = [];
413
+ skipWhitespace();
414
+ if (value[index] === "]") {
415
+ index += 1;
416
+ return result;
417
+ }
418
+ while (index < value.length) {
419
+ const entry = parseValue();
420
+ if (entry === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
421
+ result.push(entry);
422
+ skipWhitespace();
423
+ if (value[index] === ",") {
424
+ index += 1;
425
+ skipWhitespace();
426
+ continue;
427
+ }
428
+ if (value[index] === "]") {
429
+ index += 1;
430
+ return result;
431
+ }
432
+ return INVALID_AUTHORING_ARGUMENT;
433
+ }
434
+ return INVALID_AUTHORING_ARGUMENT;
435
+ }
436
+ function parseObject() {
437
+ if (value[index] !== "{") return INVALID_AUTHORING_ARGUMENT;
438
+ index += 1;
439
+ const result = {};
440
+ skipWhitespace();
441
+ if (value[index] === "}") {
442
+ index += 1;
443
+ return result;
444
+ }
445
+ while (index < value.length) {
446
+ skipWhitespace();
447
+ const key = value[index] === "\"" || value[index] === "'" ? parseString() : parseIdentifier();
448
+ if (key === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
449
+ skipWhitespace();
450
+ if (value[index] !== ":") return INVALID_AUTHORING_ARGUMENT;
451
+ index += 1;
452
+ const entry = parseValue();
453
+ if (entry === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
454
+ result[key] = entry;
455
+ skipWhitespace();
456
+ if (value[index] === ",") {
457
+ index += 1;
458
+ skipWhitespace();
459
+ continue;
460
+ }
461
+ if (value[index] === "}") {
462
+ index += 1;
463
+ return result;
464
+ }
465
+ return INVALID_AUTHORING_ARGUMENT;
466
+ }
467
+ return INVALID_AUTHORING_ARGUMENT;
468
+ }
469
+ function parseValue() {
470
+ skipWhitespace();
471
+ const character = value[index];
472
+ if (character === "{") return parseObject();
473
+ if (character === "[") return parseArray();
474
+ if (character === "\"" || character === "'") return parseString();
475
+ if (character === "-" || /\d/.test(character ?? "")) return parseNumber();
476
+ const identifier = parseIdentifier();
477
+ if (identifier === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
478
+ if (identifier === "true") return true;
479
+ if (identifier === "false") return false;
480
+ if (identifier === "null") return null;
481
+ return INVALID_AUTHORING_ARGUMENT;
482
+ }
483
+ skipWhitespace();
484
+ const parsed = parseValue();
485
+ if (parsed === INVALID_AUTHORING_ARGUMENT) return parsed;
486
+ skipWhitespace();
487
+ return index === value.length ? parsed : INVALID_AUTHORING_ARGUMENT;
488
+ }
489
+ function parseStringArrayLiteral(value) {
490
+ const parsed = parseJsLikeLiteral(value);
491
+ if (parsed === INVALID_AUTHORING_ARGUMENT || !Array.isArray(parsed)) return INVALID_AUTHORING_ARGUMENT;
492
+ if (!parsed.every((item) => typeof item === "string")) return INVALID_AUTHORING_ARGUMENT;
493
+ return parsed;
494
+ }
495
+ function isPlainObject(value) {
496
+ return typeof value === "object" && value !== null && !Array.isArray(value);
497
+ }
498
+ function parsePslObjectLiteral(value) {
499
+ const trimmed = value.trim();
500
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return INVALID_AUTHORING_ARGUMENT;
501
+ let parsed;
502
+ try {
503
+ parsed = JSON.parse(trimmed);
504
+ } catch {
505
+ parsed = parseJsLikeLiteral(trimmed);
506
+ if (parsed === INVALID_AUTHORING_ARGUMENT) return INVALID_AUTHORING_ARGUMENT;
507
+ }
508
+ if (!isPlainObject(parsed)) return INVALID_AUTHORING_ARGUMENT;
509
+ return parsed;
510
+ }
511
+ function parsePslAuthoringArgumentValue(descriptor, rawValue) {
512
+ switch (descriptor.kind) {
513
+ case "string": return unquoteStringLiteral(rawValue);
514
+ case "number": {
515
+ const parsed = Number(unquoteStringLiteral(rawValue));
516
+ return Number.isNaN(parsed) ? INVALID_AUTHORING_ARGUMENT : parsed;
517
+ }
518
+ case "stringArray": return parseStringArrayLiteral(rawValue);
519
+ case "object": return parsePslObjectLiteral(rawValue);
520
+ default: return INVALID_AUTHORING_ARGUMENT;
521
+ }
522
+ }
523
+ function pushInvalidPslHelperArgument(input) {
524
+ input.diagnostics.push({
525
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
526
+ message: `${input.entityLabel} ${input.helperLabel} ${input.message}`,
527
+ sourceId: input.sourceId,
528
+ span: input.span
529
+ });
530
+ }
531
+ function mapPslHelperArgs(input) {
532
+ const mappedArgs = input.descriptors.map(() => void 0);
533
+ const positionalArgs = input.args.filter((arg) => arg.kind === "positional");
534
+ const namedArgs = input.args.filter((arg) => arg.kind === "named");
535
+ if (positionalArgs.length > input.descriptors.length) return pushInvalidPslHelperArgument({
536
+ diagnostics: input.diagnostics,
537
+ sourceId: input.sourceId,
538
+ span: input.span,
539
+ entityLabel: input.entityLabel,
540
+ helperLabel: input.helperLabel,
541
+ message: `accepts at most ${input.descriptors.length} argument(s), received ${positionalArgs.length}.`
542
+ });
543
+ for (const [index, argument] of positionalArgs.entries()) {
544
+ const descriptor = input.descriptors[index];
545
+ if (!descriptor) return pushInvalidPslHelperArgument({
546
+ diagnostics: input.diagnostics,
547
+ sourceId: input.sourceId,
548
+ span: argument.span,
549
+ entityLabel: input.entityLabel,
550
+ helperLabel: input.helperLabel,
551
+ message: `does not define positional argument #${index + 1}.`
552
+ });
553
+ const value = parsePslAuthoringArgumentValue(descriptor, argument.value);
554
+ if (value === INVALID_AUTHORING_ARGUMENT) return pushInvalidPslHelperArgument({
555
+ diagnostics: input.diagnostics,
556
+ sourceId: input.sourceId,
557
+ span: argument.span,
558
+ entityLabel: input.entityLabel,
559
+ helperLabel: input.helperLabel,
560
+ message: `cannot parse argument #${index + 1} for descriptor kind "${descriptor.kind}".`
561
+ });
562
+ mappedArgs[index] = value;
563
+ }
564
+ for (const argument of namedArgs) {
565
+ const descriptorIndex = input.descriptors.findIndex((descriptor$1) => descriptor$1.name === argument.name);
566
+ if (descriptorIndex < 0) return pushInvalidPslHelperArgument({
567
+ diagnostics: input.diagnostics,
568
+ sourceId: input.sourceId,
569
+ span: argument.span,
570
+ entityLabel: input.entityLabel,
571
+ helperLabel: input.helperLabel,
572
+ message: `received unknown named argument "${argument.name}".`
573
+ });
574
+ if (mappedArgs[descriptorIndex] !== void 0) return pushInvalidPslHelperArgument({
575
+ diagnostics: input.diagnostics,
576
+ sourceId: input.sourceId,
577
+ span: argument.span,
578
+ entityLabel: input.entityLabel,
579
+ helperLabel: input.helperLabel,
580
+ message: `received duplicate value for argument "${argument.name}".`
581
+ });
582
+ const descriptor = input.descriptors[descriptorIndex];
583
+ if (!descriptor) return pushInvalidPslHelperArgument({
584
+ diagnostics: input.diagnostics,
585
+ sourceId: input.sourceId,
586
+ span: argument.span,
587
+ entityLabel: input.entityLabel,
588
+ helperLabel: input.helperLabel,
589
+ message: `does not define named argument "${argument.name}".`
590
+ });
591
+ const value = parsePslAuthoringArgumentValue(descriptor, argument.value);
592
+ if (value === INVALID_AUTHORING_ARGUMENT) return pushInvalidPslHelperArgument({
593
+ diagnostics: input.diagnostics,
594
+ sourceId: input.sourceId,
595
+ span: argument.span,
596
+ entityLabel: input.entityLabel,
597
+ helperLabel: input.helperLabel,
598
+ message: `cannot parse named argument "${argument.name}" for descriptor kind "${descriptor.kind}".`
599
+ });
600
+ mappedArgs[descriptorIndex] = value;
601
+ }
602
+ return mappedArgs;
603
+ }
604
+
605
+ //#endregion
606
+ //#region src/psl-column-resolution.ts
607
+ function toNamedTypeFieldDescriptor(typeRef, descriptor) {
608
+ return {
609
+ codecId: descriptor.codecId,
610
+ nativeType: descriptor.nativeType,
611
+ typeRef
612
+ };
613
+ }
614
+ function getAuthoringTypeConstructor(contributions, path) {
615
+ let current = contributions?.type;
616
+ for (const segment of path) {
617
+ if (typeof current !== "object" || current === null || Array.isArray(current)) return;
618
+ current = current[segment];
619
+ }
620
+ return isAuthoringTypeConstructorDescriptor(current) ? current : void 0;
621
+ }
622
+ /**
623
+ * Returns the namespace prefix of `attributeName` if it references an
624
+ * unrecognized extension namespace, otherwise `undefined`. A namespace is
625
+ * considered recognized when it is:
626
+ *
627
+ * - `db` (native-type spec, always allowed),
628
+ * - the active family id (e.g. `sql`),
629
+ * - the active target id (e.g. `postgres`),
630
+ * - present in `composedExtensions`.
631
+ *
632
+ * Family/target namespaces are exempted so that e.g. `@sql.foo` surfaces as
633
+ * PSL_UNSUPPORTED_*_ATTRIBUTE (the attribute isn't defined) rather than
634
+ * PSL_EXTENSION_NAMESPACE_NOT_COMPOSED (the namespace is already composed).
635
+ */
636
+ function checkUncomposedNamespace(attributeName, composedExtensions, context) {
637
+ const dotIndex = attributeName.indexOf(".");
638
+ if (dotIndex <= 0 || dotIndex === attributeName.length - 1) return;
639
+ const namespace = attributeName.slice(0, dotIndex);
640
+ if (namespace === "db" || namespace === context?.familyId || namespace === context?.targetId || composedExtensions.has(namespace)) return;
641
+ return namespace;
642
+ }
643
+ /**
644
+ * Pushes the canonical `PSL_EXTENSION_NAMESPACE_NOT_COMPOSED` diagnostic for a
645
+ * subject (attribute, model attribute, or type constructor) that references an
646
+ * extension namespace which is not composed in the current contract.
647
+ *
648
+ * The `data` payload carries the missing namespace so machine consumers
649
+ * (agents, IDE extensions, CLI auto-fix) don't have to parse the prose.
650
+ */
651
+ function reportUncomposedNamespace(input) {
652
+ input.diagnostics.push({
653
+ code: "PSL_EXTENSION_NAMESPACE_NOT_COMPOSED",
654
+ message: `${input.subjectLabel} uses unrecognized namespace "${input.namespace}". Add extension pack "${input.namespace}" to extensionPacks in prisma-next.config.ts.`,
655
+ sourceId: input.sourceId,
656
+ span: input.span,
657
+ data: {
658
+ namespace: input.namespace,
659
+ suggestedPack: input.namespace
660
+ }
661
+ });
662
+ }
663
+ function instantiatePslTypeConstructor(input) {
664
+ const helperPath = input.call.path.join(".");
665
+ const args = mapPslHelperArgs({
666
+ args: input.call.args,
667
+ descriptors: input.descriptor.args ?? [],
668
+ helperLabel: `constructor "${helperPath}"`,
669
+ span: input.call.span,
670
+ diagnostics: input.diagnostics,
671
+ sourceId: input.sourceId,
672
+ entityLabel: input.entityLabel
673
+ });
674
+ if (!args) return;
675
+ try {
676
+ validateAuthoringHelperArguments(helperPath, input.descriptor.args, args);
677
+ return instantiateAuthoringTypeConstructor(input.descriptor, args);
678
+ } catch (error) {
679
+ const message = error instanceof Error ? error.message : String(error);
680
+ input.diagnostics.push({
681
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
682
+ message: `${input.entityLabel} constructor "${helperPath}" ${message}`,
683
+ sourceId: input.sourceId,
684
+ span: input.call.span
685
+ });
686
+ return;
687
+ }
688
+ }
689
+ function pushUnsupportedTypeConstructorDiagnostic(input) {
690
+ input.diagnostics.push({
691
+ code: input.code,
692
+ message: input.message,
693
+ sourceId: input.sourceId,
694
+ span: input.span
695
+ });
696
+ }
697
+ function resolvePslTypeConstructorDescriptor(input) {
698
+ const descriptor = getAuthoringTypeConstructor(input.authoringContributions, input.call.path);
699
+ if (descriptor) return descriptor;
700
+ const namespace = input.call.path.length > 1 ? input.call.path[0] : void 0;
701
+ if (namespace && namespace !== "db" && namespace !== input.familyId && namespace !== input.targetId && !input.composedExtensions.has(namespace)) {
702
+ reportUncomposedNamespace({
703
+ subjectLabel: `Type constructor "${input.call.path.join(".")}"`,
704
+ namespace,
705
+ sourceId: input.sourceId,
706
+ span: input.call.span,
707
+ diagnostics: input.diagnostics
708
+ });
709
+ return;
710
+ }
711
+ return pushUnsupportedTypeConstructorDiagnostic({
712
+ diagnostics: input.diagnostics,
713
+ sourceId: input.sourceId,
714
+ span: input.call.span,
715
+ code: input.unsupportedCode,
716
+ message: input.unsupportedMessage
717
+ });
718
+ }
719
+ function resolveFieldTypeDescriptor(input) {
720
+ if (input.field.typeConstructor) {
721
+ const helperPath = input.field.typeConstructor.path.join(".");
722
+ const descriptor$1 = resolvePslTypeConstructorDescriptor({
723
+ call: input.field.typeConstructor,
724
+ authoringContributions: input.authoringContributions,
725
+ composedExtensions: input.composedExtensions,
726
+ familyId: input.familyId,
727
+ targetId: input.targetId,
728
+ diagnostics: input.diagnostics,
729
+ sourceId: input.sourceId,
730
+ unsupportedCode: "PSL_UNSUPPORTED_FIELD_TYPE",
731
+ unsupportedMessage: `${input.entityLabel} type constructor "${helperPath}" is not supported in SQL PSL provider v1`
732
+ });
733
+ if (!descriptor$1) return {
734
+ ok: false,
735
+ alreadyReported: true
736
+ };
737
+ const instantiated = instantiatePslTypeConstructor({
738
+ call: input.field.typeConstructor,
739
+ descriptor: descriptor$1,
740
+ diagnostics: input.diagnostics,
741
+ sourceId: input.sourceId,
742
+ entityLabel: input.entityLabel
743
+ });
744
+ if (!instantiated) return {
745
+ ok: false,
746
+ alreadyReported: true
747
+ };
748
+ return {
749
+ ok: true,
750
+ descriptor: instantiated
751
+ };
752
+ }
753
+ const descriptor = resolveColumnDescriptor(input.field, input.enumTypeDescriptors, input.namedTypeDescriptors, input.scalarTypeDescriptors);
754
+ if (!descriptor) return {
755
+ ok: false,
756
+ alreadyReported: false
757
+ };
758
+ return {
759
+ ok: true,
760
+ descriptor
761
+ };
762
+ }
763
+ const NATIVE_TYPE_SPECS = {
764
+ "db.VarChar": {
765
+ args: "optionalLength",
766
+ baseType: "String",
767
+ codecId: "sql/varchar@1",
768
+ nativeType: "character varying"
769
+ },
770
+ "db.Char": {
771
+ args: "optionalLength",
772
+ baseType: "String",
773
+ codecId: "sql/char@1",
774
+ nativeType: "character"
775
+ },
776
+ "db.Uuid": {
777
+ args: "noArgs",
778
+ baseType: "String",
779
+ codecId: null,
780
+ nativeType: "uuid"
781
+ },
782
+ "db.SmallInt": {
783
+ args: "noArgs",
784
+ baseType: "Int",
785
+ codecId: "pg/int2@1",
786
+ nativeType: "int2"
787
+ },
788
+ "db.Real": {
789
+ args: "noArgs",
790
+ baseType: "Float",
791
+ codecId: "pg/float4@1",
792
+ nativeType: "float4"
793
+ },
794
+ "db.Numeric": {
795
+ args: "optionalNumeric",
796
+ baseType: "Decimal",
797
+ codecId: "pg/numeric@1",
798
+ nativeType: "numeric"
799
+ },
800
+ "db.Timestamp": {
801
+ args: "optionalPrecision",
802
+ baseType: "DateTime",
803
+ codecId: "pg/timestamp@1",
804
+ nativeType: "timestamp"
805
+ },
806
+ "db.Timestamptz": {
807
+ args: "optionalPrecision",
808
+ baseType: "DateTime",
809
+ codecId: "pg/timestamptz@1",
810
+ nativeType: "timestamptz"
811
+ },
812
+ "db.Date": {
813
+ args: "noArgs",
814
+ baseType: "DateTime",
815
+ codecId: null,
816
+ nativeType: "date"
817
+ },
818
+ "db.Time": {
819
+ args: "optionalPrecision",
820
+ baseType: "DateTime",
821
+ codecId: "pg/time@1",
822
+ nativeType: "time"
823
+ },
824
+ "db.Timetz": {
825
+ args: "optionalPrecision",
826
+ baseType: "DateTime",
827
+ codecId: "pg/timetz@1",
828
+ nativeType: "timetz"
829
+ },
830
+ "db.Json": {
831
+ args: "noArgs",
832
+ baseType: "Json",
833
+ codecId: "pg/json@1",
834
+ nativeType: "json"
835
+ }
836
+ };
837
+ function resolveDbNativeTypeAttribute(input) {
838
+ const spec = NATIVE_TYPE_SPECS[input.attribute.name];
839
+ if (!spec) {
840
+ input.diagnostics.push({
841
+ code: "PSL_UNSUPPORTED_NAMED_TYPE_ATTRIBUTE",
842
+ message: `${input.entityLabel} uses unsupported attribute "@${input.attribute.name}"`,
843
+ sourceId: input.sourceId,
844
+ span: input.attribute.span
845
+ });
846
+ return;
847
+ }
848
+ if (input.baseType !== spec.baseType) return pushInvalidAttributeArgument({
849
+ diagnostics: input.diagnostics,
850
+ sourceId: input.sourceId,
851
+ span: input.attribute.span,
852
+ message: `${input.entityLabel} uses @${input.attribute.name} on unsupported base type "${input.baseType}". Expected "${spec.baseType}".`
853
+ });
854
+ switch (spec.args) {
855
+ case "noArgs":
856
+ if (getPositionalArguments(input.attribute).length > 0 || input.attribute.args.length > 0) return pushInvalidAttributeArgument({
857
+ diagnostics: input.diagnostics,
858
+ sourceId: input.sourceId,
859
+ span: input.attribute.span,
860
+ message: `${input.entityLabel} @${input.attribute.name} does not accept arguments.`
861
+ });
862
+ return {
863
+ codecId: spec.codecId ?? input.baseDescriptor.codecId,
864
+ nativeType: spec.nativeType
865
+ };
866
+ case "optionalLength": {
867
+ const length = parseOptionalSingleIntegerArgument({
868
+ attribute: input.attribute,
869
+ diagnostics: input.diagnostics,
870
+ sourceId: input.sourceId,
871
+ entityLabel: input.entityLabel,
872
+ minimum: 1,
873
+ valueLabel: "positive integer length"
874
+ });
875
+ if (length === void 0) return;
876
+ return {
877
+ codecId: spec.codecId,
878
+ nativeType: spec.nativeType,
879
+ ...length === null ? {} : { typeParams: { length } }
880
+ };
881
+ }
882
+ case "optionalPrecision": {
883
+ const precision = parseOptionalSingleIntegerArgument({
884
+ attribute: input.attribute,
885
+ diagnostics: input.diagnostics,
886
+ sourceId: input.sourceId,
887
+ entityLabel: input.entityLabel,
888
+ minimum: 0,
889
+ valueLabel: "non-negative integer precision"
890
+ });
891
+ if (precision === void 0) return;
892
+ return {
893
+ codecId: spec.codecId,
894
+ nativeType: spec.nativeType,
895
+ ...precision === null ? {} : { typeParams: { precision } }
896
+ };
897
+ }
898
+ case "optionalNumeric": {
899
+ const numeric = parseOptionalNumericArguments({
900
+ attribute: input.attribute,
901
+ diagnostics: input.diagnostics,
902
+ sourceId: input.sourceId,
903
+ entityLabel: input.entityLabel
904
+ });
905
+ if (numeric === void 0) return;
906
+ return {
907
+ codecId: spec.codecId,
908
+ nativeType: spec.nativeType,
909
+ ...numeric === null ? {} : { typeParams: numeric }
910
+ };
911
+ }
912
+ }
913
+ }
914
+ function parseDefaultLiteralValue(expression) {
915
+ const trimmed = expression.trim();
916
+ if (trimmed === "true" || trimmed === "false") return {
917
+ kind: "literal",
918
+ value: trimmed === "true"
919
+ };
920
+ const numericValue = Number(trimmed);
921
+ if (!Number.isNaN(numericValue) && trimmed.length > 0 && !/^(['"]).*\1$/.test(trimmed)) return {
922
+ kind: "literal",
923
+ value: numericValue
924
+ };
925
+ if (/^(['"]).*\1$/.test(trimmed)) return {
926
+ kind: "literal",
927
+ value: unquoteStringLiteral(trimmed)
928
+ };
929
+ }
930
+ function lowerDefaultForField(input) {
931
+ const positionalEntries = input.defaultAttribute.args.filter((arg) => arg.kind === "positional");
932
+ if (input.defaultAttribute.args.filter((arg) => arg.kind === "named").length > 0 || positionalEntries.length !== 1) {
933
+ input.diagnostics.push({
934
+ code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
935
+ message: `Field "${input.modelName}.${input.fieldName}" requires exactly one positional @default(...) expression.`,
936
+ sourceId: input.sourceId,
937
+ span: input.defaultAttribute.span
938
+ });
939
+ return {};
940
+ }
941
+ const expressionEntry = getPositionalArgumentEntry(input.defaultAttribute);
942
+ if (!expressionEntry) {
943
+ input.diagnostics.push({
944
+ code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
945
+ message: `Field "${input.modelName}.${input.fieldName}" requires a positional @default(...) expression.`,
946
+ sourceId: input.sourceId,
947
+ span: input.defaultAttribute.span
948
+ });
949
+ return {};
950
+ }
951
+ const literalDefault = parseDefaultLiteralValue(expressionEntry.value);
952
+ if (literalDefault) return { defaultValue: literalDefault };
953
+ const defaultFunctionCall = parseDefaultFunctionCall(expressionEntry.value, expressionEntry.span);
954
+ if (!defaultFunctionCall) {
955
+ input.diagnostics.push({
956
+ code: "PSL_INVALID_DEFAULT_VALUE",
957
+ message: `Unsupported default value "${expressionEntry.value}"`,
958
+ sourceId: input.sourceId,
959
+ span: input.defaultAttribute.span
960
+ });
961
+ return {};
962
+ }
963
+ const lowered = lowerDefaultFunctionWithRegistry({
964
+ call: defaultFunctionCall,
965
+ registry: input.defaultFunctionRegistry,
966
+ context: {
967
+ sourceId: input.sourceId,
968
+ modelName: input.modelName,
969
+ fieldName: input.fieldName,
970
+ columnCodecId: input.columnDescriptor.codecId
971
+ }
972
+ });
973
+ if (!lowered.ok) {
974
+ input.diagnostics.push(lowered.diagnostic);
975
+ return {};
976
+ }
977
+ if (lowered.value.kind === "storage") return { defaultValue: lowered.value.defaultValue };
978
+ const generatorDescriptor = input.generatorDescriptorById.get(lowered.value.generated.id);
979
+ if (!generatorDescriptor) {
980
+ input.diagnostics.push({
981
+ code: "PSL_INVALID_DEFAULT_APPLICABILITY",
982
+ message: `Default generator "${lowered.value.generated.id}" is not available in the composed mutation default registry.`,
983
+ sourceId: input.sourceId,
984
+ span: expressionEntry.span
985
+ });
986
+ return {};
987
+ }
988
+ if (!generatorDescriptor.applicableCodecIds.includes(input.columnDescriptor.codecId)) {
989
+ input.diagnostics.push({
990
+ code: "PSL_INVALID_DEFAULT_APPLICABILITY",
991
+ message: `Default generator "${generatorDescriptor.id}" is not applicable to "${input.modelName}.${input.fieldName}" with codecId "${input.columnDescriptor.codecId}".`,
992
+ sourceId: input.sourceId,
993
+ span: expressionEntry.span
994
+ });
995
+ return {};
996
+ }
997
+ return { executionDefault: lowered.value.generated };
998
+ }
999
+ function resolveColumnDescriptor(field, enumTypeDescriptors, namedTypeDescriptors, scalarTypeDescriptors) {
1000
+ if (field.typeRef && namedTypeDescriptors.has(field.typeRef)) return namedTypeDescriptors.get(field.typeRef);
1001
+ if (namedTypeDescriptors.has(field.typeName)) return namedTypeDescriptors.get(field.typeName);
1002
+ if (enumTypeDescriptors.has(field.typeName)) return enumTypeDescriptors.get(field.typeName);
1003
+ return scalarTypeDescriptors.get(field.typeName);
1004
+ }
1005
+
1006
+ //#endregion
1007
+ //#region src/psl-field-resolution.ts
1008
+ const BUILTIN_FIELD_ATTRIBUTE_NAMES = new Set([
1009
+ "id",
1010
+ "unique",
1011
+ "default",
1012
+ "relation",
1013
+ "map"
1014
+ ]);
1015
+ function validateFieldAttributes(input) {
1016
+ for (const attribute of input.field.attributes) {
1017
+ if (BUILTIN_FIELD_ATTRIBUTE_NAMES.has(attribute.name)) continue;
1018
+ const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
1019
+ familyId: input.familyId,
1020
+ targetId: input.targetId
1021
+ });
1022
+ if (uncomposedNamespace) {
1023
+ reportUncomposedNamespace({
1024
+ subjectLabel: `Attribute "@${attribute.name}"`,
1025
+ namespace: uncomposedNamespace,
1026
+ sourceId: input.sourceId,
1027
+ span: attribute.span,
1028
+ diagnostics: input.diagnostics
1029
+ });
1030
+ continue;
1031
+ }
1032
+ input.diagnostics.push({
1033
+ code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
1034
+ message: `Field "${input.model.name}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`,
1035
+ sourceId: input.sourceId,
1036
+ span: attribute.span
1037
+ });
1038
+ }
1039
+ }
1040
+ function extractFieldConstraintNames(input) {
1041
+ const idAttribute = getAttribute(input.field.attributes, "id");
1042
+ const uniqueAttribute = getAttribute(input.field.attributes, "unique");
1043
+ return {
1044
+ idAttribute,
1045
+ uniqueAttribute,
1046
+ idName: parseConstraintMapArgument({
1047
+ attribute: idAttribute,
1048
+ sourceId: input.sourceId,
1049
+ diagnostics: input.diagnostics,
1050
+ entityLabel: `Field "${input.model.name}.${input.field.name}" @id`,
1051
+ span: input.field.span,
1052
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
1053
+ }),
1054
+ uniqueName: parseConstraintMapArgument({
1055
+ attribute: uniqueAttribute,
1056
+ sourceId: input.sourceId,
1057
+ diagnostics: input.diagnostics,
1058
+ entityLabel: `Field "${input.model.name}.${input.field.name}" @unique`,
1059
+ span: input.field.span,
1060
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
1061
+ })
1062
+ };
1063
+ }
1064
+ function collectResolvedFields(input) {
1065
+ const { model, mapping, enumTypeDescriptors, namedTypeDescriptors, modelNames, compositeTypeNames, composedExtensions, authoringContributions, familyId, targetId, defaultFunctionRegistry, generatorDescriptorById, diagnostics, sourceId, scalarTypeDescriptors } = input;
1066
+ const resolvedFields = [];
1067
+ for (const field of model.fields) {
1068
+ if (field.list && modelNames.has(field.typeName)) continue;
1069
+ validateFieldAttributes({
1070
+ model,
1071
+ field,
1072
+ composedExtensions,
1073
+ diagnostics,
1074
+ sourceId,
1075
+ familyId,
1076
+ targetId
1077
+ });
1078
+ if (getAttribute(field.attributes, "relation") && modelNames.has(field.typeName)) continue;
1079
+ const isValueObjectField = compositeTypeNames.has(field.typeName);
1080
+ const isListField = field.list;
1081
+ let descriptor;
1082
+ let scalarCodecId;
1083
+ const resolveInput = {
1084
+ field,
1085
+ enumTypeDescriptors,
1086
+ namedTypeDescriptors,
1087
+ scalarTypeDescriptors,
1088
+ authoringContributions,
1089
+ composedExtensions,
1090
+ familyId,
1091
+ targetId,
1092
+ diagnostics,
1093
+ sourceId,
1094
+ entityLabel: `Field "${model.name}.${field.name}"`
1095
+ };
1096
+ if (isValueObjectField) descriptor = scalarTypeDescriptors.get("Json");
1097
+ else if (isListField) {
1098
+ const resolved = resolveFieldTypeDescriptor(resolveInput);
1099
+ if (!resolved.ok) {
1100
+ if (!resolved.alreadyReported) diagnostics.push({
1101
+ code: "PSL_UNSUPPORTED_FIELD_TYPE",
1102
+ message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
1103
+ sourceId,
1104
+ span: field.span
1105
+ });
1106
+ continue;
1107
+ }
1108
+ scalarCodecId = resolved.descriptor.codecId;
1109
+ descriptor = scalarTypeDescriptors.get("Json");
1110
+ } else {
1111
+ const resolved = resolveFieldTypeDescriptor(resolveInput);
1112
+ if (!resolved.ok) {
1113
+ if (!resolved.alreadyReported) diagnostics.push({
1114
+ code: "PSL_UNSUPPORTED_FIELD_TYPE",
1115
+ message: `Field "${model.name}.${field.name}" type "${field.typeName}" is not supported in SQL PSL provider v1`,
1116
+ sourceId,
1117
+ span: field.span
1118
+ });
1119
+ continue;
1120
+ }
1121
+ descriptor = resolved.descriptor;
1122
+ }
1123
+ if (!descriptor) continue;
1124
+ const defaultAttribute = getAttribute(field.attributes, "default");
1125
+ const loweredDefault = defaultAttribute ? lowerDefaultForField({
1126
+ modelName: model.name,
1127
+ fieldName: field.name,
1128
+ defaultAttribute,
1129
+ columnDescriptor: descriptor,
1130
+ generatorDescriptorById,
1131
+ sourceId,
1132
+ defaultFunctionRegistry,
1133
+ diagnostics
1134
+ }) : {};
1135
+ if (field.optional && loweredDefault.executionDefault) {
1136
+ const generatorDescription = loweredDefault.executionDefault.kind === "generator" ? `"${loweredDefault.executionDefault.id}"` : "for this field";
1137
+ diagnostics.push({
1138
+ code: "PSL_INVALID_DEFAULT_FUNCTION_ARGUMENT",
1139
+ message: `Field "${model.name}.${field.name}" cannot be optional when using execution default ${generatorDescription}. Remove "?" or use a storage default.`,
1140
+ sourceId,
1141
+ span: defaultAttribute?.span ?? field.span
1142
+ });
1143
+ continue;
1144
+ }
1145
+ if (loweredDefault.executionDefault) {
1146
+ const generatedDescriptor = generatorDescriptorById.get(loweredDefault.executionDefault.id)?.resolveGeneratedColumnDescriptor?.({ generated: loweredDefault.executionDefault });
1147
+ if (generatedDescriptor) descriptor = generatedDescriptor;
1148
+ }
1149
+ const mappedColumnName = mapping.fieldColumns.get(field.name) ?? field.name;
1150
+ const { idAttribute, uniqueAttribute, idName, uniqueName } = extractFieldConstraintNames({
1151
+ model,
1152
+ field,
1153
+ sourceId,
1154
+ diagnostics
1155
+ });
1156
+ resolvedFields.push({
1157
+ field,
1158
+ columnName: mappedColumnName,
1159
+ descriptor,
1160
+ ...ifDefined("defaultValue", loweredDefault.defaultValue),
1161
+ ...ifDefined("executionDefault", loweredDefault.executionDefault),
1162
+ isId: Boolean(idAttribute),
1163
+ isUnique: Boolean(uniqueAttribute),
1164
+ ...ifDefined("idName", idName),
1165
+ ...ifDefined("uniqueName", uniqueName),
1166
+ ...ifDefined("many", isListField ? true : void 0),
1167
+ ...ifDefined("valueObjectTypeName", isValueObjectField ? field.typeName : void 0),
1168
+ ...ifDefined("scalarCodecId", scalarCodecId)
1169
+ });
1170
+ }
1171
+ return resolvedFields;
1172
+ }
1173
+ function buildModelMappings(models, diagnostics, sourceId) {
1174
+ const result = /* @__PURE__ */ new Map();
1175
+ for (const model of models) {
1176
+ const tableName = parseMapName({
1177
+ attribute: getAttribute(model.attributes, "map"),
1178
+ defaultValue: lowerFirst(model.name),
1179
+ sourceId,
1180
+ diagnostics,
1181
+ entityLabel: `Model "${model.name}"`,
1182
+ span: model.span
1183
+ });
1184
+ const fieldColumns = /* @__PURE__ */ new Map();
1185
+ for (const field of model.fields) {
1186
+ const columnName = parseMapName({
1187
+ attribute: getAttribute(field.attributes, "map"),
1188
+ defaultValue: field.name,
1189
+ sourceId,
1190
+ diagnostics,
1191
+ entityLabel: `Field "${model.name}.${field.name}"`,
1192
+ span: field.span
1193
+ });
1194
+ fieldColumns.set(field.name, columnName);
1195
+ }
1196
+ result.set(model.name, {
1197
+ model,
1198
+ tableName,
1199
+ fieldColumns
1200
+ });
1201
+ }
1202
+ return result;
1203
+ }
1204
+
1205
+ //#endregion
1206
+ //#region src/psl-relation-resolution.ts
1207
+ const REFERENTIAL_ACTION_MAP = {
1208
+ NoAction: "noAction",
1209
+ Restrict: "restrict",
1210
+ Cascade: "cascade",
1211
+ SetNull: "setNull",
1212
+ SetDefault: "setDefault",
1213
+ noAction: "noAction",
1214
+ restrict: "restrict",
1215
+ cascade: "cascade",
1216
+ setNull: "setNull",
1217
+ setDefault: "setDefault"
1218
+ };
1219
+ function fkRelationPairKey(declaringModelName, targetModelName) {
1220
+ return `${declaringModelName}::${targetModelName}`;
1221
+ }
1222
+ function normalizeReferentialAction(input) {
1223
+ const normalized = REFERENTIAL_ACTION_MAP[input.actionToken];
1224
+ if (normalized) return normalized;
1225
+ input.diagnostics.push({
1226
+ code: "PSL_UNSUPPORTED_REFERENTIAL_ACTION",
1227
+ message: `Relation field "${input.modelName}.${input.fieldName}" has unsupported ${input.actionName} action "${input.actionToken}"`,
1228
+ sourceId: input.sourceId,
1229
+ span: input.span
1230
+ });
1231
+ }
1232
+ function parseRelationAttribute(input) {
1233
+ if (input.attribute.args.filter((arg) => arg.kind === "positional").length > 1) {
1234
+ input.diagnostics.push({
1235
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1236
+ message: `Relation field "${input.modelName}.${input.fieldName}" has too many positional arguments`,
1237
+ sourceId: input.sourceId,
1238
+ span: input.attribute.span
1239
+ });
1240
+ return;
1241
+ }
1242
+ let relationNameFromPositional;
1243
+ const positionalNameEntry = getPositionalArgumentEntry(input.attribute);
1244
+ if (positionalNameEntry) {
1245
+ const parsedName = parseQuotedStringLiteral(positionalNameEntry.value);
1246
+ if (!parsedName) {
1247
+ input.diagnostics.push({
1248
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1249
+ message: `Relation field "${input.modelName}.${input.fieldName}" positional relation name must be a quoted string literal`,
1250
+ sourceId: input.sourceId,
1251
+ span: positionalNameEntry.span
1252
+ });
1253
+ return;
1254
+ }
1255
+ relationNameFromPositional = parsedName;
1256
+ }
1257
+ for (const arg of input.attribute.args) {
1258
+ if (arg.kind === "positional") continue;
1259
+ if (arg.name !== "name" && arg.name !== "fields" && arg.name !== "references" && arg.name !== "map" && arg.name !== "onDelete" && arg.name !== "onUpdate") {
1260
+ input.diagnostics.push({
1261
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1262
+ message: `Relation field "${input.modelName}.${input.fieldName}" has unsupported argument "${arg.name}"`,
1263
+ sourceId: input.sourceId,
1264
+ span: arg.span
1265
+ });
1266
+ return;
1267
+ }
1268
+ }
1269
+ const namedRelationNameRaw = getNamedArgument(input.attribute, "name");
1270
+ const namedRelationName = namedRelationNameRaw ? parseQuotedStringLiteral(namedRelationNameRaw) : void 0;
1271
+ if (namedRelationNameRaw && !namedRelationName) {
1272
+ input.diagnostics.push({
1273
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1274
+ message: `Relation field "${input.modelName}.${input.fieldName}" named relation name must be a quoted string literal`,
1275
+ sourceId: input.sourceId,
1276
+ span: input.attribute.span
1277
+ });
1278
+ return;
1279
+ }
1280
+ if (relationNameFromPositional && namedRelationName && relationNameFromPositional !== namedRelationName) {
1281
+ input.diagnostics.push({
1282
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1283
+ message: `Relation field "${input.modelName}.${input.fieldName}" has conflicting positional and named relation names`,
1284
+ sourceId: input.sourceId,
1285
+ span: input.attribute.span
1286
+ });
1287
+ return;
1288
+ }
1289
+ const relationName = namedRelationName ?? relationNameFromPositional;
1290
+ const constraintNameRaw = getNamedArgument(input.attribute, "map");
1291
+ const constraintName = constraintNameRaw ? parseQuotedStringLiteral(constraintNameRaw) : void 0;
1292
+ if (constraintNameRaw && !constraintName) {
1293
+ input.diagnostics.push({
1294
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1295
+ message: `Relation field "${input.modelName}.${input.fieldName}" map argument must be a quoted string literal`,
1296
+ sourceId: input.sourceId,
1297
+ span: input.attribute.span
1298
+ });
1299
+ return;
1300
+ }
1301
+ const fieldsRaw = getNamedArgument(input.attribute, "fields");
1302
+ const referencesRaw = getNamedArgument(input.attribute, "references");
1303
+ if (fieldsRaw && !referencesRaw || !fieldsRaw && referencesRaw) {
1304
+ input.diagnostics.push({
1305
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1306
+ message: `Relation field "${input.modelName}.${input.fieldName}" requires fields and references arguments`,
1307
+ sourceId: input.sourceId,
1308
+ span: input.attribute.span
1309
+ });
1310
+ return;
1311
+ }
1312
+ let fields;
1313
+ let references;
1314
+ if (fieldsRaw && referencesRaw) {
1315
+ const parsedFields = parseFieldList(fieldsRaw);
1316
+ const parsedReferences = parseFieldList(referencesRaw);
1317
+ if (!parsedFields || !parsedReferences || parsedFields.length === 0 || parsedReferences.length === 0) {
1318
+ input.diagnostics.push({
1319
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1320
+ message: `Relation field "${input.modelName}.${input.fieldName}" requires bracketed fields and references lists`,
1321
+ sourceId: input.sourceId,
1322
+ span: input.attribute.span
1323
+ });
1324
+ return;
1325
+ }
1326
+ fields = parsedFields;
1327
+ references = parsedReferences;
1328
+ }
1329
+ const onDeleteArgument = getNamedArgument(input.attribute, "onDelete");
1330
+ const onUpdateArgument = getNamedArgument(input.attribute, "onUpdate");
1331
+ return {
1332
+ ...ifDefined("relationName", relationName),
1333
+ ...ifDefined("fields", fields),
1334
+ ...ifDefined("references", references),
1335
+ ...ifDefined("constraintName", constraintName),
1336
+ ...ifDefined("onDelete", onDeleteArgument ? unquoteStringLiteral(onDeleteArgument) : void 0),
1337
+ ...ifDefined("onUpdate", onUpdateArgument ? unquoteStringLiteral(onUpdateArgument) : void 0)
1338
+ };
1339
+ }
1340
+ function indexFkRelations(input) {
1341
+ const modelRelations = /* @__PURE__ */ new Map();
1342
+ const fkRelationsByPair = /* @__PURE__ */ new Map();
1343
+ for (const relation of input.fkRelationMetadata) {
1344
+ const existing = modelRelations.get(relation.declaringModelName);
1345
+ const current = existing ?? [];
1346
+ if (!existing) modelRelations.set(relation.declaringModelName, current);
1347
+ current.push({
1348
+ fieldName: relation.declaringFieldName,
1349
+ toModel: relation.targetModelName,
1350
+ toTable: relation.targetTableName,
1351
+ cardinality: "N:1",
1352
+ on: {
1353
+ parentTable: relation.declaringTableName,
1354
+ parentColumns: relation.localColumns,
1355
+ childTable: relation.targetTableName,
1356
+ childColumns: relation.referencedColumns
1357
+ }
1358
+ });
1359
+ const pairKey = fkRelationPairKey(relation.declaringModelName, relation.targetModelName);
1360
+ const pairRelations = fkRelationsByPair.get(pairKey);
1361
+ if (!pairRelations) {
1362
+ fkRelationsByPair.set(pairKey, [relation]);
1363
+ continue;
1364
+ }
1365
+ pairRelations.push(relation);
1366
+ }
1367
+ return {
1368
+ modelRelations,
1369
+ fkRelationsByPair
1370
+ };
1371
+ }
1372
+ function applyBackrelationCandidates(input) {
1373
+ for (const candidate of input.backrelationCandidates) {
1374
+ const pairKey = fkRelationPairKey(candidate.targetModelName, candidate.modelName);
1375
+ const pairMatches = input.fkRelationsByPair.get(pairKey) ?? [];
1376
+ const matches = candidate.relationName ? pairMatches.filter((relation) => relation.relationName === candidate.relationName) : [...pairMatches];
1377
+ if (matches.length === 0) {
1378
+ input.diagnostics.push({
1379
+ code: "PSL_ORPHANED_BACKRELATION_LIST",
1380
+ message: `Backrelation list field "${candidate.modelName}.${candidate.field.name}" has no matching FK-side relation on model "${candidate.targetModelName}". Add @relation(fields: [...], references: [...]) on the FK-side relation or use an explicit join model for many-to-many.`,
1381
+ sourceId: input.sourceId,
1382
+ span: candidate.field.span
1383
+ });
1384
+ continue;
1385
+ }
1386
+ if (matches.length > 1) {
1387
+ input.diagnostics.push({
1388
+ code: "PSL_AMBIGUOUS_BACKRELATION_LIST",
1389
+ message: `Backrelation list field "${candidate.modelName}.${candidate.field.name}" matches multiple FK-side relations on model "${candidate.targetModelName}". Add @relation(name: "...") (or @relation("...")) to both sides to disambiguate.`,
1390
+ sourceId: input.sourceId,
1391
+ span: candidate.field.span
1392
+ });
1393
+ continue;
1394
+ }
1395
+ invariant(matches.length === 1, "Backrelation matching requires exactly one match");
1396
+ const matched = matches[0];
1397
+ assertDefined(matched, "Backrelation matching requires a defined relation match");
1398
+ const existing = input.modelRelations.get(candidate.modelName);
1399
+ const current = existing ?? [];
1400
+ if (!existing) input.modelRelations.set(candidate.modelName, current);
1401
+ current.push({
1402
+ fieldName: candidate.field.name,
1403
+ toModel: matched.declaringModelName,
1404
+ toTable: matched.declaringTableName,
1405
+ cardinality: "1:N",
1406
+ on: {
1407
+ parentTable: candidate.tableName,
1408
+ parentColumns: matched.referencedColumns,
1409
+ childTable: matched.declaringTableName,
1410
+ childColumns: matched.localColumns
1411
+ }
1412
+ });
1413
+ }
1414
+ }
1415
+ function validateNavigationListFieldAttributes(input) {
1416
+ let valid = true;
1417
+ for (const attribute of input.field.attributes) {
1418
+ if (attribute.name === "relation") continue;
1419
+ const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
1420
+ familyId: input.familyId,
1421
+ targetId: input.targetId
1422
+ });
1423
+ if (uncomposedNamespace) {
1424
+ reportUncomposedNamespace({
1425
+ subjectLabel: `Attribute "@${attribute.name}"`,
1426
+ namespace: uncomposedNamespace,
1427
+ sourceId: input.sourceId,
1428
+ span: attribute.span,
1429
+ diagnostics: input.diagnostics
1430
+ });
1431
+ valid = false;
1432
+ continue;
1433
+ }
1434
+ input.diagnostics.push({
1435
+ code: "PSL_UNSUPPORTED_FIELD_ATTRIBUTE",
1436
+ message: `Field "${input.modelName}.${input.field.name}" uses unsupported attribute "@${attribute.name}"`,
1437
+ sourceId: input.sourceId,
1438
+ span: attribute.span
1439
+ });
1440
+ valid = false;
1441
+ }
1442
+ return valid;
1443
+ }
1444
+
1445
+ //#endregion
1446
+ //#region src/interpreter.ts
1447
+ function buildComposedExtensionPackRefs(target, extensionIds, extensionPackRefs = []) {
1448
+ if (extensionIds.length === 0) return;
1449
+ const extensionPackRefById = new Map(extensionPackRefs.map((packRef) => [packRef.id, packRef]));
1450
+ return Object.fromEntries(extensionIds.map((extensionId) => [extensionId, extensionPackRefById.get(extensionId) ?? {
1451
+ kind: "extension",
1452
+ id: extensionId,
1453
+ familyId: target.familyId,
1454
+ targetId: target.targetId,
1455
+ version: "0.0.1"
1456
+ }]));
1457
+ }
1458
+ function diagnosticDedupKey(diagnostic) {
1459
+ const span = diagnostic.span;
1460
+ const spanKey = span ? `${span.start.offset}:${span.end.offset}:${span.start.line}:${span.end.line}` : "";
1461
+ return `${diagnostic.code}\u0000${diagnostic.sourceId}\u0000${spanKey}\u0000${diagnostic.message}`;
1462
+ }
1463
+ function dedupeDiagnostics(diagnostics) {
1464
+ const seen = /* @__PURE__ */ new Map();
1465
+ for (const diagnostic of diagnostics) {
1466
+ const key = diagnosticDedupKey(diagnostic);
1467
+ if (!seen.has(key)) seen.set(key, diagnostic);
1468
+ }
1469
+ return [...seen.values()];
1470
+ }
1471
+ function compareStrings(left, right) {
1472
+ if (left < right) return -1;
1473
+ if (left > right) return 1;
1474
+ return 0;
1475
+ }
1476
+ function mapParserDiagnostics(document) {
1477
+ return document.diagnostics.map((diagnostic) => ({
1478
+ code: diagnostic.code,
1479
+ message: diagnostic.message,
1480
+ sourceId: diagnostic.sourceId,
1481
+ span: diagnostic.span
1482
+ }));
1483
+ }
1484
+ function processEnumDeclarations(input) {
1485
+ const storageTypes = {};
1486
+ const enumTypeDescriptors = /* @__PURE__ */ new Map();
1487
+ for (const enumDeclaration of input.enums) {
1488
+ const nativeType = parseMapName({
1489
+ attribute: getAttribute(enumDeclaration.attributes, "map"),
1490
+ defaultValue: enumDeclaration.name,
1491
+ sourceId: input.sourceId,
1492
+ diagnostics: input.diagnostics,
1493
+ entityLabel: `Enum "${enumDeclaration.name}"`,
1494
+ span: enumDeclaration.span
1495
+ });
1496
+ const enumStorageType = input.enumTypeConstructor ? instantiateAuthoringTypeConstructor(input.enumTypeConstructor, [nativeType, enumDeclaration.values.map((value) => value.name)]) : {
1497
+ codecId: "pg/enum@1",
1498
+ nativeType,
1499
+ typeParams: { values: enumDeclaration.values.map((value) => value.name) }
1500
+ };
1501
+ const descriptor = {
1502
+ codecId: enumStorageType.codecId,
1503
+ nativeType: enumStorageType.nativeType,
1504
+ typeRef: enumDeclaration.name
1505
+ };
1506
+ enumTypeDescriptors.set(enumDeclaration.name, descriptor);
1507
+ storageTypes[enumDeclaration.name] = {
1508
+ codecId: enumStorageType.codecId,
1509
+ nativeType: enumStorageType.nativeType,
1510
+ typeParams: enumStorageType.typeParams ?? { values: enumDeclaration.values.map((value) => value.name) }
1511
+ };
1512
+ }
1513
+ return {
1514
+ storageTypes,
1515
+ enumTypeDescriptors
1516
+ };
1517
+ }
1518
+ function validateNamedTypeAttributes(input) {
1519
+ const [dbNativeTypeAttribute, ...extraDbNativeTypeAttributes] = input.allowDbNativeType ? input.declaration.attributes.filter((attribute) => attribute.name.startsWith("db.")) : [];
1520
+ let hasUnsupportedNamedTypeAttribute = false;
1521
+ for (const extra of extraDbNativeTypeAttributes) {
1522
+ input.diagnostics.push({
1523
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
1524
+ message: `Named type "${input.declaration.name}" can declare at most one @db.* attribute`,
1525
+ sourceId: input.sourceId,
1526
+ span: extra.span
1527
+ });
1528
+ hasUnsupportedNamedTypeAttribute = true;
1529
+ }
1530
+ for (const attribute of input.declaration.attributes) {
1531
+ if (input.allowDbNativeType && attribute.name.startsWith("db.")) continue;
1532
+ const uncomposedNamespace = checkUncomposedNamespace(attribute.name, input.composedExtensions, {
1533
+ familyId: input.familyId,
1534
+ targetId: input.targetId
1535
+ });
1536
+ if (uncomposedNamespace) {
1537
+ reportUncomposedNamespace({
1538
+ subjectLabel: `Attribute "@${attribute.name}"`,
1539
+ namespace: uncomposedNamespace,
1540
+ sourceId: input.sourceId,
1541
+ span: attribute.span,
1542
+ diagnostics: input.diagnostics
1543
+ });
1544
+ hasUnsupportedNamedTypeAttribute = true;
1545
+ continue;
1546
+ }
1547
+ input.diagnostics.push({
1548
+ code: "PSL_UNSUPPORTED_NAMED_TYPE_ATTRIBUTE",
1549
+ message: `Named type "${input.declaration.name}" uses unsupported attribute "${attribute.name}"`,
1550
+ sourceId: input.sourceId,
1551
+ span: attribute.span
1552
+ });
1553
+ hasUnsupportedNamedTypeAttribute = true;
1554
+ }
1555
+ return {
1556
+ dbNativeTypeAttribute,
1557
+ hasUnsupportedNamedTypeAttribute
1558
+ };
1559
+ }
1560
+ function resolveNamedTypeDeclarations(input) {
1561
+ const storageTypes = {};
1562
+ const namedTypeDescriptors = /* @__PURE__ */ new Map();
1563
+ for (const declaration of input.declarations) {
1564
+ if (declaration.typeConstructor) {
1565
+ const { hasUnsupportedNamedTypeAttribute: hasUnsupportedNamedTypeAttribute$1 } = validateNamedTypeAttributes({
1566
+ declaration,
1567
+ sourceId: input.sourceId,
1568
+ diagnostics: input.diagnostics,
1569
+ composedExtensions: input.composedExtensions,
1570
+ allowDbNativeType: false,
1571
+ familyId: input.familyId,
1572
+ targetId: input.targetId
1573
+ });
1574
+ if (hasUnsupportedNamedTypeAttribute$1) continue;
1575
+ const helperPath = declaration.typeConstructor.path.join(".");
1576
+ const typeConstructor = resolvePslTypeConstructorDescriptor({
1577
+ call: declaration.typeConstructor,
1578
+ authoringContributions: input.authoringContributions,
1579
+ composedExtensions: input.composedExtensions,
1580
+ familyId: input.familyId,
1581
+ targetId: input.targetId,
1582
+ diagnostics: input.diagnostics,
1583
+ sourceId: input.sourceId,
1584
+ unsupportedCode: "PSL_UNSUPPORTED_NAMED_TYPE_CONSTRUCTOR",
1585
+ unsupportedMessage: `Named type "${declaration.name}" references unsupported constructor "${helperPath}"`
1586
+ });
1587
+ if (!typeConstructor) continue;
1588
+ const storageType = instantiatePslTypeConstructor({
1589
+ call: declaration.typeConstructor,
1590
+ descriptor: typeConstructor,
1591
+ diagnostics: input.diagnostics,
1592
+ sourceId: input.sourceId,
1593
+ entityLabel: `Named type "${declaration.name}"`
1594
+ });
1595
+ if (!storageType) continue;
1596
+ namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, storageType));
1597
+ storageTypes[declaration.name] = {
1598
+ codecId: storageType.codecId,
1599
+ nativeType: storageType.nativeType,
1600
+ typeParams: storageType.typeParams ?? {}
1601
+ };
1602
+ continue;
1603
+ }
1604
+ if (declaration.baseType === void 0) {
1605
+ input.diagnostics.push({
1606
+ code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
1607
+ message: `Named type "${declaration.name}" must declare a base type or constructor`,
1608
+ sourceId: input.sourceId,
1609
+ span: declaration.span
1610
+ });
1611
+ continue;
1612
+ }
1613
+ const { baseType } = declaration;
1614
+ const baseDescriptor = input.enumTypeDescriptors.get(baseType) ?? input.scalarTypeDescriptors.get(baseType);
1615
+ if (!baseDescriptor) {
1616
+ input.diagnostics.push({
1617
+ code: "PSL_UNSUPPORTED_NAMED_TYPE_BASE",
1618
+ message: `Named type "${declaration.name}" references unsupported base type "${baseType}"`,
1619
+ sourceId: input.sourceId,
1620
+ span: declaration.span
1621
+ });
1622
+ continue;
1623
+ }
1624
+ const { dbNativeTypeAttribute, hasUnsupportedNamedTypeAttribute } = validateNamedTypeAttributes({
1625
+ declaration,
1626
+ sourceId: input.sourceId,
1627
+ diagnostics: input.diagnostics,
1628
+ composedExtensions: input.composedExtensions,
1629
+ allowDbNativeType: true,
1630
+ familyId: input.familyId,
1631
+ targetId: input.targetId
1632
+ });
1633
+ if (hasUnsupportedNamedTypeAttribute) continue;
1634
+ if (dbNativeTypeAttribute) {
1635
+ const descriptor$1 = resolveDbNativeTypeAttribute({
1636
+ attribute: dbNativeTypeAttribute,
1637
+ baseType,
1638
+ baseDescriptor,
1639
+ diagnostics: input.diagnostics,
1640
+ sourceId: input.sourceId,
1641
+ entityLabel: `Named type "${declaration.name}"`
1642
+ });
1643
+ if (!descriptor$1) continue;
1644
+ namedTypeDescriptors.set(declaration.name, toNamedTypeFieldDescriptor(declaration.name, descriptor$1));
1645
+ storageTypes[declaration.name] = {
1646
+ codecId: descriptor$1.codecId,
1647
+ nativeType: descriptor$1.nativeType,
1648
+ typeParams: descriptor$1.typeParams ?? {}
1649
+ };
1650
+ continue;
1651
+ }
1652
+ const descriptor = toNamedTypeFieldDescriptor(declaration.name, baseDescriptor);
1653
+ namedTypeDescriptors.set(declaration.name, descriptor);
1654
+ storageTypes[declaration.name] = {
1655
+ codecId: baseDescriptor.codecId,
1656
+ nativeType: baseDescriptor.nativeType,
1657
+ typeParams: {}
1658
+ };
1659
+ }
1660
+ return {
1661
+ storageTypes,
1662
+ namedTypeDescriptors
1663
+ };
1664
+ }
1665
+ function buildModelNodeFromPsl(input) {
1666
+ const { model, mapping, sourceId, diagnostics } = input;
1667
+ const tableName = mapping.tableName;
1668
+ const resolvedFields = collectResolvedFields({
1669
+ model,
1670
+ mapping,
1671
+ enumTypeDescriptors: input.enumTypeDescriptors,
1672
+ namedTypeDescriptors: input.namedTypeDescriptors,
1673
+ modelNames: input.modelNames,
1674
+ compositeTypeNames: input.compositeTypeNames,
1675
+ composedExtensions: input.composedExtensions,
1676
+ authoringContributions: input.authoringContributions,
1677
+ familyId: input.familyId,
1678
+ targetId: input.targetId,
1679
+ defaultFunctionRegistry: input.defaultFunctionRegistry,
1680
+ generatorDescriptorById: input.generatorDescriptorById,
1681
+ diagnostics,
1682
+ sourceId,
1683
+ scalarTypeDescriptors: input.scalarTypeDescriptors
1684
+ });
1685
+ const primaryKeyFields = resolvedFields.filter((field) => field.isId);
1686
+ const primaryKeyColumns = primaryKeyFields.map((field) => field.columnName);
1687
+ const primaryKeyName = primaryKeyFields.length === 1 ? primaryKeyFields[0]?.idName : void 0;
1688
+ const isVariantModel = model.attributes.some((attr) => attr.name === "base");
1689
+ if (primaryKeyColumns.length === 0 && !isVariantModel) diagnostics.push({
1690
+ code: "PSL_MISSING_PRIMARY_KEY",
1691
+ message: `Model "${model.name}" must declare at least one @id field for SQL provider`,
1692
+ sourceId,
1693
+ span: model.span
1694
+ });
1695
+ const resultBackrelationCandidates = [];
1696
+ for (const field of model.fields) {
1697
+ if (!field.list || !input.modelNames.has(field.typeName)) continue;
1698
+ const attributesValid = validateNavigationListFieldAttributes({
1699
+ modelName: model.name,
1700
+ field,
1701
+ sourceId,
1702
+ composedExtensions: input.composedExtensions,
1703
+ diagnostics,
1704
+ familyId: input.familyId,
1705
+ targetId: input.targetId
1706
+ });
1707
+ const relationAttribute = getAttribute(field.attributes, "relation");
1708
+ let relationName;
1709
+ if (relationAttribute) {
1710
+ const parsedRelation = parseRelationAttribute({
1711
+ attribute: relationAttribute,
1712
+ modelName: model.name,
1713
+ fieldName: field.name,
1714
+ sourceId,
1715
+ diagnostics
1716
+ });
1717
+ if (!parsedRelation) continue;
1718
+ if (parsedRelation.fields || parsedRelation.references) {
1719
+ diagnostics.push({
1720
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1721
+ message: `Backrelation list field "${model.name}.${field.name}" cannot declare fields/references; define them on the FK-side relation field`,
1722
+ sourceId,
1723
+ span: relationAttribute.span
1724
+ });
1725
+ continue;
1726
+ }
1727
+ if (parsedRelation.onDelete || parsedRelation.onUpdate) {
1728
+ diagnostics.push({
1729
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1730
+ message: `Backrelation list field "${model.name}.${field.name}" cannot declare onDelete/onUpdate; define referential actions on the FK-side relation field`,
1731
+ sourceId,
1732
+ span: relationAttribute.span
1733
+ });
1734
+ continue;
1735
+ }
1736
+ relationName = parsedRelation.relationName;
1737
+ }
1738
+ if (!attributesValid) continue;
1739
+ resultBackrelationCandidates.push({
1740
+ modelName: model.name,
1741
+ tableName,
1742
+ field,
1743
+ targetModelName: field.typeName,
1744
+ ...ifDefined("relationName", relationName)
1745
+ });
1746
+ }
1747
+ const relationAttributes = model.fields.map((field) => ({
1748
+ field,
1749
+ relation: getAttribute(field.attributes, "relation")
1750
+ })).filter((entry) => Boolean(entry.relation));
1751
+ const uniqueConstraints = resolvedFields.filter((field) => field.isUnique).map((field) => ({
1752
+ columns: [field.columnName],
1753
+ ...ifDefined("name", field.uniqueName)
1754
+ }));
1755
+ const indexNodes = [];
1756
+ const foreignKeyNodes = [];
1757
+ for (const modelAttribute of model.attributes) {
1758
+ if (modelAttribute.name === "map") continue;
1759
+ if (modelAttribute.name === "discriminator" || modelAttribute.name === "base") continue;
1760
+ if (modelAttribute.name === "unique" || modelAttribute.name === "index") {
1761
+ const fieldNames = parseAttributeFieldList({
1762
+ attribute: modelAttribute,
1763
+ sourceId,
1764
+ diagnostics,
1765
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
1766
+ messagePrefix: `Model "${model.name}" @@${modelAttribute.name}`
1767
+ });
1768
+ if (!fieldNames) continue;
1769
+ const columnNames = mapFieldNamesToColumns({
1770
+ modelName: model.name,
1771
+ fieldNames,
1772
+ mapping,
1773
+ sourceId,
1774
+ diagnostics,
1775
+ span: modelAttribute.span,
1776
+ contextLabel: `Model "${model.name}" @@${modelAttribute.name}`
1777
+ });
1778
+ if (!columnNames) continue;
1779
+ const constraintName = parseConstraintMapArgument({
1780
+ attribute: modelAttribute,
1781
+ sourceId,
1782
+ diagnostics,
1783
+ entityLabel: `Model "${model.name}" @@${modelAttribute.name}`,
1784
+ span: modelAttribute.span,
1785
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT"
1786
+ });
1787
+ if (modelAttribute.name === "unique") uniqueConstraints.push({
1788
+ columns: columnNames,
1789
+ ...ifDefined("name", constraintName)
1790
+ });
1791
+ else indexNodes.push({
1792
+ columns: columnNames,
1793
+ ...ifDefined("name", constraintName)
1794
+ });
1795
+ continue;
1796
+ }
1797
+ const uncomposedNamespace = checkUncomposedNamespace(modelAttribute.name, input.composedExtensions, {
1798
+ familyId: input.familyId,
1799
+ targetId: input.targetId
1800
+ });
1801
+ if (uncomposedNamespace) {
1802
+ reportUncomposedNamespace({
1803
+ subjectLabel: `Attribute "@@${modelAttribute.name}"`,
1804
+ namespace: uncomposedNamespace,
1805
+ sourceId,
1806
+ span: modelAttribute.span,
1807
+ diagnostics
1808
+ });
1809
+ continue;
1810
+ }
1811
+ diagnostics.push({
1812
+ code: "PSL_UNSUPPORTED_MODEL_ATTRIBUTE",
1813
+ message: `Model "${model.name}" uses unsupported attribute "@@${modelAttribute.name}"`,
1814
+ sourceId,
1815
+ span: modelAttribute.span
1816
+ });
1817
+ }
1818
+ const resultFkRelationMetadata = [];
1819
+ for (const relationAttribute of relationAttributes) {
1820
+ if (relationAttribute.field.list) continue;
1821
+ if (!input.modelNames.has(relationAttribute.field.typeName)) {
1822
+ diagnostics.push({
1823
+ code: "PSL_INVALID_RELATION_TARGET",
1824
+ message: `Relation field "${model.name}.${relationAttribute.field.name}" references unknown model "${relationAttribute.field.typeName}"`,
1825
+ sourceId,
1826
+ span: relationAttribute.field.span
1827
+ });
1828
+ continue;
1829
+ }
1830
+ const parsedRelation = parseRelationAttribute({
1831
+ attribute: relationAttribute.relation,
1832
+ modelName: model.name,
1833
+ fieldName: relationAttribute.field.name,
1834
+ sourceId,
1835
+ diagnostics
1836
+ });
1837
+ if (!parsedRelation) continue;
1838
+ if (!parsedRelation.fields || !parsedRelation.references) {
1839
+ diagnostics.push({
1840
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1841
+ message: `Relation field "${model.name}.${relationAttribute.field.name}" requires fields and references arguments`,
1842
+ sourceId,
1843
+ span: relationAttribute.relation.span
1844
+ });
1845
+ continue;
1846
+ }
1847
+ const targetMapping = input.modelMappings.get(relationAttribute.field.typeName);
1848
+ if (!targetMapping) {
1849
+ diagnostics.push({
1850
+ code: "PSL_INVALID_RELATION_TARGET",
1851
+ message: `Relation field "${model.name}.${relationAttribute.field.name}" references unknown model "${relationAttribute.field.typeName}"`,
1852
+ sourceId,
1853
+ span: relationAttribute.field.span
1854
+ });
1855
+ continue;
1856
+ }
1857
+ const localColumns = mapFieldNamesToColumns({
1858
+ modelName: model.name,
1859
+ fieldNames: parsedRelation.fields,
1860
+ mapping,
1861
+ sourceId,
1862
+ diagnostics,
1863
+ span: relationAttribute.relation.span,
1864
+ contextLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
1865
+ });
1866
+ if (!localColumns) continue;
1867
+ const referencedColumns = mapFieldNamesToColumns({
1868
+ modelName: targetMapping.model.name,
1869
+ fieldNames: parsedRelation.references,
1870
+ mapping: targetMapping,
1871
+ sourceId,
1872
+ diagnostics,
1873
+ span: relationAttribute.relation.span,
1874
+ contextLabel: `Relation field "${model.name}.${relationAttribute.field.name}"`
1875
+ });
1876
+ if (!referencedColumns) continue;
1877
+ if (localColumns.length !== referencedColumns.length) {
1878
+ diagnostics.push({
1879
+ code: "PSL_INVALID_RELATION_ATTRIBUTE",
1880
+ message: `Relation field "${model.name}.${relationAttribute.field.name}" must provide the same number of fields and references`,
1881
+ sourceId,
1882
+ span: relationAttribute.relation.span
1883
+ });
1884
+ continue;
1885
+ }
1886
+ const onDelete = parsedRelation.onDelete ? normalizeReferentialAction({
1887
+ modelName: model.name,
1888
+ fieldName: relationAttribute.field.name,
1889
+ actionName: "onDelete",
1890
+ actionToken: parsedRelation.onDelete,
1891
+ sourceId,
1892
+ span: relationAttribute.field.span,
1893
+ diagnostics
1894
+ }) : void 0;
1895
+ const onUpdate = parsedRelation.onUpdate ? normalizeReferentialAction({
1896
+ modelName: model.name,
1897
+ fieldName: relationAttribute.field.name,
1898
+ actionName: "onUpdate",
1899
+ actionToken: parsedRelation.onUpdate,
1900
+ sourceId,
1901
+ span: relationAttribute.field.span,
1902
+ diagnostics
1903
+ }) : void 0;
1904
+ foreignKeyNodes.push({
1905
+ columns: localColumns,
1906
+ references: {
1907
+ model: targetMapping.model.name,
1908
+ table: targetMapping.tableName,
1909
+ columns: referencedColumns
1910
+ },
1911
+ ...ifDefined("name", parsedRelation.constraintName),
1912
+ ...ifDefined("onDelete", onDelete),
1913
+ ...ifDefined("onUpdate", onUpdate)
1914
+ });
1915
+ resultFkRelationMetadata.push({
1916
+ declaringModelName: model.name,
1917
+ declaringFieldName: relationAttribute.field.name,
1918
+ declaringTableName: tableName,
1919
+ targetModelName: targetMapping.model.name,
1920
+ targetTableName: targetMapping.tableName,
1921
+ ...ifDefined("relationName", parsedRelation.relationName),
1922
+ localColumns,
1923
+ referencedColumns
1924
+ });
1925
+ }
1926
+ return {
1927
+ modelNode: {
1928
+ modelName: model.name,
1929
+ tableName,
1930
+ fields: resolvedFields.map((resolvedField) => ({
1931
+ fieldName: resolvedField.field.name,
1932
+ columnName: resolvedField.columnName,
1933
+ descriptor: resolvedField.descriptor,
1934
+ nullable: resolvedField.field.optional,
1935
+ ...ifDefined("default", resolvedField.defaultValue),
1936
+ ...ifDefined("executionDefault", resolvedField.executionDefault)
1937
+ })),
1938
+ ...primaryKeyColumns.length > 0 ? { id: {
1939
+ columns: primaryKeyColumns,
1940
+ ...ifDefined("name", primaryKeyName)
1941
+ } } : {},
1942
+ ...uniqueConstraints.length > 0 ? { uniques: uniqueConstraints } : {},
1943
+ ...indexNodes.length > 0 ? { indexes: indexNodes } : {},
1944
+ ...foreignKeyNodes.length > 0 ? { foreignKeys: foreignKeyNodes } : {}
1945
+ },
1946
+ fkRelationMetadata: resultFkRelationMetadata,
1947
+ backrelationCandidates: resultBackrelationCandidates,
1948
+ resolvedFields
1949
+ };
1950
+ }
1951
+ function buildValueObjects(input) {
1952
+ const { compositeTypes, enumTypeDescriptors, namedTypeDescriptors, scalarTypeDescriptors, composedExtensions, familyId, targetId, authoringContributions, diagnostics, sourceId } = input;
1953
+ const valueObjects = {};
1954
+ const compositeTypeNames = new Set(compositeTypes.map((ct) => ct.name));
1955
+ for (const compositeType of compositeTypes) {
1956
+ const fields = {};
1957
+ for (const field of compositeType.fields) {
1958
+ if (compositeTypeNames.has(field.typeName)) {
1959
+ const result = {
1960
+ type: {
1961
+ kind: "valueObject",
1962
+ name: field.typeName
1963
+ },
1964
+ nullable: field.optional
1965
+ };
1966
+ fields[field.name] = field.list ? {
1967
+ ...result,
1968
+ many: true
1969
+ } : result;
1970
+ continue;
1971
+ }
1972
+ const resolved = resolveFieldTypeDescriptor({
1973
+ field,
1974
+ enumTypeDescriptors,
1975
+ namedTypeDescriptors,
1976
+ scalarTypeDescriptors,
1977
+ authoringContributions,
1978
+ composedExtensions,
1979
+ familyId,
1980
+ targetId,
1981
+ diagnostics,
1982
+ sourceId,
1983
+ entityLabel: `Field "${compositeType.name}.${field.name}"`
1984
+ });
1985
+ if (!resolved.ok) {
1986
+ if (!resolved.alreadyReported) diagnostics.push({
1987
+ code: "PSL_UNSUPPORTED_FIELD_TYPE",
1988
+ message: `Field "${compositeType.name}.${field.name}" type "${field.typeName}" is not supported`,
1989
+ sourceId,
1990
+ span: field.span
1991
+ });
1992
+ continue;
1993
+ }
1994
+ const scalarField = {
1995
+ nullable: field.optional,
1996
+ type: {
1997
+ kind: "scalar",
1998
+ codecId: resolved.descriptor.codecId
1999
+ }
2000
+ };
2001
+ fields[field.name] = field.list ? {
2002
+ ...scalarField,
2003
+ many: true
2004
+ } : scalarField;
2005
+ }
2006
+ valueObjects[compositeType.name] = { fields };
2007
+ }
2008
+ return valueObjects;
2009
+ }
2010
+ function patchModelDomainFields(models, modelResolvedFields) {
2011
+ let patched = models;
2012
+ for (const [modelName, resolvedFields] of modelResolvedFields) {
2013
+ const model = patched[modelName];
2014
+ if (!model) continue;
2015
+ let needsPatch = false;
2016
+ const patchedFields = { ...model.fields };
2017
+ for (const rf of resolvedFields) if (rf.valueObjectTypeName) {
2018
+ needsPatch = true;
2019
+ patchedFields[rf.field.name] = {
2020
+ nullable: rf.field.optional,
2021
+ type: {
2022
+ kind: "valueObject",
2023
+ name: rf.valueObjectTypeName
2024
+ },
2025
+ ...rf.many ? { many: true } : {}
2026
+ };
2027
+ } else if (rf.many && rf.scalarCodecId) {
2028
+ needsPatch = true;
2029
+ patchedFields[rf.field.name] = {
2030
+ nullable: rf.field.optional,
2031
+ type: {
2032
+ kind: "scalar",
2033
+ codecId: rf.scalarCodecId
2034
+ },
2035
+ many: true
2036
+ };
2037
+ }
2038
+ if (needsPatch) patched = {
2039
+ ...patched,
2040
+ [modelName]: {
2041
+ ...model,
2042
+ fields: patchedFields
2043
+ }
2044
+ };
2045
+ }
2046
+ return patched;
2047
+ }
2048
+ function collectPolymorphismDeclarations(models, sourceId, diagnostics) {
2049
+ const discriminatorDeclarations = /* @__PURE__ */ new Map();
2050
+ const baseDeclarations = /* @__PURE__ */ new Map();
2051
+ for (const model of models) for (const attr of model.attributes) {
2052
+ if (attr.name === "discriminator") {
2053
+ const fieldName = getPositionalArgument(attr);
2054
+ if (!fieldName) {
2055
+ diagnostics.push({
2056
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
2057
+ message: `Model "${model.name}" @@discriminator requires a field name argument`,
2058
+ sourceId,
2059
+ span: attr.span
2060
+ });
2061
+ continue;
2062
+ }
2063
+ const discField = model.fields.find((f) => f.name === fieldName);
2064
+ if (discField && discField.typeName !== "String") {
2065
+ diagnostics.push({
2066
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
2067
+ message: `Discriminator field "${fieldName}" on model "${model.name}" must be of type String, but is "${discField.typeName}"`,
2068
+ sourceId,
2069
+ span: attr.span
2070
+ });
2071
+ continue;
2072
+ }
2073
+ discriminatorDeclarations.set(model.name, {
2074
+ fieldName,
2075
+ span: attr.span
2076
+ });
2077
+ }
2078
+ if (attr.name === "base") {
2079
+ const baseName = getPositionalArgument(attr, 0);
2080
+ const rawValue = getPositionalArgument(attr, 1);
2081
+ if (!baseName || !rawValue) {
2082
+ diagnostics.push({
2083
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
2084
+ message: `Model "${model.name}" @@base requires two arguments: base model name and discriminator value`,
2085
+ sourceId,
2086
+ span: attr.span
2087
+ });
2088
+ continue;
2089
+ }
2090
+ const value = parseQuotedStringLiteral(rawValue);
2091
+ if (value === void 0) {
2092
+ diagnostics.push({
2093
+ code: "PSL_INVALID_ATTRIBUTE_ARGUMENT",
2094
+ message: `Model "${model.name}" @@base discriminator value must be a quoted string literal`,
2095
+ sourceId,
2096
+ span: attr.span
2097
+ });
2098
+ continue;
2099
+ }
2100
+ baseDeclarations.set(model.name, {
2101
+ baseName,
2102
+ value,
2103
+ span: attr.span
2104
+ });
2105
+ }
2106
+ }
2107
+ return {
2108
+ discriminatorDeclarations,
2109
+ baseDeclarations
2110
+ };
2111
+ }
2112
+ function resolvePolymorphism(models, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, sourceId, diagnostics) {
2113
+ let patched = models;
2114
+ for (const [modelName, decl] of discriminatorDeclarations) {
2115
+ if (baseDeclarations.has(modelName)) {
2116
+ diagnostics.push({
2117
+ code: "PSL_DISCRIMINATOR_AND_BASE",
2118
+ message: `Model "${modelName}" cannot have both @@discriminator and @@base`,
2119
+ sourceId,
2120
+ span: decl.span
2121
+ });
2122
+ continue;
2123
+ }
2124
+ const model = patched[modelName];
2125
+ if (!model) continue;
2126
+ if (!Object.hasOwn(model.fields, decl.fieldName)) {
2127
+ diagnostics.push({
2128
+ code: "PSL_DISCRIMINATOR_FIELD_NOT_FOUND",
2129
+ message: `Discriminator field "${decl.fieldName}" is not a field on model "${modelName}"`,
2130
+ sourceId,
2131
+ span: decl.span
2132
+ });
2133
+ continue;
2134
+ }
2135
+ const variants = {};
2136
+ const seenValues = /* @__PURE__ */ new Map();
2137
+ for (const [variantName, baseDecl] of baseDeclarations) {
2138
+ if (baseDecl.baseName !== modelName) continue;
2139
+ const existingVariant = seenValues.get(baseDecl.value);
2140
+ if (existingVariant) {
2141
+ diagnostics.push({
2142
+ code: "PSL_DUPLICATE_DISCRIMINATOR_VALUE",
2143
+ message: `Discriminator value "${baseDecl.value}" is used by both "${existingVariant}" and "${variantName}" on base model "${modelName}"`,
2144
+ sourceId,
2145
+ span: baseDecl.span
2146
+ });
2147
+ continue;
2148
+ }
2149
+ seenValues.set(baseDecl.value, variantName);
2150
+ variants[variantName] = { value: baseDecl.value };
2151
+ }
2152
+ if (Object.keys(variants).length === 0) {
2153
+ diagnostics.push({
2154
+ code: "PSL_ORPHANED_DISCRIMINATOR",
2155
+ message: `Model "${modelName}" has @@discriminator but no variant models declare @@base(${modelName}, ...)`,
2156
+ sourceId,
2157
+ span: decl.span
2158
+ });
2159
+ continue;
2160
+ }
2161
+ patched = {
2162
+ ...patched,
2163
+ [modelName]: {
2164
+ ...model,
2165
+ discriminator: { field: decl.fieldName },
2166
+ variants
2167
+ }
2168
+ };
2169
+ }
2170
+ for (const [variantName, baseDecl] of baseDeclarations) {
2171
+ if (!modelNames.has(baseDecl.baseName)) {
2172
+ diagnostics.push({
2173
+ code: "PSL_BASE_TARGET_NOT_FOUND",
2174
+ message: `Model "${variantName}" @@base references non-existent model "${baseDecl.baseName}"`,
2175
+ sourceId,
2176
+ span: baseDecl.span
2177
+ });
2178
+ continue;
2179
+ }
2180
+ if (!discriminatorDeclarations.has(baseDecl.baseName)) {
2181
+ diagnostics.push({
2182
+ code: "PSL_ORPHANED_BASE",
2183
+ message: `Model "${variantName}" declares @@base(${baseDecl.baseName}, ...) but "${baseDecl.baseName}" has no @@discriminator`,
2184
+ sourceId,
2185
+ span: baseDecl.span
2186
+ });
2187
+ continue;
2188
+ }
2189
+ if (discriminatorDeclarations.has(variantName)) continue;
2190
+ const variantModel = patched[variantName];
2191
+ if (!variantModel) continue;
2192
+ const baseMapping = modelMappings.get(baseDecl.baseName);
2193
+ const variantMapping = modelMappings.get(variantName);
2194
+ const resolvedTable = variantMapping?.model.attributes.some((attr) => attr.name === "map") ?? false ? variantMapping?.tableName : baseMapping?.tableName;
2195
+ patched = {
2196
+ ...patched,
2197
+ [variantName]: {
2198
+ ...variantModel,
2199
+ base: baseDecl.baseName,
2200
+ ...resolvedTable ? { storage: {
2201
+ ...variantModel.storage,
2202
+ table: resolvedTable
2203
+ } } : {}
2204
+ }
2205
+ };
2206
+ }
2207
+ return patched;
2208
+ }
2209
+ function interpretPslDocumentToSqlContract(input) {
2210
+ const sourceId = input.document.ast.sourceId;
2211
+ if (!input.target) return notOk({
2212
+ summary: "PSL to SQL contract interpretation failed",
2213
+ diagnostics: [{
2214
+ code: "PSL_TARGET_CONTEXT_REQUIRED",
2215
+ message: "PSL interpretation requires an explicit target context from composition.",
2216
+ sourceId
2217
+ }]
2218
+ });
2219
+ if (!input.scalarTypeDescriptors) return notOk({
2220
+ summary: "PSL to SQL contract interpretation failed",
2221
+ diagnostics: [{
2222
+ code: "PSL_SCALAR_TYPE_CONTEXT_REQUIRED",
2223
+ message: "PSL interpretation requires composed scalar type descriptors.",
2224
+ sourceId
2225
+ }]
2226
+ });
2227
+ const diagnostics = mapParserDiagnostics(input.document);
2228
+ const models = input.document.ast.models ?? [];
2229
+ const enums = input.document.ast.enums ?? [];
2230
+ const compositeTypes = input.document.ast.compositeTypes ?? [];
2231
+ const modelNames = new Set(models.map((model) => model.name));
2232
+ const compositeTypeNames = new Set(compositeTypes.map((ct) => ct.name));
2233
+ const composedExtensions = new Set(input.composedExtensionPacks ?? []);
2234
+ const defaultFunctionRegistry = input.controlMutationDefaults?.defaultFunctionRegistry ?? /* @__PURE__ */ new Map();
2235
+ const generatorDescriptors = input.controlMutationDefaults?.generatorDescriptors ?? [];
2236
+ const generatorDescriptorById = /* @__PURE__ */ new Map();
2237
+ for (const descriptor of generatorDescriptors) generatorDescriptorById.set(descriptor.id, descriptor);
2238
+ const enumResult = processEnumDeclarations({
2239
+ enums,
2240
+ sourceId,
2241
+ enumTypeConstructor: getAuthoringTypeConstructor(input.authoringContributions, ["enum"]),
2242
+ diagnostics
2243
+ });
2244
+ const namedTypeResult = resolveNamedTypeDeclarations({
2245
+ declarations: input.document.ast.types?.declarations ?? [],
2246
+ sourceId,
2247
+ enumTypeDescriptors: enumResult.enumTypeDescriptors,
2248
+ scalarTypeDescriptors: input.scalarTypeDescriptors,
2249
+ composedExtensions,
2250
+ familyId: input.target.familyId,
2251
+ targetId: input.target.targetId,
2252
+ authoringContributions: input.authoringContributions,
2253
+ diagnostics
2254
+ });
2255
+ const storageTypes = {
2256
+ ...enumResult.storageTypes,
2257
+ ...namedTypeResult.storageTypes
2258
+ };
2259
+ const modelMappings = buildModelMappings(models, diagnostics, sourceId);
2260
+ const modelNodes = [];
2261
+ const fkRelationMetadata = [];
2262
+ const backrelationCandidates = [];
2263
+ const modelResolvedFields = /* @__PURE__ */ new Map();
2264
+ for (const model of models) {
2265
+ const mapping = modelMappings.get(model.name);
2266
+ if (!mapping) continue;
2267
+ const result = buildModelNodeFromPsl({
2268
+ model,
2269
+ mapping,
2270
+ modelMappings,
2271
+ modelNames,
2272
+ compositeTypeNames,
2273
+ enumTypeDescriptors: enumResult.enumTypeDescriptors,
2274
+ namedTypeDescriptors: namedTypeResult.namedTypeDescriptors,
2275
+ composedExtensions,
2276
+ familyId: input.target.familyId,
2277
+ targetId: input.target.targetId,
2278
+ authoringContributions: input.authoringContributions,
2279
+ defaultFunctionRegistry,
2280
+ generatorDescriptorById,
2281
+ scalarTypeDescriptors: input.scalarTypeDescriptors,
2282
+ sourceId,
2283
+ diagnostics
2284
+ });
2285
+ modelNodes.push(result.modelNode);
2286
+ fkRelationMetadata.push(...result.fkRelationMetadata);
2287
+ backrelationCandidates.push(...result.backrelationCandidates);
2288
+ modelResolvedFields.set(model.name, result.resolvedFields);
2289
+ }
2290
+ const { modelRelations, fkRelationsByPair } = indexFkRelations({ fkRelationMetadata });
2291
+ applyBackrelationCandidates({
2292
+ backrelationCandidates,
2293
+ fkRelationsByPair,
2294
+ modelRelations,
2295
+ diagnostics,
2296
+ sourceId
2297
+ });
2298
+ const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(models, sourceId, diagnostics);
2299
+ const valueObjects = buildValueObjects({
2300
+ compositeTypes,
2301
+ enumTypeDescriptors: enumResult.enumTypeDescriptors,
2302
+ namedTypeDescriptors: namedTypeResult.namedTypeDescriptors,
2303
+ scalarTypeDescriptors: input.scalarTypeDescriptors,
2304
+ composedExtensions,
2305
+ familyId: input.target.familyId,
2306
+ targetId: input.target.targetId,
2307
+ authoringContributions: input.authoringContributions,
2308
+ diagnostics,
2309
+ sourceId
2310
+ });
2311
+ if (diagnostics.length > 0) return notOk({
2312
+ summary: "PSL to SQL contract interpretation failed",
2313
+ diagnostics: dedupeDiagnostics(diagnostics)
2314
+ });
2315
+ const contract = buildSqlContractFromDefinition({
2316
+ target: input.target,
2317
+ ...ifDefined("extensionPacks", buildComposedExtensionPackRefs(input.target, [...composedExtensions].sort(compareStrings), input.composedExtensionPackRefs)),
2318
+ ...Object.keys(storageTypes).length > 0 ? { storageTypes } : {},
2319
+ models: modelNodes.map((model) => ({
2320
+ ...model,
2321
+ ...modelRelations.has(model.modelName) ? { relations: [...modelRelations.get(model.modelName) ?? []].sort((left, right) => compareStrings(left.fieldName, right.fieldName)) } : {}
2322
+ }))
2323
+ });
2324
+ let patchedModels = patchModelDomainFields(contract.models, modelResolvedFields);
2325
+ const polyDiagnostics = [];
2326
+ patchedModels = resolvePolymorphism(patchedModels, discriminatorDeclarations, baseDeclarations, modelNames, modelMappings, sourceId, polyDiagnostics);
2327
+ if (polyDiagnostics.length > 0) return notOk({
2328
+ summary: "PSL to SQL contract interpretation failed",
2329
+ diagnostics: polyDiagnostics
2330
+ });
2331
+ const variantModelNames = new Set(baseDeclarations.keys());
2332
+ const filteredRoots = Object.fromEntries(Object.entries(contract.roots).filter(([, modelName]) => !variantModelNames.has(modelName)));
2333
+ return ok({
2334
+ ...contract,
2335
+ roots: filteredRoots,
2336
+ models: patchedModels,
2337
+ ...Object.keys(valueObjects).length > 0 ? { valueObjects } : {}
2338
+ });
2339
+ }
2340
+
2341
+ //#endregion
2342
+ export { interpretPslDocumentToSqlContract as t };
2343
+ //# sourceMappingURL=interpreter-iFCRN9nb.mjs.map