diff --git a/.chronus/changes/fixDirectiveParsing-2024-3-16-17-9-37.md b/.chronus/changes/fixDirectiveParsing-2024-3-16-17-9-37.md new file mode 100644 index 0000000000..9afb07bcb5 --- /dev/null +++ b/.chronus/changes/fixDirectiveParsing-2024-3-16-17-9-37.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Fix issue where directives were not parsed to the leaf node in multi-segment Namespace segments. diff --git a/packages/compiler/src/core/parser.ts b/packages/compiler/src/core/parser.ts index 46328c00a0..6bd6ab4205 100644 --- a/packages/compiler/src/core/parser.ts +++ b/packages/compiler/src/core/parser.ts @@ -420,7 +420,7 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa item = parseScalarStatement(pos, decorators); break; case Token.NamespaceKeyword: - item = parseNamespaceStatement(pos, decorators, docs); + item = parseNamespaceStatement(pos, decorators, docs, directives); break; case Token.InterfaceKeyword: item = parseInterfaceStatement(pos, decorators); @@ -461,8 +461,8 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa break; } - mutate(item).directives = directives; if (tok !== Token.NamespaceKeyword) { + mutate(item).directives = directives; mutate(item).docs = docs; } @@ -515,7 +515,7 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa item = parseScalarStatement(pos, decorators); break; case Token.NamespaceKeyword: - const ns = parseNamespaceStatement(pos, decorators, docs); + const ns = parseNamespaceStatement(pos, decorators, docs, directives); if (!Array.isArray(ns.statements)) { error({ code: "blockless-namespace-first", messageId: "topLevel", target: ns }); @@ -595,7 +595,8 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa function parseNamespaceStatement( pos: number, decorators: DecoratorExpressionNode[], - docs: DocNode[] + docs: DocNode[], + directives: DirectiveExpressionNode[] ): NamespaceStatementNode { parseExpected(Token.NamespaceKeyword); let currentName = parseIdentifierOrMemberExpression(); @@ -621,7 +622,7 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa id: nsSegments[0], locals: undefined!, statements, - + directives: directives, ...finishNode(pos), }; @@ -629,6 +630,7 @@ function createParser(code: string | SourceFile, options: ParseOptions = {}): Pa outerNs = { kind: SyntaxKind.NamespaceStatement, decorators: [], + directives: [], id: nsSegments[i], statements: outerNs, locals: undefined!, diff --git a/packages/compiler/test/parser.test.ts b/packages/compiler/test/parser.test.ts index 784064d1e5..6d78183e8a 100644 --- a/packages/compiler/test/parser.test.ts +++ b/packages/compiler/test/parser.test.ts @@ -713,6 +713,26 @@ describe("compiler: parser", () => { { strict: true } ); }); + + describe("ensure directives and decorators are applied to leaf node", () => { + parseEach([ + [ + `@doc("foo")\n#suppress "foo"\nnamespace Foo.Bar {}`, + (node) => { + const fooNs = node.statements[0]; + strictEqual(fooNs.kind, SyntaxKind.NamespaceStatement); + const barNs = (fooNs as any).statements; + strictEqual(barNs.kind, SyntaxKind.NamespaceStatement); + strictEqual(fooNs.id.sv, "Foo"); + strictEqual(barNs.id.sv, "Bar"); + strictEqual(fooNs.directives?.length, 0); + strictEqual(fooNs.decorators.length, 0); + strictEqual(barNs.directives?.length, 1); + strictEqual(barNs.decorators.length, 1); + }, + ], + ]); + }); }); describe("augment decorator statements", () => {