@prisma-next/psl-parser 0.14.0-dev.3 → 0.14.0-dev.30

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 (47) hide show
  1. package/README.md +28 -10
  2. package/dist/declarations-DWUyG1DT.mjs +829 -0
  3. package/dist/declarations-DWUyG1DT.mjs.map +1 -0
  4. package/dist/format.d.mts +19 -0
  5. package/dist/format.d.mts.map +1 -0
  6. package/dist/format.mjs +470 -0
  7. package/dist/format.mjs.map +1 -0
  8. package/dist/index.d.mts +136 -3
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +472 -3
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/parse-Ce9Em5k9.d.mts +358 -0
  13. package/dist/parse-Ce9Em5k9.d.mts.map +1 -0
  14. package/dist/parse-iG0rOMKS.mjs +618 -0
  15. package/dist/parse-iG0rOMKS.mjs.map +1 -0
  16. package/dist/syntax.d.mts +3 -347
  17. package/dist/syntax.d.mts.map +1 -1
  18. package/dist/syntax.mjs +2 -1420
  19. package/package.json +6 -6
  20. package/src/block-reconstruction.ts +139 -0
  21. package/src/exports/format.ts +3 -0
  22. package/src/exports/index.ts +27 -3
  23. package/src/exports/syntax.ts +7 -1
  24. package/src/extension-block.ts +107 -0
  25. package/src/format/emit.ts +603 -0
  26. package/src/format/error.ts +13 -0
  27. package/src/format/format.ts +13 -0
  28. package/src/format/options.ts +28 -0
  29. package/src/resolve.ts +120 -0
  30. package/src/source-file.ts +25 -0
  31. package/src/symbol-table.ts +446 -0
  32. package/src/syntax/ast/attributes.ts +5 -6
  33. package/src/syntax/ast/declarations.ts +45 -20
  34. package/src/syntax/ast/expressions.ts +12 -13
  35. package/src/syntax/ast/identifier.ts +2 -3
  36. package/src/syntax/ast/qualified-name.ts +3 -4
  37. package/src/syntax/ast/type-annotation.ts +4 -5
  38. package/src/syntax/ast-helpers.ts +3 -3
  39. package/dist/parser-CaplKvRs.mjs +0 -1145
  40. package/dist/parser-CaplKvRs.mjs.map +0 -1
  41. package/dist/parser-Dfi3Wfdq.d.mts +0 -7
  42. package/dist/parser-Dfi3Wfdq.d.mts.map +0 -1
  43. package/dist/parser.d.mts +0 -2
  44. package/dist/parser.mjs +0 -2
  45. package/dist/syntax.mjs.map +0 -1
  46. package/src/exports/parser.ts +0 -1
  47. package/src/parser.ts +0 -1642
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@prisma-next/psl-parser",
3
- "version": "0.14.0-dev.3",
3
+ "version": "0.14.0-dev.30",
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.3",
10
- "@prisma-next/utils": "0.14.0-dev.3"
9
+ "@prisma-next/framework-components": "0.14.0-dev.30",
10
+ "@prisma-next/utils": "0.14.0-dev.30"
11
11
  },
12
12
  "devDependencies": {
13
- "@prisma-next/tsconfig": "0.14.0-dev.3",
14
- "@prisma-next/tsdown": "0.14.0-dev.3",
13
+ "@prisma-next/tsconfig": "0.14.0-dev.30",
14
+ "@prisma-next/tsdown": "0.14.0-dev.30",
15
15
  "tsdown": "0.22.1",
16
16
  "typescript": "5.9.3",
17
17
  "vitest": "4.1.8"
@@ -31,7 +31,7 @@
31
31
  "types": "./dist/index.d.mts",
32
32
  "exports": {
33
33
  ".": "./dist/index.mjs",
34
- "./parser": "./dist/parser.mjs",
34
+ "./format": "./dist/format.mjs",
35
35
  "./syntax": "./dist/syntax.mjs",
36
36
  "./tokenizer": "./dist/tokenizer.mjs",
37
37
  "./package.json": "./package.json"
@@ -0,0 +1,139 @@
1
+ import type { AuthoringPslBlockDescriptor } from '@prisma-next/framework-components/authoring';
2
+ import type {
3
+ PslBlockParam,
4
+ PslExtensionBlock,
5
+ PslExtensionBlockAttribute,
6
+ PslExtensionBlockParamValue,
7
+ PslSpan,
8
+ } from '@prisma-next/framework-components/psl-ast';
9
+ import type { ParseDiagnostic } from './parse';
10
+ import { nodePslSpan } from './resolve';
11
+ import type { SourceFile } from './source-file';
12
+ import type { GenericBlockDeclarationAst, KeyValuePairAst } from './syntax/ast/declarations';
13
+ import { ArrayLiteralAst, type ExpressionAst } from './syntax/ast/expressions';
14
+ import { printSyntax } from './syntax/ast-helpers';
15
+
16
+ /**
17
+ * Descriptor-free and unknown parameters become `value` stubs so validation can
18
+ * report them via key-set comparison. Duplicate member names are first-wins.
19
+ */
20
+ export function reconstructExtensionBlock(
21
+ node: GenericBlockDeclarationAst,
22
+ descriptor: AuthoringPslBlockDescriptor | undefined,
23
+ sourceFile: SourceFile,
24
+ diagnostics: ParseDiagnostic[],
25
+ ): PslExtensionBlock {
26
+ const keyword = node.keyword()?.text ?? '';
27
+ const blockName = node.name()?.name() ?? '';
28
+
29
+ const blockAttributes: PslExtensionBlockAttribute[] = [];
30
+ for (const attribute of node.attributes()) {
31
+ const name = attribute.name()?.path().join('.') ?? '';
32
+ const args = Array.from(attribute.argList()?.args() ?? [], (arg) => {
33
+ const value = arg.value();
34
+ return {
35
+ kind: 'positional' as const,
36
+ value: value === undefined ? '' : printSyntax(value.syntax).trim(),
37
+ span: nodePslSpan(arg.syntax, sourceFile),
38
+ };
39
+ });
40
+ blockAttributes.push({
41
+ name,
42
+ args,
43
+ span: nodePslSpan(attribute.syntax, sourceFile),
44
+ });
45
+ }
46
+
47
+ const parameters: Record<string, PslExtensionBlockParamValue> = {};
48
+ for (const entry of node.entries()) {
49
+ const key = entry.key()?.name();
50
+ if (key === undefined) continue;
51
+ const span = nodePslSpan(entry.syntax, sourceFile);
52
+ if (Object.hasOwn(parameters, key)) {
53
+ diagnostics.push({
54
+ code: 'PSL_EXTENSION_DUPLICATE_PARAMETER',
55
+ message: `Duplicate parameter "${key}" in "${keyword}" block "${blockName}"; first occurrence wins`,
56
+ range: {
57
+ start: sourceFile.positionAt(entry.syntax.offset),
58
+ end: sourceFile.positionAt(entry.syntax.offset + entry.syntax.green.textLength),
59
+ },
60
+ });
61
+ continue;
62
+ }
63
+ parameters[key] = reconstructParamValue(
64
+ entry,
65
+ descriptor?.parameters[key],
66
+ span,
67
+ sourceFile,
68
+ diagnostics,
69
+ );
70
+ }
71
+
72
+ return {
73
+ kind: descriptor?.discriminator ?? keyword,
74
+ name: blockName,
75
+ parameters,
76
+ blockAttributes,
77
+ span: nodePslSpan(node.syntax, sourceFile),
78
+ };
79
+ }
80
+
81
+ function reconstructParamValue(
82
+ entry: KeyValuePairAst,
83
+ param: PslBlockParam | undefined,
84
+ span: PslSpan,
85
+ sourceFile: SourceFile,
86
+ diagnostics: ParseDiagnostic[],
87
+ ): PslExtensionBlockParamValue {
88
+ const value = entry.value();
89
+ if (value === undefined) {
90
+ return { kind: 'bare', span };
91
+ }
92
+ return reconstructFromExpression(value, param, span, sourceFile, diagnostics);
93
+ }
94
+
95
+ function reconstructFromExpression(
96
+ value: ExpressionAst,
97
+ param: PslBlockParam | undefined,
98
+ span: PslSpan,
99
+ sourceFile: SourceFile,
100
+ diagnostics?: ParseDiagnostic[],
101
+ ): PslExtensionBlockParamValue {
102
+ const raw = printSyntax(value.syntax).trim();
103
+ if (param?.kind === 'list') {
104
+ const array = ArrayLiteralAst.cast(value.syntax);
105
+ if (!array) {
106
+ diagnostics?.push({
107
+ code: 'PSL_EXTENSION_INVALID_VALUE',
108
+ message: `List parameter expects an array literal, got ${raw}`,
109
+ range: {
110
+ start: sourceFile.positionAt(value.syntax.offset),
111
+ end: sourceFile.positionAt(value.syntax.offset + value.syntax.green.textLength),
112
+ },
113
+ });
114
+ return { kind: 'value', raw, span };
115
+ }
116
+
117
+ const items: PslExtensionBlockParamValue[] = [];
118
+ for (const element of array.elements()) {
119
+ items.push(
120
+ reconstructFromExpression(
121
+ element,
122
+ param.of,
123
+ nodePslSpan(element.syntax, sourceFile),
124
+ sourceFile,
125
+ diagnostics,
126
+ ),
127
+ );
128
+ }
129
+ return { kind: 'list', items, span };
130
+ }
131
+ switch (param?.kind) {
132
+ case 'ref':
133
+ return { kind: 'ref', identifier: raw, span };
134
+ case 'option':
135
+ return { kind: 'option', token: raw, span };
136
+ default:
137
+ return { kind: 'value', raw, span };
138
+ }
139
+ }
@@ -0,0 +1,3 @@
1
+ export { PslFormatError } from '../format/error';
2
+ export { format } from '../format/format';
3
+ export type { FormatOptions } from '../format/options';
@@ -1,6 +1,4 @@
1
1
  export type {
2
- ParsePslDocumentInput,
3
- ParsePslDocumentResult,
4
2
  PslAttribute,
5
3
  PslAttributeArgument,
6
4
  PslAttributeNamedArgument,
@@ -38,4 +36,30 @@ export {
38
36
  namespacePslExtensionBlocks,
39
37
  } from '@prisma-next/framework-components/psl-ast';
40
38
  export { getPositionalArgument, parseQuotedStringLiteral } from '../attribute-helpers';
41
- export { parsePslDocument } from '../parser';
39
+ export { findBlockDescriptor, validateExtensionBlockFromSymbol } from '../extension-block';
40
+ export {
41
+ keywordPslSpan,
42
+ nodePslSpan,
43
+ rangeToPslSpan,
44
+ readResolvedAttribute,
45
+ readResolvedAttributes,
46
+ readResolvedConstructorCall,
47
+ } from '../resolve';
48
+ export type {
49
+ BlockSymbol,
50
+ BuildSymbolTableOptions,
51
+ CompositeTypeSymbol,
52
+ FieldSymbol,
53
+ ModelSymbol,
54
+ NamespaceSymbol,
55
+ ResolvedAttribute,
56
+ ResolvedAttributeArg,
57
+ ResolvedNamedTypeBinding,
58
+ ResolvedTypeConstructorCall,
59
+ ScalarSymbol,
60
+ SymbolTable,
61
+ SymbolTableResult,
62
+ TopLevelScope,
63
+ TypeAliasSymbol,
64
+ } from '../symbol-table';
65
+ export { buildSymbolTable } from '../symbol-table';
@@ -7,7 +7,13 @@ export {
7
7
  FieldAttributeAst,
8
8
  ModelAttributeAst,
9
9
  } from '../syntax/ast/attributes';
10
- export type { NamespaceMemberAst } from '../syntax/ast/declarations';
10
+ export type {
11
+ AttributeAst,
12
+ BlockMemberAst,
13
+ DeclarationAst,
14
+ GenericBlockMemberAst,
15
+ NamespaceMemberAst,
16
+ } from '../syntax/ast/declarations';
11
17
  export {
12
18
  CompositeTypeDeclarationAst,
13
19
  DocumentAst,
@@ -0,0 +1,107 @@
1
+ import {
2
+ type AuthoringPslBlockDescriptor,
3
+ type AuthoringPslBlockDescriptorNamespace,
4
+ isAuthoringPslBlockDescriptor,
5
+ } from '@prisma-next/framework-components/authoring';
6
+ import type { CodecLookup } from '@prisma-next/framework-components/codec';
7
+ import {
8
+ makePslNamespace,
9
+ makePslNamespaceEntries,
10
+ type PslDiagnostic,
11
+ type PslModel,
12
+ type PslSpan,
13
+ UNSPECIFIED_PSL_NAMESPACE_ID,
14
+ validateExtensionBlock,
15
+ } from '@prisma-next/framework-components/psl-ast';
16
+ import type { SourceFile } from './source-file';
17
+ import type { BlockSymbol, ModelSymbol, SymbolTable } from './symbol-table';
18
+
19
+ export function findBlockDescriptor(
20
+ descriptors: AuthoringPslBlockDescriptorNamespace | undefined,
21
+ keyword: string,
22
+ ): AuthoringPslBlockDescriptor | undefined {
23
+ if (descriptors === undefined) return undefined;
24
+ for (const value of Object.values(descriptors)) {
25
+ if (value === undefined) continue;
26
+ if (isAuthoringPslBlockDescriptor(value)) {
27
+ if (value.keyword === keyword) return value;
28
+ continue;
29
+ }
30
+ const nested = findBlockDescriptor(value, keyword);
31
+ if (nested !== undefined) return nested;
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ export function validateExtensionBlockFromSymbol(input: {
37
+ readonly block: BlockSymbol;
38
+ readonly descriptor: AuthoringPslBlockDescriptor;
39
+ readonly symbolTable: SymbolTable;
40
+ readonly sourceFile: SourceFile;
41
+ readonly sourceId: string;
42
+ readonly codecLookup: CodecLookup;
43
+ }): readonly PslDiagnostic[] {
44
+ const refCtx = buildRefResolutionContext(input.symbolTable, input.block);
45
+ return validateExtensionBlock(
46
+ input.block.block,
47
+ input.descriptor,
48
+ input.sourceId,
49
+ input.codecLookup,
50
+ refCtx,
51
+ );
52
+ }
53
+
54
+ const ZERO_SPAN: PslSpan = {
55
+ start: { offset: 0, line: 1, column: 1 },
56
+ end: { offset: 0, line: 1, column: 1 },
57
+ };
58
+
59
+ function buildRefResolutionContext(
60
+ symbolTable: SymbolTable,
61
+ block: BlockSymbol,
62
+ ): {
63
+ ownerNamespace: ReturnType<typeof makePslNamespace>;
64
+ allNamespaces: readonly ReturnType<typeof makePslNamespace>[];
65
+ } {
66
+ const unspecifiedNamespace = makeNamespace(
67
+ UNSPECIFIED_PSL_NAMESPACE_ID,
68
+ Object.values(symbolTable.topLevel.models),
69
+ );
70
+ const namedNamespaces = Object.values(symbolTable.topLevel.namespaces).map((namespace) =>
71
+ makeNamespace(namespace.name, Object.values(namespace.models)),
72
+ );
73
+ const allNamespaces = [unspecifiedNamespace, ...namedNamespaces];
74
+ const ownerNamespaceName = findOwnerNamespaceName(symbolTable, block);
75
+ const ownerNamespace =
76
+ allNamespaces.find((namespace) => namespace.name === ownerNamespaceName) ??
77
+ unspecifiedNamespace;
78
+ return { ownerNamespace, allNamespaces };
79
+ }
80
+
81
+ function makeNamespace(
82
+ name: string,
83
+ models: readonly ModelSymbol[],
84
+ ): ReturnType<typeof makePslNamespace> {
85
+ const modelStubs: PslModel[] = models.map((model) => ({
86
+ kind: 'model',
87
+ name: model.name,
88
+ fields: [],
89
+ attributes: [],
90
+ span: ZERO_SPAN,
91
+ }));
92
+ return makePslNamespace({
93
+ kind: 'namespace',
94
+ name,
95
+ entries: makePslNamespaceEntries(modelStubs, [], []),
96
+ span: ZERO_SPAN,
97
+ });
98
+ }
99
+
100
+ function findOwnerNamespaceName(symbolTable: SymbolTable, block: BlockSymbol): string {
101
+ for (const namespace of Object.values(symbolTable.topLevel.namespaces)) {
102
+ if (Object.values(namespace.blocks).some((candidate) => candidate === block)) {
103
+ return namespace.name;
104
+ }
105
+ }
106
+ return UNSPECIFIED_PSL_NAMESPACE_ID;
107
+ }