diff --git a/packages/langium/src/parser/langium-parser.ts b/packages/langium/src/parser/langium-parser.ts index 2eb66ce97..ba630176e 100644 --- a/packages/langium/src/parser/langium-parser.ts +++ b/packages/langium/src/parser/langium-parser.ts @@ -342,6 +342,7 @@ export class LangiumParser extends AbstractLangiumParser { let last = this.current; if (action.feature && action.operator) { last = this.construct(); + this.nodeBuilder.removeNode(last.$cstNode); const node = this.nodeBuilder.buildCompositeNode(action); node.content.push(last.$cstNode); const newItem = { $type }; diff --git a/packages/langium/test/parser/langium-parser-builder.test.ts b/packages/langium/test/parser/langium-parser-builder.test.ts index c501ec70d..5ebd679bb 100644 --- a/packages/langium/test/parser/langium-parser-builder.test.ts +++ b/packages/langium/test/parser/langium-parser-builder.test.ts @@ -6,7 +6,7 @@ import type { TokenType, TokenVocabulary } from 'chevrotain'; import type { AstNode, CstNode, GenericAstNode, Grammar, GrammarAST, LangiumParser, ParseResult, TokenBuilderOptions } from 'langium'; -import { EmptyFileSystem, DefaultTokenBuilder, GrammarUtils } from 'langium'; +import { EmptyFileSystem, DefaultTokenBuilder, GrammarUtils, CstUtils } from 'langium'; import { describe, expect, test, onTestFailed, beforeAll } from 'vitest'; import { createLangiumGrammarServices, createServicesForGrammar } from 'langium/grammar'; import { expandToString } from 'langium/generate'; @@ -926,6 +926,21 @@ describe('Unassigned subrules', () => { }); +describe('Handling hidden nodes', () => { + test('Should find comment node of element affected by an assigned action', async () => { + const grammar = createLangiumGrammarServices(EmptyFileSystem); + const parser = parseHelper(grammar.grammar); + const doc = await parser("Test returns string: /** comment 1 */ 'A' | /** comment 2 */ 'B' | /** comment 3 */ 'C';"); + expect(doc).toBeDefined(); + const value = doc.parseResult.value as Grammar; + const ruleDef = value.rules[0].definition as GrammarAST.Alternatives; + const a = ruleDef.elements[0]; + const commentNode = CstUtils.findCommentNode(a.$cstNode, ['ML_COMMENT']); + expect(commentNode).toBeDefined(); + expect(commentNode!.text).toBe('/** comment 1 */'); + }); +}); + describe('Handling EOF', () => { test('Use EOF as last part of the entry rule definition', async () => { const grammar = `