@prisma-next/psl-parser 0.12.0 → 0.13.0-dev.2
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/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{parser-R7ldFfcr.mjs → parser-Cw_zV0M5.mjs} +176 -10
- package/dist/parser-Cw_zV0M5.mjs.map +1 -0
- package/dist/{parser-Bjdnhl7C.d.mts → parser-Dfi3Wfdq.d.mts} +1 -1
- package/dist/parser-Dfi3Wfdq.d.mts.map +1 -0
- package/dist/parser.d.mts +1 -1
- package/dist/parser.mjs +1 -1
- package/dist/syntax.d.mts +282 -0
- package/dist/syntax.d.mts.map +1 -0
- package/dist/syntax.mjs +708 -0
- package/dist/syntax.mjs.map +1 -0
- package/dist/tokenizer-DcYI0Xrq.d.mts +15 -0
- package/dist/tokenizer-DcYI0Xrq.d.mts.map +1 -0
- package/dist/tokenizer.d.mts +2 -15
- package/package.json +8 -7
- package/src/exports/syntax.ts +41 -0
- package/src/parser.ts +271 -13
- package/src/syntax/ast/attributes.ts +97 -0
- package/src/syntax/ast/declarations.ts +359 -0
- package/src/syntax/ast/expressions.ts +199 -0
- package/src/syntax/ast/identifier.ts +20 -0
- package/src/syntax/ast/type-annotation.ts +82 -0
- package/src/syntax/ast-helpers.ts +36 -0
- package/src/syntax/green-builder.ts +33 -0
- package/src/syntax/green.ts +29 -0
- package/src/syntax/red.ts +154 -0
- package/src/syntax/syntax-kind.ts +23 -0
- package/dist/parser-Bjdnhl7C.d.mts.map +0 -1
- package/dist/parser-R7ldFfcr.mjs.map +0 -1
- package/dist/tokenizer.d.mts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syntax.mjs","names":["#lastSegment","#penultimateSegment","#stack"],"sources":["../src/syntax/red.ts","../src/syntax/ast-helpers.ts","../src/syntax/ast/identifier.ts","../src/syntax/ast/expressions.ts","../src/syntax/ast/attributes.ts","../src/syntax/ast/type-annotation.ts","../src/syntax/ast/declarations.ts","../src/syntax/green.ts","../src/syntax/green-builder.ts"],"sourcesContent":["import type { Token } from '../tokenizer';\nimport type { GreenElement, GreenNode } from './green';\nimport type { SyntaxKind } from './syntax-kind';\n\n/**\n * A token in the red tree. Unlike the green-layer {@link Token} (kind + text\n * only), a red token also carries its absolute `offset` within the source,\n * computed lazily as the tree is walked.\n */\nexport interface SyntaxToken extends Token {\n readonly offset: number;\n}\n\nexport type SyntaxElement = SyntaxNode | SyntaxToken;\n\nexport class SyntaxNode {\n readonly green: GreenNode;\n readonly offset: number;\n readonly parent: SyntaxNode | undefined;\n\n constructor(green: GreenNode, offset: number, parent: SyntaxNode | undefined) {\n this.green = green;\n this.offset = offset;\n this.parent = parent;\n }\n\n get kind(): SyntaxKind {\n return this.green.kind;\n }\n\n get textLength(): number {\n return this.green.textLength;\n }\n\n get firstChild(): SyntaxElement | undefined {\n return childAt(this, 0);\n }\n\n get lastChild(): SyntaxElement | undefined {\n const len = this.green.children.length;\n if (len === 0) return undefined;\n return childAt(this, len - 1);\n }\n\n get nextSibling(): SyntaxElement | undefined {\n if (!this.parent) return undefined;\n const siblings = this.parent.green.children;\n let offset = this.parent.offset;\n let found = false;\n for (const child of siblings) {\n if (found) {\n return wrapElement(child, offset, this.parent);\n }\n const childLen = elementTextLength(child);\n if (child.type === 'node' && offset === this.offset && child === this.green) {\n found = true;\n }\n offset += childLen;\n }\n return undefined;\n }\n\n get prevSibling(): SyntaxElement | undefined {\n if (!this.parent) return undefined;\n const siblings = this.parent.green.children;\n let offset = this.parent.offset;\n let prev: { green: GreenElement; offset: number } | undefined;\n for (const child of siblings) {\n if (child.type === 'node' && offset === this.offset && child === this.green) {\n if (!prev) return undefined;\n return wrapElement(prev.green, prev.offset, this.parent);\n }\n prev = { green: child, offset };\n offset += elementTextLength(child);\n }\n return undefined;\n }\n\n *children(): Iterable<SyntaxElement> {\n let offset = this.offset;\n for (const child of this.green.children) {\n yield wrapElement(child, offset, this);\n offset += elementTextLength(child);\n }\n }\n\n *childNodes(): Iterable<SyntaxNode> {\n for (const child of this.children()) {\n if (child instanceof SyntaxNode) yield child;\n }\n }\n\n *ancestors(): Iterable<SyntaxNode> {\n let current: SyntaxNode | undefined = this.parent;\n while (current) {\n yield current;\n current = current.parent;\n }\n }\n\n *descendants(): Iterable<SyntaxElement> {\n const stack: SyntaxElement[] = [this];\n for (let el = stack.pop(); el !== undefined; el = stack.pop()) {\n yield el;\n if (el instanceof SyntaxNode) {\n const children = Array.from(el.children());\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i];\n if (child !== undefined) {\n stack.push(child);\n }\n }\n }\n }\n }\n\n *tokens(): Iterable<SyntaxToken> {\n for (const el of this.descendants()) {\n if (!(el instanceof SyntaxNode)) {\n yield el;\n }\n }\n }\n}\n\nfunction elementTextLength(el: GreenElement): number {\n return el.type === 'token' ? el.text.length : el.textLength;\n}\n\nfunction wrapElement(green: GreenElement, offset: number, parent: SyntaxNode): SyntaxElement {\n if (green.type === 'token') {\n const token: SyntaxToken = { kind: green.kind, text: green.text, offset };\n return token;\n }\n return new SyntaxNode(green, offset, parent);\n}\n\nfunction childAt(node: SyntaxNode, index: number): SyntaxElement | undefined {\n const children = node.green.children;\n const target = children[index];\n if (target === undefined) return undefined;\n let offset = node.offset;\n for (let i = 0; i < index; i++) {\n const child = children[i];\n if (child !== undefined) {\n offset += elementTextLength(child);\n }\n }\n return wrapElement(target, offset, node);\n}\n\nexport function createSyntaxTree(green: GreenNode): SyntaxNode {\n return new SyntaxNode(green, 0, undefined);\n}\n","import type { Token, TokenKind } from '../tokenizer';\nimport { SyntaxNode } from './red';\n\nexport interface AstNode {\n readonly syntax: SyntaxNode;\n}\n\nexport function findChildToken(node: SyntaxNode, kind: TokenKind): Token | undefined {\n for (const child of node.children()) {\n if (!(child instanceof SyntaxNode) && child.kind === kind) {\n return child;\n }\n }\n return undefined;\n}\n\nexport function findFirstChild<T>(\n node: SyntaxNode,\n cast: (node: SyntaxNode) => T | undefined,\n): T | undefined {\n for (const child of node.childNodes()) {\n const result = cast(child);\n if (result !== undefined) return result;\n }\n return undefined;\n}\n\nexport function* filterChildren<T>(\n node: SyntaxNode,\n cast: (node: SyntaxNode) => T | undefined,\n): Iterable<T> {\n for (const child of node.childNodes()) {\n const result = cast(child);\n if (result !== undefined) yield result;\n }\n}\n","import type { Token } from '../../tokenizer';\nimport type { AstNode } from '../ast-helpers';\nimport { findChildToken } from '../ast-helpers';\nimport type { SyntaxNode } from '../red';\n\nexport class IdentifierAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n token(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n static cast(node: SyntaxNode): IdentifierAst | undefined {\n return node.kind === 'Identifier' ? new IdentifierAst(node) : undefined;\n }\n}\n","import type { Token } from '../../tokenizer';\nimport type { AstNode } from '../ast-helpers';\nimport { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';\nimport { SyntaxNode } from '../red';\nimport { IdentifierAst } from './identifier';\n\nexport class FunctionCallAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lparen(): Token | undefined {\n return findChildToken(this.syntax, 'LParen');\n }\n\n rparen(): Token | undefined {\n return findChildToken(this.syntax, 'RParen');\n }\n\n *args(): Iterable<AttributeArgAst> {\n yield* filterChildren(this.syntax, AttributeArgAst.cast);\n }\n\n static cast(node: SyntaxNode): FunctionCallAst | undefined {\n return node.kind === 'FunctionCall' ? new FunctionCallAst(node) : undefined;\n }\n}\n\nexport class ArrayLiteralAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n lbracket(): Token | undefined {\n return findChildToken(this.syntax, 'LBracket');\n }\n\n rbracket(): Token | undefined {\n return findChildToken(this.syntax, 'RBracket');\n }\n\n *elements(): Iterable<ExpressionAst> {\n yield* filterChildren(this.syntax, castExpression);\n }\n\n static cast(node: SyntaxNode): ArrayLiteralAst | undefined {\n return node.kind === 'ArrayLiteral' ? new ArrayLiteralAst(node) : undefined;\n }\n}\n\nexport class StringLiteralExprAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n token(): Token | undefined {\n return findChildToken(this.syntax, 'StringLiteral');\n }\n\n value(): string | undefined {\n const tok = this.token();\n if (!tok) return undefined;\n const raw = tok.text.slice(1, -1);\n return raw.replace(/\\\\(.)/g, (_match, char: string) => {\n switch (char) {\n case 'n':\n return '\\n';\n case 'r':\n return '\\r';\n case 't':\n return '\\t';\n case '\"':\n return '\"';\n case '\\\\':\n return '\\\\';\n default:\n return `\\\\${char}`;\n }\n });\n }\n\n static cast(node: SyntaxNode): StringLiteralExprAst | undefined {\n return node.kind === 'StringLiteralExpr' ? new StringLiteralExprAst(node) : undefined;\n }\n}\n\nexport class NumberLiteralExprAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n token(): Token | undefined {\n return findChildToken(this.syntax, 'NumberLiteral');\n }\n\n value(): number | undefined {\n const tok = this.token();\n if (!tok) return undefined;\n return Number(tok.text);\n }\n\n static cast(node: SyntaxNode): NumberLiteralExprAst | undefined {\n return node.kind === 'NumberLiteralExpr' ? new NumberLiteralExprAst(node) : undefined;\n }\n}\n\nexport class BooleanLiteralExprAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n token(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n value(): boolean | undefined {\n const tok = this.token();\n if (!tok) return undefined;\n if (tok.text === 'true') return true;\n if (tok.text === 'false') return false;\n return undefined;\n }\n\n static cast(node: SyntaxNode): BooleanLiteralExprAst | undefined {\n return node.kind === 'BooleanLiteralExpr' ? new BooleanLiteralExprAst(node) : undefined;\n }\n}\n\nexport type ExpressionAst =\n | FunctionCallAst\n | ArrayLiteralAst\n | StringLiteralExprAst\n | NumberLiteralExprAst\n | BooleanLiteralExprAst\n | IdentifierAst;\n\nexport function castExpression(node: SyntaxNode): ExpressionAst | undefined {\n return (\n FunctionCallAst.cast(node) ??\n ArrayLiteralAst.cast(node) ??\n StringLiteralExprAst.cast(node) ??\n NumberLiteralExprAst.cast(node) ??\n BooleanLiteralExprAst.cast(node) ??\n IdentifierAst.cast(node)\n );\n}\n\nexport class AttributeArgAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n name(): IdentifierAst | undefined {\n if (!this.colon()) return undefined;\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n colon(): Token | undefined {\n return findChildToken(this.syntax, 'Colon');\n }\n\n value(): ExpressionAst | undefined {\n if (this.colon()) {\n let pastColon = false;\n for (const child of this.syntax.children()) {\n if (!(child instanceof SyntaxNode)) {\n if (child.kind === 'Colon') pastColon = true;\n continue;\n }\n if (pastColon) {\n const expr = castExpression(child);\n if (expr) return expr;\n }\n }\n return undefined;\n }\n return findFirstChild(this.syntax, castExpression);\n }\n\n static cast(node: SyntaxNode): AttributeArgAst | undefined {\n return node.kind === 'AttributeArg' ? new AttributeArgAst(node) : undefined;\n }\n}\n","import type { Token } from '../../tokenizer';\nimport type { AstNode } from '../ast-helpers';\nimport { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';\nimport type { SyntaxNode } from '../red';\nimport { AttributeArgAst } from './expressions';\nimport { IdentifierAst } from './identifier';\n\nexport class AttributeArgListAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n lparen(): Token | undefined {\n return findChildToken(this.syntax, 'LParen');\n }\n\n rparen(): Token | undefined {\n return findChildToken(this.syntax, 'RParen');\n }\n\n *args(): Iterable<AttributeArgAst> {\n yield* filterChildren(this.syntax, AttributeArgAst.cast);\n }\n\n static cast(node: SyntaxNode): AttributeArgListAst | undefined {\n return node.kind === 'AttributeArgList' ? new AttributeArgListAst(node) : undefined;\n }\n}\n\nexport class FieldAttributeAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n at(): Token | undefined {\n return findChildToken(this.syntax, 'At');\n }\n\n name(): IdentifierAst | undefined {\n if (this.dot()) {\n let count = 0;\n for (const child of this.syntax.childNodes()) {\n if (child.kind === 'Identifier') {\n count++;\n if (count === 2) return new IdentifierAst(child);\n }\n }\n return undefined;\n }\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n dot(): Token | undefined {\n return findChildToken(this.syntax, 'Dot');\n }\n\n namespaceName(): IdentifierAst | undefined {\n if (!this.dot()) return undefined;\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n argList(): AttributeArgListAst | undefined {\n return findFirstChild(this.syntax, AttributeArgListAst.cast);\n }\n\n static cast(node: SyntaxNode): FieldAttributeAst | undefined {\n return node.kind === 'FieldAttribute' ? new FieldAttributeAst(node) : undefined;\n }\n}\n\nexport class ModelAttributeAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n doubleAt(): Token | undefined {\n return findChildToken(this.syntax, 'DoubleAt');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n argList(): AttributeArgListAst | undefined {\n return findFirstChild(this.syntax, AttributeArgListAst.cast);\n }\n\n static cast(node: SyntaxNode): ModelAttributeAst | undefined {\n return node.kind === 'ModelAttribute' ? new ModelAttributeAst(node) : undefined;\n }\n}\n","import type { Token } from '../../tokenizer';\nimport type { AstNode } from '../ast-helpers';\nimport { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';\nimport type { SyntaxNode } from '../red';\nimport { FunctionCallAst } from './expressions';\nimport { IdentifierAst } from './identifier';\n\nexport class TypeAnnotationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n #lastSegment(): IdentifierAst | undefined {\n let last: IdentifierAst | undefined;\n for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {\n last = segment;\n }\n return last;\n }\n\n #penultimateSegment(): IdentifierAst | undefined {\n let last: IdentifierAst | undefined;\n let penultimate: IdentifierAst | undefined;\n for (const segment of filterChildren(this.syntax, IdentifierAst.cast)) {\n penultimate = last;\n last = segment;\n }\n return penultimate;\n }\n\n name(): IdentifierAst | undefined {\n return this.#lastSegment();\n }\n\n colon(): Token | undefined {\n return findChildToken(this.syntax, 'Colon');\n }\n\n dot(): Token | undefined {\n return findChildToken(this.syntax, 'Dot');\n }\n\n spaceName(): IdentifierAst | undefined {\n if (!this.colon()) return undefined;\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n namespaceName(): IdentifierAst | undefined {\n if (!this.dot()) return undefined;\n return this.#penultimateSegment();\n }\n\n constructorCall(): FunctionCallAst | undefined {\n return findFirstChild(this.syntax, FunctionCallAst.cast);\n }\n\n lbracket(): Token | undefined {\n return findChildToken(this.syntax, 'LBracket');\n }\n\n rbracket(): Token | undefined {\n return findChildToken(this.syntax, 'RBracket');\n }\n\n questionMark(): Token | undefined {\n return findChildToken(this.syntax, 'Question');\n }\n\n isList(): boolean {\n return this.lbracket() !== undefined;\n }\n\n isOptional(): boolean {\n return this.questionMark() !== undefined;\n }\n\n static cast(node: SyntaxNode): TypeAnnotationAst | undefined {\n return node.kind === 'TypeAnnotation' ? new TypeAnnotationAst(node) : undefined;\n }\n}\n","import type { Token } from '../../tokenizer';\nimport type { AstNode } from '../ast-helpers';\nimport { filterChildren, findChildToken, findFirstChild } from '../ast-helpers';\nimport { SyntaxNode } from '../red';\nimport { FieldAttributeAst, ModelAttributeAst } from './attributes';\nimport type { ExpressionAst } from './expressions';\nimport { castExpression } from './expressions';\nimport { IdentifierAst } from './identifier';\nimport { TypeAnnotationAst } from './type-annotation';\n\n/**\n * What may appear inside a `namespace` block: models, enums, composite types,\n * and extension (block) declarations. Mirrors what `parsePslDocument` accepts\n * in a namespace body. `types {}` blocks and nested `namespace` blocks are\n * document-only, so they are not namespace members.\n */\nexport type NamespaceMemberAst =\n | ModelDeclarationAst\n | EnumDeclarationAst\n | CompositeTypeDeclarationAst\n | BlockDeclarationAst;\n\nfunction castNamespaceMember(node: SyntaxNode): NamespaceMemberAst | undefined {\n return (\n ModelDeclarationAst.cast(node) ??\n EnumDeclarationAst.cast(node) ??\n CompositeTypeDeclarationAst.cast(node) ??\n BlockDeclarationAst.cast(node)\n );\n}\n\nexport class DocumentAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n *declarations(): Iterable<NamespaceMemberAst | TypesBlockAst | NamespaceDeclarationAst> {\n yield* filterChildren(\n this.syntax,\n (node) =>\n castNamespaceMember(node) ?? TypesBlockAst.cast(node) ?? NamespaceDeclarationAst.cast(node),\n );\n }\n\n static cast(node: SyntaxNode): DocumentAst | undefined {\n return node.kind === 'Document' ? new DocumentAst(node) : undefined;\n }\n}\n\nexport class ModelDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *fields(): Iterable<FieldDeclarationAst> {\n yield* filterChildren(this.syntax, FieldDeclarationAst.cast);\n }\n\n *attributes(): Iterable<ModelAttributeAst> {\n yield* filterChildren(this.syntax, ModelAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): ModelDeclarationAst | undefined {\n return node.kind === 'ModelDeclaration' ? new ModelDeclarationAst(node) : undefined;\n }\n}\n\nexport class EnumDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *values(): Iterable<EnumValueDeclarationAst> {\n yield* filterChildren(this.syntax, EnumValueDeclarationAst.cast);\n }\n\n *attributes(): Iterable<ModelAttributeAst> {\n yield* filterChildren(this.syntax, ModelAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): EnumDeclarationAst | undefined {\n return node.kind === 'EnumDeclaration' ? new EnumDeclarationAst(node) : undefined;\n }\n}\n\nexport class CompositeTypeDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *fields(): Iterable<FieldDeclarationAst> {\n yield* filterChildren(this.syntax, FieldDeclarationAst.cast);\n }\n\n *attributes(): Iterable<ModelAttributeAst> {\n yield* filterChildren(this.syntax, ModelAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): CompositeTypeDeclarationAst | undefined {\n return node.kind === 'CompositeTypeDeclaration'\n ? new CompositeTypeDeclarationAst(node)\n : undefined;\n }\n}\n\nexport class NamespaceDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *declarations(): Iterable<NamespaceMemberAst> {\n yield* filterChildren(this.syntax, castNamespaceMember);\n }\n\n static cast(node: SyntaxNode): NamespaceDeclarationAst | undefined {\n return node.kind === 'Namespace' ? new NamespaceDeclarationAst(node) : undefined;\n }\n}\n\nexport class TypesBlockAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *declarations(): Iterable<NamedTypeDeclarationAst> {\n yield* filterChildren(this.syntax, NamedTypeDeclarationAst.cast);\n }\n\n static cast(node: SyntaxNode): TypesBlockAst | undefined {\n return node.kind === 'TypesBlock' ? new TypesBlockAst(node) : undefined;\n }\n}\n\nexport class BlockDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n keyword(): Token | undefined {\n return findChildToken(this.syntax, 'Ident');\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n lbrace(): Token | undefined {\n return findChildToken(this.syntax, 'LBrace');\n }\n\n rbrace(): Token | undefined {\n return findChildToken(this.syntax, 'RBrace');\n }\n\n *entries(): Iterable<KeyValuePairAst> {\n yield* filterChildren(this.syntax, KeyValuePairAst.cast);\n }\n\n static cast(node: SyntaxNode): BlockDeclarationAst | undefined {\n return node.kind === 'BlockDeclaration' ? new BlockDeclarationAst(node) : undefined;\n }\n}\n\nexport class KeyValuePairAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n key(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n equals(): Token | undefined {\n return findChildToken(this.syntax, 'Equals');\n }\n\n value(): ExpressionAst | undefined {\n let pastEquals = false;\n for (const child of this.syntax.children()) {\n if (!(child instanceof SyntaxNode)) {\n if (child.kind === 'Equals') pastEquals = true;\n continue;\n }\n if (pastEquals) {\n const expr = castExpression(child);\n if (expr) return expr;\n }\n }\n return undefined;\n }\n\n static cast(node: SyntaxNode): KeyValuePairAst | undefined {\n return node.kind === 'KeyValuePair' ? new KeyValuePairAst(node) : undefined;\n }\n}\n\nexport class FieldDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n typeAnnotation(): TypeAnnotationAst | undefined {\n return findFirstChild(this.syntax, TypeAnnotationAst.cast);\n }\n\n *attributes(): Iterable<FieldAttributeAst> {\n yield* filterChildren(this.syntax, FieldAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): FieldDeclarationAst | undefined {\n return node.kind === 'FieldDeclaration' ? new FieldDeclarationAst(node) : undefined;\n }\n}\n\nexport class EnumValueDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n *attributes(): Iterable<FieldAttributeAst> {\n yield* filterChildren(this.syntax, FieldAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): EnumValueDeclarationAst | undefined {\n return node.kind === 'EnumValueDeclaration' ? new EnumValueDeclarationAst(node) : undefined;\n }\n}\n\nexport class NamedTypeDeclarationAst implements AstNode {\n readonly syntax: SyntaxNode;\n\n constructor(syntax: SyntaxNode) {\n this.syntax = syntax;\n }\n\n name(): IdentifierAst | undefined {\n return findFirstChild(this.syntax, IdentifierAst.cast);\n }\n\n equals(): Token | undefined {\n return findChildToken(this.syntax, 'Equals');\n }\n\n typeAnnotation(): TypeAnnotationAst | undefined {\n return findFirstChild(this.syntax, TypeAnnotationAst.cast);\n }\n\n *attributes(): Iterable<FieldAttributeAst> {\n yield* filterChildren(this.syntax, FieldAttributeAst.cast);\n }\n\n static cast(node: SyntaxNode): NamedTypeDeclarationAst | undefined {\n return node.kind === 'NamedTypeDeclaration' ? new NamedTypeDeclarationAst(node) : undefined;\n }\n}\n","import type { TokenKind } from '../tokenizer';\nimport type { SyntaxKind } from './syntax-kind';\n\nexport interface GreenToken {\n readonly type: 'token';\n readonly kind: TokenKind;\n readonly text: string;\n}\n\nexport interface GreenNode {\n readonly type: 'node';\n readonly kind: SyntaxKind;\n readonly children: ReadonlyArray<GreenElement>;\n readonly textLength: number;\n}\n\nexport type GreenElement = GreenNode | GreenToken;\n\nexport function greenToken(kind: TokenKind, text: string): GreenToken {\n return { type: 'token', kind, text };\n}\n\nexport function greenNode(kind: SyntaxKind, children: ReadonlyArray<GreenElement>): GreenNode {\n let textLength = 0;\n for (const child of children) {\n textLength += child.type === 'token' ? child.text.length : child.textLength;\n }\n return { type: 'node', kind, children, textLength };\n}\n","import type { TokenKind } from '../tokenizer';\nimport type { GreenElement, GreenNode } from './green';\nimport { greenNode, greenToken } from './green';\nimport type { SyntaxKind } from './syntax-kind';\n\nexport class GreenNodeBuilder {\n readonly #stack: Array<{ kind: SyntaxKind; children: GreenElement[] }> = [];\n\n startNode(kind: SyntaxKind): void {\n this.#stack.push({ kind, children: [] });\n }\n\n token(kind: TokenKind, text: string): void {\n const current = this.#stack.at(-1);\n if (!current) {\n throw new Error('GreenNodeBuilder: token() called with no open node');\n }\n current.children.push(greenToken(kind, text));\n }\n\n finishNode(): GreenNode {\n const completed = this.#stack.pop();\n if (!completed) {\n throw new Error('GreenNodeBuilder: finishNode() called with no open node');\n }\n const node = greenNode(completed.kind, completed.children);\n const parent = this.#stack.at(-1);\n if (parent) {\n parent.children.push(node);\n }\n return node;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/tokenizer.d.ts
|
|
2
|
+
type TokenKind = 'Ident' | 'StringLiteral' | 'NumberLiteral' | 'At' | 'DoubleAt' | 'LBrace' | 'RBrace' | 'LParen' | 'RParen' | 'LBracket' | 'RBracket' | 'Equals' | 'Question' | 'Dot' | 'Comma' | 'Colon' | 'Whitespace' | 'Newline' | 'Comment' | 'Invalid' | 'Eof';
|
|
3
|
+
interface Token {
|
|
4
|
+
readonly kind: TokenKind;
|
|
5
|
+
readonly text: string;
|
|
6
|
+
}
|
|
7
|
+
declare class Tokenizer {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(source: string);
|
|
10
|
+
next(): Token;
|
|
11
|
+
peek(offset?: number): Token;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { TokenKind as n, Tokenizer as r, Token as t };
|
|
15
|
+
//# sourceMappingURL=tokenizer-DcYI0Xrq.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizer-DcYI0Xrq.d.mts","names":[],"sources":["../src/tokenizer.ts"],"mappings":";KAAY,SAAA;AAAA,UAuBK,KAAA;EAAA,SACN,IAAA,EAAM,SAAS;EAAA,SACf,IAAA;AAAA;AAAA,cAGE,SAAA;EAAA;cAKC,MAAA;EAMZ,IAAA,IAAQ,KAAA;EAQR,IAAA,CAAK,MAAA,YAAa,KAAK;AAAA"}
|
package/dist/tokenizer.d.mts
CHANGED
|
@@ -1,15 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
interface Token {
|
|
4
|
-
readonly kind: TokenKind;
|
|
5
|
-
readonly text: string;
|
|
6
|
-
}
|
|
7
|
-
declare class Tokenizer {
|
|
8
|
-
#private;
|
|
9
|
-
constructor(source: string);
|
|
10
|
-
next(): Token;
|
|
11
|
-
peek(offset?: number): Token;
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { type Token, type TokenKind, Tokenizer };
|
|
15
|
-
//# sourceMappingURL=tokenizer.d.mts.map
|
|
1
|
+
import { n as TokenKind, r as Tokenizer, t as Token } from "./tokenizer-DcYI0Xrq.mjs";
|
|
2
|
+
export { type Token, type TokenKind, Tokenizer };
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/psl-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0-dev.2",
|
|
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.
|
|
10
|
-
"@prisma-next/utils": "0.
|
|
9
|
+
"@prisma-next/framework-components": "0.13.0-dev.2",
|
|
10
|
+
"@prisma-next/utils": "0.13.0-dev.2"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@prisma-next/tsconfig": "0.
|
|
14
|
-
"@prisma-next/tsdown": "0.
|
|
15
|
-
"tsdown": "0.22.
|
|
13
|
+
"@prisma-next/tsconfig": "0.13.0-dev.2",
|
|
14
|
+
"@prisma-next/tsdown": "0.13.0-dev.2",
|
|
15
|
+
"tsdown": "0.22.1",
|
|
16
16
|
"typescript": "5.9.3",
|
|
17
|
-
"vitest": "4.1.
|
|
17
|
+
"vitest": "4.1.8"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"typescript": ">=5.9"
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"exports": {
|
|
33
33
|
".": "./dist/index.mjs",
|
|
34
34
|
"./parser": "./dist/parser.mjs",
|
|
35
|
+
"./syntax": "./dist/syntax.mjs",
|
|
35
36
|
"./tokenizer": "./dist/tokenizer.mjs",
|
|
36
37
|
"./package.json": "./package.json"
|
|
37
38
|
},
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AttributeArgListAst,
|
|
3
|
+
FieldAttributeAst,
|
|
4
|
+
ModelAttributeAst,
|
|
5
|
+
} from '../syntax/ast/attributes';
|
|
6
|
+
export type { NamespaceMemberAst } from '../syntax/ast/declarations';
|
|
7
|
+
export {
|
|
8
|
+
BlockDeclarationAst,
|
|
9
|
+
CompositeTypeDeclarationAst,
|
|
10
|
+
DocumentAst,
|
|
11
|
+
EnumDeclarationAst,
|
|
12
|
+
EnumValueDeclarationAst,
|
|
13
|
+
FieldDeclarationAst,
|
|
14
|
+
KeyValuePairAst,
|
|
15
|
+
ModelDeclarationAst,
|
|
16
|
+
NamedTypeDeclarationAst,
|
|
17
|
+
NamespaceDeclarationAst,
|
|
18
|
+
TypesBlockAst,
|
|
19
|
+
} from '../syntax/ast/declarations';
|
|
20
|
+
export type { ExpressionAst } from '../syntax/ast/expressions';
|
|
21
|
+
export {
|
|
22
|
+
ArrayLiteralAst,
|
|
23
|
+
AttributeArgAst,
|
|
24
|
+
BooleanLiteralExprAst,
|
|
25
|
+
castExpression,
|
|
26
|
+
FunctionCallAst,
|
|
27
|
+
NumberLiteralExprAst,
|
|
28
|
+
StringLiteralExprAst,
|
|
29
|
+
} from '../syntax/ast/expressions';
|
|
30
|
+
// AST wrappers
|
|
31
|
+
export { IdentifierAst } from '../syntax/ast/identifier';
|
|
32
|
+
export { TypeAnnotationAst } from '../syntax/ast/type-annotation';
|
|
33
|
+
export type { AstNode } from '../syntax/ast-helpers';
|
|
34
|
+
export { filterChildren, findChildToken, findFirstChild } from '../syntax/ast-helpers';
|
|
35
|
+
export type { GreenElement, GreenNode, GreenToken } from '../syntax/green';
|
|
36
|
+
export { greenNode, greenToken } from '../syntax/green';
|
|
37
|
+
export { GreenNodeBuilder } from '../syntax/green-builder';
|
|
38
|
+
// Red layer
|
|
39
|
+
export type { SyntaxElement, SyntaxToken } from '../syntax/red';
|
|
40
|
+
export { createSyntaxTree, SyntaxNode } from '../syntax/red';
|
|
41
|
+
export type { SyntaxKind } from '../syntax/syntax-kind';
|
package/src/parser.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AuthoringPslBlockDescriptor,
|
|
3
|
+
AuthoringPslBlockDescriptorNamespace,
|
|
4
|
+
} from '@prisma-next/framework-components/authoring';
|
|
5
|
+
import { isAuthoringPslBlockDescriptor } from '@prisma-next/framework-components/authoring';
|
|
6
|
+
import { emptyCodecLookup } from '@prisma-next/framework-components/codec';
|
|
1
7
|
import type {
|
|
2
8
|
ParsePslDocumentInput,
|
|
3
9
|
ParsePslDocumentResult,
|
|
@@ -10,6 +16,8 @@ import type {
|
|
|
10
16
|
PslDocumentAst,
|
|
11
17
|
PslEnum,
|
|
12
18
|
PslEnumValue,
|
|
19
|
+
PslExtensionBlock,
|
|
20
|
+
PslExtensionBlockParamValue,
|
|
13
21
|
PslField,
|
|
14
22
|
PslFieldAttribute,
|
|
15
23
|
PslModel,
|
|
@@ -21,7 +29,13 @@ import type {
|
|
|
21
29
|
PslTypeConstructorCall,
|
|
22
30
|
PslTypesBlock,
|
|
23
31
|
} from '@prisma-next/framework-components/psl-ast';
|
|
24
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
makePslNamespace,
|
|
34
|
+
makePslNamespaceEntries,
|
|
35
|
+
namespacePslExtensionBlocks,
|
|
36
|
+
UNSPECIFIED_PSL_NAMESPACE_ID,
|
|
37
|
+
validateExtensionBlock,
|
|
38
|
+
} from '@prisma-next/framework-components/psl-ast';
|
|
25
39
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
26
40
|
|
|
27
41
|
const SCALAR_TYPES = new Set([
|
|
@@ -68,6 +82,7 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
68
82
|
models: PslModel[];
|
|
69
83
|
enums: PslEnum[];
|
|
70
84
|
compositeTypes: PslCompositeType[];
|
|
85
|
+
extensionBlocks: PslExtensionBlock[];
|
|
71
86
|
span: PslSpan | undefined;
|
|
72
87
|
}
|
|
73
88
|
|
|
@@ -79,7 +94,14 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
79
94
|
): NamespaceAccumulator => {
|
|
80
95
|
let acc = namespacesByName.get(name);
|
|
81
96
|
if (!acc) {
|
|
82
|
-
acc = {
|
|
97
|
+
acc = {
|
|
98
|
+
name,
|
|
99
|
+
models: [],
|
|
100
|
+
enums: [],
|
|
101
|
+
compositeTypes: [],
|
|
102
|
+
extensionBlocks: [],
|
|
103
|
+
span: spanIfNew,
|
|
104
|
+
};
|
|
83
105
|
namespacesByName.set(name, acc);
|
|
84
106
|
namespaceOrder.push(name);
|
|
85
107
|
}
|
|
@@ -87,6 +109,7 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
87
109
|
};
|
|
88
110
|
|
|
89
111
|
let typesBlock: PslTypesBlock | undefined;
|
|
112
|
+
const pslBlockNamespace: AuthoringPslBlockDescriptorNamespace = input.pslBlockDescriptors ?? {};
|
|
90
113
|
|
|
91
114
|
// Walk a contiguous range of lines, routing top-level declarations into the
|
|
92
115
|
// active namespace bucket. Called once for the whole document and once per
|
|
@@ -198,6 +221,26 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
198
221
|
continue;
|
|
199
222
|
}
|
|
200
223
|
|
|
224
|
+
const extensionBlockMatch = line.match(/^([A-Za-z_]\w*)\s+([A-Za-z_]\w*)\s*\{$/);
|
|
225
|
+
if (extensionBlockMatch) {
|
|
226
|
+
const keyword = extensionBlockMatch[1] ?? '';
|
|
227
|
+
const blockName = extensionBlockMatch[2] ?? '';
|
|
228
|
+
const descriptor = lookupExtensionBlockDescriptor(pslBlockNamespace, keyword);
|
|
229
|
+
if (descriptor) {
|
|
230
|
+
const bounds = findBlockBounds(context, lineIndex);
|
|
231
|
+
if (blockName.length > 0) {
|
|
232
|
+
const acc = getOrCreateNamespace(
|
|
233
|
+
currentNamespaceName,
|
|
234
|
+
createTrimmedLineSpan(context, lineIndex),
|
|
235
|
+
);
|
|
236
|
+
const node = parseExtensionBlock(context, descriptor, blockName, lineIndex, bounds);
|
|
237
|
+
acc.extensionBlocks.push(node);
|
|
238
|
+
}
|
|
239
|
+
lineIndex = bounds.endLine + 1;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
201
244
|
if (line.includes('{')) {
|
|
202
245
|
const blockName = line.split(/\s+/)[0] ?? 'block';
|
|
203
246
|
pushDiagnostic(context, {
|
|
@@ -288,7 +331,8 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
288
331
|
name === UNSPECIFIED_PSL_NAMESPACE_ID &&
|
|
289
332
|
acc.models.length === 0 &&
|
|
290
333
|
acc.enums.length === 0 &&
|
|
291
|
-
acc.compositeTypes.length === 0
|
|
334
|
+
acc.compositeTypes.length === 0 &&
|
|
335
|
+
acc.extensionBlocks.length === 0
|
|
292
336
|
) {
|
|
293
337
|
continue;
|
|
294
338
|
}
|
|
@@ -316,14 +360,59 @@ export function parsePslDocument(input: ParsePslDocumentInput): ParsePslDocument
|
|
|
316
360
|
};
|
|
317
361
|
}),
|
|
318
362
|
}));
|
|
319
|
-
namespaces.push(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
363
|
+
namespaces.push(
|
|
364
|
+
makePslNamespace({
|
|
365
|
+
kind: 'namespace',
|
|
366
|
+
name,
|
|
367
|
+
entries: makePslNamespaceEntries(
|
|
368
|
+
normalizedModels,
|
|
369
|
+
acc.enums,
|
|
370
|
+
acc.compositeTypes,
|
|
371
|
+
acc.extensionBlocks,
|
|
372
|
+
),
|
|
373
|
+
span: acc.span ?? documentSpan,
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Validate extension blocks with the generic validator after the full
|
|
379
|
+
// AST is assembled. The validator needs all namespaces for ref resolution.
|
|
380
|
+
// It runs whenever pslBlockDescriptors are registered — codecLookup falls
|
|
381
|
+
// back to emptyCodecLookup when not provided, which rejects value-kind
|
|
382
|
+
// parameters with unknown codecs. Callers with value parameters should
|
|
383
|
+
// always supply a codecLookup.
|
|
384
|
+
if (Object.keys(pslBlockNamespace).length > 0) {
|
|
385
|
+
const codecLookup = input.codecLookup ?? emptyCodecLookup;
|
|
386
|
+
// Build a discriminator → descriptor reverse map from the descriptor
|
|
387
|
+
// namespace. The parser keyed by keyword; the validator resolves by
|
|
388
|
+
// node.kind (= discriminator) so we need the reverse direction.
|
|
389
|
+
const descriptorByDiscriminator = new Map<string, AuthoringPslBlockDescriptor>();
|
|
390
|
+
for (const value of Object.values(pslBlockNamespace)) {
|
|
391
|
+
if (isAuthoringPslBlockDescriptor(value)) {
|
|
392
|
+
descriptorByDiscriminator.set(value.discriminator, value);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const ns of namespaces) {
|
|
396
|
+
// Collect extension blocks from entries using the canonical helper, then
|
|
397
|
+
// filter to only those whose discriminator is registered in the namespace.
|
|
398
|
+
for (const block of namespacePslExtensionBlocks(ns)) {
|
|
399
|
+
const descriptor = descriptorByDiscriminator.get(block.kind);
|
|
400
|
+
if (descriptor === undefined) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const blockDiagnostics = validateExtensionBlock(
|
|
404
|
+
block,
|
|
405
|
+
descriptor,
|
|
406
|
+
input.sourceId,
|
|
407
|
+
codecLookup,
|
|
408
|
+
{
|
|
409
|
+
ownerNamespace: ns,
|
|
410
|
+
allNamespaces: namespaces,
|
|
411
|
+
},
|
|
412
|
+
);
|
|
413
|
+
diagnostics.push(...blockDiagnostics);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
327
416
|
}
|
|
328
417
|
|
|
329
418
|
const ast: PslDocumentAst = {
|
|
@@ -787,11 +876,45 @@ function parseField(context: ParserContext, line: string, lineIndex: number): Ps
|
|
|
787
876
|
|
|
788
877
|
let typeName: string;
|
|
789
878
|
let typeNamespaceId: string | undefined;
|
|
879
|
+
let typeContractSpaceId: string | undefined;
|
|
790
880
|
|
|
791
881
|
if (typeConstructor) {
|
|
792
882
|
typeName = typeConstructor.path.join('.');
|
|
793
883
|
} else {
|
|
794
|
-
|
|
884
|
+
// Detect the colon-prefix cross-contract-space form: `<space>:<rest>` where
|
|
885
|
+
// `<rest>` is the existing dot-qualified or bare form (`<ns>.<Name>` or `<Name>`).
|
|
886
|
+
// Multiple colons (e.g. `a:b:c`) are invalid.
|
|
887
|
+
const colonCount = (baseTypeSource.match(/:/g) ?? []).length;
|
|
888
|
+
if (colonCount > 1) {
|
|
889
|
+
pushDiagnostic(context, {
|
|
890
|
+
code: 'PSL_INVALID_MODEL_MEMBER',
|
|
891
|
+
message: `Invalid model member declaration "${line}"`,
|
|
892
|
+
span: createTrimmedLineSpan(context, lineIndex),
|
|
893
|
+
});
|
|
894
|
+
return undefined;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
let typeRefSource: string;
|
|
898
|
+
if (colonCount === 1) {
|
|
899
|
+
// Colon-prefix form: `<space>:<rest>`
|
|
900
|
+
const colonIndex = baseTypeSource.indexOf(':');
|
|
901
|
+
const spaceCandidate = baseTypeSource.slice(0, colonIndex);
|
|
902
|
+
typeRefSource = baseTypeSource.slice(colonIndex + 1);
|
|
903
|
+
// Validate space identifier
|
|
904
|
+
if (!/^[A-Za-z_]\w*$/.test(spaceCandidate)) {
|
|
905
|
+
pushDiagnostic(context, {
|
|
906
|
+
code: 'PSL_INVALID_MODEL_MEMBER',
|
|
907
|
+
message: `Invalid model member declaration "${line}"`,
|
|
908
|
+
span: createTrimmedLineSpan(context, lineIndex),
|
|
909
|
+
});
|
|
910
|
+
return undefined;
|
|
911
|
+
}
|
|
912
|
+
typeContractSpaceId = spaceCandidate;
|
|
913
|
+
} else {
|
|
914
|
+
typeRefSource = baseTypeSource;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const dotCount = (typeRefSource.match(/\./g) ?? []).length;
|
|
795
918
|
if (dotCount > 1) {
|
|
796
919
|
pushDiagnostic(context, {
|
|
797
920
|
code: 'PSL_INVALID_QUALIFIED_TYPE',
|
|
@@ -805,7 +928,7 @@ function parseField(context: ParserContext, line: string, lineIndex: number): Ps
|
|
|
805
928
|
});
|
|
806
929
|
return undefined;
|
|
807
930
|
}
|
|
808
|
-
const singleMatch =
|
|
931
|
+
const singleMatch = typeRefSource.match(/^([A-Za-z_]\w*)(?:\.([A-Za-z_]\w*))?$/);
|
|
809
932
|
if (!singleMatch) {
|
|
810
933
|
pushDiagnostic(context, {
|
|
811
934
|
code: 'PSL_INVALID_MODEL_MEMBER',
|
|
@@ -841,6 +964,7 @@ function parseField(context: ParserContext, line: string, lineIndex: number): Ps
|
|
|
841
964
|
name: fieldName,
|
|
842
965
|
typeName,
|
|
843
966
|
...ifDefined('typeNamespaceId', typeNamespaceId),
|
|
967
|
+
...ifDefined('typeContractSpaceId', typeContractSpaceId),
|
|
844
968
|
...ifDefined('typeConstructor', typeConstructor),
|
|
845
969
|
optional,
|
|
846
970
|
list,
|
|
@@ -866,6 +990,7 @@ function parseField(context: ParserContext, line: string, lineIndex: number): Ps
|
|
|
866
990
|
name: fieldName,
|
|
867
991
|
typeName,
|
|
868
992
|
...ifDefined('typeNamespaceId', typeNamespaceId),
|
|
993
|
+
...ifDefined('typeContractSpaceId', typeContractSpaceId),
|
|
869
994
|
...ifDefined('typeConstructor', typeConstructor),
|
|
870
995
|
optional,
|
|
871
996
|
list,
|
|
@@ -1453,3 +1578,136 @@ function pushDiagnostic(
|
|
|
1453
1578
|
sourceId: context.sourceId,
|
|
1454
1579
|
});
|
|
1455
1580
|
}
|
|
1581
|
+
|
|
1582
|
+
function lookupExtensionBlockDescriptor(
|
|
1583
|
+
namespace: AuthoringPslBlockDescriptorNamespace,
|
|
1584
|
+
keyword: string,
|
|
1585
|
+
): AuthoringPslBlockDescriptor | undefined {
|
|
1586
|
+
if (!Object.hasOwn(namespace, keyword)) {
|
|
1587
|
+
return undefined;
|
|
1588
|
+
}
|
|
1589
|
+
const value = namespace[keyword];
|
|
1590
|
+
return isAuthoringPslBlockDescriptor(value) ? value : undefined;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Reads an extension block body generically, driven by the descriptor's
|
|
1595
|
+
* `parameters` map. Each `key = <rhs>` line in the body is matched against
|
|
1596
|
+
* a declared parameter and the RHS is captured per the parameter's kind:
|
|
1597
|
+
*
|
|
1598
|
+
* - `ref` → the bareword identifier token (`PslExtensionBlockParamRef`)
|
|
1599
|
+
* - `value` → the raw RHS text verbatim (`PslExtensionBlockParamScalarValue`)
|
|
1600
|
+
* - `option` → the chosen bareword token (`PslExtensionBlockParamOption`)
|
|
1601
|
+
* - `list` → bracketed `[a, b, …]` list, each element captured per `of`
|
|
1602
|
+
* (`PslExtensionBlockParamList`)
|
|
1603
|
+
*
|
|
1604
|
+
* No validation runs here (unknown key, missing required, codec acceptance,
|
|
1605
|
+
* option-in-set, ref resolution). A body line that is not `key = value`
|
|
1606
|
+
* shaped emits a `PSL_INVALID_EXTENSION_BLOCK_MEMBER` parse diagnostic.
|
|
1607
|
+
*/
|
|
1608
|
+
function parseExtensionBlock(
|
|
1609
|
+
context: ParserContext,
|
|
1610
|
+
descriptor: AuthoringPslBlockDescriptor,
|
|
1611
|
+
blockName: string,
|
|
1612
|
+
keywordLineIndex: number,
|
|
1613
|
+
bounds: BlockBounds,
|
|
1614
|
+
): PslExtensionBlock {
|
|
1615
|
+
const parameters: Record<string, PslExtensionBlockParamValue> = {};
|
|
1616
|
+
|
|
1617
|
+
for (let lineIndex = bounds.startLine + 1; lineIndex < bounds.endLine; lineIndex += 1) {
|
|
1618
|
+
const raw = context.lines[lineIndex] ?? '';
|
|
1619
|
+
const line = stripInlineComment(raw).trim();
|
|
1620
|
+
if (line.length === 0) {
|
|
1621
|
+
continue;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
const assignMatch = line.match(/^([A-Za-z_]\w*)\s*=\s*(.+)$/);
|
|
1625
|
+
if (!assignMatch) {
|
|
1626
|
+
pushDiagnostic(context, {
|
|
1627
|
+
code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
|
|
1628
|
+
message: `Invalid extension block body line "${line}"; expected "key = value"`,
|
|
1629
|
+
span: createTrimmedLineSpan(context, lineIndex),
|
|
1630
|
+
});
|
|
1631
|
+
continue;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
const key = assignMatch[1] ?? '';
|
|
1635
|
+
const rhsRaw = (assignMatch[2] ?? '').trim();
|
|
1636
|
+
const paramDescriptor = descriptor.parameters[key];
|
|
1637
|
+
|
|
1638
|
+
if (paramDescriptor === undefined) {
|
|
1639
|
+
// Unknown parameter — captured as a raw value; the generic validator reports this.
|
|
1640
|
+
parameters[key] = {
|
|
1641
|
+
kind: 'value',
|
|
1642
|
+
raw: rhsRaw,
|
|
1643
|
+
span: createTrimmedLineSpan(context, lineIndex),
|
|
1644
|
+
};
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
const captured = captureParamRhs(context, lineIndex, rhsRaw, paramDescriptor);
|
|
1649
|
+
if (captured !== undefined) {
|
|
1650
|
+
parameters[key] = captured;
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
return {
|
|
1655
|
+
kind: descriptor.discriminator,
|
|
1656
|
+
name: blockName,
|
|
1657
|
+
parameters,
|
|
1658
|
+
span: createLineRangeSpan(context, keywordLineIndex, bounds.endLine),
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* Captures a single parameter RHS string according to the declared parameter
|
|
1664
|
+
* kind. Returns `undefined` and pushes a diagnostic only if the syntax is
|
|
1665
|
+
* genuinely malformed (e.g. a `list` with no opening bracket). Value
|
|
1666
|
+
* acceptance (codec, option-in-set, ref resolution) is handled by the validator.
|
|
1667
|
+
*/
|
|
1668
|
+
function captureParamRhs(
|
|
1669
|
+
context: ParserContext,
|
|
1670
|
+
lineIndex: number,
|
|
1671
|
+
rhs: string,
|
|
1672
|
+
param: AuthoringPslBlockDescriptor['parameters'][string],
|
|
1673
|
+
): PslExtensionBlockParamValue | undefined {
|
|
1674
|
+
const span = createTrimmedLineSpan(context, lineIndex);
|
|
1675
|
+
|
|
1676
|
+
switch (param.kind) {
|
|
1677
|
+
case 'ref': {
|
|
1678
|
+
return { kind: 'ref', identifier: rhs, span };
|
|
1679
|
+
}
|
|
1680
|
+
case 'value': {
|
|
1681
|
+
return { kind: 'value', raw: rhs, span };
|
|
1682
|
+
}
|
|
1683
|
+
case 'option': {
|
|
1684
|
+
return { kind: 'option', token: rhs, span };
|
|
1685
|
+
}
|
|
1686
|
+
case 'list': {
|
|
1687
|
+
if (!rhs.startsWith('[') || !rhs.endsWith(']')) {
|
|
1688
|
+
pushDiagnostic(context, {
|
|
1689
|
+
code: 'PSL_INVALID_EXTENSION_BLOCK_MEMBER',
|
|
1690
|
+
message: `Expected a bracketed list "[…]" for list parameter, got "${rhs}"`,
|
|
1691
|
+
span,
|
|
1692
|
+
});
|
|
1693
|
+
return undefined;
|
|
1694
|
+
}
|
|
1695
|
+
const inner = rhs.slice(1, -1).trim();
|
|
1696
|
+
const items: PslExtensionBlockParamValue[] = [];
|
|
1697
|
+
if (inner.length > 0) {
|
|
1698
|
+
const segments = splitTopLevelSegments(inner, ',');
|
|
1699
|
+
for (const segment of segments) {
|
|
1700
|
+
const itemRhs = segment.value.trim();
|
|
1701
|
+
if (itemRhs.length === 0) {
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1704
|
+
const item = captureParamRhs(context, lineIndex, itemRhs, param.of);
|
|
1705
|
+
if (item !== undefined) {
|
|
1706
|
+
items.push(item);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return { kind: 'list', items, span };
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|