@prisma-next/mongo-contract-psl 0.3.0-dev.147 → 0.3.0-dev.162

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,6 +9,11 @@ PSL-to-Mongo contract interpreter for Prisma Next. Transforms Prisma Schema Lang
9
9
  - **Contract provider**: `mongoContract()` (exported from `./provider`) integrates with the CLI's `prisma-next contract emit` command, reading a `.prisma` schema file and producing a `ContractConfig`
10
10
  - **Diagnostics**: Emits structured diagnostics for unsupported field types (`PSL_UNSUPPORTED_FIELD_TYPE`), missing `@id` fields (`PSL_MISSING_ID_FIELD`), orphaned backrelations (`PSL_ORPHANED_BACKRELATION`), and ambiguous backrelations (`PSL_AMBIGUOUS_BACKRELATION`)
11
11
 
12
+ ## Known limitations
13
+
14
+ - **Per-index `collation`**: PSL authoring does not support the `collation` index option. Users requiring per-index collation must use the TypeScript contract builder (`@prisma-next/mongo-contract-ts`).
15
+ - **`partialFilterExpression` / `wildcardProjection`**: These object-valued index options are not supported in PSL and require the TypeScript contract builder.
16
+
12
17
  ## Dependencies
13
18
 
14
19
  - **Depends on**:
@@ -1,4 +1,4 @@
1
- import { n as interpretPslDocumentToMongoContract, t as createMongoScalarTypeDescriptors } from "../scalar-type-descriptors-Bou6SVVa.mjs";
1
+ import { n as interpretPslDocumentToMongoContract, t as createMongoScalarTypeDescriptors } from "../scalar-type-descriptors-B0Lt0pJI.mjs";
2
2
  import { notOk, ok } from "@prisma-next/utils/result";
3
3
  import { parsePslDocument } from "@prisma-next/psl-parser";
4
4
  import { readFile } from "node:fs/promises";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/interpreter.ts","../src/scalar-type-descriptors.ts"],"sourcesContent":[],"mappings":";;;;;;UAsBiB,wCAAA;qBACI;EADJ,SAAA,qBAAA,EAEiB,WAFuB,CAAA,MAAA,EAAA,MACpC,CAAA;AAuSrB;AACS,iBADO,mCAAA,CACP,KAAA,EAAA,wCAAA,CAAA,EACN,MADM,CACC,QADD,EACW,yBADX,CAAA;;;iBC/TO,gCAAA,CAAA,GAAoC"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/interpreter.ts","../src/scalar-type-descriptors.ts"],"sourcesContent":[],"mappings":";;;;;;UA0BiB,wCAAA;qBACI;EADJ,SAAA,qBAAA,EAEiB,WAFuB,CAAA,MAAA,EAAA,MACpC,CAAA;AAgmBrB;AACS,iBADO,mCAAA,CACP,KAAA,EAAA,wCAAA,CAAA,EACN,MADM,CACC,QADD,EACW,yBADX,CAAA;;;iBC5nBO,gCAAA,CAAA,GAAoC"}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { n as interpretPslDocumentToMongoContract, t as createMongoScalarTypeDescriptors } from "./scalar-type-descriptors-Bou6SVVa.mjs";
1
+ import { n as interpretPslDocumentToMongoContract, t as createMongoScalarTypeDescriptors } from "./scalar-type-descriptors-B0Lt0pJI.mjs";
2
2
 
3
3
  export { createMongoScalarTypeDescriptors, interpretPslDocumentToMongoContract };
@@ -2,7 +2,111 @@ import { computeProfileHash, computeStorageHash } from "@prisma-next/contract/ha
2
2
  import { notOk, ok } from "@prisma-next/utils/result";
3
3
  import { getPositionalArgument, parseQuotedStringLiteral } from "@prisma-next/psl-parser";
4
4
 
5
+ //#region src/derive-json-schema.ts
6
+ const CODEC_TO_BSON_TYPE = {
7
+ "mongo/string@1": "string",
8
+ "mongo/int32@1": "int",
9
+ "mongo/bool@1": "bool",
10
+ "mongo/date@1": "date",
11
+ "mongo/objectId@1": "objectId"
12
+ };
13
+ function fieldToBsonSchema(field, valueObjects) {
14
+ if (field.type.kind === "scalar") {
15
+ const bsonType = CODEC_TO_BSON_TYPE[field.type.codecId];
16
+ if (!bsonType) return void 0;
17
+ if ("many" in field && field.many) return {
18
+ bsonType: "array",
19
+ items: { bsonType }
20
+ };
21
+ if (field.nullable) return { bsonType: ["null", bsonType] };
22
+ return { bsonType };
23
+ }
24
+ if (field.type.kind === "valueObject") {
25
+ const vo = valueObjects?.[field.type.name];
26
+ if (!vo) return void 0;
27
+ const voSchema = deriveObjectSchema(vo.fields, valueObjects);
28
+ if ("many" in field && field.many) return {
29
+ bsonType: "array",
30
+ items: voSchema
31
+ };
32
+ if (field.nullable) return { oneOf: [{ bsonType: "null" }, voSchema] };
33
+ return voSchema;
34
+ }
35
+ }
36
+ function deriveObjectSchema(fields, valueObjects) {
37
+ const properties = {};
38
+ const required = [];
39
+ for (const [fieldName, field] of Object.entries(fields)) {
40
+ const schema = fieldToBsonSchema(field, valueObjects);
41
+ if (schema) {
42
+ properties[fieldName] = schema;
43
+ if (!field.nullable) required.push(fieldName);
44
+ }
45
+ }
46
+ const result = {
47
+ bsonType: "object",
48
+ properties
49
+ };
50
+ if (required.length > 0) result["required"] = required.sort();
51
+ return result;
52
+ }
53
+ function deriveJsonSchema(fields, valueObjects) {
54
+ return {
55
+ jsonSchema: deriveObjectSchema(fields, valueObjects),
56
+ validationLevel: "strict",
57
+ validationAction: "error"
58
+ };
59
+ }
60
+
61
+ //#endregion
5
62
  //#region src/psl-helpers.ts
63
+ function getNamedArgument(attr, name) {
64
+ return attr.args.find((a) => a.kind === "named" && a.name === name)?.value;
65
+ }
66
+ function parseFieldList(value) {
67
+ const inner = value.replace(/^\[/, "").replace(/\]$/, "").trim();
68
+ if (inner.length === 0) return [];
69
+ return splitTopLevel(inner).map((s) => s.trim());
70
+ }
71
+ function parseIndexFieldList(value) {
72
+ return parseFieldList(value).map(parseIndexFieldSegment);
73
+ }
74
+ function parseIndexFieldSegment(segment) {
75
+ const wildcardMatch = segment.match(/^wildcard\(\s*(.*?)\s*\)$/);
76
+ if (wildcardMatch) {
77
+ const scope = wildcardMatch[1] ?? "";
78
+ return {
79
+ name: scope.length > 0 ? `${scope}.$**` : "$**",
80
+ isWildcard: true
81
+ };
82
+ }
83
+ const modifierMatch = segment.match(/^(\w+)\(\s*sort:\s*(\w+)\s*\)$/);
84
+ if (modifierMatch) return {
85
+ name: modifierMatch[1] ?? segment,
86
+ isWildcard: false,
87
+ direction: modifierMatch[2] === "Desc" ? -1 : 1
88
+ };
89
+ return {
90
+ name: segment,
91
+ isWildcard: false
92
+ };
93
+ }
94
+ function splitTopLevel(input) {
95
+ const parts = [];
96
+ let depth = 0;
97
+ let start = 0;
98
+ for (let i = 0; i < input.length; i++) {
99
+ const ch = input[i];
100
+ if (ch === "(" || ch === "[" || ch === "{") depth++;
101
+ else if (ch === ")" || ch === "]" || ch === "}") depth = Math.max(0, depth - 1);
102
+ else if (ch === "," && depth === 0) {
103
+ parts.push(input.slice(start, i));
104
+ start = i + 1;
105
+ }
106
+ }
107
+ parts.push(input.slice(start));
108
+ return parts;
109
+ }
6
110
  function lowerFirst(value) {
7
111
  if (value.length === 0) return value;
8
112
  return value[0]?.toLowerCase() + value.slice(1);
@@ -35,11 +139,6 @@ function parseRelationAttribute(attributes) {
35
139
  ...references !== void 0 ? { references } : {}
36
140
  };
37
141
  }
38
- function parseFieldList(value) {
39
- const inner = value.replace(/^\[/, "").replace(/\]$/, "").trim();
40
- if (inner.length === 0) return [];
41
- return inner.split(",").map((s) => s.trim());
42
- }
43
142
  function stripQuotes(value) {
44
143
  if (value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1);
45
144
  return value;
@@ -231,6 +330,236 @@ function resolvePolymorphism(input) {
231
330
  diagnostics
232
331
  };
233
332
  }
333
+ function parseIndexDirection(raw) {
334
+ if (!raw) return 1;
335
+ const stripped = raw.replace(/^["']/, "").replace(/["']$/, "");
336
+ const num = Number(stripped);
337
+ if (num === 1 || num === -1) return num;
338
+ if ([
339
+ "text",
340
+ "2dsphere",
341
+ "2d",
342
+ "hashed"
343
+ ].includes(stripped)) return stripped;
344
+ return 1;
345
+ }
346
+ function parseNumericArg(raw) {
347
+ if (!raw) return void 0;
348
+ const n = Number(raw);
349
+ return Number.isFinite(n) ? n : void 0;
350
+ }
351
+ function parseBooleanArg(raw) {
352
+ if (raw === "true") return true;
353
+ if (raw === "false") return false;
354
+ }
355
+ function parseJsonArg(raw) {
356
+ if (!raw) return void 0;
357
+ const stripped = raw.replace(/^["']/, "").replace(/["']$/, "").replace(/\\"/g, "\"");
358
+ try {
359
+ const parsed = JSON.parse(stripped);
360
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
361
+ } catch {}
362
+ }
363
+ function parseCollation(attr) {
364
+ const locale = stripQuotesHelper(getNamedArgument(attr, "collationLocale"));
365
+ if (!locale) return getNamedArgument(attr, "collationStrength") != null || getNamedArgument(attr, "collationCaseLevel") != null || getNamedArgument(attr, "collationCaseFirst") != null || getNamedArgument(attr, "collationNumericOrdering") != null || getNamedArgument(attr, "collationAlternate") != null || getNamedArgument(attr, "collationMaxVariable") != null || getNamedArgument(attr, "collationBackwards") != null || getNamedArgument(attr, "collationNormalization") != null ? null : void 0;
366
+ const collation = { locale };
367
+ const strength = parseNumericArg(getNamedArgument(attr, "collationStrength"));
368
+ if (strength != null) collation["strength"] = strength;
369
+ const caseLevel = parseBooleanArg(getNamedArgument(attr, "collationCaseLevel"));
370
+ if (caseLevel != null) collation["caseLevel"] = caseLevel;
371
+ const caseFirst = stripQuotesHelper(getNamedArgument(attr, "collationCaseFirst"));
372
+ if (caseFirst != null) collation["caseFirst"] = caseFirst;
373
+ const numericOrdering = parseBooleanArg(getNamedArgument(attr, "collationNumericOrdering"));
374
+ if (numericOrdering != null) collation["numericOrdering"] = numericOrdering;
375
+ const alternate = stripQuotesHelper(getNamedArgument(attr, "collationAlternate"));
376
+ if (alternate != null) collation["alternate"] = alternate;
377
+ const maxVariable = stripQuotesHelper(getNamedArgument(attr, "collationMaxVariable"));
378
+ if (maxVariable != null) collation["maxVariable"] = maxVariable;
379
+ const backwards = parseBooleanArg(getNamedArgument(attr, "collationBackwards"));
380
+ if (backwards != null) collation["backwards"] = backwards;
381
+ const normalization = parseBooleanArg(getNamedArgument(attr, "collationNormalization"));
382
+ if (normalization != null) collation["normalization"] = normalization;
383
+ return collation;
384
+ }
385
+ function stripQuotesHelper(raw) {
386
+ if (!raw) return void 0;
387
+ return raw.replace(/^["']/, "").replace(/["']$/, "");
388
+ }
389
+ function parseProjectionList(raw, value) {
390
+ if (!raw) return void 0;
391
+ const inner = raw.replace(/^["']/, "").replace(/["']$/, "").replace(/^\[/, "").replace(/\]$/, "").trim();
392
+ if (inner.length === 0) return void 0;
393
+ const fields = inner.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
394
+ const result = {};
395
+ for (const f of fields) result[f] = value;
396
+ return result;
397
+ }
398
+ function collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics) {
399
+ const indexes = [];
400
+ let textIndexCount = 0;
401
+ for (const field of pslModel.fields) {
402
+ if (modelNames.has(field.typeName)) continue;
403
+ if (!getAttribute(field.attributes, "unique")) continue;
404
+ const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;
405
+ indexes.push({
406
+ keys: [{
407
+ field: mappedName,
408
+ direction: 1
409
+ }],
410
+ unique: true
411
+ });
412
+ }
413
+ for (const attr of pslModel.attributes) {
414
+ const isIndex = attr.name === "index";
415
+ const isUnique = attr.name === "unique";
416
+ const isTextIndex = attr.name === "textIndex";
417
+ if (!isIndex && !isUnique && !isTextIndex) continue;
418
+ const fieldsArg = getPositionalArgument(attr, 0);
419
+ if (!fieldsArg) continue;
420
+ const parsedFields = parseIndexFieldList(fieldsArg);
421
+ if (parsedFields.length === 0) continue;
422
+ const hasWildcard = parsedFields.some((f) => f.isWildcard);
423
+ if (parsedFields.filter((f) => f.isWildcard).length > 1) {
424
+ diagnostics.push({
425
+ code: "PSL_INVALID_INDEX",
426
+ message: "An index can contain at most one wildcard() field",
427
+ sourceId,
428
+ span: attr.span
429
+ });
430
+ continue;
431
+ }
432
+ if (isUnique && hasWildcard) {
433
+ diagnostics.push({
434
+ code: "PSL_INVALID_INDEX",
435
+ message: "Unique indexes cannot use wildcard() fields",
436
+ sourceId,
437
+ span: attr.span
438
+ });
439
+ continue;
440
+ }
441
+ if (isTextIndex) {
442
+ textIndexCount++;
443
+ if (textIndexCount > 1) {
444
+ diagnostics.push({
445
+ code: "PSL_INVALID_INDEX",
446
+ message: `Only one @@textIndex is allowed per collection (model "${pslModel.name}")`,
447
+ sourceId,
448
+ span: attr.span
449
+ });
450
+ continue;
451
+ }
452
+ if (hasWildcard) {
453
+ diagnostics.push({
454
+ code: "PSL_INVALID_INDEX",
455
+ message: "wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex",
456
+ sourceId,
457
+ span: attr.span
458
+ });
459
+ continue;
460
+ }
461
+ }
462
+ const typeArg = getNamedArgument(attr, "type");
463
+ const defaultDirection = isTextIndex ? "text" : parseIndexDirection(typeArg);
464
+ if (hasWildcard && typeof defaultDirection === "string" && [
465
+ "hashed",
466
+ "2dsphere",
467
+ "2d"
468
+ ].includes(defaultDirection)) {
469
+ diagnostics.push({
470
+ code: "PSL_INVALID_INDEX",
471
+ message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,
472
+ sourceId,
473
+ span: attr.span
474
+ });
475
+ continue;
476
+ }
477
+ if (defaultDirection === "hashed" && parsedFields.length > 1) {
478
+ diagnostics.push({
479
+ code: "PSL_INVALID_INDEX",
480
+ message: "Hashed indexes must have exactly one field",
481
+ sourceId,
482
+ span: attr.span
483
+ });
484
+ continue;
485
+ }
486
+ const keys = parsedFields.map((pf) => {
487
+ return {
488
+ field: pf.isWildcard ? pf.name.replace(/^(.+)\.\$\*\*$/, (_, prefix) => {
489
+ const mapped = fieldMappings.pslNameToMapped.get(prefix);
490
+ return mapped ? `${mapped}.$**` : `${prefix}.$**`;
491
+ }) : fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name,
492
+ direction: pf.direction != null ? pf.direction : defaultDirection
493
+ };
494
+ });
495
+ const unique = isUnique ? true : void 0;
496
+ const sparse = isTextIndex ? void 0 : parseBooleanArg(getNamedArgument(attr, "sparse"));
497
+ const expireAfterSeconds = isTextIndex ? void 0 : parseNumericArg(getNamedArgument(attr, "expireAfterSeconds"));
498
+ if (hasWildcard && expireAfterSeconds != null) {
499
+ diagnostics.push({
500
+ code: "PSL_INVALID_INDEX",
501
+ message: "expireAfterSeconds cannot be combined with wildcard() fields",
502
+ sourceId,
503
+ span: attr.span
504
+ });
505
+ continue;
506
+ }
507
+ const partialFilterExpression = parseJsonArg(getNamedArgument(attr, "filter"));
508
+ const includeArg = getNamedArgument(attr, "include");
509
+ const excludeArg = getNamedArgument(attr, "exclude");
510
+ if (includeArg != null && excludeArg != null) {
511
+ diagnostics.push({
512
+ code: "PSL_INVALID_INDEX",
513
+ message: "Cannot specify both include and exclude on the same index",
514
+ sourceId,
515
+ span: attr.span
516
+ });
517
+ continue;
518
+ }
519
+ if ((includeArg != null || excludeArg != null) && !hasWildcard) {
520
+ diagnostics.push({
521
+ code: "PSL_INVALID_INDEX",
522
+ message: "include/exclude options are only valid when the index contains a wildcard() field",
523
+ sourceId,
524
+ span: attr.span
525
+ });
526
+ continue;
527
+ }
528
+ const wildcardProjection = includeArg != null ? parseProjectionList(includeArg, 1) : excludeArg != null ? parseProjectionList(excludeArg, 0) : void 0;
529
+ const collation = parseCollation(attr);
530
+ if (collation === null) {
531
+ diagnostics.push({
532
+ code: "PSL_INVALID_INDEX",
533
+ message: "collationLocale is required when using collation options",
534
+ sourceId,
535
+ span: attr.span
536
+ });
537
+ continue;
538
+ }
539
+ const rawWeights = parseJsonArg(getNamedArgument(attr, "weights"));
540
+ let weights;
541
+ if (rawWeights) {
542
+ weights = {};
543
+ for (const [k, v] of Object.entries(rawWeights)) if (typeof v === "number") weights[k] = v;
544
+ }
545
+ const default_language = stripQuotesHelper(isTextIndex ? getNamedArgument(attr, "language") : getNamedArgument(attr, "default_language"));
546
+ const language_override = stripQuotesHelper(getNamedArgument(attr, "languageOverride"));
547
+ const index = {
548
+ keys,
549
+ ...unique != null && { unique },
550
+ ...sparse != null && { sparse },
551
+ ...expireAfterSeconds != null && { expireAfterSeconds },
552
+ ...partialFilterExpression != null && { partialFilterExpression },
553
+ ...wildcardProjection != null && { wildcardProjection },
554
+ ...collation != null && { collation },
555
+ ...weights != null && { weights },
556
+ ...default_language != null && { default_language },
557
+ ...language_override != null && { language_override }
558
+ };
559
+ indexes.push(index);
560
+ }
561
+ return indexes;
562
+ }
234
563
  function isRelationField(field, modelNames) {
235
564
  return modelNames.has(field.typeName);
236
565
  }
@@ -343,7 +672,8 @@ function interpretPslDocumentToMongoContract(input) {
343
672
  relations,
344
673
  storage: { collection: collectionName }
345
674
  };
346
- collections[collectionName] = {};
675
+ const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);
676
+ collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};
347
677
  roots[collectionName] = pslModel.name;
348
678
  }
349
679
  const valueObjects = {};
@@ -356,6 +686,10 @@ function interpretPslDocumentToMongoContract(input) {
356
686
  }
357
687
  valueObjects[compositeType.name] = { fields };
358
688
  }
689
+ for (const [, modelEntry] of Object.entries(models)) {
690
+ const coll = collections[modelEntry.storage.collection];
691
+ if (coll) coll["validator"] = deriveJsonSchema(modelEntry.fields, valueObjects);
692
+ }
359
693
  const fkRelationsByPair = /* @__PURE__ */ new Map();
360
694
  for (const fk of allFkRelations) {
361
695
  const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);
@@ -456,4 +790,4 @@ function createMongoScalarTypeDescriptors() {
456
790
 
457
791
  //#endregion
458
792
  export { interpretPslDocumentToMongoContract as n, createMongoScalarTypeDescriptors as t };
459
- //# sourceMappingURL=scalar-type-descriptors-Bou6SVVa.mjs.map
793
+ //# sourceMappingURL=scalar-type-descriptors-B0Lt0pJI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalar-type-descriptors-B0Lt0pJI.mjs","names":["CODEC_TO_BSON_TYPE: Record<string, string>","properties: Record<string, unknown>","required: string[]","result: Record<string, unknown>","parts: string[]","relationName: string | undefined","fieldsArg: PslAttributeArgument | undefined","referencesArg: PslAttributeArgument | undefined","diagnostics: ContractSourceDiagnostic[]","variants: Record<string, { readonly value: string }>","collation: Record<string, unknown>","result: Record<string, 0 | 1>","indexes: MongoStorageIndex[]","defaultDirection: MongoIndexKeyDirection","weights: Record<string, number> | undefined","index: MongoStorageIndex","result: ContractField","result","models: Record<string, MongoModelEntry>","collections: Record<string, Record<string, unknown>>","roots: Record<string, string>","allFkRelations: FkRelation[]","backrelationCandidates: BackrelationCandidate[]","fields: Record<string, ContractField>","relations: Record<string, ContractReferenceRelation>","valueObjects: Record<string, ContractValueObject>","capabilities: Record<string, Record<string, boolean>>"],"sources":["../src/derive-json-schema.ts","../src/psl-helpers.ts","../src/interpreter.ts","../src/scalar-type-descriptors.ts"],"sourcesContent":["import type { ContractField, ContractValueObject } from '@prisma-next/contract/types';\nimport type { MongoStorageValidator } from '@prisma-next/mongo-contract';\n\nconst CODEC_TO_BSON_TYPE: Record<string, string> = {\n 'mongo/string@1': 'string',\n 'mongo/int32@1': 'int',\n 'mongo/bool@1': 'bool',\n 'mongo/date@1': 'date',\n 'mongo/objectId@1': 'objectId',\n};\n\nfunction fieldToBsonSchema(\n field: ContractField,\n valueObjects: Record<string, ContractValueObject> | undefined,\n): Record<string, unknown> | undefined {\n if (field.type.kind === 'scalar') {\n const bsonType = CODEC_TO_BSON_TYPE[field.type.codecId];\n if (!bsonType) return undefined;\n\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: { bsonType } };\n }\n\n if (field.nullable) {\n return { bsonType: ['null', bsonType] };\n }\n\n return { bsonType };\n }\n\n if (field.type.kind === 'valueObject') {\n const vo = valueObjects?.[field.type.name];\n if (!vo) return undefined;\n const voSchema = deriveObjectSchema(vo.fields, valueObjects);\n if ('many' in field && field.many) {\n return { bsonType: 'array', items: voSchema };\n }\n if (field.nullable) {\n return { oneOf: [{ bsonType: 'null' }, voSchema] };\n }\n return voSchema;\n }\n\n return undefined;\n}\n\nfunction deriveObjectSchema(\n fields: Record<string, ContractField>,\n valueObjects: Record<string, ContractValueObject> | undefined,\n): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [fieldName, field] of Object.entries(fields)) {\n const schema = fieldToBsonSchema(field, valueObjects);\n if (schema) {\n properties[fieldName] = schema;\n if (!field.nullable) {\n required.push(fieldName);\n }\n }\n }\n\n const result: Record<string, unknown> = {\n bsonType: 'object',\n properties,\n };\n if (required.length > 0) {\n result['required'] = required.sort();\n }\n return result;\n}\n\nexport function deriveJsonSchema(\n fields: Record<string, ContractField>,\n valueObjects?: Record<string, ContractValueObject>,\n): MongoStorageValidator {\n return {\n jsonSchema: deriveObjectSchema(fields, valueObjects),\n validationLevel: 'strict',\n validationAction: 'error',\n };\n}\n","import type { PslAttribute, PslAttributeArgument } from '@prisma-next/psl-parser';\nimport { getPositionalArgument, parseQuotedStringLiteral } from '@prisma-next/psl-parser';\n\nexport { getPositionalArgument, parseQuotedStringLiteral };\n\nexport function getNamedArgument(attr: PslAttribute, name: string): string | undefined {\n const arg = attr.args.find((a) => a.kind === 'named' && a.name === name);\n return arg?.value;\n}\n\nexport function parseFieldList(value: string): readonly string[] {\n const inner = value.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return [];\n return splitTopLevel(inner).map((s) => s.trim());\n}\n\nexport interface ParsedIndexField {\n readonly name: string;\n readonly isWildcard: boolean;\n readonly direction?: number;\n}\n\nexport function parseIndexFieldList(value: string): readonly ParsedIndexField[] {\n const segments = parseFieldList(value);\n return segments.map(parseIndexFieldSegment);\n}\n\nfunction parseIndexFieldSegment(segment: string): ParsedIndexField {\n const wildcardMatch = segment.match(/^wildcard\\(\\s*(.*?)\\s*\\)$/);\n if (wildcardMatch) {\n const scope = wildcardMatch[1] ?? '';\n return {\n name: scope.length > 0 ? `${scope}.$**` : '$**',\n isWildcard: true,\n };\n }\n\n const modifierMatch = segment.match(/^(\\w+)\\(\\s*sort:\\s*(\\w+)\\s*\\)$/);\n if (modifierMatch) {\n const fieldName = modifierMatch[1] ?? segment;\n const sortValue = modifierMatch[2];\n return {\n name: fieldName,\n isWildcard: false,\n direction: sortValue === 'Desc' ? -1 : 1,\n };\n }\n\n return { name: segment, isWildcard: false };\n}\n\nfunction splitTopLevel(input: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let start = 0;\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '(' || ch === '[' || ch === '{') depth++;\n else if (ch === ')' || ch === ']' || ch === '}') depth = Math.max(0, depth - 1);\n else if (ch === ',' && depth === 0) {\n parts.push(input.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(input.slice(start));\n return parts;\n}\n\nexport function lowerFirst(value: string): string {\n if (value.length === 0) return value;\n return value[0]?.toLowerCase() + value.slice(1);\n}\n\nexport function getAttribute(\n attributes: readonly PslAttribute[],\n name: string,\n): PslAttribute | undefined {\n return attributes.find((attr) => attr.name === name);\n}\n\nexport function getMapName(attributes: readonly PslAttribute[]): string | undefined {\n const mapAttr = getAttribute(attributes, 'map');\n if (!mapAttr) return undefined;\n const arg = mapAttr.args[0];\n if (!arg) return undefined;\n return stripQuotes(arg.value);\n}\n\nexport interface ParsedRelationAttribute {\n readonly relationName?: string;\n readonly fields?: readonly string[];\n readonly references?: readonly string[];\n}\n\nexport function parseRelationAttribute(\n attributes: readonly PslAttribute[],\n): ParsedRelationAttribute | undefined {\n const relationAttr = getAttribute(attributes, 'relation');\n if (!relationAttr) return undefined;\n\n let relationName: string | undefined;\n let fieldsArg: PslAttributeArgument | undefined;\n let referencesArg: PslAttributeArgument | undefined;\n\n for (const arg of relationAttr.args) {\n if (arg.kind === 'positional') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'name') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'fields') {\n fieldsArg = arg;\n } else if (arg.name === 'references') {\n referencesArg = arg;\n }\n }\n\n const fields = fieldsArg ? parseFieldList(fieldsArg.value) : undefined;\n const references = referencesArg ? parseFieldList(referencesArg.value) : undefined;\n\n return {\n ...(relationName !== undefined ? { relationName } : {}),\n ...(fields !== undefined ? { fields } : {}),\n ...(references !== undefined ? { references } : {}),\n };\n}\n\nfunction stripQuotes(value: string): string {\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n ContractSourceDiagnostic,\n ContractSourceDiagnostics,\n} from '@prisma-next/config/config-types';\nimport { computeProfileHash, computeStorageHash } from '@prisma-next/contract/hashing';\nimport type {\n Contract,\n ContractField,\n ContractReferenceRelation,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { MongoIndexKeyDirection, MongoStorageIndex } from '@prisma-next/mongo-contract';\nimport type { ParsePslDocumentResult, PslField, PslModel } from '@prisma-next/psl-parser';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { deriveJsonSchema } from './derive-json-schema';\nimport {\n getAttribute,\n getMapName,\n getNamedArgument,\n getPositionalArgument,\n lowerFirst,\n parseIndexFieldList,\n parseQuotedStringLiteral,\n parseRelationAttribute,\n} from './psl-helpers';\n\nexport interface InterpretPslDocumentToMongoContractInput {\n readonly document: ParsePslDocumentResult;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n}\n\ninterface FieldMappings {\n readonly pslNameToMapped: Map<string, string>;\n}\n\ninterface FkRelation {\n readonly declaringModel: string;\n readonly fieldName: string;\n readonly targetModel: string;\n readonly relationName?: string;\n readonly localFields: readonly string[];\n readonly targetFields: readonly string[];\n}\n\nfunction fkRelationPairKey(declaringModel: string, targetModel: string): string {\n return `${declaringModel}::${targetModel}`;\n}\n\nfunction resolveFieldMappings(model: PslModel): FieldMappings {\n const pslNameToMapped = new Map<string, string>();\n for (const field of model.fields) {\n const mapped = getMapName(field.attributes) ?? field.name;\n pslNameToMapped.set(field.name, mapped);\n }\n return { pslNameToMapped };\n}\n\nfunction resolveCollectionName(model: PslModel): string {\n return getMapName(model.attributes) ?? lowerFirst(model.name);\n}\n\ninterface MongoModelEntry {\n readonly fields: Record<string, ContractField>;\n readonly relations: Record<string, ContractReferenceRelation>;\n readonly storage: { readonly collection: string };\n readonly discriminator?: { readonly field: string };\n readonly variants?: Record<string, { readonly value: string }>;\n readonly base?: string;\n}\n\ntype DiscriminatorDeclaration = { readonly fieldName: string; readonly span: PslModel['span'] };\ntype BaseDeclaration = {\n readonly baseName: string;\n readonly value: string;\n readonly collectionName: string;\n readonly span: PslModel['span'];\n};\n\nfunction collectPolymorphismDeclarations(\n document: ParsePslDocumentResult,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): {\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n} {\n const discriminatorDeclarations = new Map<string, DiscriminatorDeclaration>();\n const baseDeclarations = new Map<string, BaseDeclaration>();\n\n for (const pslModel of document.ast.models) {\n for (const attr of pslModel.attributes) {\n if (attr.name === 'discriminator') {\n const fieldName = getPositionalArgument(attr);\n if (!fieldName) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@discriminator requires a field name argument`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const discField = pslModel.fields.find((f) => f.name === fieldName);\n if (discField && discField.typeName !== 'String') {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Discriminator field \"${fieldName}\" on model \"${pslModel.name}\" must be of type String, but is \"${discField.typeName}\"`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n discriminatorDeclarations.set(pslModel.name, { fieldName, span: attr.span });\n }\n if (attr.name === 'base') {\n const baseName = getPositionalArgument(attr, 0);\n const rawValue = getPositionalArgument(attr, 1);\n if (!baseName || !rawValue) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base requires two arguments: base model name and discriminator value`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const value = parseQuotedStringLiteral(rawValue);\n if (value === undefined) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base discriminator value must be a quoted string literal`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const collectionName = resolveCollectionName(pslModel);\n baseDeclarations.set(pslModel.name, { baseName, value, collectionName, span: attr.span });\n }\n }\n }\n\n return { discriminatorDeclarations, baseDeclarations };\n}\n\nfunction resolvePolymorphism(input: {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n document: ParsePslDocumentResult;\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n modelNames: ReadonlySet<string>;\n sourceId: string;\n}): {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n diagnostics: ContractSourceDiagnostic[];\n} {\n const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document } = input;\n let patched = input.models;\n let roots = input.roots;\n const diagnostics: ContractSourceDiagnostic[] = [];\n\n for (const [modelName, decl] of discriminatorDeclarations) {\n if (baseDeclarations.has(modelName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_AND_BASE',\n message: `Model \"${modelName}\" cannot have both @@discriminator and @@base`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const model = patched[modelName];\n if (!model) continue;\n\n if (!Object.hasOwn(model.fields, decl.fieldName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_FIELD_NOT_FOUND',\n message: `Discriminator field \"${decl.fieldName}\" is not a field on model \"${modelName}\"`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const variants: Record<string, { readonly value: string }> = {};\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (baseDecl.baseName !== modelName) continue;\n variants[variantName] = { value: baseDecl.value };\n }\n\n if (Object.keys(variants).length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_DISCRIMINATOR',\n message: `Model \"${modelName}\" has @@discriminator but no variant models declare @@base(${modelName}, ...)`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n patched = {\n ...patched,\n [modelName]: { ...model, discriminator: { field: decl.fieldName }, variants },\n };\n }\n\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (!modelNames.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_BASE_TARGET_NOT_FOUND',\n message: `Model \"${variantName}\" @@base references non-existent model \"${baseDecl.baseName}\"`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (!discriminatorDeclarations.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BASE',\n message: `Model \"${variantName}\" declares @@base(${baseDecl.baseName}, ...) but \"${baseDecl.baseName}\" has no @@discriminator`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (discriminatorDeclarations.has(variantName)) {\n continue;\n }\n\n const baseModel = patched[baseDecl.baseName];\n const variantPslModel = document.ast.models.find((m) => m.name === variantName);\n if (!variantPslModel) continue;\n const hasExplicitMap = getMapName(variantPslModel.attributes) !== undefined;\n\n if (hasExplicitMap && baseModel && baseDecl.collectionName !== baseModel.storage.collection) {\n diagnostics.push({\n code: 'PSL_MONGO_VARIANT_SEPARATE_COLLECTION',\n message: `Mongo variant \"${variantName}\" cannot use a different collection than its base \"${baseDecl.baseName}\". Mongo only supports single-collection polymorphism.`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n const baseCollection = baseModel?.storage.collection ?? baseDecl.collectionName;\n const variantModel = patched[variantName];\n if (variantModel) {\n patched = {\n ...patched,\n [variantName]: {\n ...variantModel,\n base: baseDecl.baseName,\n storage: { collection: baseCollection },\n },\n };\n }\n\n const variantCollectionName = resolveCollectionName(variantPslModel);\n if (roots[variantCollectionName] === variantName) {\n if (variantCollectionName === baseCollection && baseModel) {\n roots = { ...roots, [variantCollectionName]: baseDecl.baseName };\n } else {\n roots = Object.fromEntries(\n Object.entries(roots).filter(([key]) => key !== variantCollectionName),\n );\n }\n }\n }\n\n return { models: patched, roots, diagnostics };\n}\n\nfunction parseIndexDirection(raw: string | undefined): MongoIndexKeyDirection {\n if (!raw) return 1;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const num = Number(stripped);\n if (num === 1 || num === -1) return num;\n if (['text', '2dsphere', '2d', 'hashed'].includes(stripped))\n return stripped as MongoIndexKeyDirection;\n return 1;\n}\n\nfunction parseNumericArg(raw: string | undefined): number | undefined {\n if (!raw) return undefined;\n const n = Number(raw);\n return Number.isFinite(n) ? n : undefined;\n}\n\nfunction parseBooleanArg(raw: string | undefined): boolean | undefined {\n if (raw === 'true') return true;\n if (raw === 'false') return false;\n return undefined;\n}\n\nfunction parseJsonArg(raw: string | undefined): Record<string, unknown> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '').replace(/\\\\\"/g, '\"');\n try {\n const parsed = JSON.parse(stripped);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // not valid JSON\n }\n return undefined;\n}\n\nfunction parseCollation(\n attr: import('@prisma-next/psl-parser').PslAttribute,\n): Record<string, unknown> | null | undefined {\n const locale = stripQuotesHelper(getNamedArgument(attr, 'collationLocale'));\n if (!locale) {\n const hasAnyCollationArg =\n getNamedArgument(attr, 'collationStrength') != null ||\n getNamedArgument(attr, 'collationCaseLevel') != null ||\n getNamedArgument(attr, 'collationCaseFirst') != null ||\n getNamedArgument(attr, 'collationNumericOrdering') != null ||\n getNamedArgument(attr, 'collationAlternate') != null ||\n getNamedArgument(attr, 'collationMaxVariable') != null ||\n getNamedArgument(attr, 'collationBackwards') != null ||\n getNamedArgument(attr, 'collationNormalization') != null;\n return hasAnyCollationArg ? null : undefined;\n }\n\n const collation: Record<string, unknown> = { locale };\n const strength = parseNumericArg(getNamedArgument(attr, 'collationStrength'));\n if (strength != null) collation['strength'] = strength;\n const caseLevel = parseBooleanArg(getNamedArgument(attr, 'collationCaseLevel'));\n if (caseLevel != null) collation['caseLevel'] = caseLevel;\n const caseFirst = stripQuotesHelper(getNamedArgument(attr, 'collationCaseFirst'));\n if (caseFirst != null) collation['caseFirst'] = caseFirst;\n const numericOrdering = parseBooleanArg(getNamedArgument(attr, 'collationNumericOrdering'));\n if (numericOrdering != null) collation['numericOrdering'] = numericOrdering;\n const alternate = stripQuotesHelper(getNamedArgument(attr, 'collationAlternate'));\n if (alternate != null) collation['alternate'] = alternate;\n const maxVariable = stripQuotesHelper(getNamedArgument(attr, 'collationMaxVariable'));\n if (maxVariable != null) collation['maxVariable'] = maxVariable;\n const backwards = parseBooleanArg(getNamedArgument(attr, 'collationBackwards'));\n if (backwards != null) collation['backwards'] = backwards;\n const normalization = parseBooleanArg(getNamedArgument(attr, 'collationNormalization'));\n if (normalization != null) collation['normalization'] = normalization;\n return collation;\n}\n\nfunction stripQuotesHelper(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n return raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n}\n\nfunction parseProjectionList(\n raw: string | undefined,\n value: 0 | 1,\n): Record<string, 0 | 1> | undefined {\n if (!raw) return undefined;\n const stripped = raw.replace(/^[\"']/, '').replace(/[\"']$/, '');\n const inner = stripped.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return undefined;\n const fields = inner\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n const result: Record<string, 0 | 1> = {};\n for (const f of fields) {\n result[f] = value;\n }\n return result;\n}\n\nfunction collectIndexes(\n pslModel: PslModel,\n fieldMappings: FieldMappings,\n modelNames: ReadonlySet<string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): MongoStorageIndex[] {\n const indexes: MongoStorageIndex[] = [];\n let textIndexCount = 0;\n\n for (const field of pslModel.fields) {\n if (modelNames.has(field.typeName)) continue;\n const uniqueAttr = getAttribute(field.attributes, 'unique');\n if (!uniqueAttr) continue;\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n indexes.push({\n keys: [{ field: mappedName, direction: 1 }],\n unique: true,\n });\n }\n\n for (const attr of pslModel.attributes) {\n const isIndex = attr.name === 'index';\n const isUnique = attr.name === 'unique';\n const isTextIndex = attr.name === 'textIndex';\n if (!isIndex && !isUnique && !isTextIndex) continue;\n\n const fieldsArg = getPositionalArgument(attr, 0);\n if (!fieldsArg) continue;\n const parsedFields = parseIndexFieldList(fieldsArg);\n if (parsedFields.length === 0) continue;\n\n const hasWildcard = parsedFields.some((f) => f.isWildcard);\n const wildcardCount = parsedFields.filter((f) => f.isWildcard).length;\n\n if (wildcardCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'An index can contain at most one wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isUnique && hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Unique indexes cannot use wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (isTextIndex) {\n textIndexCount++;\n if (textIndexCount > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `Only one @@textIndex is allowed per collection (model \"${pslModel.name}\")`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n }\n\n const typeArg = getNamedArgument(attr, 'type');\n const defaultDirection: MongoIndexKeyDirection = isTextIndex\n ? 'text'\n : parseIndexDirection(typeArg);\n\n if (\n hasWildcard &&\n typeof defaultDirection === 'string' &&\n ['hashed', '2dsphere', '2d'].includes(defaultDirection)\n ) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if (defaultDirection === 'hashed' && parsedFields.length > 1) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Hashed indexes must have exactly one field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const keys = parsedFields.map((pf) => {\n const mappedName = pf.isWildcard\n ? pf.name.replace(/^(.+)\\.\\$\\*\\*$/, (_, prefix: string) => {\n const mapped = fieldMappings.pslNameToMapped.get(prefix);\n return mapped ? `${mapped}.$**` : `${prefix}.$**`;\n })\n : (fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name);\n const direction: MongoIndexKeyDirection =\n pf.direction != null ? (pf.direction as MongoIndexKeyDirection) : defaultDirection;\n return { field: mappedName, direction };\n });\n\n const unique = isUnique ? true : undefined;\n const sparse = isTextIndex ? undefined : parseBooleanArg(getNamedArgument(attr, 'sparse'));\n const expireAfterSeconds = isTextIndex\n ? undefined\n : parseNumericArg(getNamedArgument(attr, 'expireAfterSeconds'));\n\n if (hasWildcard && expireAfterSeconds != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'expireAfterSeconds cannot be combined with wildcard() fields',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const partialFilterExpression = parseJsonArg(getNamedArgument(attr, 'filter'));\n\n const includeArg = getNamedArgument(attr, 'include');\n const excludeArg = getNamedArgument(attr, 'exclude');\n\n if (includeArg != null && excludeArg != null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'Cannot specify both include and exclude on the same index',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n if ((includeArg != null || excludeArg != null) && !hasWildcard) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message:\n 'include/exclude options are only valid when the index contains a wildcard() field',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const wildcardProjection =\n includeArg != null\n ? parseProjectionList(includeArg, 1)\n : excludeArg != null\n ? parseProjectionList(excludeArg, 0)\n : undefined;\n\n const collation = parseCollation(attr);\n if (collation === null) {\n diagnostics.push({\n code: 'PSL_INVALID_INDEX',\n message: 'collationLocale is required when using collation options',\n sourceId,\n span: attr.span,\n });\n continue;\n }\n\n const rawWeights = parseJsonArg(getNamedArgument(attr, 'weights'));\n let weights: Record<string, number> | undefined;\n if (rawWeights) {\n weights = {};\n for (const [k, v] of Object.entries(rawWeights)) {\n if (typeof v === 'number') weights[k] = v;\n }\n }\n\n const rawDefaultLang = isTextIndex\n ? getNamedArgument(attr, 'language')\n : getNamedArgument(attr, 'default_language');\n const default_language = stripQuotesHelper(rawDefaultLang);\n\n const rawLangOverride = getNamedArgument(attr, 'languageOverride');\n const language_override = stripQuotesHelper(rawLangOverride);\n\n const index: MongoStorageIndex = {\n keys,\n ...(unique != null && { unique }),\n ...(sparse != null && { sparse }),\n ...(expireAfterSeconds != null && { expireAfterSeconds }),\n ...(partialFilterExpression != null && { partialFilterExpression }),\n ...(wildcardProjection != null && { wildcardProjection }),\n ...(collation != null && { collation }),\n ...(weights != null && { weights }),\n ...(default_language != null && { default_language }),\n ...(language_override != null && { language_override }),\n };\n\n indexes.push(index);\n }\n\n return indexes;\n}\n\nfunction isRelationField(field: PslField, modelNames: ReadonlySet<string>): boolean {\n return modelNames.has(field.typeName);\n}\n\nfunction resolveFieldCodecId(\n field: PslField,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n): string | undefined {\n return scalarTypeDescriptors.get(field.typeName);\n}\n\nfunction resolveNonRelationField(\n field: PslField,\n ownerName: string,\n compositeTypeNames: ReadonlySet<string>,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): ContractField | undefined {\n if (compositeTypeNames.has(field.typeName)) {\n const result: ContractField = {\n type: { kind: 'valueObject', name: field.typeName },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n }\n\n const codecId = resolveFieldCodecId(field, scalarTypeDescriptors);\n if (!codecId) {\n diagnostics.push({\n code: 'PSL_UNSUPPORTED_FIELD_TYPE',\n message: `Field \"${ownerName}.${field.name}\" type \"${field.typeName}\" is not supported in Mongo PSL interpreter`,\n sourceId,\n span: field.span,\n });\n return undefined;\n }\n\n const result: ContractField = {\n type: { kind: 'scalar', codecId },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n}\n\nexport function interpretPslDocumentToMongoContract(\n input: InterpretPslDocumentToMongoContractInput,\n): Result<Contract, ContractSourceDiagnostics> {\n const { document, scalarTypeDescriptors } = input;\n const sourceId = document.ast.sourceId;\n const diagnostics: ContractSourceDiagnostic[] = [];\n const modelNames = new Set(document.ast.models.map((m) => m.name));\n const compositeTypeNames = new Set(document.ast.compositeTypes.map((ct) => ct.name));\n\n const models: Record<string, MongoModelEntry> = {};\n const collections: Record<string, Record<string, unknown>> = {};\n const roots: Record<string, string> = {};\n const allFkRelations: FkRelation[] = [];\n\n interface BackrelationCandidate {\n readonly modelName: string;\n readonly fieldName: string;\n readonly targetModelName: string;\n readonly relationName?: string;\n readonly cardinality: '1:1' | '1:N';\n readonly field: PslField;\n }\n const backrelationCandidates: BackrelationCandidate[] = [];\n\n for (const pslModel of document.ast.models) {\n const collectionName = resolveCollectionName(pslModel);\n const fieldMappings = resolveFieldMappings(pslModel);\n\n const fields: Record<string, ContractField> = {};\n const relations: Record<string, ContractReferenceRelation> = {};\n\n for (const field of pslModel.fields) {\n if (isRelationField(field, modelNames)) {\n const relation = parseRelationAttribute(field.attributes);\n\n if (field.list || !(relation?.fields && relation?.references)) {\n backrelationCandidates.push({\n modelName: pslModel.name,\n fieldName: field.name,\n targetModelName: field.typeName,\n ...(relation?.relationName !== undefined\n ? { relationName: relation.relationName }\n : {}),\n cardinality: field.list ? '1:N' : '1:1',\n field,\n });\n continue;\n }\n\n if (relation?.fields && relation?.references) {\n const localMapped = relation.fields.map((f) => fieldMappings.pslNameToMapped.get(f) ?? f);\n\n const targetModel = document.ast.models.find((m) => m.name === field.typeName);\n const targetFieldMappings = targetModel ? resolveFieldMappings(targetModel) : undefined;\n const targetMapped = relation.references.map(\n (f) => targetFieldMappings?.pslNameToMapped.get(f) ?? f,\n );\n\n relations[field.name] = {\n to: field.typeName,\n cardinality: 'N:1' as const,\n on: {\n localFields: localMapped,\n targetFields: targetMapped,\n },\n };\n\n allFkRelations.push({\n declaringModel: pslModel.name,\n fieldName: field.name,\n targetModel: field.typeName,\n ...(relation.relationName !== undefined ? { relationName: relation.relationName } : {}),\n localFields: localMapped,\n targetFields: targetMapped,\n });\n }\n continue;\n }\n\n const resolved = resolveNonRelationField(\n field,\n pslModel.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n fields[mappedName] = resolved;\n }\n\n const isVariantModel = pslModel.attributes.some((attr) => attr.name === 'base');\n const hasIdField = pslModel.fields.some((f) => getAttribute(f.attributes, 'id') !== undefined);\n if (!hasIdField && !isVariantModel) {\n diagnostics.push({\n code: 'PSL_MISSING_ID_FIELD',\n message: `Model \"${pslModel.name}\" has no field with @id attribute. Every model must have exactly one @id field.`,\n sourceId,\n });\n }\n\n models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };\n const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);\n collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};\n roots[collectionName] = pslModel.name;\n }\n\n const valueObjects: Record<string, ContractValueObject> = {};\n for (const compositeType of document.ast.compositeTypes) {\n const fields: Record<string, ContractField> = {};\n for (const field of compositeType.fields) {\n const resolved = resolveNonRelationField(\n field,\n compositeType.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n fields[field.name] = resolved;\n }\n valueObjects[compositeType.name] = { fields };\n }\n\n for (const [, modelEntry] of Object.entries(models)) {\n const collectionName = modelEntry.storage.collection;\n const coll = collections[collectionName];\n if (coll) {\n const validator = deriveJsonSchema(modelEntry.fields, valueObjects);\n coll['validator'] = validator;\n }\n }\n\n const fkRelationsByPair = new Map<string, FkRelation[]>();\n for (const fk of allFkRelations) {\n const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);\n const existing = fkRelationsByPair.get(key);\n if (existing) {\n existing.push(fk);\n } else {\n fkRelationsByPair.set(key, [fk]);\n }\n }\n\n for (const candidate of backrelationCandidates) {\n const pairKey = fkRelationPairKey(candidate.targetModelName, candidate.modelName);\n const pairMatches = fkRelationsByPair.get(pairKey) ?? [];\n const matches = candidate.relationName\n ? pairMatches.filter((r) => r.relationName === candidate.relationName)\n : [...pairMatches];\n\n if (matches.length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" 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.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n if (matches.length > 1) {\n diagnostics.push({\n code: 'PSL_AMBIGUOUS_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" matches multiple FK-side relations on model \"${candidate.targetModelName}\". Add @relation(\"...\") to both sides to disambiguate.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n\n const fk = matches[0];\n if (!fk) continue;\n const modelEntry = models[candidate.modelName];\n if (!modelEntry) continue;\n modelEntry.relations[candidate.fieldName] = {\n to: candidate.targetModelName,\n cardinality: candidate.cardinality,\n on: {\n localFields: fk.targetFields,\n targetFields: fk.localFields,\n },\n };\n }\n\n const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(\n document,\n sourceId,\n diagnostics,\n );\n const polyResult = resolvePolymorphism({\n models,\n roots,\n document,\n discriminatorDeclarations,\n baseDeclarations,\n modelNames,\n sourceId,\n });\n\n if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) {\n return notOk({\n summary: 'PSL to Mongo contract interpretation failed',\n diagnostics: [...diagnostics, ...polyResult.diagnostics],\n });\n }\n\n const target = 'mongo';\n const targetFamily = 'mongo';\n const storageWithoutHash = { collections };\n const storageHash = computeStorageHash({ target, targetFamily, storage: storageWithoutHash });\n const capabilities: Record<string, Record<string, boolean>> = {};\n\n return ok({\n targetFamily,\n target,\n roots: polyResult.roots,\n models: polyResult.models,\n ...(Object.keys(valueObjects).length > 0 ? { valueObjects } : {}),\n storage: { ...storageWithoutHash, storageHash },\n extensionPacks: {},\n capabilities,\n profileHash: computeProfileHash({ target, targetFamily, capabilities }),\n meta: {},\n });\n}\n","export function createMongoScalarTypeDescriptors(): ReadonlyMap<string, string> {\n return new Map<string, string>([\n ['String', 'mongo/string@1'],\n ['Int', 'mongo/int32@1'],\n ['Boolean', 'mongo/bool@1'],\n ['DateTime', 'mongo/date@1'],\n ['ObjectId', 'mongo/objectId@1'],\n ]);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,22 +1,23 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo-contract-psl",
3
- "version": "0.3.0-dev.147",
3
+ "version": "0.3.0-dev.162",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "PSL-to-Mongo ContractIR interpreter for Prisma Next",
7
7
  "dependencies": {
8
8
  "pathe": "^2.0.3",
9
- "@prisma-next/config": "0.3.0-dev.147",
10
- "@prisma-next/contract": "0.3.0-dev.147",
11
- "@prisma-next/psl-parser": "0.3.0-dev.147",
12
- "@prisma-next/utils": "0.3.0-dev.147"
9
+ "@prisma-next/config": "0.3.0-dev.162",
10
+ "@prisma-next/contract": "0.3.0-dev.162",
11
+ "@prisma-next/mongo-contract": "0.3.0-dev.162",
12
+ "@prisma-next/psl-parser": "0.3.0-dev.162",
13
+ "@prisma-next/utils": "0.3.0-dev.162"
13
14
  },
14
15
  "devDependencies": {
15
16
  "tsdown": "0.18.4",
16
17
  "typescript": "5.9.3",
17
18
  "vitest": "4.0.17",
18
- "@prisma-next/tsdown": "0.0.0",
19
- "@prisma-next/tsconfig": "0.0.0"
19
+ "@prisma-next/tsconfig": "0.0.0",
20
+ "@prisma-next/tsdown": "0.0.0"
20
21
  },
21
22
  "files": [
22
23
  "dist",
@@ -0,0 +1,83 @@
1
+ import type { ContractField, ContractValueObject } from '@prisma-next/contract/types';
2
+ import type { MongoStorageValidator } from '@prisma-next/mongo-contract';
3
+
4
+ const CODEC_TO_BSON_TYPE: Record<string, string> = {
5
+ 'mongo/string@1': 'string',
6
+ 'mongo/int32@1': 'int',
7
+ 'mongo/bool@1': 'bool',
8
+ 'mongo/date@1': 'date',
9
+ 'mongo/objectId@1': 'objectId',
10
+ };
11
+
12
+ function fieldToBsonSchema(
13
+ field: ContractField,
14
+ valueObjects: Record<string, ContractValueObject> | undefined,
15
+ ): Record<string, unknown> | undefined {
16
+ if (field.type.kind === 'scalar') {
17
+ const bsonType = CODEC_TO_BSON_TYPE[field.type.codecId];
18
+ if (!bsonType) return undefined;
19
+
20
+ if ('many' in field && field.many) {
21
+ return { bsonType: 'array', items: { bsonType } };
22
+ }
23
+
24
+ if (field.nullable) {
25
+ return { bsonType: ['null', bsonType] };
26
+ }
27
+
28
+ return { bsonType };
29
+ }
30
+
31
+ if (field.type.kind === 'valueObject') {
32
+ const vo = valueObjects?.[field.type.name];
33
+ if (!vo) return undefined;
34
+ const voSchema = deriveObjectSchema(vo.fields, valueObjects);
35
+ if ('many' in field && field.many) {
36
+ return { bsonType: 'array', items: voSchema };
37
+ }
38
+ if (field.nullable) {
39
+ return { oneOf: [{ bsonType: 'null' }, voSchema] };
40
+ }
41
+ return voSchema;
42
+ }
43
+
44
+ return undefined;
45
+ }
46
+
47
+ function deriveObjectSchema(
48
+ fields: Record<string, ContractField>,
49
+ valueObjects: Record<string, ContractValueObject> | undefined,
50
+ ): Record<string, unknown> {
51
+ const properties: Record<string, unknown> = {};
52
+ const required: string[] = [];
53
+
54
+ for (const [fieldName, field] of Object.entries(fields)) {
55
+ const schema = fieldToBsonSchema(field, valueObjects);
56
+ if (schema) {
57
+ properties[fieldName] = schema;
58
+ if (!field.nullable) {
59
+ required.push(fieldName);
60
+ }
61
+ }
62
+ }
63
+
64
+ const result: Record<string, unknown> = {
65
+ bsonType: 'object',
66
+ properties,
67
+ };
68
+ if (required.length > 0) {
69
+ result['required'] = required.sort();
70
+ }
71
+ return result;
72
+ }
73
+
74
+ export function deriveJsonSchema(
75
+ fields: Record<string, ContractField>,
76
+ valueObjects?: Record<string, ContractValueObject>,
77
+ ): MongoStorageValidator {
78
+ return {
79
+ jsonSchema: deriveObjectSchema(fields, valueObjects),
80
+ validationLevel: 'strict',
81
+ validationAction: 'error',
82
+ };
83
+ }
@@ -9,13 +9,17 @@ import type {
9
9
  ContractReferenceRelation,
10
10
  ContractValueObject,
11
11
  } from '@prisma-next/contract/types';
12
+ import type { MongoIndexKeyDirection, MongoStorageIndex } from '@prisma-next/mongo-contract';
12
13
  import type { ParsePslDocumentResult, PslField, PslModel } from '@prisma-next/psl-parser';
13
14
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
15
+ import { deriveJsonSchema } from './derive-json-schema';
14
16
  import {
15
17
  getAttribute,
16
18
  getMapName,
19
+ getNamedArgument,
17
20
  getPositionalArgument,
18
21
  lowerFirst,
22
+ parseIndexFieldList,
19
23
  parseQuotedStringLiteral,
20
24
  parseRelationAttribute,
21
25
  } from './psl-helpers';
@@ -271,6 +275,319 @@ function resolvePolymorphism(input: {
271
275
  return { models: patched, roots, diagnostics };
272
276
  }
273
277
 
278
+ function parseIndexDirection(raw: string | undefined): MongoIndexKeyDirection {
279
+ if (!raw) return 1;
280
+ const stripped = raw.replace(/^["']/, '').replace(/["']$/, '');
281
+ const num = Number(stripped);
282
+ if (num === 1 || num === -1) return num;
283
+ if (['text', '2dsphere', '2d', 'hashed'].includes(stripped))
284
+ return stripped as MongoIndexKeyDirection;
285
+ return 1;
286
+ }
287
+
288
+ function parseNumericArg(raw: string | undefined): number | undefined {
289
+ if (!raw) return undefined;
290
+ const n = Number(raw);
291
+ return Number.isFinite(n) ? n : undefined;
292
+ }
293
+
294
+ function parseBooleanArg(raw: string | undefined): boolean | undefined {
295
+ if (raw === 'true') return true;
296
+ if (raw === 'false') return false;
297
+ return undefined;
298
+ }
299
+
300
+ function parseJsonArg(raw: string | undefined): Record<string, unknown> | undefined {
301
+ if (!raw) return undefined;
302
+ const stripped = raw.replace(/^["']/, '').replace(/["']$/, '').replace(/\\"/g, '"');
303
+ try {
304
+ const parsed = JSON.parse(stripped);
305
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
306
+ return parsed as Record<string, unknown>;
307
+ }
308
+ } catch {
309
+ // not valid JSON
310
+ }
311
+ return undefined;
312
+ }
313
+
314
+ function parseCollation(
315
+ attr: import('@prisma-next/psl-parser').PslAttribute,
316
+ ): Record<string, unknown> | null | undefined {
317
+ const locale = stripQuotesHelper(getNamedArgument(attr, 'collationLocale'));
318
+ if (!locale) {
319
+ const hasAnyCollationArg =
320
+ getNamedArgument(attr, 'collationStrength') != null ||
321
+ getNamedArgument(attr, 'collationCaseLevel') != null ||
322
+ getNamedArgument(attr, 'collationCaseFirst') != null ||
323
+ getNamedArgument(attr, 'collationNumericOrdering') != null ||
324
+ getNamedArgument(attr, 'collationAlternate') != null ||
325
+ getNamedArgument(attr, 'collationMaxVariable') != null ||
326
+ getNamedArgument(attr, 'collationBackwards') != null ||
327
+ getNamedArgument(attr, 'collationNormalization') != null;
328
+ return hasAnyCollationArg ? null : undefined;
329
+ }
330
+
331
+ const collation: Record<string, unknown> = { locale };
332
+ const strength = parseNumericArg(getNamedArgument(attr, 'collationStrength'));
333
+ if (strength != null) collation['strength'] = strength;
334
+ const caseLevel = parseBooleanArg(getNamedArgument(attr, 'collationCaseLevel'));
335
+ if (caseLevel != null) collation['caseLevel'] = caseLevel;
336
+ const caseFirst = stripQuotesHelper(getNamedArgument(attr, 'collationCaseFirst'));
337
+ if (caseFirst != null) collation['caseFirst'] = caseFirst;
338
+ const numericOrdering = parseBooleanArg(getNamedArgument(attr, 'collationNumericOrdering'));
339
+ if (numericOrdering != null) collation['numericOrdering'] = numericOrdering;
340
+ const alternate = stripQuotesHelper(getNamedArgument(attr, 'collationAlternate'));
341
+ if (alternate != null) collation['alternate'] = alternate;
342
+ const maxVariable = stripQuotesHelper(getNamedArgument(attr, 'collationMaxVariable'));
343
+ if (maxVariable != null) collation['maxVariable'] = maxVariable;
344
+ const backwards = parseBooleanArg(getNamedArgument(attr, 'collationBackwards'));
345
+ if (backwards != null) collation['backwards'] = backwards;
346
+ const normalization = parseBooleanArg(getNamedArgument(attr, 'collationNormalization'));
347
+ if (normalization != null) collation['normalization'] = normalization;
348
+ return collation;
349
+ }
350
+
351
+ function stripQuotesHelper(raw: string | undefined): string | undefined {
352
+ if (!raw) return undefined;
353
+ return raw.replace(/^["']/, '').replace(/["']$/, '');
354
+ }
355
+
356
+ function parseProjectionList(
357
+ raw: string | undefined,
358
+ value: 0 | 1,
359
+ ): Record<string, 0 | 1> | undefined {
360
+ if (!raw) return undefined;
361
+ const stripped = raw.replace(/^["']/, '').replace(/["']$/, '');
362
+ const inner = stripped.replace(/^\[/, '').replace(/\]$/, '').trim();
363
+ if (inner.length === 0) return undefined;
364
+ const fields = inner
365
+ .split(',')
366
+ .map((s) => s.trim())
367
+ .filter((s) => s.length > 0);
368
+ const result: Record<string, 0 | 1> = {};
369
+ for (const f of fields) {
370
+ result[f] = value;
371
+ }
372
+ return result;
373
+ }
374
+
375
+ function collectIndexes(
376
+ pslModel: PslModel,
377
+ fieldMappings: FieldMappings,
378
+ modelNames: ReadonlySet<string>,
379
+ sourceId: string,
380
+ diagnostics: ContractSourceDiagnostic[],
381
+ ): MongoStorageIndex[] {
382
+ const indexes: MongoStorageIndex[] = [];
383
+ let textIndexCount = 0;
384
+
385
+ for (const field of pslModel.fields) {
386
+ if (modelNames.has(field.typeName)) continue;
387
+ const uniqueAttr = getAttribute(field.attributes, 'unique');
388
+ if (!uniqueAttr) continue;
389
+ const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;
390
+ indexes.push({
391
+ keys: [{ field: mappedName, direction: 1 }],
392
+ unique: true,
393
+ });
394
+ }
395
+
396
+ for (const attr of pslModel.attributes) {
397
+ const isIndex = attr.name === 'index';
398
+ const isUnique = attr.name === 'unique';
399
+ const isTextIndex = attr.name === 'textIndex';
400
+ if (!isIndex && !isUnique && !isTextIndex) continue;
401
+
402
+ const fieldsArg = getPositionalArgument(attr, 0);
403
+ if (!fieldsArg) continue;
404
+ const parsedFields = parseIndexFieldList(fieldsArg);
405
+ if (parsedFields.length === 0) continue;
406
+
407
+ const hasWildcard = parsedFields.some((f) => f.isWildcard);
408
+ const wildcardCount = parsedFields.filter((f) => f.isWildcard).length;
409
+
410
+ if (wildcardCount > 1) {
411
+ diagnostics.push({
412
+ code: 'PSL_INVALID_INDEX',
413
+ message: 'An index can contain at most one wildcard() field',
414
+ sourceId,
415
+ span: attr.span,
416
+ });
417
+ continue;
418
+ }
419
+
420
+ if (isUnique && hasWildcard) {
421
+ diagnostics.push({
422
+ code: 'PSL_INVALID_INDEX',
423
+ message: 'Unique indexes cannot use wildcard() fields',
424
+ sourceId,
425
+ span: attr.span,
426
+ });
427
+ continue;
428
+ }
429
+
430
+ if (isTextIndex) {
431
+ textIndexCount++;
432
+ if (textIndexCount > 1) {
433
+ diagnostics.push({
434
+ code: 'PSL_INVALID_INDEX',
435
+ message: `Only one @@textIndex is allowed per collection (model "${pslModel.name}")`,
436
+ sourceId,
437
+ span: attr.span,
438
+ });
439
+ continue;
440
+ }
441
+
442
+ if (hasWildcard) {
443
+ diagnostics.push({
444
+ code: 'PSL_INVALID_INDEX',
445
+ message:
446
+ 'wildcard() fields cannot be combined with type: hashed/2dsphere/2d or @@textIndex',
447
+ sourceId,
448
+ span: attr.span,
449
+ });
450
+ continue;
451
+ }
452
+ }
453
+
454
+ const typeArg = getNamedArgument(attr, 'type');
455
+ const defaultDirection: MongoIndexKeyDirection = isTextIndex
456
+ ? 'text'
457
+ : parseIndexDirection(typeArg);
458
+
459
+ if (
460
+ hasWildcard &&
461
+ typeof defaultDirection === 'string' &&
462
+ ['hashed', '2dsphere', '2d'].includes(defaultDirection)
463
+ ) {
464
+ diagnostics.push({
465
+ code: 'PSL_INVALID_INDEX',
466
+ message: `wildcard() fields cannot be combined with type: ${defaultDirection}`,
467
+ sourceId,
468
+ span: attr.span,
469
+ });
470
+ continue;
471
+ }
472
+
473
+ if (defaultDirection === 'hashed' && parsedFields.length > 1) {
474
+ diagnostics.push({
475
+ code: 'PSL_INVALID_INDEX',
476
+ message: 'Hashed indexes must have exactly one field',
477
+ sourceId,
478
+ span: attr.span,
479
+ });
480
+ continue;
481
+ }
482
+
483
+ const keys = parsedFields.map((pf) => {
484
+ const mappedName = pf.isWildcard
485
+ ? pf.name.replace(/^(.+)\.\$\*\*$/, (_, prefix: string) => {
486
+ const mapped = fieldMappings.pslNameToMapped.get(prefix);
487
+ return mapped ? `${mapped}.$**` : `${prefix}.$**`;
488
+ })
489
+ : (fieldMappings.pslNameToMapped.get(pf.name) ?? pf.name);
490
+ const direction: MongoIndexKeyDirection =
491
+ pf.direction != null ? (pf.direction as MongoIndexKeyDirection) : defaultDirection;
492
+ return { field: mappedName, direction };
493
+ });
494
+
495
+ const unique = isUnique ? true : undefined;
496
+ const sparse = isTextIndex ? undefined : parseBooleanArg(getNamedArgument(attr, 'sparse'));
497
+ const expireAfterSeconds = isTextIndex
498
+ ? undefined
499
+ : parseNumericArg(getNamedArgument(attr, 'expireAfterSeconds'));
500
+
501
+ if (hasWildcard && expireAfterSeconds != null) {
502
+ diagnostics.push({
503
+ code: 'PSL_INVALID_INDEX',
504
+ message: 'expireAfterSeconds cannot be combined with wildcard() fields',
505
+ sourceId,
506
+ span: attr.span,
507
+ });
508
+ continue;
509
+ }
510
+
511
+ const partialFilterExpression = parseJsonArg(getNamedArgument(attr, 'filter'));
512
+
513
+ const includeArg = getNamedArgument(attr, 'include');
514
+ const excludeArg = getNamedArgument(attr, 'exclude');
515
+
516
+ if (includeArg != null && excludeArg != null) {
517
+ diagnostics.push({
518
+ code: 'PSL_INVALID_INDEX',
519
+ message: 'Cannot specify both include and exclude on the same index',
520
+ sourceId,
521
+ span: attr.span,
522
+ });
523
+ continue;
524
+ }
525
+
526
+ if ((includeArg != null || excludeArg != null) && !hasWildcard) {
527
+ diagnostics.push({
528
+ code: 'PSL_INVALID_INDEX',
529
+ message:
530
+ 'include/exclude options are only valid when the index contains a wildcard() field',
531
+ sourceId,
532
+ span: attr.span,
533
+ });
534
+ continue;
535
+ }
536
+
537
+ const wildcardProjection =
538
+ includeArg != null
539
+ ? parseProjectionList(includeArg, 1)
540
+ : excludeArg != null
541
+ ? parseProjectionList(excludeArg, 0)
542
+ : undefined;
543
+
544
+ const collation = parseCollation(attr);
545
+ if (collation === null) {
546
+ diagnostics.push({
547
+ code: 'PSL_INVALID_INDEX',
548
+ message: 'collationLocale is required when using collation options',
549
+ sourceId,
550
+ span: attr.span,
551
+ });
552
+ continue;
553
+ }
554
+
555
+ const rawWeights = parseJsonArg(getNamedArgument(attr, 'weights'));
556
+ let weights: Record<string, number> | undefined;
557
+ if (rawWeights) {
558
+ weights = {};
559
+ for (const [k, v] of Object.entries(rawWeights)) {
560
+ if (typeof v === 'number') weights[k] = v;
561
+ }
562
+ }
563
+
564
+ const rawDefaultLang = isTextIndex
565
+ ? getNamedArgument(attr, 'language')
566
+ : getNamedArgument(attr, 'default_language');
567
+ const default_language = stripQuotesHelper(rawDefaultLang);
568
+
569
+ const rawLangOverride = getNamedArgument(attr, 'languageOverride');
570
+ const language_override = stripQuotesHelper(rawLangOverride);
571
+
572
+ const index: MongoStorageIndex = {
573
+ keys,
574
+ ...(unique != null && { unique }),
575
+ ...(sparse != null && { sparse }),
576
+ ...(expireAfterSeconds != null && { expireAfterSeconds }),
577
+ ...(partialFilterExpression != null && { partialFilterExpression }),
578
+ ...(wildcardProjection != null && { wildcardProjection }),
579
+ ...(collation != null && { collation }),
580
+ ...(weights != null && { weights }),
581
+ ...(default_language != null && { default_language }),
582
+ ...(language_override != null && { language_override }),
583
+ };
584
+
585
+ indexes.push(index);
586
+ }
587
+
588
+ return indexes;
589
+ }
590
+
274
591
  function isRelationField(field: PslField, modelNames: ReadonlySet<string>): boolean {
275
592
  return modelNames.has(field.typeName);
276
593
  }
@@ -420,7 +737,8 @@ export function interpretPslDocumentToMongoContract(
420
737
  }
421
738
 
422
739
  models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };
423
- collections[collectionName] = {};
740
+ const modelIndexes = collectIndexes(pslModel, fieldMappings, modelNames, sourceId, diagnostics);
741
+ collections[collectionName] = modelIndexes.length > 0 ? { indexes: modelIndexes } : {};
424
742
  roots[collectionName] = pslModel.name;
425
743
  }
426
744
 
@@ -442,6 +760,15 @@ export function interpretPslDocumentToMongoContract(
442
760
  valueObjects[compositeType.name] = { fields };
443
761
  }
444
762
 
763
+ for (const [, modelEntry] of Object.entries(models)) {
764
+ const collectionName = modelEntry.storage.collection;
765
+ const coll = collections[collectionName];
766
+ if (coll) {
767
+ const validator = deriveJsonSchema(modelEntry.fields, valueObjects);
768
+ coll['validator'] = validator;
769
+ }
770
+ }
771
+
445
772
  const fkRelationsByPair = new Map<string, FkRelation[]>();
446
773
  for (const fk of allFkRelations) {
447
774
  const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);
@@ -3,6 +3,69 @@ import { getPositionalArgument, parseQuotedStringLiteral } from '@prisma-next/ps
3
3
 
4
4
  export { getPositionalArgument, parseQuotedStringLiteral };
5
5
 
6
+ export function getNamedArgument(attr: PslAttribute, name: string): string | undefined {
7
+ const arg = attr.args.find((a) => a.kind === 'named' && a.name === name);
8
+ return arg?.value;
9
+ }
10
+
11
+ export function parseFieldList(value: string): readonly string[] {
12
+ const inner = value.replace(/^\[/, '').replace(/\]$/, '').trim();
13
+ if (inner.length === 0) return [];
14
+ return splitTopLevel(inner).map((s) => s.trim());
15
+ }
16
+
17
+ export interface ParsedIndexField {
18
+ readonly name: string;
19
+ readonly isWildcard: boolean;
20
+ readonly direction?: number;
21
+ }
22
+
23
+ export function parseIndexFieldList(value: string): readonly ParsedIndexField[] {
24
+ const segments = parseFieldList(value);
25
+ return segments.map(parseIndexFieldSegment);
26
+ }
27
+
28
+ function parseIndexFieldSegment(segment: string): ParsedIndexField {
29
+ const wildcardMatch = segment.match(/^wildcard\(\s*(.*?)\s*\)$/);
30
+ if (wildcardMatch) {
31
+ const scope = wildcardMatch[1] ?? '';
32
+ return {
33
+ name: scope.length > 0 ? `${scope}.$**` : '$**',
34
+ isWildcard: true,
35
+ };
36
+ }
37
+
38
+ const modifierMatch = segment.match(/^(\w+)\(\s*sort:\s*(\w+)\s*\)$/);
39
+ if (modifierMatch) {
40
+ const fieldName = modifierMatch[1] ?? segment;
41
+ const sortValue = modifierMatch[2];
42
+ return {
43
+ name: fieldName,
44
+ isWildcard: false,
45
+ direction: sortValue === 'Desc' ? -1 : 1,
46
+ };
47
+ }
48
+
49
+ return { name: segment, isWildcard: false };
50
+ }
51
+
52
+ function splitTopLevel(input: string): string[] {
53
+ const parts: string[] = [];
54
+ let depth = 0;
55
+ let start = 0;
56
+ for (let i = 0; i < input.length; i++) {
57
+ const ch = input[i];
58
+ if (ch === '(' || ch === '[' || ch === '{') depth++;
59
+ else if (ch === ')' || ch === ']' || ch === '}') depth = Math.max(0, depth - 1);
60
+ else if (ch === ',' && depth === 0) {
61
+ parts.push(input.slice(start, i));
62
+ start = i + 1;
63
+ }
64
+ }
65
+ parts.push(input.slice(start));
66
+ return parts;
67
+ }
68
+
6
69
  export function lowerFirst(value: string): string {
7
70
  if (value.length === 0) return value;
8
71
  return value[0]?.toLowerCase() + value.slice(1);
@@ -61,12 +124,6 @@ export function parseRelationAttribute(
61
124
  };
62
125
  }
63
126
 
64
- function parseFieldList(value: string): readonly string[] {
65
- const inner = value.replace(/^\[/, '').replace(/\]$/, '').trim();
66
- if (inner.length === 0) return [];
67
- return inner.split(',').map((s) => s.trim());
68
- }
69
-
70
127
  function stripQuotes(value: string): string {
71
128
  if (value.startsWith('"') && value.endsWith('"')) {
72
129
  return value.slice(1, -1);
@@ -1 +0,0 @@
1
- {"version":3,"file":"scalar-type-descriptors-Bou6SVVa.mjs","names":["relationName: string | undefined","fieldsArg: PslAttributeArgument | undefined","referencesArg: PslAttributeArgument | undefined","diagnostics: ContractSourceDiagnostic[]","variants: Record<string, { readonly value: string }>","result: ContractField","result","models: Record<string, MongoModelEntry>","collections: Record<string, Record<string, unknown>>","roots: Record<string, string>","allFkRelations: FkRelation[]","backrelationCandidates: BackrelationCandidate[]","fields: Record<string, ContractField>","relations: Record<string, ContractReferenceRelation>","valueObjects: Record<string, ContractValueObject>","capabilities: Record<string, Record<string, boolean>>"],"sources":["../src/psl-helpers.ts","../src/interpreter.ts","../src/scalar-type-descriptors.ts"],"sourcesContent":["import type { PslAttribute, PslAttributeArgument } from '@prisma-next/psl-parser';\nimport { getPositionalArgument, parseQuotedStringLiteral } from '@prisma-next/psl-parser';\n\nexport { getPositionalArgument, parseQuotedStringLiteral };\n\nexport function lowerFirst(value: string): string {\n if (value.length === 0) return value;\n return value[0]?.toLowerCase() + value.slice(1);\n}\n\nexport function getAttribute(\n attributes: readonly PslAttribute[],\n name: string,\n): PslAttribute | undefined {\n return attributes.find((attr) => attr.name === name);\n}\n\nexport function getMapName(attributes: readonly PslAttribute[]): string | undefined {\n const mapAttr = getAttribute(attributes, 'map');\n if (!mapAttr) return undefined;\n const arg = mapAttr.args[0];\n if (!arg) return undefined;\n return stripQuotes(arg.value);\n}\n\nexport interface ParsedRelationAttribute {\n readonly relationName?: string;\n readonly fields?: readonly string[];\n readonly references?: readonly string[];\n}\n\nexport function parseRelationAttribute(\n attributes: readonly PslAttribute[],\n): ParsedRelationAttribute | undefined {\n const relationAttr = getAttribute(attributes, 'relation');\n if (!relationAttr) return undefined;\n\n let relationName: string | undefined;\n let fieldsArg: PslAttributeArgument | undefined;\n let referencesArg: PslAttributeArgument | undefined;\n\n for (const arg of relationAttr.args) {\n if (arg.kind === 'positional') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'name') {\n relationName = stripQuotes(arg.value);\n } else if (arg.name === 'fields') {\n fieldsArg = arg;\n } else if (arg.name === 'references') {\n referencesArg = arg;\n }\n }\n\n const fields = fieldsArg ? parseFieldList(fieldsArg.value) : undefined;\n const references = referencesArg ? parseFieldList(referencesArg.value) : undefined;\n\n return {\n ...(relationName !== undefined ? { relationName } : {}),\n ...(fields !== undefined ? { fields } : {}),\n ...(references !== undefined ? { references } : {}),\n };\n}\n\nfunction parseFieldList(value: string): readonly string[] {\n const inner = value.replace(/^\\[/, '').replace(/\\]$/, '').trim();\n if (inner.length === 0) return [];\n return inner.split(',').map((s) => s.trim());\n}\n\nfunction stripQuotes(value: string): string {\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return value.slice(1, -1);\n }\n return value;\n}\n","import type {\n ContractSourceDiagnostic,\n ContractSourceDiagnostics,\n} from '@prisma-next/config/config-types';\nimport { computeProfileHash, computeStorageHash } from '@prisma-next/contract/hashing';\nimport type {\n Contract,\n ContractField,\n ContractReferenceRelation,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { ParsePslDocumentResult, PslField, PslModel } from '@prisma-next/psl-parser';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport {\n getAttribute,\n getMapName,\n getPositionalArgument,\n lowerFirst,\n parseQuotedStringLiteral,\n parseRelationAttribute,\n} from './psl-helpers';\n\nexport interface InterpretPslDocumentToMongoContractInput {\n readonly document: ParsePslDocumentResult;\n readonly scalarTypeDescriptors: ReadonlyMap<string, string>;\n}\n\ninterface FieldMappings {\n readonly pslNameToMapped: Map<string, string>;\n}\n\ninterface FkRelation {\n readonly declaringModel: string;\n readonly fieldName: string;\n readonly targetModel: string;\n readonly relationName?: string;\n readonly localFields: readonly string[];\n readonly targetFields: readonly string[];\n}\n\nfunction fkRelationPairKey(declaringModel: string, targetModel: string): string {\n return `${declaringModel}::${targetModel}`;\n}\n\nfunction resolveFieldMappings(model: PslModel): FieldMappings {\n const pslNameToMapped = new Map<string, string>();\n for (const field of model.fields) {\n const mapped = getMapName(field.attributes) ?? field.name;\n pslNameToMapped.set(field.name, mapped);\n }\n return { pslNameToMapped };\n}\n\nfunction resolveCollectionName(model: PslModel): string {\n return getMapName(model.attributes) ?? lowerFirst(model.name);\n}\n\ninterface MongoModelEntry {\n readonly fields: Record<string, ContractField>;\n readonly relations: Record<string, ContractReferenceRelation>;\n readonly storage: { readonly collection: string };\n readonly discriminator?: { readonly field: string };\n readonly variants?: Record<string, { readonly value: string }>;\n readonly base?: string;\n}\n\ntype DiscriminatorDeclaration = { readonly fieldName: string; readonly span: PslModel['span'] };\ntype BaseDeclaration = {\n readonly baseName: string;\n readonly value: string;\n readonly collectionName: string;\n readonly span: PslModel['span'];\n};\n\nfunction collectPolymorphismDeclarations(\n document: ParsePslDocumentResult,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): {\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n} {\n const discriminatorDeclarations = new Map<string, DiscriminatorDeclaration>();\n const baseDeclarations = new Map<string, BaseDeclaration>();\n\n for (const pslModel of document.ast.models) {\n for (const attr of pslModel.attributes) {\n if (attr.name === 'discriminator') {\n const fieldName = getPositionalArgument(attr);\n if (!fieldName) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@discriminator requires a field name argument`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const discField = pslModel.fields.find((f) => f.name === fieldName);\n if (discField && discField.typeName !== 'String') {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Discriminator field \"${fieldName}\" on model \"${pslModel.name}\" must be of type String, but is \"${discField.typeName}\"`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n discriminatorDeclarations.set(pslModel.name, { fieldName, span: attr.span });\n }\n if (attr.name === 'base') {\n const baseName = getPositionalArgument(attr, 0);\n const rawValue = getPositionalArgument(attr, 1);\n if (!baseName || !rawValue) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base requires two arguments: base model name and discriminator value`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const value = parseQuotedStringLiteral(rawValue);\n if (value === undefined) {\n diagnostics.push({\n code: 'PSL_INVALID_ATTRIBUTE_ARGUMENT',\n message: `Model \"${pslModel.name}\" @@base discriminator value must be a quoted string literal`,\n sourceId,\n span: attr.span,\n });\n continue;\n }\n const collectionName = resolveCollectionName(pslModel);\n baseDeclarations.set(pslModel.name, { baseName, value, collectionName, span: attr.span });\n }\n }\n }\n\n return { discriminatorDeclarations, baseDeclarations };\n}\n\nfunction resolvePolymorphism(input: {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n document: ParsePslDocumentResult;\n discriminatorDeclarations: Map<string, DiscriminatorDeclaration>;\n baseDeclarations: Map<string, BaseDeclaration>;\n modelNames: ReadonlySet<string>;\n sourceId: string;\n}): {\n models: Record<string, MongoModelEntry>;\n roots: Record<string, string>;\n diagnostics: ContractSourceDiagnostic[];\n} {\n const { discriminatorDeclarations, baseDeclarations, modelNames, sourceId, document } = input;\n let patched = input.models;\n let roots = input.roots;\n const diagnostics: ContractSourceDiagnostic[] = [];\n\n for (const [modelName, decl] of discriminatorDeclarations) {\n if (baseDeclarations.has(modelName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_AND_BASE',\n message: `Model \"${modelName}\" cannot have both @@discriminator and @@base`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const model = patched[modelName];\n if (!model) continue;\n\n if (!Object.hasOwn(model.fields, decl.fieldName)) {\n diagnostics.push({\n code: 'PSL_DISCRIMINATOR_FIELD_NOT_FOUND',\n message: `Discriminator field \"${decl.fieldName}\" is not a field on model \"${modelName}\"`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n const variants: Record<string, { readonly value: string }> = {};\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (baseDecl.baseName !== modelName) continue;\n variants[variantName] = { value: baseDecl.value };\n }\n\n if (Object.keys(variants).length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_DISCRIMINATOR',\n message: `Model \"${modelName}\" has @@discriminator but no variant models declare @@base(${modelName}, ...)`,\n sourceId,\n span: decl.span,\n });\n continue;\n }\n\n patched = {\n ...patched,\n [modelName]: { ...model, discriminator: { field: decl.fieldName }, variants },\n };\n }\n\n for (const [variantName, baseDecl] of baseDeclarations) {\n if (!modelNames.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_BASE_TARGET_NOT_FOUND',\n message: `Model \"${variantName}\" @@base references non-existent model \"${baseDecl.baseName}\"`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (!discriminatorDeclarations.has(baseDecl.baseName)) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BASE',\n message: `Model \"${variantName}\" declares @@base(${baseDecl.baseName}, ...) but \"${baseDecl.baseName}\" has no @@discriminator`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n if (discriminatorDeclarations.has(variantName)) {\n continue;\n }\n\n const baseModel = patched[baseDecl.baseName];\n const variantPslModel = document.ast.models.find((m) => m.name === variantName);\n if (!variantPslModel) continue;\n const hasExplicitMap = getMapName(variantPslModel.attributes) !== undefined;\n\n if (hasExplicitMap && baseModel && baseDecl.collectionName !== baseModel.storage.collection) {\n diagnostics.push({\n code: 'PSL_MONGO_VARIANT_SEPARATE_COLLECTION',\n message: `Mongo variant \"${variantName}\" cannot use a different collection than its base \"${baseDecl.baseName}\". Mongo only supports single-collection polymorphism.`,\n sourceId,\n span: baseDecl.span,\n });\n continue;\n }\n\n const baseCollection = baseModel?.storage.collection ?? baseDecl.collectionName;\n const variantModel = patched[variantName];\n if (variantModel) {\n patched = {\n ...patched,\n [variantName]: {\n ...variantModel,\n base: baseDecl.baseName,\n storage: { collection: baseCollection },\n },\n };\n }\n\n const variantCollectionName = resolveCollectionName(variantPslModel);\n if (roots[variantCollectionName] === variantName) {\n if (variantCollectionName === baseCollection && baseModel) {\n roots = { ...roots, [variantCollectionName]: baseDecl.baseName };\n } else {\n roots = Object.fromEntries(\n Object.entries(roots).filter(([key]) => key !== variantCollectionName),\n );\n }\n }\n }\n\n return { models: patched, roots, diagnostics };\n}\n\nfunction isRelationField(field: PslField, modelNames: ReadonlySet<string>): boolean {\n return modelNames.has(field.typeName);\n}\n\nfunction resolveFieldCodecId(\n field: PslField,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n): string | undefined {\n return scalarTypeDescriptors.get(field.typeName);\n}\n\nfunction resolveNonRelationField(\n field: PslField,\n ownerName: string,\n compositeTypeNames: ReadonlySet<string>,\n scalarTypeDescriptors: ReadonlyMap<string, string>,\n sourceId: string,\n diagnostics: ContractSourceDiagnostic[],\n): ContractField | undefined {\n if (compositeTypeNames.has(field.typeName)) {\n const result: ContractField = {\n type: { kind: 'valueObject', name: field.typeName },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n }\n\n const codecId = resolveFieldCodecId(field, scalarTypeDescriptors);\n if (!codecId) {\n diagnostics.push({\n code: 'PSL_UNSUPPORTED_FIELD_TYPE',\n message: `Field \"${ownerName}.${field.name}\" type \"${field.typeName}\" is not supported in Mongo PSL interpreter`,\n sourceId,\n span: field.span,\n });\n return undefined;\n }\n\n const result: ContractField = {\n type: { kind: 'scalar', codecId },\n nullable: field.optional,\n };\n return field.list ? { ...result, many: true } : result;\n}\n\nexport function interpretPslDocumentToMongoContract(\n input: InterpretPslDocumentToMongoContractInput,\n): Result<Contract, ContractSourceDiagnostics> {\n const { document, scalarTypeDescriptors } = input;\n const sourceId = document.ast.sourceId;\n const diagnostics: ContractSourceDiagnostic[] = [];\n const modelNames = new Set(document.ast.models.map((m) => m.name));\n const compositeTypeNames = new Set(document.ast.compositeTypes.map((ct) => ct.name));\n\n const models: Record<string, MongoModelEntry> = {};\n const collections: Record<string, Record<string, unknown>> = {};\n const roots: Record<string, string> = {};\n const allFkRelations: FkRelation[] = [];\n\n interface BackrelationCandidate {\n readonly modelName: string;\n readonly fieldName: string;\n readonly targetModelName: string;\n readonly relationName?: string;\n readonly cardinality: '1:1' | '1:N';\n readonly field: PslField;\n }\n const backrelationCandidates: BackrelationCandidate[] = [];\n\n for (const pslModel of document.ast.models) {\n const collectionName = resolveCollectionName(pslModel);\n const fieldMappings = resolveFieldMappings(pslModel);\n\n const fields: Record<string, ContractField> = {};\n const relations: Record<string, ContractReferenceRelation> = {};\n\n for (const field of pslModel.fields) {\n if (isRelationField(field, modelNames)) {\n const relation = parseRelationAttribute(field.attributes);\n\n if (field.list || !(relation?.fields && relation?.references)) {\n backrelationCandidates.push({\n modelName: pslModel.name,\n fieldName: field.name,\n targetModelName: field.typeName,\n ...(relation?.relationName !== undefined\n ? { relationName: relation.relationName }\n : {}),\n cardinality: field.list ? '1:N' : '1:1',\n field,\n });\n continue;\n }\n\n if (relation?.fields && relation?.references) {\n const localMapped = relation.fields.map((f) => fieldMappings.pslNameToMapped.get(f) ?? f);\n\n const targetModel = document.ast.models.find((m) => m.name === field.typeName);\n const targetFieldMappings = targetModel ? resolveFieldMappings(targetModel) : undefined;\n const targetMapped = relation.references.map(\n (f) => targetFieldMappings?.pslNameToMapped.get(f) ?? f,\n );\n\n relations[field.name] = {\n to: field.typeName,\n cardinality: 'N:1' as const,\n on: {\n localFields: localMapped,\n targetFields: targetMapped,\n },\n };\n\n allFkRelations.push({\n declaringModel: pslModel.name,\n fieldName: field.name,\n targetModel: field.typeName,\n ...(relation.relationName !== undefined ? { relationName: relation.relationName } : {}),\n localFields: localMapped,\n targetFields: targetMapped,\n });\n }\n continue;\n }\n\n const resolved = resolveNonRelationField(\n field,\n pslModel.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n\n const mappedName = fieldMappings.pslNameToMapped.get(field.name) ?? field.name;\n fields[mappedName] = resolved;\n }\n\n const isVariantModel = pslModel.attributes.some((attr) => attr.name === 'base');\n const hasIdField = pslModel.fields.some((f) => getAttribute(f.attributes, 'id') !== undefined);\n if (!hasIdField && !isVariantModel) {\n diagnostics.push({\n code: 'PSL_MISSING_ID_FIELD',\n message: `Model \"${pslModel.name}\" has no field with @id attribute. Every model must have exactly one @id field.`,\n sourceId,\n });\n }\n\n models[pslModel.name] = { fields, relations, storage: { collection: collectionName } };\n collections[collectionName] = {};\n roots[collectionName] = pslModel.name;\n }\n\n const valueObjects: Record<string, ContractValueObject> = {};\n for (const compositeType of document.ast.compositeTypes) {\n const fields: Record<string, ContractField> = {};\n for (const field of compositeType.fields) {\n const resolved = resolveNonRelationField(\n field,\n compositeType.name,\n compositeTypeNames,\n scalarTypeDescriptors,\n sourceId,\n diagnostics,\n );\n if (!resolved) continue;\n fields[field.name] = resolved;\n }\n valueObjects[compositeType.name] = { fields };\n }\n\n const fkRelationsByPair = new Map<string, FkRelation[]>();\n for (const fk of allFkRelations) {\n const key = fkRelationPairKey(fk.declaringModel, fk.targetModel);\n const existing = fkRelationsByPair.get(key);\n if (existing) {\n existing.push(fk);\n } else {\n fkRelationsByPair.set(key, [fk]);\n }\n }\n\n for (const candidate of backrelationCandidates) {\n const pairKey = fkRelationPairKey(candidate.targetModelName, candidate.modelName);\n const pairMatches = fkRelationsByPair.get(pairKey) ?? [];\n const matches = candidate.relationName\n ? pairMatches.filter((r) => r.relationName === candidate.relationName)\n : [...pairMatches];\n\n if (matches.length === 0) {\n diagnostics.push({\n code: 'PSL_ORPHANED_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" 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.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n if (matches.length > 1) {\n diagnostics.push({\n code: 'PSL_AMBIGUOUS_BACKRELATION',\n message: `Backrelation list field \"${candidate.modelName}.${candidate.fieldName}\" matches multiple FK-side relations on model \"${candidate.targetModelName}\". Add @relation(\"...\") to both sides to disambiguate.`,\n sourceId,\n span: candidate.field.span,\n });\n continue;\n }\n\n const fk = matches[0];\n if (!fk) continue;\n const modelEntry = models[candidate.modelName];\n if (!modelEntry) continue;\n modelEntry.relations[candidate.fieldName] = {\n to: candidate.targetModelName,\n cardinality: candidate.cardinality,\n on: {\n localFields: fk.targetFields,\n targetFields: fk.localFields,\n },\n };\n }\n\n const { discriminatorDeclarations, baseDeclarations } = collectPolymorphismDeclarations(\n document,\n sourceId,\n diagnostics,\n );\n const polyResult = resolvePolymorphism({\n models,\n roots,\n document,\n discriminatorDeclarations,\n baseDeclarations,\n modelNames,\n sourceId,\n });\n\n if (diagnostics.length > 0 || polyResult.diagnostics.length > 0) {\n return notOk({\n summary: 'PSL to Mongo contract interpretation failed',\n diagnostics: [...diagnostics, ...polyResult.diagnostics],\n });\n }\n\n const target = 'mongo';\n const targetFamily = 'mongo';\n const storageWithoutHash = { collections };\n const storageHash = computeStorageHash({ target, targetFamily, storage: storageWithoutHash });\n const capabilities: Record<string, Record<string, boolean>> = {};\n\n return ok({\n targetFamily,\n target,\n roots: polyResult.roots,\n models: polyResult.models,\n ...(Object.keys(valueObjects).length > 0 ? { valueObjects } : {}),\n storage: { ...storageWithoutHash, storageHash },\n extensionPacks: {},\n capabilities,\n profileHash: computeProfileHash({ target, targetFamily, capabilities }),\n meta: {},\n });\n}\n","export function createMongoScalarTypeDescriptors(): ReadonlyMap<string, string> {\n return new Map<string, string>([\n ['String', 'mongo/string@1'],\n ['Int', 'mongo/int32@1'],\n ['Boolean', 'mongo/bool@1'],\n ['DateTime', 'mongo/date@1'],\n ['ObjectId', 'mongo/objectId@1'],\n ]);\n}\n"],"mappings":";;;;;AAKA,SAAgB,WAAW,OAAuB;AAChD,KAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAO,MAAM,IAAI,aAAa,GAAG,MAAM,MAAM,EAAE;;AAGjD,SAAgB,aACd,YACA,MAC0B;AAC1B,QAAO,WAAW,MAAM,SAAS,KAAK,SAAS,KAAK;;AAGtD,SAAgB,WAAW,YAAyD;CAClF,MAAM,UAAU,aAAa,YAAY,MAAM;AAC/C,KAAI,CAAC,QAAS,QAAO;CACrB,MAAM,MAAM,QAAQ,KAAK;AACzB,KAAI,CAAC,IAAK,QAAO;AACjB,QAAO,YAAY,IAAI,MAAM;;AAS/B,SAAgB,uBACd,YACqC;CACrC,MAAM,eAAe,aAAa,YAAY,WAAW;AACzD,KAAI,CAAC,aAAc,QAAO;CAE1B,IAAIA;CACJ,IAAIC;CACJ,IAAIC;AAEJ,MAAK,MAAM,OAAO,aAAa,KAC7B,KAAI,IAAI,SAAS,aACf,gBAAe,YAAY,IAAI,MAAM;UAC5B,IAAI,SAAS,OACtB,gBAAe,YAAY,IAAI,MAAM;UAC5B,IAAI,SAAS,SACtB,aAAY;UACH,IAAI,SAAS,aACtB,iBAAgB;CAIpB,MAAM,SAAS,YAAY,eAAe,UAAU,MAAM,GAAG;CAC7D,MAAM,aAAa,gBAAgB,eAAe,cAAc,MAAM,GAAG;AAEzE,QAAO;EACL,GAAI,iBAAiB,SAAY,EAAE,cAAc,GAAG,EAAE;EACtD,GAAI,WAAW,SAAY,EAAE,QAAQ,GAAG,EAAE;EAC1C,GAAI,eAAe,SAAY,EAAE,YAAY,GAAG,EAAE;EACnD;;AAGH,SAAS,eAAe,OAAkC;CACxD,MAAM,QAAQ,MAAM,QAAQ,OAAO,GAAG,CAAC,QAAQ,OAAO,GAAG,CAAC,MAAM;AAChE,KAAI,MAAM,WAAW,EAAG,QAAO,EAAE;AACjC,QAAO,MAAM,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC;;AAG9C,SAAS,YAAY,OAAuB;AAC1C,KAAI,MAAM,WAAW,KAAI,IAAI,MAAM,SAAS,KAAI,CAC9C,QAAO,MAAM,MAAM,GAAG,GAAG;AAE3B,QAAO;;;;;ACjCT,SAAS,kBAAkB,gBAAwB,aAA6B;AAC9E,QAAO,GAAG,eAAe,IAAI;;AAG/B,SAAS,qBAAqB,OAAgC;CAC5D,MAAM,kCAAkB,IAAI,KAAqB;AACjD,MAAK,MAAM,SAAS,MAAM,QAAQ;EAChC,MAAM,SAAS,WAAW,MAAM,WAAW,IAAI,MAAM;AACrD,kBAAgB,IAAI,MAAM,MAAM,OAAO;;AAEzC,QAAO,EAAE,iBAAiB;;AAG5B,SAAS,sBAAsB,OAAyB;AACtD,QAAO,WAAW,MAAM,WAAW,IAAI,WAAW,MAAM,KAAK;;AAoB/D,SAAS,gCACP,UACA,UACA,aAIA;CACA,MAAM,4CAA4B,IAAI,KAAuC;CAC7E,MAAM,mCAAmB,IAAI,KAA8B;AAE3D,MAAK,MAAM,YAAY,SAAS,IAAI,OAClC,MAAK,MAAM,QAAQ,SAAS,YAAY;AACtC,MAAI,KAAK,SAAS,iBAAiB;GACjC,MAAM,YAAY,sBAAsB,KAAK;AAC7C,OAAI,CAAC,WAAW;AACd,gBAAY,KAAK;KACf,MAAM;KACN,SAAS,UAAU,SAAS,KAAK;KACjC;KACA,MAAM,KAAK;KACZ,CAAC;AACF;;GAEF,MAAM,YAAY,SAAS,OAAO,MAAM,MAAM,EAAE,SAAS,UAAU;AACnE,OAAI,aAAa,UAAU,aAAa,UAAU;AAChD,gBAAY,KAAK;KACf,MAAM;KACN,SAAS,wBAAwB,UAAU,cAAc,SAAS,KAAK,oCAAoC,UAAU,SAAS;KAC9H;KACA,MAAM,KAAK;KACZ,CAAC;AACF;;AAEF,6BAA0B,IAAI,SAAS,MAAM;IAAE;IAAW,MAAM,KAAK;IAAM,CAAC;;AAE9E,MAAI,KAAK,SAAS,QAAQ;GACxB,MAAM,WAAW,sBAAsB,MAAM,EAAE;GAC/C,MAAM,WAAW,sBAAsB,MAAM,EAAE;AAC/C,OAAI,CAAC,YAAY,CAAC,UAAU;AAC1B,gBAAY,KAAK;KACf,MAAM;KACN,SAAS,UAAU,SAAS,KAAK;KACjC;KACA,MAAM,KAAK;KACZ,CAAC;AACF;;GAEF,MAAM,QAAQ,yBAAyB,SAAS;AAChD,OAAI,UAAU,QAAW;AACvB,gBAAY,KAAK;KACf,MAAM;KACN,SAAS,UAAU,SAAS,KAAK;KACjC;KACA,MAAM,KAAK;KACZ,CAAC;AACF;;GAEF,MAAM,iBAAiB,sBAAsB,SAAS;AACtD,oBAAiB,IAAI,SAAS,MAAM;IAAE;IAAU;IAAO;IAAgB,MAAM,KAAK;IAAM,CAAC;;;AAK/F,QAAO;EAAE;EAA2B;EAAkB;;AAGxD,SAAS,oBAAoB,OAY3B;CACA,MAAM,EAAE,2BAA2B,kBAAkB,YAAY,UAAU,aAAa;CACxF,IAAI,UAAU,MAAM;CACpB,IAAI,QAAQ,MAAM;CAClB,MAAMC,cAA0C,EAAE;AAElD,MAAK,MAAM,CAAC,WAAW,SAAS,2BAA2B;AACzD,MAAI,iBAAiB,IAAI,UAAU,EAAE;AACnC,eAAY,KAAK;IACf,MAAM;IACN,SAAS,UAAU,UAAU;IAC7B;IACA,MAAM,KAAK;IACZ,CAAC;AACF;;EAGF,MAAM,QAAQ,QAAQ;AACtB,MAAI,CAAC,MAAO;AAEZ,MAAI,CAAC,OAAO,OAAO,MAAM,QAAQ,KAAK,UAAU,EAAE;AAChD,eAAY,KAAK;IACf,MAAM;IACN,SAAS,wBAAwB,KAAK,UAAU,6BAA6B,UAAU;IACvF;IACA,MAAM,KAAK;IACZ,CAAC;AACF;;EAGF,MAAMC,WAAuD,EAAE;AAC/D,OAAK,MAAM,CAAC,aAAa,aAAa,kBAAkB;AACtD,OAAI,SAAS,aAAa,UAAW;AACrC,YAAS,eAAe,EAAE,OAAO,SAAS,OAAO;;AAGnD,MAAI,OAAO,KAAK,SAAS,CAAC,WAAW,GAAG;AACtC,eAAY,KAAK;IACf,MAAM;IACN,SAAS,UAAU,UAAU,6DAA6D,UAAU;IACpG;IACA,MAAM,KAAK;IACZ,CAAC;AACF;;AAGF,YAAU;GACR,GAAG;IACF,YAAY;IAAE,GAAG;IAAO,eAAe,EAAE,OAAO,KAAK,WAAW;IAAE;IAAU;GAC9E;;AAGH,MAAK,MAAM,CAAC,aAAa,aAAa,kBAAkB;AACtD,MAAI,CAAC,WAAW,IAAI,SAAS,SAAS,EAAE;AACtC,eAAY,KAAK;IACf,MAAM;IACN,SAAS,UAAU,YAAY,0CAA0C,SAAS,SAAS;IAC3F;IACA,MAAM,SAAS;IAChB,CAAC;AACF;;AAGF,MAAI,CAAC,0BAA0B,IAAI,SAAS,SAAS,EAAE;AACrD,eAAY,KAAK;IACf,MAAM;IACN,SAAS,UAAU,YAAY,oBAAoB,SAAS,SAAS,cAAc,SAAS,SAAS;IACrG;IACA,MAAM,SAAS;IAChB,CAAC;AACF;;AAGF,MAAI,0BAA0B,IAAI,YAAY,CAC5C;EAGF,MAAM,YAAY,QAAQ,SAAS;EACnC,MAAM,kBAAkB,SAAS,IAAI,OAAO,MAAM,MAAM,EAAE,SAAS,YAAY;AAC/E,MAAI,CAAC,gBAAiB;AAGtB,MAFuB,WAAW,gBAAgB,WAAW,KAAK,UAE5C,aAAa,SAAS,mBAAmB,UAAU,QAAQ,YAAY;AAC3F,eAAY,KAAK;IACf,MAAM;IACN,SAAS,kBAAkB,YAAY,qDAAqD,SAAS,SAAS;IAC9G;IACA,MAAM,SAAS;IAChB,CAAC;AACF;;EAGF,MAAM,iBAAiB,WAAW,QAAQ,cAAc,SAAS;EACjE,MAAM,eAAe,QAAQ;AAC7B,MAAI,aACF,WAAU;GACR,GAAG;IACF,cAAc;IACb,GAAG;IACH,MAAM,SAAS;IACf,SAAS,EAAE,YAAY,gBAAgB;IACxC;GACF;EAGH,MAAM,wBAAwB,sBAAsB,gBAAgB;AACpE,MAAI,MAAM,2BAA2B,YACnC,KAAI,0BAA0B,kBAAkB,UAC9C,SAAQ;GAAE,GAAG;IAAQ,wBAAwB,SAAS;GAAU;MAEhE,SAAQ,OAAO,YACb,OAAO,QAAQ,MAAM,CAAC,QAAQ,CAAC,SAAS,QAAQ,sBAAsB,CACvE;;AAKP,QAAO;EAAE,QAAQ;EAAS;EAAO;EAAa;;AAGhD,SAAS,gBAAgB,OAAiB,YAA0C;AAClF,QAAO,WAAW,IAAI,MAAM,SAAS;;AAGvC,SAAS,oBACP,OACA,uBACoB;AACpB,QAAO,sBAAsB,IAAI,MAAM,SAAS;;AAGlD,SAAS,wBACP,OACA,WACA,oBACA,uBACA,UACA,aAC2B;AAC3B,KAAI,mBAAmB,IAAI,MAAM,SAAS,EAAE;EAC1C,MAAMC,WAAwB;GAC5B,MAAM;IAAE,MAAM;IAAe,MAAM,MAAM;IAAU;GACnD,UAAU,MAAM;GACjB;AACD,SAAO,MAAM,OAAO;GAAE,GAAGC;GAAQ,MAAM;GAAM,GAAGA;;CAGlD,MAAM,UAAU,oBAAoB,OAAO,sBAAsB;AACjE,KAAI,CAAC,SAAS;AACZ,cAAY,KAAK;GACf,MAAM;GACN,SAAS,UAAU,UAAU,GAAG,MAAM,KAAK,UAAU,MAAM,SAAS;GACpE;GACA,MAAM,MAAM;GACb,CAAC;AACF;;CAGF,MAAMD,SAAwB;EAC5B,MAAM;GAAE,MAAM;GAAU;GAAS;EACjC,UAAU,MAAM;EACjB;AACD,QAAO,MAAM,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAM,GAAG;;AAGlD,SAAgB,oCACd,OAC6C;CAC7C,MAAM,EAAE,UAAU,0BAA0B;CAC5C,MAAM,WAAW,SAAS,IAAI;CAC9B,MAAMF,cAA0C,EAAE;CAClD,MAAM,aAAa,IAAI,IAAI,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,KAAK,CAAC;CAClE,MAAM,qBAAqB,IAAI,IAAI,SAAS,IAAI,eAAe,KAAK,OAAO,GAAG,KAAK,CAAC;CAEpF,MAAMI,SAA0C,EAAE;CAClD,MAAMC,cAAuD,EAAE;CAC/D,MAAMC,QAAgC,EAAE;CACxC,MAAMC,iBAA+B,EAAE;CAUvC,MAAMC,yBAAkD,EAAE;AAE1D,MAAK,MAAM,YAAY,SAAS,IAAI,QAAQ;EAC1C,MAAM,iBAAiB,sBAAsB,SAAS;EACtD,MAAM,gBAAgB,qBAAqB,SAAS;EAEpD,MAAMC,SAAwC,EAAE;EAChD,MAAMC,YAAuD,EAAE;AAE/D,OAAK,MAAM,SAAS,SAAS,QAAQ;AACnC,OAAI,gBAAgB,OAAO,WAAW,EAAE;IACtC,MAAM,WAAW,uBAAuB,MAAM,WAAW;AAEzD,QAAI,MAAM,QAAQ,EAAE,UAAU,UAAU,UAAU,aAAa;AAC7D,4BAAuB,KAAK;MAC1B,WAAW,SAAS;MACpB,WAAW,MAAM;MACjB,iBAAiB,MAAM;MACvB,GAAI,UAAU,iBAAiB,SAC3B,EAAE,cAAc,SAAS,cAAc,GACvC,EAAE;MACN,aAAa,MAAM,OAAO,QAAQ;MAClC;MACD,CAAC;AACF;;AAGF,QAAI,UAAU,UAAU,UAAU,YAAY;KAC5C,MAAM,cAAc,SAAS,OAAO,KAAK,MAAM,cAAc,gBAAgB,IAAI,EAAE,IAAI,EAAE;KAEzF,MAAM,cAAc,SAAS,IAAI,OAAO,MAAM,MAAM,EAAE,SAAS,MAAM,SAAS;KAC9E,MAAM,sBAAsB,cAAc,qBAAqB,YAAY,GAAG;KAC9E,MAAM,eAAe,SAAS,WAAW,KACtC,MAAM,qBAAqB,gBAAgB,IAAI,EAAE,IAAI,EACvD;AAED,eAAU,MAAM,QAAQ;MACtB,IAAI,MAAM;MACV,aAAa;MACb,IAAI;OACF,aAAa;OACb,cAAc;OACf;MACF;AAED,oBAAe,KAAK;MAClB,gBAAgB,SAAS;MACzB,WAAW,MAAM;MACjB,aAAa,MAAM;MACnB,GAAI,SAAS,iBAAiB,SAAY,EAAE,cAAc,SAAS,cAAc,GAAG,EAAE;MACtF,aAAa;MACb,cAAc;MACf,CAAC;;AAEJ;;GAGF,MAAM,WAAW,wBACf,OACA,SAAS,MACT,oBACA,uBACA,UACA,YACD;AACD,OAAI,CAAC,SAAU;GAEf,MAAM,aAAa,cAAc,gBAAgB,IAAI,MAAM,KAAK,IAAI,MAAM;AAC1E,UAAO,cAAc;;EAGvB,MAAM,iBAAiB,SAAS,WAAW,MAAM,SAAS,KAAK,SAAS,OAAO;AAE/E,MAAI,CADe,SAAS,OAAO,MAAM,MAAM,aAAa,EAAE,YAAY,KAAK,KAAK,OAAU,IAC3E,CAAC,eAClB,aAAY,KAAK;GACf,MAAM;GACN,SAAS,UAAU,SAAS,KAAK;GACjC;GACD,CAAC;AAGJ,SAAO,SAAS,QAAQ;GAAE;GAAQ;GAAW,SAAS,EAAE,YAAY,gBAAgB;GAAE;AACtF,cAAY,kBAAkB,EAAE;AAChC,QAAM,kBAAkB,SAAS;;CAGnC,MAAMC,eAAoD,EAAE;AAC5D,MAAK,MAAM,iBAAiB,SAAS,IAAI,gBAAgB;EACvD,MAAMF,SAAwC,EAAE;AAChD,OAAK,MAAM,SAAS,cAAc,QAAQ;GACxC,MAAM,WAAW,wBACf,OACA,cAAc,MACd,oBACA,uBACA,UACA,YACD;AACD,OAAI,CAAC,SAAU;AACf,UAAO,MAAM,QAAQ;;AAEvB,eAAa,cAAc,QAAQ,EAAE,QAAQ;;CAG/C,MAAM,oCAAoB,IAAI,KAA2B;AACzD,MAAK,MAAM,MAAM,gBAAgB;EAC/B,MAAM,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,YAAY;EAChE,MAAM,WAAW,kBAAkB,IAAI,IAAI;AAC3C,MAAI,SACF,UAAS,KAAK,GAAG;MAEjB,mBAAkB,IAAI,KAAK,CAAC,GAAG,CAAC;;AAIpC,MAAK,MAAM,aAAa,wBAAwB;EAC9C,MAAM,UAAU,kBAAkB,UAAU,iBAAiB,UAAU,UAAU;EACjF,MAAM,cAAc,kBAAkB,IAAI,QAAQ,IAAI,EAAE;EACxD,MAAM,UAAU,UAAU,eACtB,YAAY,QAAQ,MAAM,EAAE,iBAAiB,UAAU,aAAa,GACpE,CAAC,GAAG,YAAY;AAEpB,MAAI,QAAQ,WAAW,GAAG;AACxB,eAAY,KAAK;IACf,MAAM;IACN,SAAS,4BAA4B,UAAU,UAAU,GAAG,UAAU,UAAU,+CAA+C,UAAU,gBAAgB;IACzJ;IACA,MAAM,UAAU,MAAM;IACvB,CAAC;AACF;;AAEF,MAAI,QAAQ,SAAS,GAAG;AACtB,eAAY,KAAK;IACf,MAAM;IACN,SAAS,4BAA4B,UAAU,UAAU,GAAG,UAAU,UAAU,iDAAiD,UAAU,gBAAgB;IAC3J;IACA,MAAM,UAAU,MAAM;IACvB,CAAC;AACF;;EAGF,MAAM,KAAK,QAAQ;AACnB,MAAI,CAAC,GAAI;EACT,MAAM,aAAa,OAAO,UAAU;AACpC,MAAI,CAAC,WAAY;AACjB,aAAW,UAAU,UAAU,aAAa;GAC1C,IAAI,UAAU;GACd,aAAa,UAAU;GACvB,IAAI;IACF,aAAa,GAAG;IAChB,cAAc,GAAG;IAClB;GACF;;CAGH,MAAM,EAAE,2BAA2B,qBAAqB,gCACtD,UACA,UACA,YACD;CACD,MAAM,aAAa,oBAAoB;EACrC;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,YAAY,SAAS,KAAK,WAAW,YAAY,SAAS,EAC5D,QAAO,MAAM;EACX,SAAS;EACT,aAAa,CAAC,GAAG,aAAa,GAAG,WAAW,YAAY;EACzD,CAAC;CAGJ,MAAM,SAAS;CACf,MAAM,eAAe;CACrB,MAAM,qBAAqB,EAAE,aAAa;CAC1C,MAAM,cAAc,mBAAmB;EAAE;EAAQ;EAAc,SAAS;EAAoB,CAAC;CAC7F,MAAMG,eAAwD,EAAE;AAEhE,QAAO,GAAG;EACR;EACA;EACA,OAAO,WAAW;EAClB,QAAQ,WAAW;EACnB,GAAI,OAAO,KAAK,aAAa,CAAC,SAAS,IAAI,EAAE,cAAc,GAAG,EAAE;EAChE,SAAS;GAAE,GAAG;GAAoB;GAAa;EAC/C,gBAAgB,EAAE;EAClB;EACA,aAAa,mBAAmB;GAAE;GAAQ;GAAc;GAAc,CAAC;EACvE,MAAM,EAAE;EACT,CAAC;;;;;ACthBJ,SAAgB,mCAAgE;AAC9E,QAAO,IAAI,IAAoB;EAC7B,CAAC,UAAU,iBAAiB;EAC5B,CAAC,OAAO,gBAAgB;EACxB,CAAC,WAAW,eAAe;EAC3B,CAAC,YAAY,eAAe;EAC5B,CAAC,YAAY,mBAAmB;EACjC,CAAC"}