Skip to content

Commit 334eedc

Browse files
committed
feat: allow apidom-ls strict filter
Refs swagger-api/swagger-editor#4216
1 parent 47363af commit 334eedc

File tree

4 files changed

+110
-6
lines changed

4 files changed

+110
-6
lines changed

packages/apidom-ls/src/apidom-language-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ export interface ValidationContext {
277277

278278
export interface CompletionContext {
279279
maxNumberOfItems?: number;
280+
enableLSPFilter?: boolean;
280281
}
281282

282283
export interface DerefContext {

packages/apidom-ls/src/services/completion/completion-service.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export class DefaultCompletionService implements CompletionService {
169169
}
170170

171171
// eslint-disable-next-line class-methods-use-this
172-
private resolveCaretContext(node: Element, offset: number): CaretContext {
172+
private resolveCaretContext(node: Element, offset: number, textModified: boolean): CaretContext {
173173
let caretContext: CaretContext = CaretContext.UNDEFINED;
174174
if (node) {
175175
const sm = getSourceMap(node);
@@ -180,7 +180,11 @@ export class DefaultCompletionService implements CompletionService {
180180
if (offset > sm.offset && offset < sm.endOffset!) {
181181
caretContext = CaretContext.KEY_INNER;
182182
} else if (offset === sm.offset) {
183-
caretContext = CaretContext.KEY_START;
183+
if (sm.length === 0 && textModified) {
184+
caretContext = CaretContext.KEY_END;
185+
} else {
186+
caretContext = CaretContext.KEY_START;
187+
}
184188
} else {
185189
caretContext = CaretContext.KEY_END;
186190
}
@@ -251,6 +255,7 @@ export class DefaultCompletionService implements CompletionService {
251255
): Promise<CompletionList> {
252256
perfStart(PerfLabels.START);
253257
const context = !completionContext ? this.settings?.completionContext : completionContext;
258+
const enableFiltering = context?.enableLSPFilter;
254259
const completionList: CompletionList = {
255260
items: [],
256261
isIncomplete: false,
@@ -543,7 +548,7 @@ export class DefaultCompletionService implements CompletionService {
543548
// only if we have a node
544549
let completionNode: Element | undefined;
545550
if (node) {
546-
const caretContext = this.resolveCaretContext(node, targetOffset);
551+
const caretContext = this.resolveCaretContext(node, targetOffset, textModified);
547552
completionNode = this.resolveCompletionNode(node, caretContext);
548553
const completionNodeContext = this.resolveCompletionNodeContext(caretContext);
549554

@@ -707,7 +712,15 @@ export class DefaultCompletionService implements CompletionService {
707712
} else if (contentLanguage.format === 'YAML') {
708713
// item.insertText = `${item.insertText}\n`;
709714
}
710-
collector.add(item);
715+
if (word && word.length > 0) {
716+
if (enableFiltering && item.insertText?.includes(word)) {
717+
collector.add(item);
718+
} else if (!enableFiltering) {
719+
collector.add(item);
720+
}
721+
} else if (!word) {
722+
collector.add(item);
723+
}
711724
}
712725
} else if (
713726
// in a primitive value node
@@ -781,8 +794,12 @@ export class DefaultCompletionService implements CompletionService {
781794
*/
782795
item.filterText = text.substring(nodeSourceMap.offset, nodeSourceMap.endOffset!);
783796

784-
if (word && word.length > 0 && unquotedOriginalInsertText?.includes(word)) {
785-
collector.add(item);
797+
if (word && word.length > 0) {
798+
if (enableFiltering && unquotedOriginalInsertText?.includes(word)) {
799+
collector.add(item);
800+
} else if (!enableFiltering) {
801+
collector.add(item);
802+
}
786803
} else if (!word) {
787804
collector.add(item);
788805
}

packages/apidom-ls/test/complete.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,4 +1243,84 @@ describe('apidom-ls-complete', function () {
12431243
},
12441244
] as ApidomCompletionItem[]);
12451245
});
1246+
1247+
it('openapi / yaml - test LSP provided filter', async function () {
1248+
const completionContext: CompletionContext = {
1249+
maxNumberOfItems: 100,
1250+
enableLSPFilter: true,
1251+
};
1252+
1253+
const spec = fs
1254+
.readFileSync(path.join(__dirname, 'fixtures', 'openapi-complete-filter.yaml'))
1255+
.toString();
1256+
1257+
const doc: TextDocument = TextDocument.create(
1258+
'foo://bar/penapi-complete-filter.yaml',
1259+
'yaml',
1260+
0,
1261+
spec,
1262+
);
1263+
1264+
const pos = Position.create(4, 8);
1265+
const result = await languageService.doCompletion(
1266+
doc,
1267+
{ textDocument: doc, position: pos },
1268+
completionContext,
1269+
);
1270+
assert.deepEqual(result!.items, [
1271+
{
1272+
label: 'responses',
1273+
insertText: 'responses: \n $1',
1274+
kind: 14,
1275+
insertTextFormat: 2,
1276+
documentation: {
1277+
kind: 'markdown',
1278+
value:
1279+
'[Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responsesObject)\n\\\n\\\nThe list of possible responses as they are returned from executing this operation.',
1280+
},
1281+
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
1282+
filterText: 'se',
1283+
textEdit: {
1284+
range: { start: { line: 4, character: 6 }, end: { line: 4, character: 8 } },
1285+
newText: 'responses: \n $1',
1286+
},
1287+
},
1288+
{
1289+
label: 'security',
1290+
insertText: 'security: \n - $1',
1291+
kind: 14,
1292+
insertTextFormat: 2,
1293+
documentation: {
1294+
kind: 'markdown',
1295+
value:
1296+
'[[Security Requirement Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#serverObject)]\n\\\n\\\nA declaration of which security mechanisms can be used for this operation. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. To make security optional, an empty security requirement (`{}`) can be included in the array. This definition overrides any declared top-level [`security`](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#oasSecurity). To remove a top-level security declaration, an empty array can be used.',
1297+
},
1298+
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
1299+
preselect: true,
1300+
filterText: 'se',
1301+
textEdit: {
1302+
range: { start: { line: 4, character: 6 }, end: { line: 4, character: 8 } },
1303+
newText: 'security: \n - $1',
1304+
},
1305+
},
1306+
{
1307+
label: 'servers',
1308+
insertText: 'servers: \n - $1',
1309+
kind: 14,
1310+
insertTextFormat: 2,
1311+
documentation: {
1312+
kind: 'markdown',
1313+
value:
1314+
'[[Server Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#serverObject)]\n\\\n\\\nAn alternative `server` array to service this operation. If an alternative `server` object is specified at the Path Item Object or Root level, it will be overridden by this value.',
1315+
},
1316+
targetSpecs: [{ namespace: 'openapi', version: '3.1.0' }],
1317+
preselect: true,
1318+
filterText: 'se',
1319+
textEdit: {
1320+
range: { start: { line: 4, character: 6 }, end: { line: 4, character: 8 } },
1321+
newText: 'servers: \n - $1',
1322+
},
1323+
},
1324+
] as ApidomCompletionItem[]);
1325+
});
12461326
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
openapi: 3.1.0
2+
paths:
3+
/pet:
4+
put:
5+
se
6+
summary: Update an existing pet

0 commit comments

Comments
 (0)