@prisma-next/psl-parser 0.14.0-dev.9 → 0.14.0-dev.90

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.
Files changed (60) hide show
  1. package/dist/{declarations-D9h_ihD3.mjs → declarations-DR6To8_k.mjs} +295 -55
  2. package/dist/declarations-DR6To8_k.mjs.map +1 -0
  3. package/dist/format.d.mts +1 -1
  4. package/dist/format.mjs +2 -2
  5. package/dist/index.d.mts +115 -107
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +437 -60
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/interpret.d.mts +39 -0
  10. package/dist/interpret.d.mts.map +1 -0
  11. package/dist/interpret.mjs +25 -0
  12. package/dist/interpret.mjs.map +1 -0
  13. package/dist/{parse-BjZ1LPe6.d.mts → parse-BazJr7Ye.d.mts} +128 -51
  14. package/dist/parse-BazJr7Ye.d.mts.map +1 -0
  15. package/dist/{parse-DhEV6av6.mjs → parse-CdeXr0T3.mjs} +28 -7
  16. package/dist/parse-CdeXr0T3.mjs.map +1 -0
  17. package/dist/symbol-table-C-AH04Ug.d.mts +127 -0
  18. package/dist/symbol-table-C-AH04Ug.d.mts.map +1 -0
  19. package/dist/syntax.d.mts +20 -2
  20. package/dist/syntax.d.mts.map +1 -1
  21. package/dist/syntax.mjs +43 -3
  22. package/dist/syntax.mjs.map +1 -0
  23. package/package.json +10 -7
  24. package/src/attribute-spec/combinators/bool.ts +19 -0
  25. package/src/attribute-spec/combinators/diagnostic.ts +15 -0
  26. package/src/attribute-spec/combinators/entity-ref.ts +24 -0
  27. package/src/attribute-spec/combinators/field-ref.ts +36 -0
  28. package/src/attribute-spec/combinators/func-call.ts +65 -0
  29. package/src/attribute-spec/combinators/identifier.ts +16 -0
  30. package/src/attribute-spec/combinators/int.ts +35 -0
  31. package/src/attribute-spec/combinators/list.ts +43 -0
  32. package/src/attribute-spec/combinators/num.ts +26 -0
  33. package/src/attribute-spec/combinators/one-of.ts +29 -0
  34. package/src/attribute-spec/combinators/record.ts +43 -0
  35. package/src/attribute-spec/combinators/str.ts +19 -0
  36. package/src/attribute-spec/field-attribute.ts +27 -0
  37. package/src/attribute-spec/interpret.ts +177 -0
  38. package/src/attribute-spec/model-attribute.ts +27 -0
  39. package/src/attribute-spec/optional.ts +8 -0
  40. package/src/attribute-spec/types.ts +72 -0
  41. package/src/block-reconstruction.ts +1 -0
  42. package/src/exports/index.ts +34 -0
  43. package/src/exports/interpret.ts +2 -0
  44. package/src/exports/syntax.ts +25 -5
  45. package/src/interpret.ts +67 -0
  46. package/src/parse.ts +23 -5
  47. package/src/resolve.ts +4 -1
  48. package/src/source-file.ts +25 -0
  49. package/src/syntax/ast/attributes.ts +5 -6
  50. package/src/syntax/ast/declarations.ts +51 -26
  51. package/src/syntax/ast/expressions.ts +12 -13
  52. package/src/syntax/ast/identifier.ts +2 -3
  53. package/src/syntax/ast/qualified-name.ts +28 -19
  54. package/src/syntax/ast/type-annotation.ts +4 -5
  55. package/src/syntax/ast-helpers.ts +27 -3
  56. package/src/syntax/navigation.ts +55 -0
  57. package/src/syntax/red.ts +317 -42
  58. package/dist/declarations-D9h_ihD3.mjs.map +0 -1
  59. package/dist/parse-BjZ1LPe6.d.mts.map +0 -1
  60. package/dist/parse-DhEV6av6.mjs.map +0 -1
@@ -0,0 +1,127 @@
1
+ import { $ as Range, H as SyntaxNode, T as ExpressionAst, b as FieldAttributeAst, c as DocumentAst, et as SourceFile, h as NamespaceDeclarationAst, l as FieldDeclarationAst, m as NamedTypeDeclarationAst, o as CompositeTypeDeclarationAst, p as ModelDeclarationAst, t as ParseDiagnostic, u as GenericBlockDeclarationAst, v as TypeAnnotationAst, x as ModelAttributeAst } from "./parse-BazJr7Ye.mjs";
2
+ import { PslExtensionBlock, PslSpan } from "@prisma-next/framework-components/psl-ast";
3
+ import { AuthoringPslBlockDescriptorNamespace } from "@prisma-next/framework-components/authoring";
4
+
5
+ //#region src/resolve.d.ts
6
+ interface ResolvedAttributeArg {
7
+ readonly kind: 'positional' | 'named';
8
+ readonly name?: string;
9
+ readonly value: string;
10
+ readonly expression?: ExpressionAst;
11
+ readonly span: PslSpan;
12
+ }
13
+ interface ResolvedAttribute {
14
+ readonly name: string;
15
+ readonly args: readonly ResolvedAttributeArg[];
16
+ readonly span: PslSpan;
17
+ }
18
+ interface ResolvedTypeConstructorCall {
19
+ readonly path: readonly string[];
20
+ readonly args: readonly ResolvedAttributeArg[];
21
+ readonly span: PslSpan;
22
+ }
23
+ declare function readResolvedAttribute(attribute: FieldAttributeAst | ModelAttributeAst, sourceFile: SourceFile): ResolvedAttribute;
24
+ declare function readResolvedAttributes(attributes: Iterable<FieldAttributeAst | ModelAttributeAst>, sourceFile: SourceFile): readonly ResolvedAttribute[];
25
+ declare function readResolvedConstructorCall(annotation: TypeAnnotationAst | undefined, sourceFile: SourceFile): ResolvedTypeConstructorCall | undefined;
26
+ declare function nodePslSpan(node: SyntaxNode, sourceFile: SourceFile): PslSpan;
27
+ /** Unsupported-top-level-block diagnostics are anchored to the keyword token. */
28
+ declare function keywordPslSpan(node: SyntaxNode, keyword: string, sourceFile: SourceFile): PslSpan;
29
+ declare function rangeToPslSpan(range: Range, sourceFile: SourceFile): PslSpan;
30
+ //#endregion
31
+ //#region src/symbol-table.d.ts
32
+ interface SymbolTable {
33
+ readonly topLevel: TopLevelScope;
34
+ }
35
+ interface TopLevelScope {
36
+ readonly namespaces: Record<string, NamespaceSymbol>;
37
+ readonly scalars: Record<string, ScalarSymbol>;
38
+ readonly typeAliases: Record<string, TypeAliasSymbol>;
39
+ readonly blocks: Record<string, BlockSymbol>;
40
+ readonly models: Record<string, ModelSymbol>;
41
+ readonly compositeTypes: Record<string, CompositeTypeSymbol>;
42
+ }
43
+ interface NamespaceSymbol {
44
+ readonly kind: 'namespace';
45
+ readonly name: string;
46
+ readonly node: NamespaceDeclarationAst;
47
+ readonly span: PslSpan;
48
+ readonly models: Record<string, ModelSymbol>;
49
+ readonly compositeTypes: Record<string, CompositeTypeSymbol>;
50
+ readonly blocks: Record<string, BlockSymbol>;
51
+ }
52
+ interface ModelSymbol {
53
+ readonly kind: 'model';
54
+ readonly name: string;
55
+ readonly node: ModelDeclarationAst;
56
+ readonly span: PslSpan;
57
+ readonly fields: Record<string, FieldSymbol>;
58
+ readonly attributes: readonly ResolvedAttribute[];
59
+ }
60
+ interface CompositeTypeSymbol {
61
+ readonly kind: 'compositeType';
62
+ readonly name: string;
63
+ readonly node: CompositeTypeDeclarationAst;
64
+ readonly span: PslSpan;
65
+ readonly fields: Record<string, FieldSymbol>;
66
+ readonly attributes: readonly ResolvedAttribute[];
67
+ }
68
+ interface BlockSymbol {
69
+ readonly kind: 'block';
70
+ readonly name: string;
71
+ readonly keyword: string;
72
+ readonly node: GenericBlockDeclarationAst;
73
+ readonly span: PslSpan;
74
+ /** Resolved once so consumers do not independently classify block parameters. */
75
+ readonly block: PslExtensionBlock;
76
+ }
77
+ interface ResolvedNamedTypeBinding {
78
+ readonly baseType?: string;
79
+ readonly typeConstructor?: ResolvedTypeConstructorCall;
80
+ readonly isConstructor: boolean;
81
+ readonly attributes: readonly ResolvedAttribute[];
82
+ }
83
+ interface ScalarSymbol extends ResolvedNamedTypeBinding {
84
+ readonly kind: 'scalar';
85
+ readonly name: string;
86
+ readonly node: NamedTypeDeclarationAst;
87
+ readonly span: PslSpan;
88
+ }
89
+ interface TypeAliasSymbol extends ResolvedNamedTypeBinding {
90
+ readonly kind: 'typeAlias';
91
+ readonly name: string;
92
+ readonly node: NamedTypeDeclarationAst;
93
+ readonly span: PslSpan;
94
+ }
95
+ interface FieldSymbol {
96
+ readonly kind: 'field';
97
+ readonly name: string;
98
+ readonly node: FieldDeclarationAst;
99
+ readonly span: PslSpan;
100
+ readonly typeName: string;
101
+ readonly typeNamespaceId?: string;
102
+ readonly typeContractSpaceId?: string;
103
+ readonly optional: boolean;
104
+ readonly list: boolean;
105
+ readonly typeConstructor?: ResolvedTypeConstructorCall;
106
+ readonly attributes: readonly ResolvedAttribute[];
107
+ /** Prevents cascading unsupported-type diagnostics after invalid qualification. */
108
+ readonly malformedType?: boolean;
109
+ }
110
+ interface BuildSymbolTableOptions {
111
+ readonly document: DocumentAst;
112
+ readonly sourceFile: SourceFile;
113
+ readonly scalarTypes: readonly string[];
114
+ readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace;
115
+ }
116
+ interface SymbolTableResult {
117
+ readonly table: SymbolTable;
118
+ readonly diagnostics: readonly ParseDiagnostic[];
119
+ }
120
+ /**
121
+ * Owns duplicate-declaration detection for all PSL scopes; downstream consumers
122
+ * should consume first-wins symbols rather than re-emitting duplicate diagnostics.
123
+ */
124
+ declare function buildSymbolTable(options: BuildSymbolTableOptions): SymbolTableResult;
125
+ //#endregion
126
+ export { readResolvedConstructorCall as S, keywordPslSpan as _, ModelSymbol as a, readResolvedAttribute as b, ScalarSymbol as c, TopLevelScope as d, TypeAliasSymbol as f, ResolvedTypeConstructorCall as g, ResolvedAttributeArg as h, FieldSymbol as i, SymbolTable as l, ResolvedAttribute as m, BuildSymbolTableOptions as n, NamespaceSymbol as o, buildSymbolTable as p, CompositeTypeSymbol as r, ResolvedNamedTypeBinding as s, BlockSymbol as t, SymbolTableResult as u, nodePslSpan as v, readResolvedAttributes as x, rangeToPslSpan as y };
127
+ //# sourceMappingURL=symbol-table-C-AH04Ug.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-table-C-AH04Ug.d.mts","names":[],"sources":["../src/resolve.ts","../src/symbol-table.ts"],"mappings":"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"}
package/dist/syntax.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AstNode, B as GreenNode, C as NumberLiteralExprAst, D as castExpression, E as StringLiteralExprAst, F as SyntaxElement, G as Position, H as greenNode, I as SyntaxNode, K as Range, L as SyntaxToken, M as findChildToken, N as findFirstChild, O as QualifiedNameAst, P as printSyntax, R as createSyntaxTree, S as FunctionCallAst, T as ObjectLiteralExprAst, U as greenToken, V as GreenToken, W as SyntaxKind, _ as ModelAttributeAst, a as DocumentAst, b as BooleanLiteralExprAst, c as KeyValuePairAst, d as NamespaceDeclarationAst, f as NamespaceMemberAst, g as FieldAttributeAst, h as AttributeArgListAst, i as CompositeTypeDeclarationAst, j as filterChildren, k as IdentifierAst, l as ModelDeclarationAst, m as TypeAnnotationAst, n as ParseResult, o as FieldDeclarationAst, p as TypesBlockAst, q as SourceFile, r as parse, s as GenericBlockDeclarationAst, t as ParseDiagnostic, u as NamedTypeDeclarationAst, v as ArrayLiteralAst, w as ObjectFieldAst, x as ExpressionAst, y as AttributeArgAst, z as GreenElement } from "./parse-BjZ1LPe6.mjs";
1
+ import { $ as Range, A as StringLiteralExprAst, B as printSyntax, C as AttributeArgAst, D as NumberLiteralExprAst, E as FunctionCallAst, F as BracedBlock, G as createSyntaxTree, H as SyntaxNode, I as any, J as GreenToken, K as GreenElement, L as filterChildren, M as QualifiedNameAst, N as IdentifierAst, O as ObjectFieldAst, P as AstNode, Q as Position, R as findChildToken, S as ArrayLiteralAst, T as ExpressionAst, U as SyntaxToken, V as SyntaxElement, W as TokenAtOffset, X as greenToken, Y as greenNode, Z as SyntaxKind, _ as TypesBlockAst, a as BlockMemberAst, b as FieldAttributeAst, c as DocumentAst, d as GenericBlockMemberAst, et as SourceFile, f as KeyValuePairAst, g as NamespaceMemberAst, h as NamespaceDeclarationAst, i as AttributeAst, j as castExpression, k as ObjectLiteralExprAst, l as FieldDeclarationAst, m as NamedTypeDeclarationAst, n as ParseResult, o as CompositeTypeDeclarationAst, p as ModelDeclarationAst, q as GreenNode, r as parse, s as DeclarationAst, t as ParseDiagnostic, u as GenericBlockDeclarationAst, v as TypeAnnotationAst, w as BooleanLiteralExprAst, x as ModelAttributeAst, y as AttributeArgListAst, z as findFirstChild } from "./parse-BazJr7Ye.mjs";
2
2
  import { n as TokenKind } from "./tokenizer-DcYI0Xrq.mjs";
3
3
 
4
4
  //#region src/syntax/green-builder.d.ts
@@ -9,5 +9,23 @@ declare class GreenNodeBuilder {
9
9
  finishNode(): GreenNode;
10
10
  }
11
11
  //#endregion
12
- export { ArrayLiteralAst, type AstNode, AttributeArgAst, AttributeArgListAst, BooleanLiteralExprAst, CompositeTypeDeclarationAst, DocumentAst, type ExpressionAst, FieldAttributeAst, FieldDeclarationAst, FunctionCallAst, GenericBlockDeclarationAst, type GreenElement, type GreenNode, GreenNodeBuilder, type GreenToken, IdentifierAst, KeyValuePairAst, ModelAttributeAst, ModelDeclarationAst, NamedTypeDeclarationAst, NamespaceDeclarationAst, type NamespaceMemberAst, NumberLiteralExprAst, ObjectFieldAst, ObjectLiteralExprAst, type ParseDiagnostic, type ParseResult, type Position, QualifiedNameAst, type Range, SourceFile, StringLiteralExprAst, type SyntaxElement, type SyntaxKind, SyntaxNode, type SyntaxToken, TypeAnnotationAst, TypesBlockAst, castExpression, createSyntaxTree, filterChildren, findChildToken, findFirstChild, greenNode, greenToken, parse, printSyntax };
12
+ //#region src/syntax/navigation.d.ts
13
+ /** Direction of a sibling/token walk. */
14
+ type Direction = 'next' | 'prev';
15
+ /** Whether a token kind is trivia (whitespace, newline, or comment). */
16
+ declare function isTriviaKind(kind: TokenKind): boolean;
17
+ /** Whether a token is trivia. */
18
+ declare function isTrivia(token: SyntaxToken): boolean;
19
+ /**
20
+ * The first non-trivia token at or beyond `token` in `direction`. Returns
21
+ * `token` itself when it is already significant.
22
+ */
23
+ declare function skipTriviaToken(token: SyntaxToken, direction: Direction): SyntaxToken | undefined;
24
+ /**
25
+ * The nearest sibling of `element` (within the same parent) in `direction` that
26
+ * is not a trivia token. Nodes are always significant.
27
+ */
28
+ declare function nonTriviaSibling(element: SyntaxElement, direction: Direction): SyntaxElement | undefined;
29
+ //#endregion
30
+ export { ArrayLiteralAst, type AstNode, AttributeArgAst, AttributeArgListAst, type AttributeAst, type BlockMemberAst, BooleanLiteralExprAst, type BracedBlock, CompositeTypeDeclarationAst, type DeclarationAst, type Direction, DocumentAst, type ExpressionAst, FieldAttributeAst, FieldDeclarationAst, FunctionCallAst, GenericBlockDeclarationAst, type GenericBlockMemberAst, type GreenElement, type GreenNode, GreenNodeBuilder, type GreenToken, IdentifierAst, KeyValuePairAst, ModelAttributeAst, ModelDeclarationAst, NamedTypeDeclarationAst, NamespaceDeclarationAst, type NamespaceMemberAst, NumberLiteralExprAst, ObjectFieldAst, ObjectLiteralExprAst, type ParseDiagnostic, type ParseResult, type Position, QualifiedNameAst, type Range, SourceFile, StringLiteralExprAst, type SyntaxElement, type SyntaxKind, SyntaxNode, SyntaxToken, TokenAtOffset, TypeAnnotationAst, TypesBlockAst, any, castExpression, createSyntaxTree, filterChildren, findChildToken, findFirstChild, greenNode, greenToken, isTrivia, isTriviaKind, nonTriviaSibling, parse, printSyntax, skipTriviaToken };
13
31
  //# sourceMappingURL=syntax.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"syntax.d.mts","names":[],"sources":["../src/syntax/green-builder.ts"],"mappings":";;;;cAKa,gBAAA;EAAA;EAGX,SAAA,CAAU,IAAA,EAAM,UAAA;EAIhB,KAAA,CAAM,IAAA,EAAM,SAAA,EAAW,IAAA;EAQvB,UAAA,IAAc,SAAA;AAAA"}
1
+ {"version":3,"file":"syntax.d.mts","names":[],"sources":["../src/syntax/green-builder.ts","../src/syntax/navigation.ts"],"mappings":";;;;cAKa,gBAAA;EAAA;EAGX,SAAA,CAAU,IAAA,EAAM,UAAA;EAIhB,KAAA,CAAM,IAAA,EAAM,SAAA,EAAW,IAAA;EAQvB,UAAA,IAAc,SAAA;AAAA;;;;KChBJ,SAAA;ADCZ;AAAA,iBCQgB,YAAA,CAAa,IAAe,EAAT,SAAS;;iBAK5B,QAAA,CAAS,KAAkB,EAAX,WAAW;;;;;iBAQ3B,eAAA,CAAgB,KAAA,EAAO,WAAA,EAAa,SAAA,EAAW,SAAA,GAAY,WAAA;;;;;iBAY3D,gBAAA,CACd,OAAA,EAAS,aAAA,EACT,SAAA,EAAW,SAAA,GACV,aAAA"}
package/dist/syntax.mjs CHANGED
@@ -1,3 +1,43 @@
1
- import { A as createSyntaxTree, C as QualifiedNameAst, D as findFirstChild, E as findChildToken, O as printSyntax, S as castExpression, T as filterChildren, _ as FunctionCallAst, a as KeyValuePairAst, b as ObjectLiteralExprAst, c as NamespaceDeclarationAst, d as AttributeArgListAst, f as FieldAttributeAst, g as BooleanLiteralExprAst, h as AttributeArgAst, i as GenericBlockDeclarationAst, k as SyntaxNode, l as TypesBlockAst, m as ArrayLiteralAst, n as DocumentAst, o as ModelDeclarationAst, p as ModelAttributeAst, r as FieldDeclarationAst, s as NamedTypeDeclarationAst, t as CompositeTypeDeclarationAst, u as TypeAnnotationAst, v as NumberLiteralExprAst, w as IdentifierAst, x as StringLiteralExprAst, y as ObjectFieldAst } from "./declarations-D9h_ihD3.mjs";
2
- import { a as SourceFile, i as greenToken, n as GreenNodeBuilder, r as greenNode, t as parse } from "./parse-DhEV6av6.mjs";
3
- 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 };
1
+ import { A as SyntaxNode, C as QualifiedNameAst, D as findChildToken, E as filterChildren, M as TokenAtOffset, N as createSyntaxTree, O as findFirstChild, S as castExpression, T as any, _ as FunctionCallAst, a as KeyValuePairAst, b as ObjectLiteralExprAst, c as NamespaceDeclarationAst, d as AttributeArgListAst, f as FieldAttributeAst, g as BooleanLiteralExprAst, h as AttributeArgAst, i as GenericBlockDeclarationAst, j as SyntaxToken, k as printSyntax, l as TypesBlockAst, m as ArrayLiteralAst, n as DocumentAst, o as ModelDeclarationAst, p as ModelAttributeAst, r as FieldDeclarationAst, s as NamedTypeDeclarationAst, t as CompositeTypeDeclarationAst, u as TypeAnnotationAst, v as NumberLiteralExprAst, w as IdentifierAst, x as StringLiteralExprAst, y as ObjectFieldAst } from "./declarations-DR6To8_k.mjs";
2
+ import { a as SourceFile, i as greenToken, n as GreenNodeBuilder, r as greenNode, t as parse } from "./parse-CdeXr0T3.mjs";
3
+ //#region src/syntax/navigation.ts
4
+ const TRIVIA_KINDS = /* @__PURE__ */ new Set([
5
+ "Whitespace",
6
+ "Newline",
7
+ "Comment"
8
+ ]);
9
+ /** Whether a token kind is trivia (whitespace, newline, or comment). */
10
+ function isTriviaKind(kind) {
11
+ return TRIVIA_KINDS.has(kind);
12
+ }
13
+ /** Whether a token is trivia. */
14
+ function isTrivia(token) {
15
+ return isTriviaKind(token.kind);
16
+ }
17
+ /**
18
+ * The first non-trivia token at or beyond `token` in `direction`. Returns
19
+ * `token` itself when it is already significant.
20
+ */
21
+ function skipTriviaToken(token, direction) {
22
+ let current = token;
23
+ while (current !== void 0 && isTrivia(current)) current = direction === "next" ? current.nextToken : current.prevToken;
24
+ return current;
25
+ }
26
+ /**
27
+ * The nearest sibling of `element` (within the same parent) in `direction` that
28
+ * is not a trivia token. Nodes are always significant.
29
+ */
30
+ function nonTriviaSibling(element, direction) {
31
+ let sibling = step(element, direction);
32
+ while (sibling !== void 0) {
33
+ if (!(sibling instanceof SyntaxToken) || !isTrivia(sibling)) return sibling;
34
+ sibling = step(sibling, direction);
35
+ }
36
+ }
37
+ function step(element, direction) {
38
+ return direction === "next" ? element.nextSiblingOrToken : element.prevSiblingOrToken;
39
+ }
40
+ //#endregion
41
+ 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, SyntaxToken, TokenAtOffset, TypeAnnotationAst, TypesBlockAst, any, castExpression, createSyntaxTree, filterChildren, findChildToken, findFirstChild, greenNode, greenToken, isTrivia, isTriviaKind, nonTriviaSibling, parse, printSyntax, skipTriviaToken };
42
+
43
+ //# sourceMappingURL=syntax.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax.mjs","names":[],"sources":["../src/syntax/navigation.ts"],"sourcesContent":["import type { TokenKind } from '../tokenizer';\nimport { type SyntaxElement, SyntaxToken } from './red';\n\n/** Direction of a sibling/token walk. */\nexport type Direction = 'next' | 'prev';\n\nconst TRIVIA_KINDS: ReadonlySet<TokenKind> = new Set<TokenKind>([\n 'Whitespace',\n 'Newline',\n 'Comment',\n]);\n\n/** Whether a token kind is trivia (whitespace, newline, or comment). */\nexport function isTriviaKind(kind: TokenKind): boolean {\n return TRIVIA_KINDS.has(kind);\n}\n\n/** Whether a token is trivia. */\nexport function isTrivia(token: SyntaxToken): boolean {\n return isTriviaKind(token.kind);\n}\n\n/**\n * The first non-trivia token at or beyond `token` in `direction`. Returns\n * `token` itself when it is already significant.\n */\nexport function skipTriviaToken(token: SyntaxToken, direction: Direction): SyntaxToken | undefined {\n let current: SyntaxToken | undefined = token;\n while (current !== undefined && isTrivia(current)) {\n current = direction === 'next' ? current.nextToken : current.prevToken;\n }\n return current;\n}\n\n/**\n * The nearest sibling of `element` (within the same parent) in `direction` that\n * is not a trivia token. Nodes are always significant.\n */\nexport function nonTriviaSibling(\n element: SyntaxElement,\n direction: Direction,\n): SyntaxElement | undefined {\n let sibling = step(element, direction);\n while (sibling !== undefined) {\n if (!(sibling instanceof SyntaxToken) || !isTrivia(sibling)) {\n return sibling;\n }\n sibling = step(sibling, direction);\n }\n return undefined;\n}\n\nfunction step(element: SyntaxElement, direction: Direction): SyntaxElement | undefined {\n return direction === 'next' ? element.nextSiblingOrToken : element.prevSiblingOrToken;\n}\n"],"mappings":";;;AAMA,MAAM,+BAAuC,IAAI,IAAe;CAC9D;CACA;CACA;AACF,CAAC;;AAGD,SAAgB,aAAa,MAA0B;CACrD,OAAO,aAAa,IAAI,IAAI;AAC9B;;AAGA,SAAgB,SAAS,OAA6B;CACpD,OAAO,aAAa,MAAM,IAAI;AAChC;;;;;AAMA,SAAgB,gBAAgB,OAAoB,WAA+C;CACjG,IAAI,UAAmC;CACvC,OAAO,YAAY,KAAA,KAAa,SAAS,OAAO,GAC9C,UAAU,cAAc,SAAS,QAAQ,YAAY,QAAQ;CAE/D,OAAO;AACT;;;;;AAMA,SAAgB,iBACd,SACA,WAC2B;CAC3B,IAAI,UAAU,KAAK,SAAS,SAAS;CACrC,OAAO,YAAY,KAAA,GAAW;EAC5B,IAAI,EAAE,mBAAmB,gBAAgB,CAAC,SAAS,OAAO,GACxD,OAAO;EAET,UAAU,KAAK,SAAS,SAAS;CACnC;AAEF;AAEA,SAAS,KAAK,SAAwB,WAAiD;CACrF,OAAO,cAAc,SAAS,QAAQ,qBAAqB,QAAQ;AACrE"}
package/package.json CHANGED
@@ -1,20 +1,22 @@
1
1
  {
2
2
  "name": "@prisma-next/psl-parser",
3
- "version": "0.14.0-dev.9",
3
+ "version": "0.14.0-dev.90",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "Reusable parser for Prisma Schema Language (PSL)",
8
8
  "dependencies": {
9
- "@prisma-next/framework-components": "0.14.0-dev.9",
10
- "@prisma-next/utils": "0.14.0-dev.9"
9
+ "@prisma-next/config": "0.14.0-dev.90",
10
+ "@prisma-next/contract": "0.14.0-dev.90",
11
+ "@prisma-next/framework-components": "0.14.0-dev.90",
12
+ "@prisma-next/utils": "0.14.0-dev.90"
11
13
  },
12
14
  "devDependencies": {
13
- "@prisma-next/tsconfig": "0.14.0-dev.9",
14
- "@prisma-next/tsdown": "0.14.0-dev.9",
15
- "tsdown": "0.22.1",
15
+ "@prisma-next/tsconfig": "0.14.0-dev.90",
16
+ "@prisma-next/tsdown": "0.14.0-dev.90",
17
+ "tsdown": "0.22.3",
16
18
  "typescript": "5.9.3",
17
- "vitest": "4.1.8"
19
+ "vitest": "4.1.10"
18
20
  },
19
21
  "peerDependencies": {
20
22
  "typescript": ">=5.9"
@@ -32,6 +34,7 @@
32
34
  "exports": {
33
35
  ".": "./dist/index.mjs",
34
36
  "./format": "./dist/format.mjs",
37
+ "./interpret": "./dist/interpret.mjs",
35
38
  "./syntax": "./dist/syntax.mjs",
36
39
  "./tokenizer": "./dist/tokenizer.mjs",
37
40
  "./package.json": "./package.json"
@@ -0,0 +1,19 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { BooleanLiteralExprAst } from '../../syntax/ast/expressions';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export function bool(): ArgType<boolean> {
8
+ return {
9
+ kind: 'bool',
10
+ label: 'boolean',
11
+ parse: (arg, ctx): Result<boolean, readonly PslDiagnostic[]> => {
12
+ if (arg instanceof BooleanLiteralExprAst) {
13
+ const value = arg.value();
14
+ if (value !== undefined) return ok(value);
15
+ }
16
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a boolean literal')]);
17
+ },
18
+ };
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { PslDiagnostic, PslDiagnosticCode } from '@prisma-next/framework-components/psl-ast';
2
+ import { nodePslSpan } from '../../resolve';
3
+ import type { AstNode } from '../../syntax/ast-helpers';
4
+ import type { InterpretCtx } from '../types';
5
+
6
+ export const ATTRIBUTE_DIAGNOSTIC_CODE: PslDiagnosticCode = 'PSL_INVALID_ATTRIBUTE_SYNTAX';
7
+
8
+ export function leafDiagnostic(ctx: InterpretCtx, node: AstNode, message: string): PslDiagnostic {
9
+ return {
10
+ code: ATTRIBUTE_DIAGNOSTIC_CODE,
11
+ message,
12
+ sourceId: ctx.sourceId,
13
+ span: nodePslSpan(node.syntax, ctx.sourceFile),
14
+ };
15
+ }
@@ -0,0 +1,24 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { IdentifierAst } from '../../syntax/ast/identifier';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ // A bare model-name reference. Existence of a model with this name is resolved
8
+ // downstream (e.g. `resolvePolymorphism`), not here.
9
+ export function entityRef(): ArgType<string> {
10
+ return {
11
+ kind: 'entityRef',
12
+ label: 'model name',
13
+ parse: (arg, ctx): Result<string, readonly PslDiagnostic[]> => {
14
+ if (!(arg instanceof IdentifierAst)) {
15
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a model name')]);
16
+ }
17
+ const name = arg.name();
18
+ if (name === undefined) {
19
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a model name')]);
20
+ }
21
+ return ok(name);
22
+ },
23
+ };
24
+ }
@@ -0,0 +1,36 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { IdentifierAst } from '../../syntax/ast/identifier';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export type FieldRefScope = 'self' | 'referenced';
8
+
9
+ export interface FieldRefArgType extends ArgType<string> {
10
+ readonly scope: FieldRefScope;
11
+ }
12
+
13
+ export function fieldRef(scope: FieldRefScope): FieldRefArgType {
14
+ return {
15
+ kind: 'fieldRef',
16
+ label: 'field name',
17
+ scope,
18
+ parse: (arg, ctx): Result<string, readonly PslDiagnostic[]> => {
19
+ if (!(arg instanceof IdentifierAst)) {
20
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a field name')]);
21
+ }
22
+ const name = arg.name();
23
+ if (name === undefined) {
24
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a field name')]);
25
+ }
26
+ const model = scope === 'self' ? ctx.selfModel : ctx.resolveReferencedModel();
27
+ // A referenced model in another space can't be resolved here (resolveReferencedModel returns undefined); skip the existence check — it runs where that model is known.
28
+ if (model !== undefined && !Object.hasOwn(model.fields, name)) {
29
+ return notOk([
30
+ leafDiagnostic(ctx, arg, `Field "${name}" does not exist on model "${model.name}"`),
31
+ ]);
32
+ }
33
+ return ok(name);
34
+ },
35
+ };
36
+ }
@@ -0,0 +1,65 @@
1
+ import type { PslDiagnostic, PslSpan } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { nodePslSpan } from '../../resolve';
4
+ import type { ExpressionAst } from '../../syntax/ast/expressions';
5
+ import { FunctionCallAst } from '../../syntax/ast/expressions';
6
+ import { interpretArgs } from '../interpret';
7
+ import type { ArgType, InterpretCtx, Param, PositionalParam } from '../types';
8
+ import { leafDiagnostic } from './diagnostic';
9
+
10
+ // The argument signature of a pinned function call — the same positional/named shape an attribute
11
+ // spec uses. Omitted groups default to empty, so a nullary call needs neither key.
12
+ export interface FuncCallSig {
13
+ readonly positional?: readonly PositionalParam<unknown>[];
14
+ readonly named?: Readonly<Record<string, Param<unknown>>>;
15
+ }
16
+
17
+ export interface TypedFuncCall {
18
+ readonly fn: string;
19
+ readonly span: PslSpan;
20
+ readonly args: Readonly<Record<string, unknown>>;
21
+ }
22
+
23
+ // A name-pinned function-call argument — `funcCall('now', {})` matches `now()`, parsing the call's
24
+ // arguments through `sig`.
25
+ export function funcCall(name: string, sig: FuncCallSig): ArgType<TypedFuncCall> {
26
+ return {
27
+ kind: 'funcCall',
28
+ label: 'function call',
29
+ parse: (arg, ctx): Result<TypedFuncCall, readonly PslDiagnostic[]> => {
30
+ const guard = matchCallee(arg, name, ctx);
31
+ if (!guard.ok) return guard;
32
+ const span = nodePslSpan(guard.value.syntax, ctx.sourceFile);
33
+ const bound = interpretArgs(
34
+ guard.value.args(),
35
+ { name, positional: sig.positional ?? [], named: sig.named ?? {} },
36
+ ctx,
37
+ span,
38
+ );
39
+ if (!bound.ok) return notOk<readonly PslDiagnostic[]>(bound.failure);
40
+ return ok({ fn: name, span, args: bound.value });
41
+ },
42
+ };
43
+ }
44
+
45
+ function matchCallee(
46
+ arg: ExpressionAst,
47
+ name: string,
48
+ ctx: InterpretCtx,
49
+ ): Result<FunctionCallAst, readonly PslDiagnostic[]> {
50
+ if (!(arg instanceof FunctionCallAst)) {
51
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a function call')]);
52
+ }
53
+ const qname = arg.name();
54
+ if (qname === undefined || qname.dot() !== undefined || qname.colon() !== undefined) {
55
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a function call')]);
56
+ }
57
+ const calleeName = qname.identifier()?.token()?.text;
58
+ if (calleeName === undefined) {
59
+ return notOk([leafDiagnostic(ctx, arg, 'Expected a function call')]);
60
+ }
61
+ if (calleeName !== name) {
62
+ return notOk([leafDiagnostic(ctx, arg, `Expected ${name}()`)]);
63
+ }
64
+ return ok(arg);
65
+ }
@@ -0,0 +1,16 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { IdentifierAst } from '../../syntax/ast/identifier';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export function identifier<const N extends string>(name: N): ArgType<N> {
8
+ return {
9
+ kind: 'identifier',
10
+ label: name,
11
+ parse: (arg, ctx): Result<N, readonly PslDiagnostic[]> => {
12
+ if (arg instanceof IdentifierAst && arg.name() === name) return ok(name);
13
+ return notOk([leafDiagnostic(ctx, arg, `Expected ${name}`)]);
14
+ },
15
+ };
16
+ }
@@ -0,0 +1,35 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { NumberLiteralExprAst } from '../../syntax/ast/expressions';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ // An integer literal reduced to its numeric value. Passing `min`/`max` additionally rejects
8
+ // out-of-range integers with a distinct range message, leaving the integer-only check intact.
9
+ export function int(opts?: { min?: number; max?: number }): ArgType<number> {
10
+ const min = opts?.min;
11
+ const max = opts?.max;
12
+ return {
13
+ kind: 'int',
14
+ label: 'integer',
15
+ parse: (arg, ctx): Result<number, readonly PslDiagnostic[]> => {
16
+ if (arg instanceof NumberLiteralExprAst) {
17
+ const value = arg.value();
18
+ if (value !== undefined && Number.isInteger(value)) {
19
+ if ((min === undefined || value >= min) && (max === undefined || value <= max)) {
20
+ return ok(value);
21
+ }
22
+ return notOk([leafDiagnostic(ctx, arg, rangeMessage(min, max))]);
23
+ }
24
+ }
25
+ return notOk([leafDiagnostic(ctx, arg, 'Expected an integer literal')]);
26
+ },
27
+ };
28
+ }
29
+
30
+ function rangeMessage(min: number | undefined, max: number | undefined): string {
31
+ if (min !== undefined && max !== undefined)
32
+ return `Expected an integer between ${min} and ${max}`;
33
+ if (min !== undefined) return `Expected an integer greater than or equal to ${min}`;
34
+ return `Expected an integer less than or equal to ${max}`;
35
+ }
@@ -0,0 +1,43 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { ArrayLiteralAst, type ExpressionAst } from '../../syntax/ast/expressions';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export interface ListOptions {
8
+ readonly nonEmpty?: boolean;
9
+ readonly unique?: boolean;
10
+ }
11
+
12
+ export function list<T>(of: ArgType<T>, opts?: ListOptions): ArgType<T[]> {
13
+ return {
14
+ kind: 'list',
15
+ label: `${of.label}[]`,
16
+ parse: (arg, ctx): Result<T[], readonly PslDiagnostic[]> => {
17
+ if (!(arg instanceof ArrayLiteralAst)) {
18
+ return notOk([leafDiagnostic(ctx, arg, `Expected a list of ${of.label}`)]);
19
+ }
20
+ const diagnostics: PslDiagnostic[] = [];
21
+ const parsed: { node: ExpressionAst; value: T }[] = [];
22
+ let count = 0;
23
+ for (const element of arg.elements()) {
24
+ count += 1;
25
+ const result = of.parse(element, ctx);
26
+ if (result.ok) parsed.push({ node: element, value: result.value });
27
+ else diagnostics.push(...result.failure);
28
+ }
29
+ if (opts?.nonEmpty === true && count === 0) {
30
+ diagnostics.push(leafDiagnostic(ctx, arg, 'Expected a non-empty list'));
31
+ }
32
+ if (opts?.unique === true) {
33
+ const seen = new Set<T>();
34
+ for (const { node, value } of parsed) {
35
+ if (seen.has(value)) diagnostics.push(leafDiagnostic(ctx, node, 'Duplicate list entry'));
36
+ else seen.add(value);
37
+ }
38
+ }
39
+ if (diagnostics.length > 0) return notOk(diagnostics);
40
+ return ok(parsed.map((entry) => entry.value));
41
+ },
42
+ };
43
+ }
@@ -0,0 +1,26 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { NumberLiteralExprAst } from '../../syntax/ast/expressions';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ // A general number literal — any number, including floats — reduced to its numeric value.
8
+ // Passing `value` pins the combinator to that single literal (`num(4)` matches only `4`),
9
+ // mirroring how `identifier(name)` pins a bare identifier. Use `int()` when only integer
10
+ // literals are allowed.
11
+ export function num(): ArgType<number>;
12
+ export function num(value: number): ArgType<number>;
13
+ export function num(value?: number): ArgType<number> {
14
+ return {
15
+ kind: 'num',
16
+ label: value === undefined ? 'number' : String(value),
17
+ parse: (arg, ctx): Result<number, readonly PslDiagnostic[]> => {
18
+ if (arg instanceof NumberLiteralExprAst) {
19
+ const parsed = arg.value();
20
+ if (parsed !== undefined && (value === undefined || parsed === value)) return ok(parsed);
21
+ }
22
+ const message = value === undefined ? 'Expected a number literal' : `Expected ${value}`;
23
+ return notOk([leafDiagnostic(ctx, arg, message)]);
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,29 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { blindCast } from '@prisma-next/utils/casts';
3
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
4
+ import type { ArgType, OutOf } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export function oneOf<Alts extends readonly [ArgType<unknown>, ...ArgType<unknown>[]]>(
8
+ ...alts: Alts
9
+ ): ArgType<OutOf<Alts[number]>> {
10
+ const label = alts.map((alt) => alt.label).join(' | ');
11
+ return {
12
+ kind: 'oneOf',
13
+ label,
14
+ parse: (arg, ctx): Result<OutOf<Alts[number]>, readonly PslDiagnostic[]> => {
15
+ for (const alt of alts) {
16
+ const result = alt.parse(arg, ctx);
17
+ if (result.ok) {
18
+ return ok(
19
+ blindCast<
20
+ OutOf<Alts[number]>,
21
+ 'The matched value comes from an alternative whose output type is a member of the union, but iterating the tuple widens each element to ArgType<unknown>, erasing that relationship.'
22
+ >(result.value),
23
+ );
24
+ }
25
+ }
26
+ return notOk([leafDiagnostic(ctx, arg, `Expected one of: ${label}`)]);
27
+ },
28
+ };
29
+ }
@@ -0,0 +1,43 @@
1
+ import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast';
2
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
3
+ import { ObjectLiteralExprAst } from '../../syntax/ast/expressions';
4
+ import type { ArgType } from '../types';
5
+ import { leafDiagnostic } from './diagnostic';
6
+
7
+ export function record<T>(of: ArgType<T>): ArgType<Record<string, T>> {
8
+ return {
9
+ kind: 'record',
10
+ label: `{ [key]: ${of.label} }`,
11
+ parse: (arg, ctx): Result<Record<string, T>, readonly PslDiagnostic[]> => {
12
+ if (!(arg instanceof ObjectLiteralExprAst)) {
13
+ return notOk([leafDiagnostic(ctx, arg, 'Expected an object literal')]);
14
+ }
15
+ const diagnostics: PslDiagnostic[] = [];
16
+ const result: Record<string, T> = {};
17
+ for (const field of arg.fields()) {
18
+ const key = field.keyName();
19
+ if (key === undefined) {
20
+ diagnostics.push(leafDiagnostic(ctx, field, 'Expected a key'));
21
+ continue;
22
+ }
23
+ const value = field.value();
24
+ if (value === undefined) {
25
+ diagnostics.push(leafDiagnostic(ctx, field, `Expected a value for key "${key}"`));
26
+ continue;
27
+ }
28
+ const parsed = of.parse(value, ctx);
29
+ if (!parsed.ok) {
30
+ diagnostics.push(...parsed.failure);
31
+ continue;
32
+ }
33
+ if (Object.hasOwn(result, key)) {
34
+ diagnostics.push(leafDiagnostic(ctx, field, `Duplicate key "${key}"`));
35
+ continue;
36
+ }
37
+ result[key] = parsed.value;
38
+ }
39
+ if (diagnostics.length > 0) return notOk(diagnostics);
40
+ return ok(result);
41
+ },
42
+ };
43
+ }