From f87e06b1aba359354ff3b2a6cecada2bd6841a12 Mon Sep 17 00:00:00 2001 From: "Zhonglei Ma (WICRESOFT NORTH AMERICA LTD)" Date: Wed, 18 Dec 2024 11:01:37 +0800 Subject: [PATCH] updated and add testing --- packages/compiler/src/core/checker.ts | 30 +++++---- .../compiler/test/server/completion.test.ts | 61 +++++++++++++++++++ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/packages/compiler/src/core/checker.ts b/packages/compiler/src/core/checker.ts index 041e5ee214..8b9ac64683 100644 --- a/packages/compiler/src/core/checker.ts +++ b/packages/compiler/src/core/checker.ts @@ -2928,25 +2928,31 @@ export function createChecker(program: Program, resolver: NameResolver): Checker } } else if (identifier.parent && identifier.parent.kind === SyntaxKind.MemberExpression) { let base = resolver.getNodeLinks(identifier.parent.base).resolvedSymbol; - if (base) { - if (base.flags & SymbolFlags.Alias) { - base = getAliasedSymbol(base, undefined); - } - if (base && (base.exports || base.members)) { - addCompletions(base.exports ?? base.members); - } else if (base?.node === undefined && base?.declarations) { + + if (identifier.parent.selector === "::") { + if (base?.node === undefined && base?.declarations) { // Process meta properties separately, such as `::parameters`, `::returnType` - const [nodeModels] = Object.values(base?.declarations); - if (nodeModels.kind === SyntaxKind.OperationStatement) { - const operation = nodeModels as OperationStatementNode; - addCompletion("parameters", operation.symbol); - addCompletion("returnType", operation.symbol); + for (const nodeModels of Object.values(base?.declarations)) { + if (nodeModels.kind === SyntaxKind.OperationStatement) { + const operation = nodeModels as OperationStatementNode; + addCompletion("parameters", operation.symbol); + addCompletion("returnType", operation.symbol); + } } } else if (base?.node?.kind === SyntaxKind.ModelProperty) { // Process meta properties separately, such as `::type` const metaProperty = base.node as ModelPropertyNode; addCompletion("type", metaProperty.symbol); } + } else { + if (base) { + if (base.flags & SymbolFlags.Alias) { + base = getAliasedSymbol(base, undefined); + } + if (base) { + addCompletions(base.exports ?? base.members); + } + } } } else { // We will only add template arguments if the template isn't already named diff --git a/packages/compiler/test/server/completion.test.ts b/packages/compiler/test/server/completion.test.ts index a14847876a..91d4f8c8b8 100644 --- a/packages/compiler/test/server/completion.test.ts +++ b/packages/compiler/test/server/completion.test.ts @@ -479,6 +479,67 @@ describe("identifiers", () => { ]); }); + it("completes meta property '::type' on model property", async () => { + const completions = await complete( + ` + model A{ + name: string; + } + + model B{ + a: A; + } + + model C { + ...B.a::┆; + } + `, + ); + + check(completions, [ + { + label: "type", + insertText: "type", + kind: CompletionItemKind.Field, + documentation: { + kind: MarkupKind.Markdown, + value: "(model property)\n```typespec\nB.a: A\n```", + }, + }, + ]); + }); + + it("completes meta property '::parameters' and '::returnType' on operation", async () => { + const completions = await complete( + ` + op a(@doc("base doc") one: string): void; + op b is a; + @@doc(b::par┆, "override for b"); + `, + ); + + check(completions, [ + { + label: "parameters", + insertText: "parameters", + kind: CompletionItemKind.Method, + documentation: { + kind: MarkupKind.Markdown, + value: "```typespec\nop b(one: string): void\n```", + }, + }, + { + label: "returnType", + insertText: "returnType", + kind: CompletionItemKind.Method, + documentation: { + kind: MarkupKind.Markdown, + value: "```typespec\nop b(one: string): void\n```", + }, + }, + ]); + }); + it("completes partial identifiers", async () => { const completions = await complete( `