22 * CST utilities for extracting metadata from Concrete Syntax Tree nodes
33 */
44
5- import type { AstNode } from "langium" ;
5+ import type { AstNode , LeafCstNode } from "langium" ;
66
77/**
8- * Extract description from comments preceding an AST node
8+ * Extract description from comments preceding an AST node.
9+ * Stops at a blank line between comment blocks.
910 */
1011export function extractDescription ( node : AstNode ) : string | undefined {
1112 const cstNode = node . $cstNode ;
@@ -16,24 +17,35 @@ export function extractDescription(node: AstNode): string | undefined {
1617 const currentIndex = children . indexOf ( cstNode ) ;
1718 const comments : string [ ] = [ ] ;
1819
19- // Look at previous siblings only at the immediate level
20- let foundNonWhitespace = false ;
20+ // nextCommentLine tracks the start line of the most recently collected
21+ // comment (the one closest to the node). We use it to detect blank lines
22+ // between comment groups: if the gap between two adjacent SL_COMMENTs is
23+ // more than 1 line, there is a blank line between them and we stop.
24+ let nextCommentLine : number | undefined ;
25+
2126 for ( let i = currentIndex - 1 ; i >= 0 ; i -- ) {
22- const sibling = children [ i ] ;
23- if ( sibling . tokenType ?. name === "SL_COMMENT" ) {
24- const commentText = sibling . text . replace ( / ^ \/ \/ \s * / , "" ) . trim ( ) ;
27+ const sibling = children [ i ] as LeafCstNode | { tokenType : undefined } ;
28+ if ( ! ( "tokenType" in sibling ) || sibling . tokenType === undefined ) {
29+ // Composite node (another declaration) — stop
30+ break ;
31+ }
32+ if ( sibling . tokenType . name === "SL_COMMENT" ) {
33+ const leaf = sibling as LeafCstNode ;
34+ // If there is a blank line between this comment and the next one
35+ // we already collected, stop before including this comment.
36+ if (
37+ nextCommentLine !== undefined &&
38+ nextCommentLine - leaf . range . end . line > 1
39+ ) {
40+ break ;
41+ }
42+ const commentText = leaf . text . replace ( / ^ \/ \/ \s * / , "" ) . trim ( ) ;
2543 if ( commentText ) {
2644 comments . unshift ( commentText ) ;
2745 }
28- foundNonWhitespace = true ;
29- } else if ( sibling . tokenType ?. name === "WS" ) {
30- const newlineCount = ( sibling . text . match ( / \n / g) || [ ] ) . length ;
31- if ( newlineCount > 1 && foundNonWhitespace ) {
32- break ;
33- }
34- } else {
35- break ;
46+ nextCommentLine = leaf . range . start . line ;
3647 }
48+ // WS tokens are not present in container.content, so no else branch needed
3749 }
3850
3951 return comments . length > 0 ? comments . join ( "\n" ) : undefined ;
0 commit comments