@prisma-next/psl-parser 0.14.0-dev.5 → 0.14.0-dev.51

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 (62) hide show
  1. package/README.md +28 -10
  2. package/dist/declarations-DR6To8_k.mjs +1060 -0
  3. package/dist/declarations-DR6To8_k.mjs.map +1 -0
  4. package/dist/format.d.mts +1 -1
  5. package/dist/format.mjs +2 -1
  6. package/dist/format.mjs.map +1 -1
  7. package/dist/index.d.mts +239 -3
  8. package/dist/index.d.mts.map +1 -1
  9. package/dist/index.mjs +785 -3
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/parse-3-vr14ej.mjs +626 -0
  12. package/dist/parse-3-vr14ej.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/syntax.d.mts +20 -2
  16. package/dist/syntax.d.mts.map +1 -1
  17. package/dist/syntax.mjs +43 -2
  18. package/dist/syntax.mjs.map +1 -0
  19. package/package.json +9 -25
  20. package/src/attribute-spec/combinators/bool.ts +19 -0
  21. package/src/attribute-spec/combinators/diagnostic.ts +15 -0
  22. package/src/attribute-spec/combinators/entity-ref.ts +24 -0
  23. package/src/attribute-spec/combinators/field-ref.ts +36 -0
  24. package/src/attribute-spec/combinators/identifier.ts +16 -0
  25. package/src/attribute-spec/combinators/int.ts +19 -0
  26. package/src/attribute-spec/combinators/list.ts +43 -0
  27. package/src/attribute-spec/combinators/one-of.ts +29 -0
  28. package/src/attribute-spec/combinators/record.ts +43 -0
  29. package/src/attribute-spec/combinators/str.ts +19 -0
  30. package/src/attribute-spec/field-attribute.ts +27 -0
  31. package/src/attribute-spec/interpret.ts +154 -0
  32. package/src/attribute-spec/model-attribute.ts +27 -0
  33. package/src/attribute-spec/optional.ts +8 -0
  34. package/src/attribute-spec/types.ts +72 -0
  35. package/src/block-reconstruction.ts +139 -0
  36. package/src/exports/index.ts +57 -3
  37. package/src/exports/syntax.ts +25 -5
  38. package/src/extension-block.ts +107 -0
  39. package/src/parse.ts +23 -5
  40. package/src/resolve.ts +123 -0
  41. package/src/source-file.ts +25 -0
  42. package/src/symbol-table.ts +446 -0
  43. package/src/syntax/ast/attributes.ts +5 -6
  44. package/src/syntax/ast/declarations.ts +51 -26
  45. package/src/syntax/ast/expressions.ts +12 -13
  46. package/src/syntax/ast/identifier.ts +2 -3
  47. package/src/syntax/ast/qualified-name.ts +28 -19
  48. package/src/syntax/ast/type-annotation.ts +4 -5
  49. package/src/syntax/ast-helpers.ts +27 -3
  50. package/src/syntax/navigation.ts +55 -0
  51. package/src/syntax/red.ts +317 -42
  52. package/dist/parse-B_3gIEFd.mjs +0 -1421
  53. package/dist/parse-B_3gIEFd.mjs.map +0 -1
  54. package/dist/parse-BjZ1LPe6.d.mts.map +0 -1
  55. package/dist/parser-CaplKvRs.mjs +0 -1145
  56. package/dist/parser-CaplKvRs.mjs.map +0 -1
  57. package/dist/parser-Dfi3Wfdq.d.mts +0 -7
  58. package/dist/parser-Dfi3Wfdq.d.mts.map +0 -1
  59. package/dist/parser.d.mts +0 -3
  60. package/dist/parser.mjs +0 -3
  61. package/src/exports/parser.ts +0 -4
  62. package/src/parser.ts +0 -1642
@@ -0,0 +1,446 @@
1
+ import type { AuthoringPslBlockDescriptorNamespace } from '@prisma-next/framework-components/authoring';
2
+ import type { PslExtensionBlock, PslSpan } from '@prisma-next/framework-components/psl-ast';
3
+ import { reconstructExtensionBlock } from './block-reconstruction';
4
+ import { findBlockDescriptor } from './extension-block';
5
+ import type { ParseDiagnostic } from './parse';
6
+ import {
7
+ nodePslSpan,
8
+ type ResolvedAttribute,
9
+ type ResolvedTypeConstructorCall,
10
+ readResolvedAttributes,
11
+ readResolvedConstructorCall,
12
+ } from './resolve';
13
+ import type { Range, SourceFile } from './source-file';
14
+ import {
15
+ CompositeTypeDeclarationAst,
16
+ type DocumentAst,
17
+ type FieldDeclarationAst,
18
+ GenericBlockDeclarationAst,
19
+ ModelDeclarationAst,
20
+ type NamedTypeDeclarationAst,
21
+ NamespaceDeclarationAst,
22
+ TypesBlockAst,
23
+ } from './syntax/ast/declarations';
24
+ import type { IdentifierAst } from './syntax/ast/identifier';
25
+ import type { SyntaxNode } from './syntax/red';
26
+
27
+ export type {
28
+ ResolvedAttribute,
29
+ ResolvedAttributeArg,
30
+ ResolvedTypeConstructorCall,
31
+ } from './resolve';
32
+
33
+ export interface SymbolTable {
34
+ readonly topLevel: TopLevelScope;
35
+ }
36
+
37
+ export interface TopLevelScope {
38
+ readonly namespaces: Record<string, NamespaceSymbol>;
39
+ readonly scalars: Record<string, ScalarSymbol>;
40
+ readonly typeAliases: Record<string, TypeAliasSymbol>;
41
+ readonly blocks: Record<string, BlockSymbol>;
42
+ readonly models: Record<string, ModelSymbol>;
43
+ readonly compositeTypes: Record<string, CompositeTypeSymbol>;
44
+ }
45
+
46
+ export interface NamespaceSymbol {
47
+ readonly kind: 'namespace';
48
+ readonly name: string;
49
+ readonly node: NamespaceDeclarationAst;
50
+ readonly span: PslSpan;
51
+ readonly models: Record<string, ModelSymbol>;
52
+ readonly compositeTypes: Record<string, CompositeTypeSymbol>;
53
+ readonly blocks: Record<string, BlockSymbol>;
54
+ }
55
+
56
+ export interface ModelSymbol {
57
+ readonly kind: 'model';
58
+ readonly name: string;
59
+ readonly node: ModelDeclarationAst;
60
+ readonly span: PslSpan;
61
+ readonly fields: Record<string, FieldSymbol>;
62
+ readonly attributes: readonly ResolvedAttribute[];
63
+ }
64
+
65
+ export interface CompositeTypeSymbol {
66
+ readonly kind: 'compositeType';
67
+ readonly name: string;
68
+ readonly node: CompositeTypeDeclarationAst;
69
+ readonly span: PslSpan;
70
+ readonly fields: Record<string, FieldSymbol>;
71
+ readonly attributes: readonly ResolvedAttribute[];
72
+ }
73
+
74
+ export interface BlockSymbol {
75
+ readonly kind: 'block';
76
+ readonly name: string;
77
+ readonly keyword: string;
78
+ readonly node: GenericBlockDeclarationAst;
79
+ readonly span: PslSpan;
80
+ /** Resolved once so consumers do not independently classify block parameters. */
81
+ readonly block: PslExtensionBlock;
82
+ }
83
+
84
+ export interface ResolvedNamedTypeBinding {
85
+ readonly baseType?: string;
86
+ readonly typeConstructor?: ResolvedTypeConstructorCall;
87
+ readonly isConstructor: boolean;
88
+ readonly attributes: readonly ResolvedAttribute[];
89
+ }
90
+
91
+ export interface ScalarSymbol extends ResolvedNamedTypeBinding {
92
+ readonly kind: 'scalar';
93
+ readonly name: string;
94
+ readonly node: NamedTypeDeclarationAst;
95
+ readonly span: PslSpan;
96
+ }
97
+
98
+ export interface TypeAliasSymbol extends ResolvedNamedTypeBinding {
99
+ readonly kind: 'typeAlias';
100
+ readonly name: string;
101
+ readonly node: NamedTypeDeclarationAst;
102
+ readonly span: PslSpan;
103
+ }
104
+
105
+ export interface FieldSymbol {
106
+ readonly kind: 'field';
107
+ readonly name: string;
108
+ readonly node: FieldDeclarationAst;
109
+ readonly span: PslSpan;
110
+ readonly typeName: string;
111
+ readonly typeNamespaceId?: string;
112
+ readonly typeContractSpaceId?: string;
113
+ readonly optional: boolean;
114
+ readonly list: boolean;
115
+ readonly typeConstructor?: ResolvedTypeConstructorCall;
116
+ readonly attributes: readonly ResolvedAttribute[];
117
+ /** Prevents cascading unsupported-type diagnostics after invalid qualification. */
118
+ readonly malformedType?: boolean;
119
+ }
120
+
121
+ export interface BuildSymbolTableOptions {
122
+ readonly document: DocumentAst;
123
+ readonly sourceFile: SourceFile;
124
+ readonly scalarTypes: readonly string[];
125
+ readonly pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace;
126
+ }
127
+
128
+ export interface SymbolTableResult {
129
+ readonly table: SymbolTable;
130
+ readonly diagnostics: readonly ParseDiagnostic[];
131
+ }
132
+
133
+ /**
134
+ * Owns duplicate-declaration detection for all PSL scopes; downstream consumers
135
+ * should consume first-wins symbols rather than re-emitting duplicate diagnostics.
136
+ */
137
+ export function buildSymbolTable(options: BuildSymbolTableOptions): SymbolTableResult {
138
+ const { document, sourceFile, scalarTypes, pslBlockDescriptors } = options;
139
+ const diagnostics: ParseDiagnostic[] = [];
140
+ const scalarSet = new Set(scalarTypes);
141
+
142
+ const namespaces: Record<string, NamespaceSymbol> = {};
143
+ const scalars: Record<string, ScalarSymbol> = {};
144
+ const typeAliases: Record<string, TypeAliasSymbol> = {};
145
+ const blocks: Record<string, BlockSymbol> = {};
146
+ const models: Record<string, ModelSymbol> = {};
147
+ const compositeTypes: Record<string, CompositeTypeSymbol> = {};
148
+ const topLevelNames = new Set<string>();
149
+
150
+ const claim = (taken: Set<string>, name: IdentifierAst | undefined): string | undefined => {
151
+ const text = name?.name();
152
+ if (text === undefined) return undefined;
153
+ if (taken.has(text)) {
154
+ const range = nameRange(name, sourceFile);
155
+ if (range) {
156
+ diagnostics.push({
157
+ code: 'PSL_DUPLICATE_DECLARATION',
158
+ message: `Duplicate declaration of "${text}"`,
159
+ range,
160
+ });
161
+ }
162
+ return undefined;
163
+ }
164
+ taken.add(text);
165
+ return text;
166
+ };
167
+
168
+ for (const declaration of document.declarations()) {
169
+ if (declaration instanceof ModelDeclarationAst) {
170
+ const name = claim(topLevelNames, declaration.name());
171
+ if (name !== undefined) models[name] = buildModel(name, declaration, sourceFile, diagnostics);
172
+ } else if (declaration instanceof CompositeTypeDeclarationAst) {
173
+ const name = claim(topLevelNames, declaration.name());
174
+ if (name !== undefined) {
175
+ compositeTypes[name] = buildCompositeType(name, declaration, sourceFile, diagnostics);
176
+ }
177
+ } else if (declaration instanceof GenericBlockDeclarationAst) {
178
+ const name = claim(topLevelNames, declaration.name());
179
+ if (name !== undefined) {
180
+ blocks[name] = buildBlock(name, declaration, sourceFile, pslBlockDescriptors, diagnostics);
181
+ }
182
+ } else if (declaration instanceof NamespaceDeclarationAst) {
183
+ const name = claim(topLevelNames, declaration.name());
184
+ if (name !== undefined) {
185
+ namespaces[name] = buildNamespace(
186
+ name,
187
+ declaration,
188
+ diagnostics,
189
+ sourceFile,
190
+ pslBlockDescriptors,
191
+ );
192
+ }
193
+ } else if (declaration instanceof TypesBlockAst) {
194
+ for (const binding of declaration.declarations()) {
195
+ const name = claim(topLevelNames, binding.name());
196
+ if (name === undefined) continue;
197
+ const resolved = resolveNamedTypeBinding(binding, sourceFile);
198
+ const span = nodePslSpan(binding.syntax, sourceFile);
199
+ if (isScalarBinding(binding, scalarSet)) {
200
+ scalars[name] = { kind: 'scalar', name, node: binding, span, ...resolved };
201
+ } else {
202
+ typeAliases[name] = { kind: 'typeAlias', name, node: binding, span, ...resolved };
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ const table: SymbolTable = {
209
+ topLevel: { namespaces, scalars, typeAliases, blocks, models, compositeTypes },
210
+ };
211
+ return { table, diagnostics };
212
+ }
213
+
214
+ function buildModel(
215
+ name: string,
216
+ node: ModelDeclarationAst,
217
+ sourceFile: SourceFile,
218
+ diagnostics: ParseDiagnostic[],
219
+ ): ModelSymbol {
220
+ return {
221
+ kind: 'model',
222
+ name,
223
+ node,
224
+ span: nodePslSpan(node.syntax, sourceFile),
225
+ fields: buildFields(name, node.fields(), sourceFile, diagnostics),
226
+ attributes: readResolvedAttributes(node.attributes(), sourceFile),
227
+ };
228
+ }
229
+
230
+ function buildCompositeType(
231
+ name: string,
232
+ node: CompositeTypeDeclarationAst,
233
+ sourceFile: SourceFile,
234
+ diagnostics: ParseDiagnostic[],
235
+ ): CompositeTypeSymbol {
236
+ return {
237
+ kind: 'compositeType',
238
+ name,
239
+ node,
240
+ span: nodePslSpan(node.syntax, sourceFile),
241
+ fields: buildFields(name, node.fields(), sourceFile, diagnostics),
242
+ attributes: readResolvedAttributes(node.attributes(), sourceFile),
243
+ };
244
+ }
245
+
246
+ function buildBlock(
247
+ name: string,
248
+ node: GenericBlockDeclarationAst,
249
+ sourceFile: SourceFile,
250
+ pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace,
251
+ diagnostics: ParseDiagnostic[],
252
+ ): BlockSymbol {
253
+ const keyword = node.keyword()?.text ?? '';
254
+ const descriptor = findBlockDescriptor(pslBlockDescriptors, keyword);
255
+ return {
256
+ kind: 'block',
257
+ name,
258
+ keyword,
259
+ node,
260
+ span: nodePslSpan(node.syntax, sourceFile),
261
+ block: reconstructExtensionBlock(node, descriptor, sourceFile, diagnostics),
262
+ };
263
+ }
264
+
265
+ function buildNamespace(
266
+ name: string,
267
+ node: NamespaceDeclarationAst,
268
+ diagnostics: ParseDiagnostic[],
269
+ sourceFile: SourceFile,
270
+ pslBlockDescriptors: AuthoringPslBlockDescriptorNamespace,
271
+ ): NamespaceSymbol {
272
+ const models: Record<string, ModelSymbol> = {};
273
+ const compositeTypes: Record<string, CompositeTypeSymbol> = {};
274
+ const blocks: Record<string, BlockSymbol> = {};
275
+ const taken = new Set<string>();
276
+
277
+ for (const member of node.declarations()) {
278
+ const memberName = member.name()?.name();
279
+ if (memberName === undefined) continue;
280
+ if (taken.has(memberName)) {
281
+ const range = nameRange(member.name(), sourceFile);
282
+ if (range) {
283
+ diagnostics.push({
284
+ code: 'PSL_DUPLICATE_DECLARATION',
285
+ message: `Duplicate declaration of "${memberName}"`,
286
+ range,
287
+ });
288
+ }
289
+ continue;
290
+ }
291
+ taken.add(memberName);
292
+ if (member instanceof ModelDeclarationAst) {
293
+ models[memberName] = buildModel(memberName, member, sourceFile, diagnostics);
294
+ } else if (member instanceof CompositeTypeDeclarationAst) {
295
+ compositeTypes[memberName] = buildCompositeType(memberName, member, sourceFile, diagnostics);
296
+ } else if (member instanceof GenericBlockDeclarationAst) {
297
+ blocks[memberName] = buildBlock(
298
+ memberName,
299
+ member,
300
+ sourceFile,
301
+ pslBlockDescriptors,
302
+ diagnostics,
303
+ );
304
+ }
305
+ }
306
+
307
+ return {
308
+ kind: 'namespace',
309
+ name,
310
+ node,
311
+ span: nodePslSpan(node.syntax, sourceFile),
312
+ models,
313
+ compositeTypes,
314
+ blocks,
315
+ };
316
+ }
317
+
318
+ function buildFields(
319
+ ownerName: string,
320
+ fields: Iterable<FieldDeclarationAst>,
321
+ sourceFile: SourceFile,
322
+ diagnostics: ParseDiagnostic[],
323
+ ): Record<string, FieldSymbol> {
324
+ const result: Record<string, FieldSymbol> = {};
325
+ for (const field of fields) {
326
+ const nameNode = field.name();
327
+ const name = nameNode?.name();
328
+ if (name === undefined) continue;
329
+ if (Object.hasOwn(result, name)) {
330
+ const range = nameRange(nameNode, sourceFile);
331
+ if (range) {
332
+ diagnostics.push({
333
+ code: 'PSL_DUPLICATE_DECLARATION',
334
+ message: `Duplicate declaration of "${name}"`,
335
+ range,
336
+ });
337
+ }
338
+ continue;
339
+ }
340
+ result[name] = buildField(ownerName, name, field, sourceFile, diagnostics);
341
+ }
342
+ return result;
343
+ }
344
+
345
+ function buildField(
346
+ ownerName: string,
347
+ name: string,
348
+ node: FieldDeclarationAst,
349
+ sourceFile: SourceFile,
350
+ diagnostics: ParseDiagnostic[],
351
+ ): FieldSymbol {
352
+ const attributes = readResolvedAttributes(node.attributes(), sourceFile);
353
+ const span = nodePslSpan(node.syntax, sourceFile);
354
+ const annotation = node.typeAnnotation();
355
+ const typeName = annotation?.name();
356
+
357
+ if (typeName?.isOverQualified()) {
358
+ const path = typeName.path();
359
+ diagnostics.push({
360
+ code: 'PSL_INVALID_QUALIFIED_TYPE',
361
+ message: `Field "${ownerName}.${name}" has an invalid qualified type "${path.join('.')}"; use at most one namespace qualifier (e.g. "ns.TypeName")`,
362
+ range: nodeRange(typeName.syntax, sourceFile),
363
+ });
364
+ return {
365
+ kind: 'field',
366
+ name,
367
+ node,
368
+ span,
369
+ typeName: path[path.length - 1] ?? '',
370
+ optional: false,
371
+ list: false,
372
+ malformedType: true,
373
+ attributes,
374
+ };
375
+ }
376
+
377
+ const typeConstructor = annotation?.isConstructor()
378
+ ? readResolvedConstructorCall(annotation, sourceFile)
379
+ : undefined;
380
+ const typeNamespaceId = typeName?.namespace()?.name();
381
+ const typeContractSpaceId = typeName?.space()?.name();
382
+
383
+ return {
384
+ kind: 'field',
385
+ name,
386
+ node,
387
+ span,
388
+ typeName: typeName?.identifier()?.name() ?? '',
389
+ ...(typeNamespaceId !== undefined ? { typeNamespaceId } : {}),
390
+ ...(typeContractSpaceId !== undefined ? { typeContractSpaceId } : {}),
391
+ optional: annotation?.isOptional() ?? false,
392
+ list: annotation?.isList() ?? false,
393
+ ...(typeConstructor !== undefined ? { typeConstructor } : {}),
394
+ attributes,
395
+ };
396
+ }
397
+
398
+ function resolveNamedTypeBinding(
399
+ node: NamedTypeDeclarationAst,
400
+ sourceFile: SourceFile,
401
+ ): {
402
+ baseType?: string;
403
+ typeConstructor?: ResolvedTypeConstructorCall;
404
+ isConstructor: boolean;
405
+ attributes: readonly ResolvedAttribute[];
406
+ } {
407
+ const annotation = node.typeAnnotation();
408
+ const isConstructor = annotation?.isConstructor() ?? false;
409
+ const baseType = annotation?.name()?.identifier()?.name();
410
+ const typeConstructor = readResolvedConstructorCall(annotation, sourceFile);
411
+ return {
412
+ isConstructor,
413
+ ...(!isConstructor && baseType !== undefined ? { baseType } : {}),
414
+ ...(typeConstructor !== undefined ? { typeConstructor } : {}),
415
+ attributes: readResolvedAttributes(node.attributes(), sourceFile),
416
+ };
417
+ }
418
+
419
+ function isScalarBinding(node: NamedTypeDeclarationAst, scalarTypes: Set<string>): boolean {
420
+ const annotation = node.typeAnnotation();
421
+ if (annotation === undefined || annotation.isConstructor()) return false;
422
+ const base = annotation.name()?.identifier()?.name();
423
+ return base !== undefined && scalarTypes.has(base);
424
+ }
425
+
426
+ function nameRange(name: IdentifierAst | undefined, sourceFile: SourceFile): Range | undefined {
427
+ if (name === undefined) return undefined;
428
+ for (const token of name.syntax.tokens()) {
429
+ if (token.kind === 'Ident') {
430
+ return {
431
+ start: sourceFile.positionAt(token.offset),
432
+ end: sourceFile.positionAt(token.offset + token.text.length),
433
+ };
434
+ }
435
+ }
436
+ return undefined;
437
+ }
438
+
439
+ function nodeRange(node: SyntaxNode, sourceFile: SourceFile): Range {
440
+ const start = node.offset;
441
+ const end = start + node.green.textLength;
442
+ return {
443
+ start: sourceFile.positionAt(start),
444
+ end: sourceFile.positionAt(end),
445
+ };
446
+ }
@@ -1,7 +1,6 @@
1
- import type { Token } from '../../tokenizer';
2
1
  import type { AstNode } from '../ast-helpers';
3
2
  import { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';
4
- import type { SyntaxNode } from '../red';
3
+ import type { SyntaxNode, SyntaxToken } from '../red';
5
4
  import { AttributeArgAst } from './expressions';
6
5
  import { QualifiedNameAst } from './qualified-name';
7
6
 
@@ -12,11 +11,11 @@ export class AttributeArgListAst implements AstNode {
12
11
  this.syntax = syntax;
13
12
  }
14
13
 
15
- lparen(): Token | undefined {
14
+ lparen(): SyntaxToken | undefined {
16
15
  return findChildToken(this.syntax, 'LParen');
17
16
  }
18
17
 
19
- rparen(): Token | undefined {
18
+ rparen(): SyntaxToken | undefined {
20
19
  return findChildToken(this.syntax, 'RParen');
21
20
  }
22
21
 
@@ -36,7 +35,7 @@ export class FieldAttributeAst implements AstNode {
36
35
  this.syntax = syntax;
37
36
  }
38
37
 
39
- at(): Token | undefined {
38
+ at(): SyntaxToken | undefined {
40
39
  return findChildToken(this.syntax, 'At');
41
40
  }
42
41
 
@@ -60,7 +59,7 @@ export class ModelAttributeAst implements AstNode {
60
59
  this.syntax = syntax;
61
60
  }
62
61
 
63
- doubleAt(): Token | undefined {
62
+ doubleAt(): SyntaxToken | undefined {
64
63
  return findChildToken(this.syntax, 'DoubleAt');
65
64
  }
66
65