monaco-yql-languages 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import type { CancellationToken, Position, editor, languages } from './fillers/m
2
2
  export type CompletionListProvider = {
3
3
  (content: string, offset: number, signal?: AbortSignal | null): Promise<string[]>;
4
4
  };
5
- export declare function provideCompletionItems(getCompletionList: CompletionListProvider): (model: editor.ITextModel, position: Position, context: languages.CompletionContext, token: CancellationToken) => languages.ProviderResult<languages.CompletionList>;
5
+ export declare function provideCompletionItems(getCompletionList: CompletionListProvider, preserveOrder?: boolean): (model: editor.ITextModel, position: Position, context: languages.CompletionContext, token: CancellationToken) => languages.ProviderResult<languages.CompletionList>;
6
6
  export type CompletionLists = Partial<Record<`${Uncapitalize<keyof typeof languages.CompletionItemKind>}List`, Readonly<string[]>>>;
7
7
  export declare function getCompletionItemsProvider(completions: CompletionLists, completionItemKind: typeof languages.CompletionItemKind): {
8
8
  provideCompletionItems(model: editor.ITextModel, position: Position, _context: languages.CompletionContext, _token: CancellationToken): languages.CompletionList | undefined;
@@ -1,5 +1,6 @@
1
+ import { suggestionIndexToWeight } from './utils';
1
2
  const allUpperCaseRe = new RegExp('^[$A-Z_\\s]+$');
2
- export function provideCompletionItems(getCompletionList) {
3
+ export function provideCompletionItems(getCompletionList, preserveOrder) {
3
4
  return (model, position, context, token) => {
4
5
  const controller = new AbortController();
5
6
  const signal = controller.signal;
@@ -49,7 +50,12 @@ export function provideCompletionItems(getCompletionList) {
49
50
  range,
50
51
  });
51
52
  }
52
- return { suggestions, incomplete: suggestions.length > 0 };
53
+ return {
54
+ suggestions: preserveOrder
55
+ ? suggestions.map((item, index) => (Object.assign(Object.assign({}, item), { sortText: suggestionIndexToWeight(index) })))
56
+ : suggestions,
57
+ incomplete: suggestions.length > 0,
58
+ };
53
59
  });
54
60
  };
55
61
  }
@@ -0,0 +1 @@
1
+ export declare function suggestionIndexToWeight(index: number): string;
package/build/utils.js ADDED
@@ -0,0 +1,11 @@
1
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz';
2
+ export function suggestionIndexToWeight(index) {
3
+ const characterInsideAlphabet = alphabet[index];
4
+ if (characterInsideAlphabet) {
5
+ return characterInsideAlphabet;
6
+ }
7
+ const duplicateTimes = Math.floor(index / alphabet.length);
8
+ const remains = index % alphabet.length;
9
+ const lastCharacter = alphabet.slice(-1);
10
+ return lastCharacter.repeat(duplicateTimes) + alphabet[remains];
11
+ }
@@ -0,0 +1,307 @@
1
+ import { generateColumnsSuggestion, generateEntitiesSuggestion } from '../generateSuggestions';
2
+ jest.mock('../../../fillers/monaco-editor-core', () => ({
3
+ languages: {
4
+ CompletionItemKind: {
5
+ Variable: 1,
6
+ },
7
+ CompletionItemInsertTextRule: {
8
+ None: 0,
9
+ InsertAsSnippet: 1,
10
+ },
11
+ },
12
+ IRange: {
13
+ startLineNumber: 1,
14
+ startColumn: 1,
15
+ endLineNumber: 1,
16
+ endColumn: 1,
17
+ },
18
+ }));
19
+ jest.mock('../utils', () => ({
20
+ suggestionIndexToWeight: (_index) => '0',
21
+ removeStringDuplicates: (value) => value !== null && value !== void 0 ? value : [],
22
+ isVariable: (_value) => false,
23
+ removeBackticks: (value) => value,
24
+ wrapStringToBackticks: (value) => value,
25
+ getSuggestionIndex: (_value) => 0,
26
+ }));
27
+ const mockRange = {
28
+ startLineNumber: 1,
29
+ startColumn: 1,
30
+ endLineNumber: 1,
31
+ endColumn: 1,
32
+ };
33
+ describe('generateColumnsSuggestion', () => {
34
+ it('should return an empty array if suggestColumns is undefined', async () => {
35
+ expect(await generateColumnsSuggestion(mockRange, undefined, [], [])).toEqual([]);
36
+ expect(await generateColumnsSuggestion(mockRange, { tables: [] }, [], [])).toEqual([]);
37
+ });
38
+ it('should generate suggestions for a single table with columns', async () => {
39
+ const result = await generateColumnsSuggestion(mockRange, {
40
+ tables: [{ name: 'table1', columns: ['col1', 'col2'] }],
41
+ }, [], []);
42
+ expect(result).toEqual([
43
+ {
44
+ label: { label: 'col1', description: undefined },
45
+ insertText: 'col1',
46
+ kind: 1,
47
+ detail: 'Column',
48
+ range: mockRange,
49
+ sortText: 'aa',
50
+ },
51
+ {
52
+ label: { label: 'col2', description: undefined },
53
+ insertText: 'col2',
54
+ kind: 1,
55
+ detail: 'Column',
56
+ range: mockRange,
57
+ sortText: 'ab',
58
+ },
59
+ ]);
60
+ });
61
+ it('should generate suggestions for multiple tables with columns', async () => {
62
+ const result = await generateColumnsSuggestion(mockRange, {
63
+ tables: [
64
+ { name: 'table1', columns: ['col1'] },
65
+ { name: 'table2', columns: ['col2'] },
66
+ ],
67
+ }, [], []);
68
+ expect(result).toEqual([
69
+ {
70
+ label: { label: 'table1.col1', description: undefined },
71
+ insertText: 'table1.col1',
72
+ kind: 1,
73
+ detail: 'Column',
74
+ range: mockRange,
75
+ sortText: 'aa',
76
+ },
77
+ {
78
+ label: { label: 'table2.col2', description: undefined },
79
+ insertText: 'table2.col2',
80
+ kind: 1,
81
+ detail: 'Column',
82
+ range: mockRange,
83
+ sortText: 'ab',
84
+ },
85
+ ]);
86
+ });
87
+ it('should generate suggestions for tables with aliases', async () => {
88
+ const result = await generateColumnsSuggestion(mockRange, {
89
+ tables: [{ name: 'table1', columns: ['col1'], alias: 't1' }],
90
+ }, [], []);
91
+ expect(result).toEqual([
92
+ {
93
+ label: { label: 't1.col1', description: undefined },
94
+ insertText: 't1.col1',
95
+ kind: 1,
96
+ detail: 'Column',
97
+ range: mockRange,
98
+ sortText: 'aa',
99
+ },
100
+ ]);
101
+ });
102
+ it('should handle variables as table sources', async () => {
103
+ const result = await generateColumnsSuggestion(mockRange, {
104
+ tables: [{ name: '$var1', columns: ['col1'] }],
105
+ all: false,
106
+ }, [{ name: 'var1', value: { columns: ['col1'] } }], []);
107
+ expect(result).toEqual([
108
+ {
109
+ label: { label: 'col1', description: undefined },
110
+ insertText: 'col1',
111
+ kind: 1,
112
+ detail: 'Column',
113
+ range: mockRange,
114
+ sortText: 'aa',
115
+ },
116
+ ]);
117
+ });
118
+ it('should generate all columns suggestion when multiple tables are present', async () => {
119
+ const result = await generateColumnsSuggestion(mockRange, {
120
+ tables: [
121
+ { name: 'table1', columns: ['col1'] },
122
+ { name: 'table2', columns: ['col2'] },
123
+ ],
124
+ all: true,
125
+ }, [], []);
126
+ expect(result).toEqual([
127
+ {
128
+ label: { label: 'table1.col1', description: undefined },
129
+ insertText: 'table1.col1',
130
+ kind: 1,
131
+ detail: 'Column',
132
+ range: mockRange,
133
+ sortText: 'aa',
134
+ },
135
+ {
136
+ label: { label: 'table2.col2', description: undefined },
137
+ insertText: 'table2.col2',
138
+ kind: 1,
139
+ detail: 'Column',
140
+ range: mockRange,
141
+ sortText: 'ab',
142
+ },
143
+ {
144
+ label: 'table1.col1, table2.col2',
145
+ insertText: 'table1.col1, table2.col2',
146
+ kind: 1,
147
+ range: mockRange,
148
+ sortText: 'a',
149
+ },
150
+ ]);
151
+ });
152
+ it('should handle fetched columns', async () => {
153
+ const fetchedColumns = [
154
+ { name: 'col3', parent: 'table1', detail: 'detail3' },
155
+ ];
156
+ const result = await generateColumnsSuggestion(mockRange, {
157
+ tables: [{ name: 'table1', columns: ['col1'] }],
158
+ }, [], fetchedColumns);
159
+ expect(result).toEqual([
160
+ {
161
+ label: { label: 'col3', description: 'detail3' },
162
+ insertText: 'col3',
163
+ kind: 1,
164
+ detail: 'Column',
165
+ range: mockRange,
166
+ sortText: 'aa',
167
+ },
168
+ {
169
+ label: { label: 'col1', description: undefined },
170
+ insertText: 'col1',
171
+ kind: 1,
172
+ detail: 'Column',
173
+ range: mockRange,
174
+ sortText: 'ab',
175
+ },
176
+ ]);
177
+ });
178
+ it('should handle empty tables', async () => {
179
+ const result = await generateColumnsSuggestion(mockRange, {
180
+ tables: [{ name: 'table1', columns: [] }],
181
+ }, [], []);
182
+ expect(result).toEqual([]);
183
+ });
184
+ });
185
+ describe('generateEntitiesSuggestion', () => {
186
+ it('should return an empty array if there are no entities', async () => {
187
+ const result = await generateEntitiesSuggestion(mockRange, []);
188
+ expect(result).toEqual([]);
189
+ });
190
+ it('should generate suggestions for multiple entities', async () => {
191
+ const entities = [
192
+ { value: 'entity1', isDir: false },
193
+ { value: 'entity2', isDir: true },
194
+ ];
195
+ const suggestions = await generateEntitiesSuggestion(mockRange, entities, 'ent');
196
+ expect(suggestions).toEqual([
197
+ {
198
+ label: 'entity1',
199
+ insertText: 'entity1',
200
+ kind: undefined,
201
+ insertTextRules: 0,
202
+ detail: undefined,
203
+ range: {
204
+ startLineNumber: 1,
205
+ startColumn: 1,
206
+ endLineNumber: 1,
207
+ endColumn: 1,
208
+ },
209
+ command: undefined,
210
+ sortText: 'aa',
211
+ },
212
+ {
213
+ label: 'entity2/',
214
+ insertText: '`entity2/$0`',
215
+ kind: undefined,
216
+ insertTextRules: 1,
217
+ detail: undefined,
218
+ range: {
219
+ startLineNumber: 1,
220
+ startColumn: 1,
221
+ endLineNumber: 1,
222
+ endColumn: 1,
223
+ },
224
+ command: { id: 'editor.action.triggerSuggest', title: '' },
225
+ sortText: 'ab',
226
+ },
227
+ ]);
228
+ });
229
+ it('should generate suggestions with prefix with backtick', async () => {
230
+ const entities = [
231
+ { value: 'entity1', isDir: false },
232
+ { value: 'entity2', isDir: true },
233
+ ];
234
+ const suggestions = await generateEntitiesSuggestion(mockRange, entities, '`ent');
235
+ expect(suggestions).toEqual([
236
+ {
237
+ label: 'entity1',
238
+ insertText: 'entity1',
239
+ kind: undefined,
240
+ insertTextRules: 0,
241
+ detail: undefined,
242
+ range: {
243
+ startLineNumber: 1,
244
+ startColumn: 1,
245
+ endLineNumber: 1,
246
+ endColumn: 1,
247
+ },
248
+ command: undefined,
249
+ sortText: 'aa',
250
+ },
251
+ {
252
+ label: 'entity2/',
253
+ insertText: 'entity2/',
254
+ kind: undefined,
255
+ insertTextRules: 0,
256
+ detail: undefined,
257
+ range: {
258
+ startLineNumber: 1,
259
+ startColumn: 1,
260
+ endLineNumber: 1,
261
+ endColumn: 1,
262
+ },
263
+ command: { id: 'editor.action.triggerSuggest', title: '' },
264
+ sortText: 'ab',
265
+ },
266
+ ]);
267
+ });
268
+ it('should handle entities with descriptions', async () => {
269
+ const entities = [
270
+ { value: 'entity1', detail: 'description1', isDir: true },
271
+ { value: 'entity2', isDir: false },
272
+ ];
273
+ const suggestions = await generateEntitiesSuggestion(mockRange, entities);
274
+ expect(suggestions).toEqual([
275
+ {
276
+ label: 'entity1/',
277
+ insertText: '`entity1/$0`',
278
+ kind: undefined,
279
+ insertTextRules: 1,
280
+ detail: 'description1',
281
+ range: {
282
+ startLineNumber: 1,
283
+ startColumn: 1,
284
+ endLineNumber: 1,
285
+ endColumn: 1,
286
+ },
287
+ command: { id: 'editor.action.triggerSuggest', title: '' },
288
+ sortText: 'aa',
289
+ },
290
+ {
291
+ label: 'entity2',
292
+ insertText: 'entity2',
293
+ kind: undefined,
294
+ insertTextRules: 0,
295
+ detail: undefined,
296
+ range: {
297
+ startLineNumber: 1,
298
+ startColumn: 1,
299
+ endLineNumber: 1,
300
+ endColumn: 1,
301
+ },
302
+ command: undefined,
303
+ sortText: 'ab',
304
+ },
305
+ ]);
306
+ });
307
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ import { suggestionIndexToWeight } from '../../../utils';
2
+ import { wrapStringToBackticks } from '../utils';
3
+ describe('wrapStringToBackticks', () => {
4
+ it('should return the same string if it already starts and ends with backticks', () => {
5
+ expect(wrapStringToBackticks('`test`')).toBe('`test`');
6
+ });
7
+ it('should wrap the string with backticks if it contains special symbols', () => {
8
+ expect(wrapStringToBackticks("test'")).toBe("`test'`");
9
+ expect(wrapStringToBackticks('test "')).toBe('`test "`');
10
+ expect(wrapStringToBackticks('test-')).toBe('`test-`');
11
+ expect(wrapStringToBackticks('test@')).toBe('`test@`');
12
+ expect(wrapStringToBackticks('test/')).toBe('`test/`');
13
+ expect(wrapStringToBackticks('test\' " - / @')).toBe('`test\' " - / @`');
14
+ });
15
+ it('should not wrap the string with backticks if it is empty', () => {
16
+ expect(wrapStringToBackticks('')).toBe('');
17
+ });
18
+ it('should not wrap the string with backticks if it does not contain special symbols', () => {
19
+ expect(wrapStringToBackticks('test1234')).toBe('test1234');
20
+ });
21
+ it('should handle strings with only special symbols', () => {
22
+ expect(wrapStringToBackticks("'")).toBe("`'`");
23
+ expect(wrapStringToBackticks('-')).toBe('`-`');
24
+ expect(wrapStringToBackticks('@')).toBe('`@`');
25
+ expect(wrapStringToBackticks('/')).toBe('`/`');
26
+ });
27
+ it('should handle strings with leading and trailing spaces', () => {
28
+ expect(wrapStringToBackticks(' test ')).toBe('` test `');
29
+ });
30
+ it('should handle strings with only spaces', () => {
31
+ expect(wrapStringToBackticks(' ')).toBe('` `');
32
+ });
33
+ });
34
+ describe('suggestionIndexToWeight', () => {
35
+ it('should return a single character for indices within the alphabet', () => {
36
+ expect(suggestionIndexToWeight(0)).toBe('a');
37
+ expect(suggestionIndexToWeight(25)).toBe('z');
38
+ });
39
+ it('should handle indices beyond the alphabet length', () => {
40
+ expect(suggestionIndexToWeight(26)).toBe('za');
41
+ expect(suggestionIndexToWeight(51)).toBe('zz');
42
+ expect(suggestionIndexToWeight(78)).toBe('zzza');
43
+ });
44
+ it('should correctly handle edge cases', () => {
45
+ expect(suggestionIndexToWeight(0)).toBe('a');
46
+ expect(suggestionIndexToWeight(25)).toBe('z');
47
+ expect(suggestionIndexToWeight(26)).toBe('za');
48
+ expect(suggestionIndexToWeight(51)).toBe('zz');
49
+ expect(suggestionIndexToWeight(700)).toBe('zzzzzzzzzzzzzzzzzzzzzzzzzzy');
50
+ });
51
+ });
@@ -0,0 +1,38 @@
1
+ import type { ColumnAliasSuggestion, KeywordSuggestion, VariableSuggestion } from '@gravity-ui/websql-autocomplete/shared';
2
+ import type { YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete/yql';
3
+ import * as monaco from '../../fillers/monaco-editor-core';
4
+ import type { FetchedColumn, FetchedEntity } from './types';
5
+ export declare function generateSimpleTypesSuggestion(rangeToInsertSuggestion: monaco.IRange, simpleTypes?: string[]): Promise<monaco.languages.CompletionItem[]>;
6
+ export declare function generateEntitiesSuggestion(rangeToInsertSuggestion: monaco.IRange, fetchedEntities: FetchedEntity[], prefix?: string): Promise<monaco.languages.CompletionItem[]>;
7
+ export declare function generateKeywordsSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestKeywords?: KeywordSuggestion[]): {
8
+ label: string;
9
+ insertText: string;
10
+ kind: monaco.languages.CompletionItemKind;
11
+ detail: string;
12
+ range: monaco.IRange;
13
+ sortText: string;
14
+ }[];
15
+ export declare function generateVariableSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestVariables?: VariableSuggestion[]): {
16
+ label: string;
17
+ insertText: string;
18
+ kind: monaco.languages.CompletionItemKind;
19
+ detail: string;
20
+ range: monaco.IRange;
21
+ sortText: string;
22
+ }[];
23
+ export declare function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange, functions?: string[]): Promise<monaco.languages.CompletionItem[]>;
24
+ export declare function generateAggregateFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange, aggreagteFunctions?: string[]): Promise<monaco.languages.CompletionItem[]>;
25
+ export declare function generateWindowFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange, windowFunctions?: string[]): Promise<monaco.languages.CompletionItem[]>;
26
+ export declare function generateTableFunctionsSuggestion(rangeToInsertSuggestion: monaco.IRange, tableFunctions?: string[]): Promise<monaco.languages.CompletionItem[]>;
27
+ export declare function generateUdfSuggestion(rangeToInsertSuggestion: monaco.IRange, udfs?: string[]): Promise<monaco.languages.CompletionItem[]>;
28
+ export declare function generatePragmasSuggestion(rangeToInsertSuggestion: monaco.IRange, pragmas?: string[]): Promise<monaco.languages.CompletionItem[]>;
29
+ export declare function generateEntitySettingsSuggestion(rangeToInsertSuggestion: monaco.IRange, entitySettings?: string[]): Promise<monaco.languages.CompletionItem[]>;
30
+ export declare function generateColumnAliasesSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumnAliases?: ColumnAliasSuggestion[]): {
31
+ label: string;
32
+ insertText: string;
33
+ kind: monaco.languages.CompletionItemKind;
34
+ detail: string;
35
+ range: monaco.IRange;
36
+ sortText: string;
37
+ }[];
38
+ export declare function generateColumnsSuggestion(rangeToInsertSuggestion: monaco.IRange, suggestColumns: YqlAutocompleteResult['suggestColumns'], suggestVariables: YqlAutocompleteResult['suggestVariables'], fetchedColumns: FetchedColumn[]): Promise<monaco.languages.CompletionItem[]>;
@@ -0,0 +1,241 @@
1
+ import * as monaco from '../../fillers/monaco-editor-core';
2
+ import { getSuggestionIndex, isVariable, removeBackticks, removeStringDuplicates, wrapStringToBackticks, } from './utils';
3
+ import { suggestionIndexToWeight } from '../../utils';
4
+ export async function generateSimpleTypesSuggestion(rangeToInsertSuggestion, simpleTypes = []) {
5
+ return simpleTypes.map((el) => ({
6
+ label: el,
7
+ insertText: el,
8
+ kind: monaco.languages.CompletionItemKind.TypeParameter,
9
+ detail: 'Type',
10
+ range: rangeToInsertSuggestion,
11
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestSimpleTypes')),
12
+ }));
13
+ }
14
+ export async function generateEntitiesSuggestion(rangeToInsertSuggestion, fetchedEntities, prefix = '') {
15
+ const withBackticks = prefix === null || prefix === void 0 ? void 0 : prefix.startsWith('`');
16
+ return fetchedEntities.reduce((acc, { value, detail, isDir }) => {
17
+ const label = isDir ? `${value}/` : value;
18
+ let labelAsSnippet;
19
+ if (isDir && !withBackticks) {
20
+ labelAsSnippet = `\`${label}$0\``;
21
+ }
22
+ const suggestionIndex = acc.length;
23
+ acc.push({
24
+ label,
25
+ insertText: labelAsSnippet !== null && labelAsSnippet !== void 0 ? labelAsSnippet : label,
26
+ kind: isDir
27
+ ? monaco.languages.CompletionItemKind.Folder
28
+ : monaco.languages.CompletionItemKind.Text,
29
+ insertTextRules: labelAsSnippet
30
+ ? monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
31
+ : monaco.languages.CompletionItemInsertTextRule.None,
32
+ detail: detail,
33
+ range: rangeToInsertSuggestion,
34
+ command: label.endsWith('/')
35
+ ? { id: 'editor.action.triggerSuggest', title: '' }
36
+ : undefined,
37
+ // first argument is responsible for sorting groups of suggestions, the second - to preserve suggestions order returned from backend
38
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestEntity')) +
39
+ suggestionIndexToWeight(suggestionIndex),
40
+ });
41
+ return acc;
42
+ }, []);
43
+ }
44
+ export function generateKeywordsSuggestion(rangeToInsertSuggestion, suggestKeywords = []) {
45
+ return suggestKeywords.map((keywordSuggestion) => ({
46
+ label: keywordSuggestion.value,
47
+ insertText: keywordSuggestion.value,
48
+ kind: monaco.languages.CompletionItemKind.Keyword,
49
+ detail: 'Keyword',
50
+ range: rangeToInsertSuggestion,
51
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestKeywords')),
52
+ }));
53
+ }
54
+ export function generateVariableSuggestion(rangeToInsertSuggestion, suggestVariables = []) {
55
+ return suggestVariables.map(({ name }) => {
56
+ const variable = '$' + name;
57
+ return {
58
+ label: variable,
59
+ insertText: variable,
60
+ kind: monaco.languages.CompletionItemKind.Variable,
61
+ detail: 'Variable',
62
+ range: rangeToInsertSuggestion,
63
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestVariables')),
64
+ };
65
+ });
66
+ }
67
+ export async function generateSimpleFunctionsSuggestion(rangeToInsertSuggestion, functions = []) {
68
+ return functions.map((el) => ({
69
+ label: el,
70
+ insertText: el,
71
+ kind: monaco.languages.CompletionItemKind.Function,
72
+ detail: 'Function',
73
+ range: rangeToInsertSuggestion,
74
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestFunctions')),
75
+ }));
76
+ }
77
+ export async function generateAggregateFunctionsSuggestion(rangeToInsertSuggestion, aggreagteFunctions = []) {
78
+ return aggreagteFunctions.map((el) => ({
79
+ label: el,
80
+ insertText: el,
81
+ kind: monaco.languages.CompletionItemKind.Function,
82
+ detail: 'Aggregate function',
83
+ range: rangeToInsertSuggestion,
84
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestAggregateFunctions')),
85
+ }));
86
+ }
87
+ export async function generateWindowFunctionsSuggestion(rangeToInsertSuggestion, windowFunctions = []) {
88
+ return windowFunctions.map((el) => ({
89
+ label: el,
90
+ insertText: el,
91
+ kind: monaco.languages.CompletionItemKind.Function,
92
+ detail: 'Window function',
93
+ range: rangeToInsertSuggestion,
94
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestWindowFunctions')),
95
+ }));
96
+ }
97
+ export async function generateTableFunctionsSuggestion(rangeToInsertSuggestion, tableFunctions = []) {
98
+ return tableFunctions.map((el) => ({
99
+ label: el,
100
+ insertText: el,
101
+ kind: monaco.languages.CompletionItemKind.Function,
102
+ detail: 'Table function',
103
+ range: rangeToInsertSuggestion,
104
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestTableFunctions')),
105
+ }));
106
+ }
107
+ export async function generateUdfSuggestion(rangeToInsertSuggestion, udfs = []) {
108
+ return udfs.map((el) => ({
109
+ label: el,
110
+ insertText: el,
111
+ kind: monaco.languages.CompletionItemKind.Function,
112
+ detail: 'UDF',
113
+ range: rangeToInsertSuggestion,
114
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestUdfs')),
115
+ }));
116
+ }
117
+ export async function generatePragmasSuggestion(rangeToInsertSuggestion, pragmas = []) {
118
+ return pragmas.map((el) => ({
119
+ label: el,
120
+ insertText: el,
121
+ kind: monaco.languages.CompletionItemKind.Module,
122
+ detail: 'Pragma',
123
+ range: rangeToInsertSuggestion,
124
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestPragmas')),
125
+ }));
126
+ }
127
+ export async function generateEntitySettingsSuggestion(rangeToInsertSuggestion, entitySettings = []) {
128
+ return entitySettings.map((el) => ({
129
+ label: el,
130
+ insertText: el,
131
+ kind: monaco.languages.CompletionItemKind.Property,
132
+ detail: 'Setting',
133
+ range: rangeToInsertSuggestion,
134
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestEntitySettings')),
135
+ }));
136
+ }
137
+ export function generateColumnAliasesSuggestion(rangeToInsertSuggestion, suggestColumnAliases = []) {
138
+ return suggestColumnAliases.map((columnAliasSuggestion) => ({
139
+ label: columnAliasSuggestion.name,
140
+ insertText: columnAliasSuggestion.name,
141
+ kind: monaco.languages.CompletionItemKind.Variable,
142
+ detail: 'Column alias',
143
+ range: rangeToInsertSuggestion,
144
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumnAliases')),
145
+ }));
146
+ }
147
+ export async function generateColumnsSuggestion(rangeToInsertSuggestion, suggestColumns, suggestVariables, fetchedColumns) {
148
+ var _a;
149
+ if (!(suggestColumns === null || suggestColumns === void 0 ? void 0 : suggestColumns.tables)) {
150
+ return [];
151
+ }
152
+ const suggestions = [];
153
+ const allColumnsSuggestion = suggestColumns.all ? [] : undefined;
154
+ const multi = suggestColumns.tables.length > 1;
155
+ const tableNames = suggestColumns.tables.map((entity) => entity.name);
156
+ const filteredTableNames = removeStringDuplicates(tableNames);
157
+ const variableSources = filteredTableNames.filter(isVariable);
158
+ const columnsFromVariable = [];
159
+ if (variableSources.length) {
160
+ variableSources.forEach((source) => {
161
+ var _a, _b, _c, _d;
162
+ const newColumns = (_d = (_c = (_b = (_a = suggestVariables === null || suggestVariables === void 0 ? void 0 : suggestVariables
163
+ // Variable name from suggestions doesn't include $ sign
164
+ .find((variable) => source.slice(1) === variable.name)) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.columns) === null || _c === void 0 ? void 0 : _c.map((col) => ({
165
+ name: col,
166
+ parent: source,
167
+ }))) !== null && _d !== void 0 ? _d : [];
168
+ columnsFromVariable.push(...newColumns);
169
+ });
170
+ }
171
+ const predefinedColumns = suggestColumns.tables.reduce((acc, entity) => {
172
+ const columns = entity.columns;
173
+ if (columns) {
174
+ acc.push(...columns.map((col) => ({
175
+ name: col,
176
+ parent: entity.name,
177
+ })));
178
+ }
179
+ return acc;
180
+ }, []);
181
+ const tableNameToAliasMap = (_a = suggestColumns.tables) === null || _a === void 0 ? void 0 : _a.reduce((acc, entity) => {
182
+ var _a;
183
+ const name = removeBackticks(entity.name);
184
+ const aliases = (_a = acc[name]) !== null && _a !== void 0 ? _a : [];
185
+ if (entity.alias) {
186
+ aliases.push(entity.alias);
187
+ }
188
+ acc[name] = aliases;
189
+ return acc;
190
+ }, {});
191
+ [...fetchedColumns, ...columnsFromVariable, ...predefinedColumns].forEach((col) => {
192
+ const normalizedName = wrapStringToBackticks(col.name);
193
+ const aliases = tableNameToAliasMap[removeBackticks(col.parent)];
194
+ const currentSuggestionIndex = suggestions.length;
195
+ if (aliases === null || aliases === void 0 ? void 0 : aliases.length) {
196
+ aliases.forEach((a) => {
197
+ const columnNameSuggestion = `${a}.${normalizedName}`;
198
+ suggestions.push({
199
+ label: { label: columnNameSuggestion, description: col.detail },
200
+ insertText: columnNameSuggestion,
201
+ kind: monaco.languages.CompletionItemKind.Variable,
202
+ detail: 'Column',
203
+ range: rangeToInsertSuggestion,
204
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')) +
205
+ suggestionIndexToWeight(currentSuggestionIndex),
206
+ });
207
+ allColumnsSuggestion === null || allColumnsSuggestion === void 0 ? void 0 : allColumnsSuggestion.push(columnNameSuggestion);
208
+ });
209
+ }
210
+ else {
211
+ let columnNameSuggestion = normalizedName;
212
+ if (multi) {
213
+ columnNameSuggestion = `${wrapStringToBackticks(col.parent)}.${normalizedName}`;
214
+ }
215
+ suggestions.push({
216
+ label: {
217
+ label: columnNameSuggestion,
218
+ description: col.detail,
219
+ },
220
+ insertText: columnNameSuggestion,
221
+ kind: monaco.languages.CompletionItemKind.Variable,
222
+ detail: 'Column',
223
+ range: rangeToInsertSuggestion,
224
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestColumns')) +
225
+ suggestionIndexToWeight(currentSuggestionIndex),
226
+ });
227
+ allColumnsSuggestion === null || allColumnsSuggestion === void 0 ? void 0 : allColumnsSuggestion.push(columnNameSuggestion);
228
+ }
229
+ });
230
+ if (allColumnsSuggestion && allColumnsSuggestion.length > 1) {
231
+ const allColumns = allColumnsSuggestion.join(', ');
232
+ suggestions.push({
233
+ label: allColumns,
234
+ insertText: allColumns,
235
+ kind: monaco.languages.CompletionItemKind.Variable,
236
+ range: rangeToInsertSuggestion,
237
+ sortText: suggestionIndexToWeight(getSuggestionIndex('suggestAllColumns')),
238
+ });
239
+ }
240
+ return suggestions;
241
+ }
@@ -0,0 +1,3 @@
1
+ export { type YQLAutocompleteConfig } from './yqlAutocomplete';
2
+ export * from './types';
3
+ export { registerCompletionItemProvider } from './registerProvider';
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export { registerCompletionItemProvider } from './registerProvider';
@@ -0,0 +1,2 @@
1
+ import type { YQLAutocompleteConfig } from './yqlAutocomplete';
2
+ export declare function registerCompletionItemProvider(langId: string, triggerCharacters: string[], config: YQLAutocompleteConfig): void;
@@ -0,0 +1,17 @@
1
+ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
2
+ import { getSuggestionsGetter } from './yqlAutocomplete';
3
+ const completionProvider = new Map();
4
+ function disableCodeSuggestions(langId) {
5
+ const provider = completionProvider.get(langId);
6
+ if (provider) {
7
+ provider.dispose();
8
+ }
9
+ }
10
+ export function registerCompletionItemProvider(langId, triggerCharacters, config) {
11
+ disableCodeSuggestions(langId);
12
+ const provider = monaco.languages.registerCompletionItemProvider(langId, {
13
+ triggerCharacters: triggerCharacters,
14
+ provideCompletionItems: getSuggestionsGetter(config),
15
+ });
16
+ completionProvider.set(langId, provider);
17
+ }
@@ -0,0 +1,16 @@
1
+ import type { YQLEntity } from '@gravity-ui/websql-autocomplete/yql';
2
+ export type CursorPosition = {
3
+ lineNumber: number;
4
+ column: number;
5
+ };
6
+ export type AutocompleteEntityType = YQLEntity | 'directory';
7
+ export type FetchedEntity = {
8
+ value: string;
9
+ isDir: boolean;
10
+ detail?: string;
11
+ };
12
+ export type FetchedColumn = {
13
+ name: string;
14
+ detail?: string;
15
+ parent: string;
16
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { YqlAutocompleteResult } from '@gravity-ui/websql-autocomplete/yql';
2
+ type SuggestionType = keyof Omit<YqlAutocompleteResult, 'errors' | 'suggestDatabases'> | 'suggestAllColumns';
3
+ export declare function getSuggestionIndex(suggestionType: SuggestionType): number;
4
+ export declare function isVariable(value: string): boolean;
5
+ export declare function removeStringDuplicates(value?: string[]): string[];
6
+ export declare function getEntitiesToFetchColumns(suggestColumns: YqlAutocompleteResult['suggestColumns']): string[];
7
+ export declare function wrapStringToBackticks(value: string): string;
8
+ export declare function removeBackticks(value: string): string;
9
+ export {};
@@ -0,0 +1,57 @@
1
+ const SuggestionsWeight = {
2
+ suggestTemplates: 0,
3
+ suggestPragmas: 1,
4
+ suggestEntity: 2,
5
+ suggestAllColumns: 3,
6
+ suggestColumns: 4,
7
+ suggestColumnAliases: 5,
8
+ suggestVariables: 6,
9
+ suggestTableIndexes: 7,
10
+ suggestTableHints: 8,
11
+ suggestEntitySettings: 9,
12
+ suggestKeywords: 10,
13
+ suggestAggregateFunctions: 11,
14
+ suggestTableFunctions: 12,
15
+ suggestWindowFunctions: 13,
16
+ suggestFunctions: 14,
17
+ suggestSimpleTypes: 15,
18
+ suggestUdfs: 16,
19
+ };
20
+ export function getSuggestionIndex(suggestionType) {
21
+ return SuggestionsWeight[suggestionType];
22
+ }
23
+ export function isVariable(value) {
24
+ return value.startsWith('$');
25
+ }
26
+ export function removeStringDuplicates(value = []) {
27
+ return Array.from(new Set(value));
28
+ }
29
+ export function getEntitiesToFetchColumns(suggestColumns) {
30
+ var _a;
31
+ const names = (_a = suggestColumns === null || suggestColumns === void 0 ? void 0 : suggestColumns.tables) === null || _a === void 0 ? void 0 : _a.map((entity) => entity.name);
32
+ // remove duplicates if any
33
+ const filteredTableNames = removeStringDuplicates(names);
34
+ return filteredTableNames.filter((name) => !isVariable(name));
35
+ }
36
+ const specialSymbols = /[\s'"-/@]/;
37
+ export function wrapStringToBackticks(value) {
38
+ if (value.startsWith('`') && value.endsWith('`')) {
39
+ return value;
40
+ }
41
+ let result = value;
42
+ if (value.match(specialSymbols)) {
43
+ result = `\`${value}\``;
44
+ }
45
+ return result;
46
+ }
47
+ export function removeBackticks(value) {
48
+ let sliceStart = 0;
49
+ let sliceEnd = value.length;
50
+ if (value.startsWith('`')) {
51
+ sliceStart = 1;
52
+ }
53
+ if (value.endsWith('`')) {
54
+ sliceEnd = -1;
55
+ }
56
+ return value.slice(sliceStart, sliceEnd);
57
+ }
@@ -0,0 +1,51 @@
1
+ import type { YQLEntity } from '@gravity-ui/websql-autocomplete/yql';
2
+ import type Monaco from 'monaco-editor';
3
+ import type { FetchedColumn, FetchedEntity } from './types';
4
+ export type YQLAutocompleteConfig = {
5
+ getQueryParser?: YQLAutocomplete['getQueryParser'];
6
+ getUdfs?: YQLAutocomplete['getUdfs'];
7
+ getSimpleTypes?: YQLAutocomplete['getSimpleTypes'];
8
+ getPragmas?: YQLAutocomplete['getPragmas'];
9
+ getWindowFunctions?: YQLAutocomplete['getWindowFunctions'];
10
+ getTableFunctions?: YQLAutocomplete['getTableFunctions'];
11
+ getAggregateFunctions?: YQLAutocomplete['getAggregateFunctions'];
12
+ getSimpleFunctions?: YQLAutocomplete['getSimpleFunctions'];
13
+ getEntitySettings?: YQLAutocomplete['getEntitySettings'];
14
+ fetchEntities?: YQLAutocomplete['fetchEntities'];
15
+ fetchEntityColumns?: YQLAutocomplete['fetchEntityColumns'];
16
+ };
17
+ export declare class YQLAutocomplete {
18
+ constructor({ getQueryParser, getUdfs, getSimpleTypes, getPragmas, getWindowFunctions, getTableFunctions, getAggregateFunctions, getSimpleFunctions, getEntitySettings, fetchEntities, fetchEntityColumns, }: YQLAutocompleteConfig);
19
+ getSuggestions(input: string, offset: number): Promise<Monaco.languages.CompletionItem[]>;
20
+ parseInput(input: string, offset: number): Promise<import("@gravity-ui/websql-autocomplete/yql").YqlAutocompleteResult>;
21
+ getQueryParser(): Promise<typeof import("@gravity-ui/websql-autocomplete/yql").parseYqlQuery>;
22
+ getSimpleTypes(_prefix?: string): Promise<string[]>;
23
+ getUdfs(_prefix?: string): Promise<string[]>;
24
+ getPragmas(_prefix?: string): Promise<string[]>;
25
+ getWindowFunctions(_prefix?: string): Promise<string[]>;
26
+ getTableFunctions(_prefix?: string): Promise<string[]>;
27
+ getAggregateFunctions(_prefix?: string): Promise<string[]>;
28
+ getSimpleFunctions(_prefix?: string): Promise<string[]>;
29
+ /**
30
+ * Fetches entity settings based on provided entity type.
31
+ * @param entityType
32
+ * @returns A promise that resolves to an array of entity settings.
33
+ */
34
+ getEntitySettings(_entityType: YQLEntity): Promise<string[]>;
35
+ /**
36
+ * Fetches entities based on the provided prefix and needed entity types.
37
+ * @param prefix - The prefix to filter entities.
38
+ * @param neededEntityTypes - An array of entity types to fetch.
39
+ * @returns A promise that resolves to an array of fetched entities.
40
+ */
41
+ fetchEntities(_prefix: string, _neededEntityTypes: YQLEntity[]): Promise<FetchedEntity[]>;
42
+ /**
43
+ * Fetches columns for the specified entities.
44
+ * @param entityNames - An array of entity names to fetch columns for.
45
+ * @returns A promise that resolves to an array of fetched columns.
46
+ */
47
+ fetchEntityColumns(_entityNames: string[]): Promise<FetchedColumn[]>;
48
+ }
49
+ export declare function getSuggestionsGetter(config?: YQLAutocompleteConfig): (model: Monaco.editor.ITextModel, monacoCursorPosition: Monaco.Position, _context: Monaco.languages.CompletionContext, _token: Monaco.CancellationToken) => Promise<{
50
+ suggestions: Monaco.languages.CompletionItem[];
51
+ }>;
@@ -0,0 +1,211 @@
1
+ import { generateAggregateFunctionsSuggestion, generateColumnAliasesSuggestion, generateColumnsSuggestion, generateEntitiesSuggestion, generateEntitySettingsSuggestion, generateKeywordsSuggestion, generatePragmasSuggestion, generateSimpleFunctionsSuggestion, generateSimpleTypesSuggestion, generateTableFunctionsSuggestion, generateUdfSuggestion, generateVariableSuggestion, generateWindowFunctionsSuggestion, } from './generateSuggestions';
2
+ import { getEntitiesToFetchColumns } from './utils';
3
+ function getCursorPosition(input, offset) {
4
+ const lines = input.slice(0, offset).split('\n');
5
+ // parser suggest to get cursor position where lineNumber and column starts from 1
6
+ return {
7
+ lineNumber: lines.length,
8
+ column: lines[lines.length - 1].length + 1,
9
+ };
10
+ }
11
+ const prefixRegexp = /([^\s]+)$/;
12
+ function getCursorPrefix(input, offset, re = prefixRegexp) {
13
+ const prevText = input.slice(0, offset);
14
+ const match = prevText.match(re);
15
+ if (match && match[1]) {
16
+ return match[1];
17
+ }
18
+ return '';
19
+ }
20
+ const prefixToReplaceRegexp = /([^\\/\s`]+)$/;
21
+ function getRangeToInsertSuggestion(input, offset) {
22
+ const cursorPosition = getCursorPosition(input, offset);
23
+ const cursorPrefix = getCursorPrefix(input, offset, prefixToReplaceRegexp);
24
+ return {
25
+ startColumn: cursorPosition.column - cursorPrefix.length,
26
+ startLineNumber: cursorPosition.lineNumber,
27
+ endColumn: cursorPosition.column,
28
+ endLineNumber: cursorPosition.lineNumber,
29
+ };
30
+ }
31
+ export class YQLAutocomplete {
32
+ constructor({ getQueryParser, getUdfs, getSimpleTypes, getPragmas, getWindowFunctions, getTableFunctions, getAggregateFunctions, getSimpleFunctions, getEntitySettings, fetchEntities, fetchEntityColumns, }) {
33
+ if (getQueryParser) {
34
+ this.getQueryParser = getQueryParser;
35
+ }
36
+ if (getUdfs) {
37
+ this.getUdfs = getUdfs;
38
+ }
39
+ if (getSimpleTypes) {
40
+ this.getSimpleTypes = getSimpleTypes;
41
+ }
42
+ if (getPragmas) {
43
+ this.getPragmas = getPragmas;
44
+ }
45
+ if (getWindowFunctions) {
46
+ this.getWindowFunctions = getWindowFunctions;
47
+ }
48
+ if (getTableFunctions) {
49
+ this.getTableFunctions = getTableFunctions;
50
+ }
51
+ if (getAggregateFunctions) {
52
+ this.getAggregateFunctions = getAggregateFunctions;
53
+ }
54
+ if (getSimpleFunctions) {
55
+ this.getSimpleFunctions = getSimpleFunctions;
56
+ }
57
+ if (getEntitySettings) {
58
+ this.getEntitySettings = getEntitySettings;
59
+ }
60
+ if (fetchEntities) {
61
+ this.fetchEntities = fetchEntities;
62
+ }
63
+ if (fetchEntityColumns) {
64
+ this.fetchEntityColumns = fetchEntityColumns;
65
+ }
66
+ }
67
+ async getSuggestions(input, offset) {
68
+ const parseResult = await this.parseInput(input, offset);
69
+ let entitiesSuggestions = [];
70
+ let functionsSuggestions = [];
71
+ let aggregateFunctionsSuggestions = [];
72
+ let windowFunctionsSuggestions = [];
73
+ let tableFunctionsSuggestions = [];
74
+ let udfsSuggestions = [];
75
+ let simpleTypesSuggestions = [];
76
+ let pragmasSuggestions = [];
77
+ let entitySettingsSuggestions = [];
78
+ let columnsSuggestions = [];
79
+ let variableSuggestions = [];
80
+ const rangeToInsertSuggestion = getRangeToInsertSuggestion(input, offset);
81
+ const cursorPrefix = getCursorPrefix(input, offset);
82
+ if (parseResult.suggestSimpleTypes) {
83
+ const simpleTypes = await this.getSimpleTypes(cursorPrefix);
84
+ simpleTypesSuggestions = await generateSimpleTypesSuggestion(rangeToInsertSuggestion, simpleTypes);
85
+ }
86
+ if (parseResult.suggestEntity) {
87
+ const fetchedEntities = await this.fetchEntities(cursorPrefix, parseResult.suggestEntity);
88
+ entitiesSuggestions = await generateEntitiesSuggestion(rangeToInsertSuggestion, fetchedEntities, cursorPrefix);
89
+ }
90
+ if (parseResult.suggestVariables) {
91
+ variableSuggestions = generateVariableSuggestion(rangeToInsertSuggestion, parseResult.suggestVariables);
92
+ }
93
+ if (parseResult.suggestFunctions) {
94
+ const simpleFunctions = await this.getSimpleFunctions(cursorPrefix);
95
+ functionsSuggestions = await generateSimpleFunctionsSuggestion(rangeToInsertSuggestion, simpleFunctions);
96
+ }
97
+ if (parseResult.suggestAggregateFunctions) {
98
+ const aggregateFunctions = await this.getAggregateFunctions(cursorPrefix);
99
+ aggregateFunctionsSuggestions = await generateAggregateFunctionsSuggestion(rangeToInsertSuggestion, aggregateFunctions);
100
+ }
101
+ if (parseResult.suggestWindowFunctions) {
102
+ const windowFunctions = await this.getWindowFunctions(cursorPrefix);
103
+ windowFunctionsSuggestions = await generateWindowFunctionsSuggestion(rangeToInsertSuggestion, windowFunctions);
104
+ }
105
+ if (parseResult.suggestTableFunctions) {
106
+ const tableFunctions = await this.getTableFunctions(cursorPrefix);
107
+ tableFunctionsSuggestions = await generateTableFunctionsSuggestion(rangeToInsertSuggestion, tableFunctions);
108
+ }
109
+ if (parseResult.suggestUdfs) {
110
+ const udfs = await this.getUdfs(cursorPrefix);
111
+ udfsSuggestions = await generateUdfSuggestion(rangeToInsertSuggestion, udfs);
112
+ }
113
+ if (parseResult.suggestPragmas) {
114
+ const pragmas = await this.getPragmas(cursorPrefix);
115
+ pragmasSuggestions = await generatePragmasSuggestion(rangeToInsertSuggestion, pragmas);
116
+ }
117
+ if (parseResult.suggestEntitySettings) {
118
+ const entitySettings = await this.getEntitySettings(parseResult.suggestEntitySettings);
119
+ entitySettingsSuggestions = await generateEntitySettingsSuggestion(rangeToInsertSuggestion, entitySettings);
120
+ }
121
+ const keywordsSuggestions = generateKeywordsSuggestion(rangeToInsertSuggestion, parseResult.suggestKeywords);
122
+ const columnAliasSuggestion = await generateColumnAliasesSuggestion(rangeToInsertSuggestion, parseResult.suggestColumnAliases);
123
+ if (parseResult.suggestColumns) {
124
+ const entities = getEntitiesToFetchColumns(parseResult.suggestColumns);
125
+ const fetchedColumns = await this.fetchEntityColumns(entities);
126
+ columnsSuggestions = await generateColumnsSuggestion(rangeToInsertSuggestion, parseResult.suggestColumns, parseResult.suggestVariables, fetchedColumns);
127
+ }
128
+ const suggestions = [
129
+ ...entitiesSuggestions,
130
+ ...functionsSuggestions,
131
+ ...windowFunctionsSuggestions,
132
+ ...tableFunctionsSuggestions,
133
+ ...udfsSuggestions,
134
+ ...simpleTypesSuggestions,
135
+ ...pragmasSuggestions,
136
+ ...columnAliasSuggestion,
137
+ ...columnsSuggestions,
138
+ ...keywordsSuggestions,
139
+ ...aggregateFunctionsSuggestions,
140
+ ...entitySettingsSuggestions,
141
+ ...variableSuggestions,
142
+ ];
143
+ return suggestions;
144
+ }
145
+ async parseInput(input, offset) {
146
+ const cursorPosition = getCursorPosition(input, offset);
147
+ const parseQuery = await this.getQueryParser();
148
+ const cursorForParsing = {
149
+ line: cursorPosition.lineNumber,
150
+ column: cursorPosition.column,
151
+ };
152
+ return parseQuery(input, cursorForParsing);
153
+ }
154
+ async getQueryParser() {
155
+ const { parseYqlQuery: parseQuery } = await import('@gravity-ui/websql-autocomplete/yql');
156
+ return parseQuery;
157
+ }
158
+ async getSimpleTypes(_prefix) {
159
+ return [];
160
+ }
161
+ async getUdfs(_prefix) {
162
+ return [];
163
+ }
164
+ async getPragmas(_prefix) {
165
+ return [];
166
+ }
167
+ async getWindowFunctions(_prefix) {
168
+ return [];
169
+ }
170
+ async getTableFunctions(_prefix) {
171
+ return [];
172
+ }
173
+ async getAggregateFunctions(_prefix) {
174
+ return [];
175
+ }
176
+ async getSimpleFunctions(_prefix) {
177
+ return [];
178
+ }
179
+ /**
180
+ * Fetches entity settings based on provided entity type.
181
+ * @param entityType
182
+ * @returns A promise that resolves to an array of entity settings.
183
+ */
184
+ async getEntitySettings(_entityType) {
185
+ return [];
186
+ }
187
+ /**
188
+ * Fetches entities based on the provided prefix and needed entity types.
189
+ * @param prefix - The prefix to filter entities.
190
+ * @param neededEntityTypes - An array of entity types to fetch.
191
+ * @returns A promise that resolves to an array of fetched entities.
192
+ */
193
+ async fetchEntities(_prefix, _neededEntityTypes) {
194
+ return [];
195
+ }
196
+ /**
197
+ * Fetches columns for the specified entities.
198
+ * @param entityNames - An array of entity names to fetch columns for.
199
+ * @returns A promise that resolves to an array of fetched columns.
200
+ */
201
+ async fetchEntityColumns(_entityNames) {
202
+ return [];
203
+ }
204
+ }
205
+ export function getSuggestionsGetter(config = {}) {
206
+ const autocompleteInstance = new YQLAutocomplete(config);
207
+ return async (model, monacoCursorPosition, _context, _token) => {
208
+ const suggestions = await autocompleteInstance.getSuggestions(model.getValue(), model.getOffsetAt(monacoCursorPosition));
209
+ return { suggestions };
210
+ };
211
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monaco-yql-languages",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "YQL languages for the Monaco Editor, based on monaco-languages.",
5
5
  "author": "YDB",
6
6
  "license": "MIT",
@@ -20,25 +20,33 @@
20
20
  "prettier": "prettier \"**/*.{md,yaml,yml}\"",
21
21
  "typecheck": "tsc --noEmit",
22
22
  "prepublishOnly": "npm run lint && npm run build",
23
- "test": "echo \"Error: no test specified\" && exit 0"
23
+ "test": "jest"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
27
27
  "url": "git+ssh://git@github.com/ydb-platform/monaco-yql-languages.git"
28
28
  },
29
29
  "devDependencies": {
30
- "@gravity-ui/eslint-config": "^3.1.1",
30
+ "@commitlint/config-conventional": "^19.7.1",
31
+ "@gravity-ui/eslint-config": "^3.3.0",
31
32
  "@gravity-ui/prettier-config": "^1.1.0",
32
33
  "@gravity-ui/stylelint-config": "^4.0.1",
33
34
  "@gravity-ui/tsconfig": "^1.0.0",
34
- "eslint": "^8.10.0",
35
- "husky": "^9.0.11",
36
- "monaco-editor": "^0.32.1",
37
- "prettier": "^3.2.5",
35
+ "@gravity-ui/websql-autocomplete": "^13.7.0",
36
+ "@jest/types": "^29.6.3",
37
+ "@types/jest": "^29.5.14",
38
+ "eslint": "^8.57.1",
39
+ "husky": "^9.1.7",
40
+ "jest": "^29.7.0",
41
+ "monaco-editor": "^0.52.2",
42
+ "prettier": "^3.4.2",
38
43
  "rimraf": "^3.0.2",
39
- "typescript": "^5.4.2"
44
+ "ts-jest": "^29.2.5",
45
+ "ts-node": "^10.9.2",
46
+ "typescript": "^5.7.3"
40
47
  },
41
48
  "peerDependencies": {
49
+ "@gravity-ui/websql-autocomplete": "^13.7.0",
42
50
  "monaco-editor": ">=0.27.0"
43
51
  },
44
52
  "nano-staged": {