Skip to content

Commit ffcc6f8

Browse files
kapral18cursoragent
andcommitted
Fix Console method suggestion order
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 9d7d161 commit ffcc6f8

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,24 @@ describe('Editor actions provider', () => {
200200
]);
201201
});
202202

203+
it('orders method suggestions with GET first and DELETE last using sortText', async () => {
204+
// Monaco sorts completion items by sortText, falling back to label. Without
205+
// an explicit sortText, alphabetical sorting puts DELETE first (#259251).
206+
mockGetParsedRequests.mockResolvedValue([]);
207+
const completionItems = await editorActionsProvider.provideCompletionItems(
208+
mockModel,
209+
mockPosition,
210+
mockContext
211+
);
212+
const sortedByMonaco = [...(completionItems?.suggestions ?? [])].sort((a, b) =>
213+
String(a.sortText ?? a.label).localeCompare(String(b.sortText ?? b.label))
214+
);
215+
const orderedLabels = sortedByMonaco.map((s) => s.label);
216+
expect(orderedLabels[0]).toBe('GET');
217+
expect(orderedLabels[orderedLabels.length - 1]).toBe('DELETE');
218+
expect(orderedLabels).toEqual(['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE']);
219+
});
220+
203221
it('returns completion items for url path if method already typed in', async () => {
204222
// mock a parsed request that only has a method
205223
mockGetParsedRequests.mockResolvedValue([

src/platform/plugins/shared/console/public/application/containers/editor/utils/autocomplete_utils.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,27 @@ const filterTermsWithoutName = (terms: ResultTerm[]): ResultTerm[] =>
6060
terms.filter((term) => term.name !== undefined && term.name !== '');
6161

6262
/*
63-
* This function returns an array of completion items for the request method
63+
* This function returns an array of completion items for the request method.
64+
*
65+
* The order is deliberate: Monaco sorts completion items by `sortText` and
66+
* falls back to alphabetical label sorting, which would otherwise put DELETE
67+
* first (#259251). GET is the safest verb to accept by default and DELETE
68+
* the most destructive, so we pin GET first and DELETE last.
6469
*/
65-
const autocompleteMethods = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'PATCH'];
70+
const autocompleteMethods = ['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE'];
6671
export const getMethodCompletionItems = (
6772
model: monaco.editor.ITextModel,
6873
position: monaco.Position
6974
): monaco.languages.CompletionItem[] => {
7075
// get the word before suggestions to replace when selecting a suggestion from the list
7176
const wordUntilPosition = model.getWordUntilPosition(position);
72-
return autocompleteMethods.map((method) => ({
77+
return autocompleteMethods.map((method, index) => ({
7378
label: method,
7479
insertText: method,
7580
detail: i18nTexts.method,
7681
// only used to configure the icon
7782
kind: monaco.languages.CompletionItemKind.Constant,
83+
sortText: String(index),
7884
range: {
7985
// replace the whole word with the suggestion
8086
startColumn: wordUntilPosition.startColumn,

0 commit comments

Comments
 (0)