@prisma-next/psl-parser 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/syntax.mjs CHANGED
@@ -1,3 +1,66 @@
1
+ import { n as isTerminatedStringLiteral, t as Tokenizer } from "./tokenizer-1hAHZzmp.mjs";
2
+ import { UNSPECIFIED_PSL_NAMESPACE_ID } from "@prisma-next/framework-components/psl-ast";
3
+ //#region src/source-file.ts
4
+ const LINE_FEED = 10;
5
+ var SourceFile = class {
6
+ #text;
7
+ #lineStarts;
8
+ constructor(text) {
9
+ this.#text = text;
10
+ const lineStarts = [0];
11
+ for (let offset = 0; offset < text.length; offset++) if (text.charCodeAt(offset) === LINE_FEED) lineStarts.push(offset + 1);
12
+ this.#lineStarts = lineStarts;
13
+ }
14
+ get text() {
15
+ return this.#text;
16
+ }
17
+ get length() {
18
+ return this.#text.length;
19
+ }
20
+ get lineCount() {
21
+ return this.#lineStarts.length;
22
+ }
23
+ lineStartOffsets() {
24
+ return this.#lineStarts;
25
+ }
26
+ positionAt(offset) {
27
+ const clamped = clamp(offset, 0, this.#text.length);
28
+ const line = this.#lineIndexAt(clamped);
29
+ return {
30
+ line,
31
+ character: clamped - this.#lineStartAt(line)
32
+ };
33
+ }
34
+ offsetAt(position) {
35
+ const line = clamp(position.line, 0, this.#lineStarts.length - 1);
36
+ const lineStart = this.#lineStartAt(line);
37
+ const lineEnd = this.#lineEndAt(line);
38
+ return clamp(lineStart + position.character, lineStart, lineEnd);
39
+ }
40
+ #lineStartAt(line) {
41
+ return this.#lineStarts[line] ?? 0;
42
+ }
43
+ #lineEndAt(line) {
44
+ return line + 1 < this.#lineStarts.length ? this.#lineStartAt(line + 1) - 1 : this.#text.length;
45
+ }
46
+ #lineIndexAt(offset) {
47
+ const lineStarts = this.#lineStarts;
48
+ let low = 0;
49
+ let high = lineStarts.length - 1;
50
+ while (low < high) {
51
+ const mid = low + high + 1 >>> 1;
52
+ if ((lineStarts[mid] ?? 0) <= offset) low = mid;
53
+ else high = mid - 1;
54
+ }
55
+ return low;
56
+ }
57
+ };
58
+ function clamp(value, min, max) {
59
+ if (value < min) return min;
60
+ if (value > max) return max;
61
+ return value;
62
+ }
63
+ //#endregion
1
64
  //#region src/syntax/red.ts
2
65
  var SyntaxNode = class SyntaxNode {
3
66
  green;
@@ -127,6 +190,15 @@ function* filterChildren(node, cast) {
127
190
  if (result !== void 0) yield result;
128
191
  }
129
192
  }
193
+ /**
194
+ * Raw source text of a CST node, verbatim (quotes and brackets preserved). For
195
+ * the decoded value of a string literal, decode it instead.
196
+ */
197
+ function printSyntax(node) {
198
+ let text = "";
199
+ for (const token of node.tokens()) text += token.text;
200
+ return text;
201
+ }
130
202
  //#endregion
131
203
  //#region src/syntax/ast/identifier.ts
132
204
  var IdentifierAst = class IdentifierAst {
@@ -137,19 +209,104 @@ var IdentifierAst = class IdentifierAst {
137
209
  token() {
138
210
  return findChildToken(this.syntax, "Ident");
139
211
  }
212
+ name() {
213
+ return this.token()?.text;
214
+ }
140
215
  static cast(node) {
141
216
  return node.kind === "Identifier" ? new IdentifierAst(node) : void 0;
142
217
  }
143
218
  };
144
219
  //#endregion
220
+ //#region src/syntax/ast/qualified-name.ts
221
+ /** A namespace-qualified name, e.g. `pgvector.Vector` or `supabase:auth.User`. */
222
+ var QualifiedNameAst = class QualifiedNameAst {
223
+ syntax;
224
+ constructor(syntax) {
225
+ this.syntax = syntax;
226
+ }
227
+ #lastSegment() {
228
+ let last;
229
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) last = segment;
230
+ return last;
231
+ }
232
+ #penultimateSegment() {
233
+ let last;
234
+ let penultimate;
235
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
236
+ penultimate = last;
237
+ last = segment;
238
+ }
239
+ return penultimate;
240
+ }
241
+ #separatorCount(kind) {
242
+ let count = 0;
243
+ for (const child of this.syntax.children()) if (!(child instanceof SyntaxNode) && child.kind === kind) count++;
244
+ return count;
245
+ }
246
+ colon() {
247
+ return findChildToken(this.syntax, "Colon");
248
+ }
249
+ dot() {
250
+ return findChildToken(this.syntax, "Dot");
251
+ }
252
+ space() {
253
+ if (!this.colon()) return void 0;
254
+ return findFirstChild(this.syntax, IdentifierAst.cast);
255
+ }
256
+ namespace() {
257
+ if (!this.dot()) return void 0;
258
+ return this.#penultimateSegment();
259
+ }
260
+ identifier() {
261
+ return this.#lastSegment();
262
+ }
263
+ /**
264
+ * Every identifier segment, in source order. A bare `Vector` yields
265
+ * `['Vector']`; a qualified `pgvector.Vector` yields `['pgvector', 'Vector']`.
266
+ */
267
+ path() {
268
+ const segments = [];
269
+ for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
270
+ const text = segment.token()?.text;
271
+ if (text !== void 0) segments.push(text);
272
+ }
273
+ return segments;
274
+ }
275
+ /**
276
+ * Flags a malformed name with more qualifier segments than allowed (a second
277
+ * `:`-space or a second `.`-namespace).
278
+ */
279
+ isOverQualified() {
280
+ return this.#separatorCount("Dot") > 1 || this.#separatorCount("Colon") > 1;
281
+ }
282
+ static cast(node) {
283
+ return node.kind === "QualifiedName" ? new QualifiedNameAst(node) : void 0;
284
+ }
285
+ };
286
+ //#endregion
145
287
  //#region src/syntax/ast/expressions.ts
146
288
  var FunctionCallAst = class FunctionCallAst {
147
289
  syntax;
148
290
  constructor(syntax) {
149
291
  this.syntax = syntax;
150
292
  }
293
+ /** The qualified-name callee, or `undefined` when identifier segments sit directly under the node. */
151
294
  name() {
152
- return findFirstChild(this.syntax, IdentifierAst.cast);
295
+ return findFirstChild(this.syntax, QualifiedNameAst.cast);
296
+ }
297
+ /**
298
+ * The dotted call path, in source order. A bare `Vector(…)` yields
299
+ * `['Vector']`; a namespace-qualified `pgvector.Vector(…)` yields
300
+ * `['pgvector', 'Vector']`. Empty when the call carries no identifier.
301
+ */
302
+ path() {
303
+ const qualified = this.name();
304
+ const segments = [];
305
+ for (const segment of filterChildren(qualified?.syntax ?? this.syntax, IdentifierAst.cast)) {
306
+ const text = segment.token()?.text;
307
+ if (text !== void 0) segments.push(text);
308
+ }
309
+ return segments;
153
310
  }
154
311
  lparen() {
155
312
  return findChildToken(this.syntax, "LParen");
@@ -182,6 +339,79 @@ var ArrayLiteralAst = class ArrayLiteralAst {
182
339
  return node.kind === "ArrayLiteral" ? new ArrayLiteralAst(node) : void 0;
183
340
  }
184
341
  };
342
+ const HEX = /^[0-9a-fA-F]+$/;
343
+ function decodeFixedHex(raw, start, width) {
344
+ if (start + width > raw.length) return void 0;
345
+ const hex = raw.slice(start, start + width);
346
+ if (!HEX.test(hex)) return void 0;
347
+ return String.fromCharCode(Number.parseInt(hex, 16));
348
+ }
349
+ function decodeStringLiteral(raw) {
350
+ let out = "";
351
+ let i = 0;
352
+ while (i < raw.length) {
353
+ const ch = raw.charAt(i);
354
+ if (ch !== "\\" || i + 1 >= raw.length) {
355
+ out += ch;
356
+ i++;
357
+ continue;
358
+ }
359
+ const next = raw.charAt(i + 1);
360
+ switch (next) {
361
+ case "n":
362
+ out += "\n";
363
+ i += 2;
364
+ continue;
365
+ case "r":
366
+ out += "\r";
367
+ i += 2;
368
+ continue;
369
+ case "t":
370
+ out += " ";
371
+ i += 2;
372
+ continue;
373
+ case "\"":
374
+ out += "\"";
375
+ i += 2;
376
+ continue;
377
+ case "'":
378
+ out += "'";
379
+ i += 2;
380
+ continue;
381
+ case "\\":
382
+ out += "\\";
383
+ i += 2;
384
+ continue;
385
+ case "x": {
386
+ const decoded = decodeFixedHex(raw, i + 2, 2);
387
+ if (decoded === void 0) {
388
+ out += "\\x";
389
+ i += 2;
390
+ continue;
391
+ }
392
+ out += decoded;
393
+ i += 4;
394
+ continue;
395
+ }
396
+ case "u": {
397
+ const decoded = decodeFixedHex(raw, i + 2, 4);
398
+ if (decoded === void 0) {
399
+ out += "\\u";
400
+ i += 2;
401
+ continue;
402
+ }
403
+ out += decoded;
404
+ i += 6;
405
+ continue;
406
+ }
407
+ default:
408
+ out += `\\${next}`;
409
+ i += 2;
410
+ continue;
411
+ }
412
+ }
413
+ return out;
414
+ }
185
415
  var StringLiteralExprAst = class StringLiteralExprAst {
186
416
  syntax;
187
417
  constructor(syntax) {
@@ -193,16 +423,7 @@ var StringLiteralExprAst = class StringLiteralExprAst {
193
423
  value() {
194
424
  const tok = this.token();
195
425
  if (!tok) return void 0;
196
- return tok.text.slice(1, -1).replace(/\\(.)/g, (_match, char) => {
197
- switch (char) {
198
- case "n": return "\n";
199
- case "r": return "\r";
200
- case "t": return " ";
201
- case "\"": return "\"";
202
- case "\\": return "\\";
203
- default: return `\\${char}`;
204
- }
205
- });
426
+ return decodeStringLiteral(tok.text.slice(1, -1));
206
427
  }
207
428
  static cast(node) {
208
429
  return node.kind === "StringLiteralExpr" ? new StringLiteralExprAst(node) : void 0;
@@ -243,8 +464,82 @@ var BooleanLiteralExprAst = class BooleanLiteralExprAst {
243
464
  return node.kind === "BooleanLiteralExpr" ? new BooleanLiteralExprAst(node) : void 0;
244
465
  }
245
466
  };
467
+ var ObjectLiteralExprAst = class ObjectLiteralExprAst {
468
+ syntax;
469
+ constructor(syntax) {
470
+ this.syntax = syntax;
471
+ }
472
+ lbrace() {
473
+ return findChildToken(this.syntax, "LBrace");
474
+ }
475
+ rbrace() {
476
+ return findChildToken(this.syntax, "RBrace");
477
+ }
478
+ *fields() {
479
+ yield* filterChildren(this.syntax, ObjectFieldAst.cast);
480
+ }
481
+ static cast(node) {
482
+ return node.kind === "ObjectLiteralExpr" ? new ObjectLiteralExprAst(node) : void 0;
483
+ }
484
+ };
485
+ var ObjectFieldAst = class ObjectFieldAst {
486
+ syntax;
487
+ constructor(syntax) {
488
+ this.syntax = syntax;
489
+ }
490
+ key() {
491
+ for (const child of this.syntax.children()) {
492
+ if (!(child instanceof SyntaxNode)) {
493
+ if (child.kind === "Colon") break;
494
+ continue;
495
+ }
496
+ return IdentifierAst.cast(child);
497
+ }
498
+ }
499
+ /**
500
+ * The field's logical key name, unquoted. An identifier key (`length:`) yields
501
+ * its text; a string-literal key (`"length":`) yields the decoded string.
502
+ * `undefined` when the field carries no key node.
503
+ */
504
+ keyName() {
505
+ for (const child of this.syntax.children()) {
506
+ if (!(child instanceof SyntaxNode)) {
507
+ if (child.kind === "Colon") break;
508
+ continue;
509
+ }
510
+ const identifier = IdentifierAst.cast(child);
511
+ if (identifier) return identifier.token()?.text;
512
+ const stringKey = StringLiteralExprAst.cast(child);
513
+ if (stringKey) return stringKey.value();
514
+ return;
515
+ }
516
+ }
517
+ colon() {
518
+ return findChildToken(this.syntax, "Colon");
519
+ }
520
+ value() {
521
+ if (this.colon()) {
522
+ let pastColon = false;
523
+ for (const child of this.syntax.children()) {
524
+ if (!(child instanceof SyntaxNode)) {
525
+ if (child.kind === "Colon") pastColon = true;
526
+ continue;
527
+ }
528
+ if (pastColon) {
529
+ const expr = castExpression(child);
530
+ if (expr) return expr;
531
+ }
532
+ }
533
+ return;
534
+ }
535
+ return findFirstChild(this.syntax, castExpression);
536
+ }
537
+ static cast(node) {
538
+ return node.kind === "ObjectField" ? new ObjectFieldAst(node) : void 0;
539
+ }
540
+ };
246
541
  function castExpression(node) {
247
- return FunctionCallAst.cast(node) ?? ArrayLiteralAst.cast(node) ?? StringLiteralExprAst.cast(node) ?? NumberLiteralExprAst.cast(node) ?? BooleanLiteralExprAst.cast(node) ?? IdentifierAst.cast(node);
542
+ return FunctionCallAst.cast(node) ?? ArrayLiteralAst.cast(node) ?? StringLiteralExprAst.cast(node) ?? NumberLiteralExprAst.cast(node) ?? BooleanLiteralExprAst.cast(node) ?? ObjectLiteralExprAst.cast(node) ?? IdentifierAst.cast(node);
248
543
  }
249
544
  var AttributeArgAst = class AttributeArgAst {
250
545
  syntax;
@@ -308,22 +603,7 @@ var FieldAttributeAst = class FieldAttributeAst {
308
603
  return findChildToken(this.syntax, "At");
309
604
  }
310
605
  name() {
311
- if (this.dot()) {
312
- let count = 0;
313
- for (const child of this.syntax.childNodes()) if (child.kind === "Identifier") {
314
- count++;
315
- if (count === 2) return new IdentifierAst(child);
316
- }
317
- return;
318
- }
319
- return findFirstChild(this.syntax, IdentifierAst.cast);
320
- }
321
- dot() {
322
- return findChildToken(this.syntax, "Dot");
323
- }
324
- namespaceName() {
325
- if (!this.dot()) return void 0;
326
- return findFirstChild(this.syntax, IdentifierAst.cast);
606
+ return findFirstChild(this.syntax, QualifiedNameAst.cast);
327
607
  }
328
608
  argList() {
329
609
  return findFirstChild(this.syntax, AttributeArgListAst.cast);
@@ -341,7 +621,7 @@ var ModelAttributeAst = class ModelAttributeAst {
341
621
  return findChildToken(this.syntax, "DoubleAt");
342
622
  }
343
623
  name() {
344
- return findFirstChild(this.syntax, IdentifierAst.cast);
624
+ return findFirstChild(this.syntax, QualifiedNameAst.cast);
345
625
  }
346
626
  argList() {
347
627
  return findFirstChild(this.syntax, AttributeArgListAst.cast);
@@ -357,39 +637,16 @@ var TypeAnnotationAst = class TypeAnnotationAst {
357
637
  constructor(syntax) {
358
638
  this.syntax = syntax;
359
639
  }
360
- #lastSegment() {
361
- let last;
362
- for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) last = segment;
363
- return last;
364
- }
365
- #penultimateSegment() {
366
- let last;
367
- let penultimate;
368
- for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {
369
- penultimate = last;
370
- last = segment;
371
- }
372
- return penultimate;
373
- }
640
+ /** The annotation's reference, doubling as the constructor callee when an {@link argList} follows. */
374
641
  name() {
375
- return this.#lastSegment();
376
- }
377
- colon() {
378
- return findChildToken(this.syntax, "Colon");
642
+ return findFirstChild(this.syntax, QualifiedNameAst.cast);
379
643
  }
380
- dot() {
381
- return findChildToken(this.syntax, "Dot");
382
- }
383
- spaceName() {
384
- if (!this.colon()) return void 0;
385
- return findFirstChild(this.syntax, IdentifierAst.cast);
386
- }
387
- namespaceName() {
388
- if (!this.dot()) return void 0;
389
- return this.#penultimateSegment();
644
+ /** Present when the annotation is a constructor (`Vector(1536)`) rather than a plain reference. */
645
+ argList() {
646
+ return findFirstChild(this.syntax, AttributeArgListAst.cast);
390
647
  }
391
- constructorCall() {
392
- return findFirstChild(this.syntax, FunctionCallAst.cast);
648
+ isConstructor() {
649
+ return this.argList() !== void 0;
393
650
  }
394
651
  lbracket() {
395
652
  return findChildToken(this.syntax, "LBracket");
@@ -413,7 +670,7 @@ var TypeAnnotationAst = class TypeAnnotationAst {
413
670
  //#endregion
414
671
  //#region src/syntax/ast/declarations.ts
415
672
  function castNamespaceMember(node) {
416
- return ModelDeclarationAst.cast(node) ?? EnumDeclarationAst.cast(node) ?? CompositeTypeDeclarationAst.cast(node) ?? BlockDeclarationAst.cast(node);
673
+ return ModelDeclarationAst.cast(node) ?? CompositeTypeDeclarationAst.cast(node) ?? GenericBlockDeclarationAst.cast(node);
417
674
  }
418
675
  var DocumentAst = class DocumentAst {
419
676
  syntax;
@@ -454,33 +711,6 @@ var ModelDeclarationAst = class ModelDeclarationAst {
454
711
  return node.kind === "ModelDeclaration" ? new ModelDeclarationAst(node) : void 0;
455
712
  }
456
713
  };
457
- var EnumDeclarationAst = class EnumDeclarationAst {
458
- syntax;
459
- constructor(syntax) {
460
- this.syntax = syntax;
461
- }
462
- keyword() {
463
- return findChildToken(this.syntax, "Ident");
464
- }
465
- name() {
466
- return findFirstChild(this.syntax, IdentifierAst.cast);
467
- }
468
- lbrace() {
469
- return findChildToken(this.syntax, "LBrace");
470
- }
471
- rbrace() {
472
- return findChildToken(this.syntax, "RBrace");
473
- }
474
- *values() {
475
- yield* filterChildren(this.syntax, EnumValueDeclarationAst.cast);
476
- }
477
- *attributes() {
478
- yield* filterChildren(this.syntax, ModelAttributeAst.cast);
479
- }
480
- static cast(node) {
481
- return node.kind === "EnumDeclaration" ? new EnumDeclarationAst(node) : void 0;
482
- }
483
- };
484
714
  var CompositeTypeDeclarationAst = class CompositeTypeDeclarationAst {
485
715
  syntax;
486
716
  constructor(syntax) {
@@ -553,7 +783,7 @@ var TypesBlockAst = class TypesBlockAst {
553
783
  return node.kind === "TypesBlock" ? new TypesBlockAst(node) : void 0;
554
784
  }
555
785
  };
556
- var BlockDeclarationAst = class BlockDeclarationAst {
786
+ var GenericBlockDeclarationAst = class GenericBlockDeclarationAst {
557
787
  syntax;
558
788
  constructor(syntax) {
559
789
  this.syntax = syntax;
@@ -573,8 +803,11 @@ var BlockDeclarationAst = class BlockDeclarationAst {
573
803
  *entries() {
574
804
  yield* filterChildren(this.syntax, KeyValuePairAst.cast);
575
805
  }
806
+ *attributes() {
807
+ yield* filterChildren(this.syntax, ModelAttributeAst.cast);
808
+ }
576
809
  static cast(node) {
577
- return node.kind === "BlockDeclaration" ? new BlockDeclarationAst(node) : void 0;
810
+ return node.kind === "GenericBlockDeclaration" ? new GenericBlockDeclarationAst(node) : void 0;
578
811
  }
579
812
  };
580
813
  var KeyValuePairAst = class KeyValuePairAst {
@@ -623,21 +856,6 @@ var FieldDeclarationAst = class FieldDeclarationAst {
623
856
  return node.kind === "FieldDeclaration" ? new FieldDeclarationAst(node) : void 0;
624
857
  }
625
858
  };
626
- var EnumValueDeclarationAst = class EnumValueDeclarationAst {
627
- syntax;
628
- constructor(syntax) {
629
- this.syntax = syntax;
630
- }
631
- name() {
632
- return findFirstChild(this.syntax, IdentifierAst.cast);
633
- }
634
- *attributes() {
635
- yield* filterChildren(this.syntax, FieldAttributeAst.cast);
636
- }
637
- static cast(node) {
638
- return node.kind === "EnumValueDeclaration" ? new EnumValueDeclarationAst(node) : void 0;
639
- }
640
- };
641
859
  var NamedTypeDeclarationAst = class NamedTypeDeclarationAst {
642
860
  syntax;
643
861
  constructor(syntax) {
@@ -703,6 +921,498 @@ var GreenNodeBuilder = class {
703
921
  }
704
922
  };
705
923
  //#endregion
706
- export { ArrayLiteralAst, AttributeArgAst, AttributeArgListAst, BlockDeclarationAst, BooleanLiteralExprAst, CompositeTypeDeclarationAst, DocumentAst, EnumDeclarationAst, EnumValueDeclarationAst, FieldAttributeAst, FieldDeclarationAst, FunctionCallAst, GreenNodeBuilder, IdentifierAst, KeyValuePairAst, ModelAttributeAst, ModelDeclarationAst, NamedTypeDeclarationAst, NamespaceDeclarationAst, NumberLiteralExprAst, StringLiteralExprAst, SyntaxNode, TypeAnnotationAst, TypesBlockAst, castExpression, createSyntaxTree, filterChildren, findChildToken, findFirstChild, greenNode, greenToken };
924
+ //#region src/parse.ts
925
+ const TRIVIA_KINDS = new Set([
926
+ "Whitespace",
927
+ "Newline",
928
+ "Comment"
929
+ ]);
930
+ /**
931
+ * The fault-tolerant parser substrate the grammars drive. Trivia is flushed
932
+ * into the enclosing open node, so every child node spans exactly its first
933
+ * through last significant token.
934
+ */
935
+ var Cursor = class {
936
+ #tokenizer;
937
+ #sourceFile;
938
+ #builder = new GreenNodeBuilder();
939
+ #diagnostics = [];
940
+ #offset = 0;
941
+ #depth = 0;
942
+ constructor(source) {
943
+ this.#tokenizer = new Tokenizer(source);
944
+ this.#sourceFile = new SourceFile(source);
945
+ }
946
+ get diagnostics() {
947
+ return this.#diagnostics;
948
+ }
949
+ get sourceFile() {
950
+ return this.#sourceFile;
951
+ }
952
+ peekKind(ahead = 0) {
953
+ return this.peekToken(ahead).kind;
954
+ }
955
+ peekToken(ahead = 0) {
956
+ let rawIndex = 0;
957
+ let remaining = ahead;
958
+ for (;;) {
959
+ const token = this.#tokenizer.peek(rawIndex);
960
+ if (token.kind === "Eof") return token;
961
+ if (TRIVIA_KINDS.has(token.kind)) {
962
+ rawIndex++;
963
+ continue;
964
+ }
965
+ if (remaining === 0) return token;
966
+ remaining--;
967
+ rawIndex++;
968
+ }
969
+ }
970
+ /** Span of the significant token `lookahead` positions ahead (`mark(0)` = the next). */
971
+ mark(lookahead = 0) {
972
+ let rawIndex = 0;
973
+ let offset = this.#offset;
974
+ let remaining = lookahead;
975
+ for (;;) {
976
+ const token = this.#tokenizer.peek(rawIndex);
977
+ if (token.kind === "Eof") return {
978
+ offset,
979
+ length: token.text.length
980
+ };
981
+ if (!TRIVIA_KINDS.has(token.kind) && remaining === 0) return {
982
+ offset,
983
+ length: token.text.length
984
+ };
985
+ if (!TRIVIA_KINDS.has(token.kind)) remaining--;
986
+ offset += token.text.length;
987
+ rawIndex++;
988
+ }
989
+ }
990
+ /**
991
+ * Zero-width mark just past the last consumed significant token — anchors an
992
+ * "expected here" diagnostic, e.g. the `{` missing after a declaration's name.
993
+ */
994
+ markAfterLastToken() {
995
+ return {
996
+ offset: this.#offset,
997
+ length: 0
998
+ };
999
+ }
1000
+ startNode(kind) {
1001
+ if (this.#depth > 0) this.flushTrivia();
1002
+ this.#builder.startNode(kind);
1003
+ this.#depth++;
1004
+ }
1005
+ finishNode() {
1006
+ this.#depth--;
1007
+ return this.#builder.finishNode();
1008
+ }
1009
+ bump() {
1010
+ this.flushTrivia();
1011
+ const token = this.#tokenizer.peek();
1012
+ if (token.kind === "Eof") return token;
1013
+ this.#builder.token(token.kind, token.text);
1014
+ this.#advance();
1015
+ return token;
1016
+ }
1017
+ recoverToSyncPoint() {
1018
+ for (;;) {
1019
+ const token = this.#tokenizer.peek();
1020
+ if (token.kind === "Eof" || token.kind === "Newline" || token.kind === "RBrace") return;
1021
+ this.#builder.token(token.kind, token.text);
1022
+ this.#advance();
1023
+ }
1024
+ }
1025
+ flushTrivia() {
1026
+ for (;;) {
1027
+ const token = this.#tokenizer.peek();
1028
+ if (!TRIVIA_KINDS.has(token.kind)) return;
1029
+ this.#builder.token(token.kind, token.text);
1030
+ this.#advance();
1031
+ }
1032
+ }
1033
+ diagnostic(code, message, mark) {
1034
+ const start = mark.offset;
1035
+ const end = start + mark.length;
1036
+ this.#diagnostics.push({
1037
+ code,
1038
+ message,
1039
+ range: {
1040
+ start: this.#sourceFile.positionAt(start),
1041
+ end: this.#sourceFile.positionAt(end)
1042
+ }
1043
+ });
1044
+ }
1045
+ #advance() {
1046
+ this.#offset += this.#tokenizer.next().text.length;
1047
+ }
1048
+ };
1049
+ function parseIdentifier(cursor) {
1050
+ cursor.startNode("Identifier");
1051
+ cursor.bump();
1052
+ cursor.finishNode();
1053
+ }
1054
+ /**
1055
+ * Returns `undefined` when the next significant token does not start a
1056
+ * recognised expression, leaving recovery to the caller.
1057
+ */
1058
+ function parseExpression(cursor) {
1059
+ return parseStringLiteralExpr(cursor) ?? parseNumberLiteralExpr(cursor) ?? parseArrayLiteral(cursor) ?? parseObjectLiteralExpr(cursor) ?? parseFunctionCall(cursor) ?? parseBooleanLiteralExpr(cursor) ?? parseIdentifierExpr(cursor);
1060
+ }
1061
+ function parseStringLiteralExpr(cursor) {
1062
+ if (cursor.peekKind() !== "StringLiteral") return void 0;
1063
+ const stringMark = cursor.mark();
1064
+ const text = cursor.peekToken().text;
1065
+ cursor.startNode("StringLiteralExpr");
1066
+ cursor.bump();
1067
+ if (!isTerminatedStringLiteral(text)) cursor.diagnostic("PSL_UNTERMINATED_STRING", "Unterminated string literal", stringMark);
1068
+ return cursor.finishNode();
1069
+ }
1070
+ function parseNumberLiteralExpr(cursor) {
1071
+ if (cursor.peekKind() !== "NumberLiteral") return void 0;
1072
+ cursor.startNode("NumberLiteralExpr");
1073
+ cursor.bump();
1074
+ return cursor.finishNode();
1075
+ }
1076
+ /**
1077
+ * Parses a namespace-qualified name `[space ':']? Ident ('.' Ident)*`. The
1078
+ * caller guarantees a leading `Ident`.
1079
+ *
1080
+ * Parsing the whole chain up front lets a position decide
1081
+ * constructor-vs-reference by peeking exactly one token for `(`, with no scan of
1082
+ * the dotted chain's length.
1083
+ */
1084
+ function parseQualifiedName(cursor) {
1085
+ cursor.startNode("QualifiedName");
1086
+ parseIdentifier(cursor);
1087
+ parseQualifiedSegments(cursor, "Colon");
1088
+ parseQualifiedSegments(cursor, "Dot");
1089
+ cursor.finishNode();
1090
+ }
1091
+ /**
1092
+ * A well-formed name carries at most one colon space and one dot namespace, so
1093
+ * each separator past the first of its kind reports `PSL_INVALID_QUALIFIED_NAME`.
1094
+ * The separator is consumed regardless, keeping the lossless round-trip intact.
1095
+ */
1096
+ function parseQualifiedSegments(cursor, separator) {
1097
+ let seen = 0;
1098
+ while (cursor.peekKind() === separator) {
1099
+ seen++;
1100
+ const separatorMark = cursor.mark();
1101
+ cursor.bump();
1102
+ if (seen > 1) cursor.diagnostic("PSL_INVALID_QUALIFIED_NAME", "Qualified name has too many segments", separatorMark);
1103
+ if (cursor.peekKind() === "Ident") parseIdentifier(cursor);
1104
+ else cursor.diagnostic("PSL_INVALID_QUALIFIED_NAME", "Qualified name is missing a name after the separator", cursor.mark());
1105
+ }
1106
+ }
1107
+ function parseBooleanLiteralExpr(cursor) {
1108
+ if (cursor.peekKind() !== "Ident") return void 0;
1109
+ const text = cursor.peekToken().text;
1110
+ if (text !== "true" && text !== "false") return void 0;
1111
+ cursor.startNode("BooleanLiteralExpr");
1112
+ cursor.bump();
1113
+ return cursor.finishNode();
1114
+ }
1115
+ function parseIdentifierExpr(cursor) {
1116
+ if (cursor.peekKind() !== "Ident") return void 0;
1117
+ cursor.startNode("Identifier");
1118
+ cursor.bump();
1119
+ return cursor.finishNode();
1120
+ }
1121
+ function parseArrayLiteral(cursor) {
1122
+ if (cursor.peekKind() !== "LBracket") return void 0;
1123
+ cursor.startNode("ArrayLiteral");
1124
+ cursor.bump();
1125
+ while (cursor.peekKind() !== "RBracket" && cursor.peekKind() !== "Eof") {
1126
+ if (!parseExpression(cursor)) break;
1127
+ if (cursor.peekKind() === "Comma") cursor.bump();
1128
+ else break;
1129
+ }
1130
+ if (cursor.peekKind() === "RBracket") cursor.bump();
1131
+ return cursor.finishNode();
1132
+ }
1133
+ function parseObjectLiteralExpr(cursor) {
1134
+ if (cursor.peekKind() !== "LBrace") return void 0;
1135
+ const braceMark = cursor.mark();
1136
+ cursor.startNode("ObjectLiteralExpr");
1137
+ cursor.bump();
1138
+ while (cursor.peekKind() !== "RBrace" && cursor.peekKind() !== "Eof") {
1139
+ parseObjectField(cursor);
1140
+ if (cursor.peekKind() === "Comma") cursor.bump();
1141
+ else if (cursor.peekKind() === "Ident") cursor.diagnostic("PSL_INVALID_OBJECT_LITERAL", "Expected \",\" between object-literal fields", cursor.markAfterLastToken());
1142
+ else break;
1143
+ }
1144
+ if (cursor.peekKind() === "RBrace") cursor.bump();
1145
+ else cursor.diagnostic("PSL_INVALID_OBJECT_LITERAL", "Unterminated object literal", braceMark);
1146
+ return cursor.finishNode();
1147
+ }
1148
+ function parseObjectField(cursor) {
1149
+ cursor.startNode("ObjectField");
1150
+ const keyMark = cursor.mark();
1151
+ const keyText = cursor.peekToken().text;
1152
+ if (cursor.peekKind() === "Ident") parseIdentifier(cursor);
1153
+ else if (cursor.peekKind() === "StringLiteral") parseStringLiteralExpr(cursor);
1154
+ if (cursor.peekKind() === "Colon") {
1155
+ cursor.bump();
1156
+ if (!parseExpression(cursor)) cursor.diagnostic("PSL_INVALID_OBJECT_LITERAL", "Expected a value after \":\"", cursor.mark());
1157
+ } else {
1158
+ cursor.diagnostic("PSL_INVALID_OBJECT_LITERAL", `Expected ":" after "${keyText}"`, keyMark);
1159
+ if (!(cursor.peekKind() === "Ident" && cursor.peekKind(1) === "Colon")) parseExpression(cursor);
1160
+ }
1161
+ return cursor.finishNode();
1162
+ }
1163
+ /**
1164
+ * Whether the next tokens open a call: a bare `Ident(` or a namespace-qualified
1165
+ * `Ident.Ident(`. The lookahead is deliberately bounded so a bare dotted
1166
+ * reference like `a.b` is not mistaken for a call, rather than scanning an
1167
+ * unbounded dotted chain ahead to find the paren.
1168
+ */
1169
+ function isCallAhead(cursor) {
1170
+ if (cursor.peekKind() !== "Ident") return false;
1171
+ if (cursor.peekKind(1) === "LParen") return true;
1172
+ return cursor.peekKind(1) === "Dot" && cursor.peekKind(2) === "Ident" && cursor.peekKind(3) === "LParen";
1173
+ }
1174
+ /**
1175
+ * Parses a function/constructor call — bare `autoincrement()` or qualified
1176
+ * `temporal.updatedAt()`. Returns `undefined` unless {@link isCallAhead}
1177
+ * confirms a trailing `(`, so the `parseExpression` chain falls through to the
1178
+ * boolean and bare-identifier forms.
1179
+ */
1180
+ function parseFunctionCall(cursor) {
1181
+ if (!isCallAhead(cursor)) return void 0;
1182
+ cursor.startNode("FunctionCall");
1183
+ parseQualifiedName(cursor);
1184
+ if (cursor.peekKind() === "LParen") parseParenArgs(cursor);
1185
+ return cursor.finishNode();
1186
+ }
1187
+ /** Parses a parenthesised, comma-separated `AttributeArg` list into the currently open node. */
1188
+ function parseParenArgs(cursor) {
1189
+ cursor.bump();
1190
+ while (cursor.peekKind() !== "RParen" && cursor.peekKind() !== "Eof") {
1191
+ parseAttributeArg(cursor);
1192
+ if (cursor.peekKind() === "Comma") cursor.bump();
1193
+ else break;
1194
+ }
1195
+ if (cursor.peekKind() === "RParen") cursor.bump();
1196
+ }
1197
+ function parseAttributeArg(cursor) {
1198
+ cursor.startNode("AttributeArg");
1199
+ if (cursor.peekKind() === "Ident" && cursor.peekKind(1) === "Colon") {
1200
+ parseIdentifier(cursor);
1201
+ cursor.bump();
1202
+ }
1203
+ parseArgValue(cursor);
1204
+ return cursor.finishNode();
1205
+ }
1206
+ function parseArgValue(cursor) {
1207
+ parseExpression(cursor);
1208
+ }
1209
+ function parseAttributeArgList(cursor) {
1210
+ cursor.startNode("AttributeArgList");
1211
+ parseParenArgs(cursor);
1212
+ return cursor.finishNode();
1213
+ }
1214
+ function parseAttribute(cursor) {
1215
+ const isBlockAttribute = cursor.peekKind() === "DoubleAt";
1216
+ const attributeMark = cursor.mark();
1217
+ cursor.startNode(isBlockAttribute ? "ModelAttribute" : "FieldAttribute");
1218
+ cursor.bump();
1219
+ if (cursor.peekKind() === "Ident") parseQualifiedName(cursor);
1220
+ else cursor.diagnostic("PSL_INVALID_ATTRIBUTE_SYNTAX", "Attribute name expected", attributeMark);
1221
+ if (cursor.peekKind() === "LParen") parseAttributeArgList(cursor);
1222
+ return cursor.finishNode();
1223
+ }
1224
+ /** A type annotation: `QualifiedName (argList)? ([])? (?)?`, e.g. `pgvector.Vector(1536)[]?`. */
1225
+ function parseTypeAnnotation(cursor) {
1226
+ cursor.startNode("TypeAnnotation");
1227
+ if (cursor.peekKind() === "Ident") {
1228
+ parseQualifiedName(cursor);
1229
+ if (cursor.peekKind() === "LParen") parseAttributeArgList(cursor);
1230
+ }
1231
+ if (cursor.peekKind() === "LBracket") {
1232
+ cursor.bump();
1233
+ if (cursor.peekKind() === "RBracket") cursor.bump();
1234
+ }
1235
+ if (cursor.peekKind() === "Question") cursor.bump();
1236
+ return cursor.finishNode();
1237
+ }
1238
+ /**
1239
+ * Parses a full PSL document. Never throws — malformed input yields diagnostics
1240
+ * and a recovered tree, not an exception.
1241
+ */
1242
+ function parse(source) {
1243
+ const cursor = new Cursor(source);
1244
+ const root = createSyntaxTree(parseDocument(cursor));
1245
+ return {
1246
+ document: DocumentAst.cast(root) ?? new DocumentAst(root),
1247
+ diagnostics: cursor.diagnostics,
1248
+ sourceFile: cursor.sourceFile
1249
+ };
1250
+ }
1251
+ function parseDocument(cursor) {
1252
+ cursor.startNode("Document");
1253
+ while (cursor.peekKind() !== "Eof") parseDeclaration(cursor, false);
1254
+ cursor.flushTrivia();
1255
+ return cursor.finishNode();
1256
+ }
1257
+ const RESERVED_BLOCK_KEYWORDS = new Set([
1258
+ "model",
1259
+ "namespace",
1260
+ "type",
1261
+ "types"
1262
+ ]);
1263
+ function keywordIs(cursor, keyword) {
1264
+ return cursor.peekKind() === "Ident" && cursor.peekToken().text === keyword;
1265
+ }
1266
+ /**
1267
+ * Each alternative is a no-op on non-match, consuming nothing, so the
1268
+ * forward-only cursor is never left half-consumed by a rejected alternative.
1269
+ * Recovery runs via the `if (!node)` tail rather than as a `??` arm, because it
1270
+ * appends raw tokens to the open parent instead of returning a child node.
1271
+ */
1272
+ function parseDeclaration(cursor, insideNamespace) {
1273
+ const name = cursor.peekKind(1) === "Ident" ? cursor.peekToken(1).text : "";
1274
+ if (insideNamespace && keywordIs(cursor, "namespace")) cursor.diagnostic("PSL_INVALID_NAMESPACE_BLOCK", `Recursive "namespace ${name}" block is not allowed; namespace blocks may not nest`, cursor.mark());
1275
+ else if (insideNamespace && keywordIs(cursor, "types")) cursor.diagnostic("PSL_INVALID_NAMESPACE_BLOCK", "`types` blocks must be declared at the document top level, not inside a namespace block", cursor.mark());
1276
+ else if (keywordIs(cursor, "namespace") && name === UNSPECIFIED_PSL_NAMESPACE_ID) cursor.diagnostic("PSL_INVALID_NAMESPACE_BLOCK", `Namespace name "${UNSPECIFIED_PSL_NAMESPACE_ID}" is reserved for the parser-synthesised bucket for top-level declarations`, cursor.mark(1));
1277
+ if (!(parseModel(cursor) ?? parseNamespace(cursor) ?? parseCompositeType(cursor) ?? parseTypesBlock(cursor) ?? parseGenericBlock(cursor))) parseUnsupportedTopLevel(cursor);
1278
+ }
1279
+ /**
1280
+ * Reports only the first missing piece — a missing name suppresses the
1281
+ * missing-brace diagnostic. `nameRequired` is false only for the `types` block.
1282
+ */
1283
+ function parseBlock(cursor, kind, nameRequired, parseMember) {
1284
+ const keyword = cursor.peekToken().text;
1285
+ const keywordMark = cursor.mark();
1286
+ cursor.startNode(kind);
1287
+ cursor.bump();
1288
+ const hasName = nameRequired && cursor.peekKind() === "Ident";
1289
+ if (hasName) parseIdentifier(cursor);
1290
+ if (nameRequired && !hasName) cursor.diagnostic("PSL_INVALID_DECLARATION", `Expected a name after "${keyword}"`, keywordMark);
1291
+ else if (cursor.peekKind() !== "LBrace") cursor.diagnostic("PSL_INVALID_DECLARATION", `Expected "{" to open the "${keyword}" block`, cursor.markAfterLastToken());
1292
+ if (cursor.peekKind() === "LBrace") parseBlockBody(cursor, parseMember);
1293
+ else cursor.recoverToSyncPoint();
1294
+ return cursor.finishNode();
1295
+ }
1296
+ function parseModel(cursor) {
1297
+ if (!keywordIs(cursor, "model")) return void 0;
1298
+ return parseBlock(cursor, "ModelDeclaration", true, parseModelMember);
1299
+ }
1300
+ /**
1301
+ * Excluding the reserved keywords keeps a malformed reserved block (e.g. `model
1302
+ * {` with no name) routed to its dedicated parser. The generic keyword set is
1303
+ * open, so a bare identifier with no brace (e.g. `oops`) is read as an unfinished
1304
+ * custom declaration rather than unsupported content.
1305
+ */
1306
+ function parseGenericBlock(cursor) {
1307
+ if (cursor.peekKind() !== "Ident") return void 0;
1308
+ const keyword = cursor.peekToken().text;
1309
+ if (RESERVED_BLOCK_KEYWORDS.has(keyword)) return void 0;
1310
+ const hasName = cursor.peekKind(1) === "Ident" && cursor.peekKind(2) === "LBrace";
1311
+ cursor.startNode("GenericBlockDeclaration");
1312
+ cursor.bump();
1313
+ if (hasName) parseIdentifier(cursor);
1314
+ if (cursor.peekKind() === "LBrace") parseBlockBody(cursor, parseKeyValueMember);
1315
+ else {
1316
+ cursor.diagnostic("PSL_INVALID_DECLARATION", `Expected "{" to open the "${keyword}" block`, cursor.markAfterLastToken());
1317
+ cursor.recoverToSyncPoint();
1318
+ }
1319
+ return cursor.finishNode();
1320
+ }
1321
+ function parseNamespace(cursor) {
1322
+ if (!keywordIs(cursor, "namespace")) return void 0;
1323
+ return parseBlock(cursor, "Namespace", true, (inner) => parseDeclaration(inner, true));
1324
+ }
1325
+ function parseCompositeType(cursor) {
1326
+ if (!keywordIs(cursor, "type")) return void 0;
1327
+ return parseBlock(cursor, "CompositeTypeDeclaration", true, parseModelMember);
1328
+ }
1329
+ /** `types` (plural) is the no-name types block; the singular `type` is the composite type above. */
1330
+ function parseTypesBlock(cursor) {
1331
+ if (!keywordIs(cursor, "types")) return void 0;
1332
+ return parseBlock(cursor, "TypesBlock", false, parseNamedTypeMember);
1333
+ }
1334
+ /** Every `parseMember` consumes at least one significant token, so the loop always terminates. */
1335
+ function parseBlockBody(cursor, parseMember) {
1336
+ const braceMark = cursor.mark();
1337
+ cursor.bump();
1338
+ for (;;) {
1339
+ const kind = cursor.peekKind();
1340
+ if (kind === "RBrace" || kind === "Eof") break;
1341
+ parseMember(cursor);
1342
+ }
1343
+ if (cursor.peekKind() === "RBrace") cursor.bump();
1344
+ else cursor.diagnostic("PSL_UNTERMINATED_BLOCK", "Unterminated block declaration", braceMark);
1345
+ }
1346
+ function parseUnsupportedTopLevel(cursor) {
1347
+ const offending = cursor.peekToken().text;
1348
+ const message = cursor.peekKind(1) === "LBrace" ? `Unsupported top-level block "${offending}"` : `Unsupported top-level declaration "${offending}"`;
1349
+ cursor.diagnostic("PSL_UNSUPPORTED_TOP_LEVEL_BLOCK", message, cursor.mark());
1350
+ cursor.bump();
1351
+ cursor.recoverToSyncPoint();
1352
+ }
1353
+ /**
1354
+ * Matches a leading `@@` block attribute, a no-op otherwise. Single-`@`
1355
+ * attributes belong to fields and are parsed inside `parseField`.
1356
+ */
1357
+ function parseBlockAttribute(cursor) {
1358
+ if (cursor.peekKind() !== "DoubleAt") return void 0;
1359
+ return parseAttribute(cursor);
1360
+ }
1361
+ function parseModelMember(cursor) {
1362
+ if (!(parseBlockAttribute(cursor) ?? parseField(cursor))) invalidMember(cursor, "PSL_INVALID_MODEL_MEMBER", `Invalid model member declaration "${cursor.peekToken().text}"`);
1363
+ }
1364
+ function parseNamedTypeMember(cursor) {
1365
+ if (!parseNamedType(cursor)) invalidMember(cursor, "PSL_INVALID_TYPES_MEMBER", `Invalid types declaration "${cursor.peekToken().text}"`);
1366
+ }
1367
+ /**
1368
+ * A generic-block member is either a `@@`-block attribute or a `key = value`
1369
+ * entry. The block-attribute alternative is purely syntactic — it does not judge
1370
+ * whether the attribute is valid for the block's kind.
1371
+ */
1372
+ function parseKeyValueMember(cursor) {
1373
+ if (!(parseBlockAttribute(cursor) ?? parseKeyValue(cursor))) invalidMember(cursor, "PSL_INVALID_EXTENSION_BLOCK_MEMBER", "Invalid block entry");
1374
+ }
1375
+ function invalidMember(cursor, code, message) {
1376
+ cursor.diagnostic(code, message, cursor.mark());
1377
+ cursor.bump();
1378
+ cursor.recoverToSyncPoint();
1379
+ }
1380
+ function parseField(cursor) {
1381
+ if (cursor.peekKind() !== "Ident") return void 0;
1382
+ cursor.startNode("FieldDeclaration");
1383
+ parseIdentifier(cursor);
1384
+ parseTypeAnnotation(cursor);
1385
+ while (cursor.peekKind() === "At") parseAttribute(cursor);
1386
+ return cursor.finishNode();
1387
+ }
1388
+ function parseNamedType(cursor) {
1389
+ if (cursor.peekKind() !== "Ident") return void 0;
1390
+ cursor.startNode("NamedTypeDeclaration");
1391
+ const nameMark = cursor.mark();
1392
+ const nameText = cursor.peekToken().text;
1393
+ parseIdentifier(cursor);
1394
+ if (cursor.peekKind() === "Equals") cursor.bump();
1395
+ else cursor.diagnostic("PSL_INVALID_TYPES_MEMBER", `Expected "=" after "${nameText}"`, nameMark);
1396
+ parseTypeAnnotation(cursor);
1397
+ while (cursor.peekKind() === "At") parseAttribute(cursor);
1398
+ return cursor.finishNode();
1399
+ }
1400
+ /**
1401
+ * A generic-block entry is either `key = value` or a bare `key` (committing a
1402
+ * `KeyValuePair` carrying only the key). A `key =` with no following expression
1403
+ * is flagged.
1404
+ */
1405
+ function parseKeyValue(cursor) {
1406
+ if (cursor.peekKind() !== "Ident") return void 0;
1407
+ cursor.startNode("KeyValuePair");
1408
+ parseIdentifier(cursor);
1409
+ if (cursor.peekKind() === "Equals") {
1410
+ cursor.bump();
1411
+ if (!parseExpression(cursor)) cursor.diagnostic("PSL_INVALID_EXTENSION_BLOCK_MEMBER", "Expected a value after \"=\"", cursor.mark());
1412
+ }
1413
+ return cursor.finishNode();
1414
+ }
1415
+ //#endregion
1416
+ export { ArrayLiteralAst, AttributeArgAst, AttributeArgListAst, BooleanLiteralExprAst, CompositeTypeDeclarationAst, DocumentAst, FieldAttributeAst, FieldDeclarationAst, FunctionCallAst, GenericBlockDeclarationAst, GreenNodeBuilder, IdentifierAst, KeyValuePairAst, ModelAttributeAst, ModelDeclarationAst, NamedTypeDeclarationAst, NamespaceDeclarationAst, NumberLiteralExprAst, ObjectFieldAst, ObjectLiteralExprAst, QualifiedNameAst, SourceFile, StringLiteralExprAst, SyntaxNode, TypeAnnotationAst, TypesBlockAst, castExpression, createSyntaxTree, filterChildren, findChildToken, findFirstChild, greenNode, greenToken, parse, printSyntax };
707
1417
 
708
1418
  //# sourceMappingURL=syntax.mjs.map