From 27c5dee2d277c4d348ec8a844fb902bb5d5c5814 Mon Sep 17 00:00:00 2001 From: "Zhonglei Ma (WICRESOFT NORTH AMERICA LTD)" Date: Thu, 12 Dec 2024 17:05:24 +0800 Subject: [PATCH 1/5] metadata will prompt after '::', i.e. 'type', 'parameters', 'returnType' --- packages/compiler/src/server/completion.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/compiler/src/server/completion.ts b/packages/compiler/src/server/completion.ts index edf287e765..148a39bd64 100644 --- a/packages/compiler/src/server/completion.ts +++ b/packages/compiler/src/server/completion.ts @@ -404,6 +404,19 @@ function addIdentifierCompletion( { program, completions }: CompletionContext, node: IdentifierNode, ) { + // Process the three keyword hints of the meta properties separately, such as `::type`, `::parameters`, `::returnType` + if (node.parent && "selector" in node.parent && node.parent.selector === "::") { + ["type", "parameters", "returnType"].map((label) => { + const item: CompletionItem = { + label: label, + kind: CompletionItemKind.Field, + documentation: `${label} of meta properties`, + }; + completions.items.push(item); + }); + return; + } + const result = program.checker.resolveCompletions(node); if (result.size === 0) { return; From 7369d0f61f2b14304f7738f3c6b20bb095502774 Mon Sep 17 00:00:00 2001 From: "Zhonglei Ma (WICRESOFT NORTH AMERICA LTD)" Date: Tue, 17 Dec 2024 11:08:18 +0800 Subject: [PATCH 2/5] updated --- packages/compiler/src/core/checker.ts | 14 +++++++++++++- packages/compiler/src/server/completion.ts | 13 ------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/compiler/src/core/checker.ts b/packages/compiler/src/core/checker.ts index 25dbc4efcd..041e5ee214 100644 --- a/packages/compiler/src/core/checker.ts +++ b/packages/compiler/src/core/checker.ts @@ -2932,8 +2932,20 @@ export function createChecker(program: Program, resolver: NameResolver): Checker if (base.flags & SymbolFlags.Alias) { base = getAliasedSymbol(base, undefined); } - if (base) { + if (base && (base.exports || base.members)) { addCompletions(base.exports ?? base.members); + } else 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); + } + } 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 { diff --git a/packages/compiler/src/server/completion.ts b/packages/compiler/src/server/completion.ts index 148a39bd64..edf287e765 100644 --- a/packages/compiler/src/server/completion.ts +++ b/packages/compiler/src/server/completion.ts @@ -404,19 +404,6 @@ function addIdentifierCompletion( { program, completions }: CompletionContext, node: IdentifierNode, ) { - // Process the three keyword hints of the meta properties separately, such as `::type`, `::parameters`, `::returnType` - if (node.parent && "selector" in node.parent && node.parent.selector === "::") { - ["type", "parameters", "returnType"].map((label) => { - const item: CompletionItem = { - label: label, - kind: CompletionItemKind.Field, - documentation: `${label} of meta properties`, - }; - completions.items.push(item); - }); - return; - } - const result = program.checker.resolveCompletions(node); if (result.size === 0) { return; 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 3/5] 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( ` From f71eb301cb96447c46eb1106048181b6537ec92e Mon Sep 17 00:00:00 2001 From: "Zhonglei Ma (WICRESOFT NORTH AMERICA LTD)" Date: Thu, 19 Dec 2024 11:18:42 +0800 Subject: [PATCH 4/5] updated and add a testing --- packages/compiler/src/core/checker.ts | 38 +++++++++---------- .../compiler/test/server/completion.test.ts | 30 +++++++++++++++ 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/packages/compiler/src/core/checker.ts b/packages/compiler/src/core/checker.ts index 8b9ac64683..9f8967b663 100644 --- a/packages/compiler/src/core/checker.ts +++ b/packages/compiler/src/core/checker.ts @@ -2929,27 +2929,27 @@ 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 (identifier.parent.selector === "::") { - if (base?.node === undefined && base?.declarations) { - // Process meta properties separately, such as `::parameters`, `::returnType` - 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); + if (base) { + if (base.flags & SymbolFlags.Alias) { + base = getAliasedSymbol(base, undefined); } - } else { + if (base) { - if (base.flags & SymbolFlags.Alias) { - base = getAliasedSymbol(base, undefined); - } - if (base) { + if (identifier.parent.selector === "::") { + if (base?.node === undefined && base?.declarations && base.declarations.length > 0) { + // Process meta properties separately, such as `::parameters`, `::returnType` + const nodeModels = base?.declarations[0]; + 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 { addCompletions(base.exports ?? base.members); } } diff --git a/packages/compiler/test/server/completion.test.ts b/packages/compiler/test/server/completion.test.ts index 91d4f8c8b8..0efecc6bb5 100644 --- a/packages/compiler/test/server/completion.test.ts +++ b/packages/compiler/test/server/completion.test.ts @@ -510,6 +510,36 @@ describe("identifiers", () => { }); it("completes meta property '::parameters' and '::returnType' on operation", async () => { + const completions = await complete( + ` + op base(one: string): void; + @@doc(base::par┆, "Override"); + `, + ); + + check(completions, [ + { + label: "parameters", + insertText: "parameters", + kind: CompletionItemKind.Method, + documentation: { + kind: MarkupKind.Markdown, + value: "```typespec\nop base(one: string): void\n```", + }, + }, + { + label: "returnType", + insertText: "returnType", + kind: CompletionItemKind.Method, + documentation: { + kind: MarkupKind.Markdown, + value: "```typespec\nop base(one: string): void\n```", + }, + }, + ]); + }); + + it("completes meta property '::parameters' and '::returnType' using alias on operation", async () => { const completions = await complete( ` op a(@doc("base doc") one: string): void; From cb4a53204a36369091ee3d8e496a47d617f6512f Mon Sep 17 00:00:00 2001 From: Zhonglei Ma Date: Thu, 19 Dec 2024 14:10:12 +0800 Subject: [PATCH 5/5] Create meta-property-autocomplete-2024-11-19-3-21-6.md --- .../meta-property-autocomplete-2024-11-19-3-21-6.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/meta-property-autocomplete-2024-11-19-3-21-6.md diff --git a/.chronus/changes/meta-property-autocomplete-2024-11-19-3-21-6.md b/.chronus/changes/meta-property-autocomplete-2024-11-19-3-21-6.md new file mode 100644 index 0000000000..11a344cd37 --- /dev/null +++ b/.chronus/changes/meta-property-autocomplete-2024-11-19-3-21-6.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/compiler" +--- + +Meta property are auto-completed, current only supported '::type', '::parameters', '::returnType'