dt-sql-parser 4.1.2-beta.0 → 4.2.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.
Files changed (87) hide show
  1. package/README.md +51 -0
  2. package/dist/lib/flink/FlinkSqlLexer.d.ts +5 -5
  3. package/dist/lib/flink/FlinkSqlLexer.js +1991 -1992
  4. package/dist/lib/flink/FlinkSqlParser.d.ts +240 -230
  5. package/dist/lib/flink/FlinkSqlParser.js +3036 -2978
  6. package/dist/lib/flink/FlinkSqlParserListener.d.ts +81 -70
  7. package/dist/lib/flink/FlinkSqlParserVisitor.d.ts +49 -42
  8. package/dist/lib/hive/HiveSqlParser.d.ts +251 -231
  9. package/dist/lib/hive/HiveSqlParser.js +6264 -5674
  10. package/dist/lib/hive/HiveSqlParserListener.d.ts +32 -10
  11. package/dist/lib/hive/HiveSqlParserVisitor.d.ts +20 -6
  12. package/dist/lib/impala/ImpalaSqlLexer.d.ts +2 -2
  13. package/dist/lib/impala/ImpalaSqlLexer.js +587 -588
  14. package/dist/lib/impala/ImpalaSqlParser.d.ts +151 -113
  15. package/dist/lib/impala/ImpalaSqlParser.js +3464 -3250
  16. package/dist/lib/impala/ImpalaSqlParserListener.d.ts +49 -5
  17. package/dist/lib/impala/ImpalaSqlParserVisitor.d.ts +31 -3
  18. package/dist/lib/mysql/MySqlLexer.d.ts +2 -2
  19. package/dist/lib/mysql/MySqlLexer.js +3515 -3516
  20. package/dist/lib/mysql/MySqlParser.d.ts +138 -138
  21. package/dist/lib/mysql/MySqlParser.js +511 -511
  22. package/dist/lib/mysql/MySqlParserListener.d.ts +105 -105
  23. package/dist/lib/mysql/MySqlParserVisitor.d.ts +63 -63
  24. package/dist/lib/postgresql/PostgreSqlLexer.d.ts +14 -15
  25. package/dist/lib/postgresql/PostgreSqlLexer.js +2077 -2092
  26. package/dist/lib/postgresql/PostgreSqlParser.d.ts +2860 -2980
  27. package/dist/lib/postgresql/PostgreSqlParser.js +20155 -20660
  28. package/dist/lib/postgresql/PostgreSqlParserListener.d.ts +2110 -2181
  29. package/dist/lib/postgresql/PostgreSqlParserVisitor.d.ts +1261 -1301
  30. package/dist/lib/spark/SparkSqlLexer.d.ts +2 -2
  31. package/dist/lib/spark/SparkSqlLexer.js +949 -950
  32. package/dist/lib/spark/SparkSqlParser.d.ts +413 -645
  33. package/dist/lib/spark/SparkSqlParser.js +6840 -8200
  34. package/dist/lib/spark/SparkSqlParserListener.d.ts +68 -356
  35. package/dist/lib/spark/SparkSqlParserVisitor.d.ts +42 -225
  36. package/dist/lib/trino/TrinoSqlLexer.d.ts +2 -2
  37. package/dist/lib/trino/TrinoSqlLexer.js +319 -321
  38. package/dist/lib/trino/TrinoSqlListener.d.ts +67 -23
  39. package/dist/lib/trino/TrinoSqlParser.d.ts +210 -181
  40. package/dist/lib/trino/TrinoSqlParser.js +4854 -4695
  41. package/dist/lib/trino/TrinoSqlVisitor.d.ts +42 -14
  42. package/dist/parser/common/basicSQL.d.ts +43 -9
  43. package/dist/parser/common/basicSQL.js +147 -40
  44. package/dist/parser/common/semanticContextCollector.d.ts +50 -0
  45. package/dist/parser/common/semanticContextCollector.js +202 -0
  46. package/dist/parser/common/tokenUtils.d.ts +12 -0
  47. package/dist/parser/common/tokenUtils.js +38 -0
  48. package/dist/parser/common/types.d.ts +25 -0
  49. package/dist/parser/common/types.js +7 -0
  50. package/dist/parser/flink/flinkErrorListener.js +14 -2
  51. package/dist/parser/flink/flinkSemanticContextCollector.d.ts +9 -0
  52. package/dist/parser/flink/flinkSemanticContextCollector.js +14 -0
  53. package/dist/parser/flink/index.d.ts +4 -2
  54. package/dist/parser/flink/index.js +22 -14
  55. package/dist/parser/hive/hiveErrorListener.js +9 -3
  56. package/dist/parser/hive/hiveSemanticContextCollector.d.ts +9 -0
  57. package/dist/parser/hive/hiveSemanticContextCollector.js +14 -0
  58. package/dist/parser/hive/index.d.ts +4 -2
  59. package/dist/parser/hive/index.js +29 -14
  60. package/dist/parser/impala/ImpalaErrorListener.js +8 -2
  61. package/dist/parser/impala/impalaSemanticContextCollector.d.ts +9 -0
  62. package/dist/parser/impala/impalaSemanticContextCollector.js +14 -0
  63. package/dist/parser/impala/index.d.ts +4 -2
  64. package/dist/parser/impala/index.js +21 -14
  65. package/dist/parser/mysql/index.d.ts +4 -2
  66. package/dist/parser/mysql/index.js +10 -14
  67. package/dist/parser/mysql/mysqlErrorListener.js +6 -2
  68. package/dist/parser/mysql/mysqlSemanticContextCollector.d.ts +9 -0
  69. package/dist/parser/mysql/mysqlSemanticContextCollector.js +14 -0
  70. package/dist/parser/postgresql/index.d.ts +4 -2
  71. package/dist/parser/postgresql/index.js +51 -42
  72. package/dist/parser/postgresql/postgreEntityCollector.d.ts +5 -5
  73. package/dist/parser/postgresql/postgreEntityCollector.js +7 -7
  74. package/dist/parser/postgresql/postgreErrorListener.js +36 -30
  75. package/dist/parser/postgresql/postgreSemanticContextCollector.d.ts +9 -0
  76. package/dist/parser/postgresql/postgreSemanticContextCollector.js +14 -0
  77. package/dist/parser/spark/index.d.ts +4 -2
  78. package/dist/parser/spark/index.js +26 -14
  79. package/dist/parser/spark/sparkErrorListener.js +9 -3
  80. package/dist/parser/spark/sparkSemanticContextCollector.d.ts +9 -0
  81. package/dist/parser/spark/sparkSemanticContextCollector.js +14 -0
  82. package/dist/parser/trino/index.d.ts +4 -2
  83. package/dist/parser/trino/index.js +22 -14
  84. package/dist/parser/trino/trinoErrorListener.js +9 -3
  85. package/dist/parser/trino/trinoSemanticContextCollector.d.ts +9 -0
  86. package/dist/parser/trino/trinoSemanticContextCollector.js +14 -0
  87. package/package.json +2 -1
@@ -114,7 +114,10 @@ import { InlineTableContext } from "./TrinoSqlParser.js";
114
114
  import { SubqueryContext } from "./TrinoSqlParser.js";
115
115
  import { SortItemContext } from "./TrinoSqlParser.js";
116
116
  import { QuerySpecificationContext } from "./TrinoSqlParser.js";
117
+ import { WhereClauseContext } from "./TrinoSqlParser.js";
118
+ import { HavingClauseContext } from "./TrinoSqlParser.js";
117
119
  import { GroupByContext } from "./TrinoSqlParser.js";
120
+ import { PartitionByContext } from "./TrinoSqlParser.js";
118
121
  import { SingleGroupingSetContext } from "./TrinoSqlParser.js";
119
122
  import { RollupContext } from "./TrinoSqlParser.js";
120
123
  import { CubeContext } from "./TrinoSqlParser.js";
@@ -135,7 +138,7 @@ import { SampledRelationContext } from "./TrinoSqlParser.js";
135
138
  import { SampleTypeContext } from "./TrinoSqlParser.js";
136
139
  import { TrimsSpecificationContext } from "./TrinoSqlParser.js";
137
140
  import { ListAggOverflowBehaviorContext } from "./TrinoSqlParser.js";
138
- import { ListaggCountIndicationContext } from "./TrinoSqlParser.js";
141
+ import { ListAggCountIndicationContext } from "./TrinoSqlParser.js";
139
142
  import { PatternRecognitionContext } from "./TrinoSqlParser.js";
140
143
  import { MeasureDefinitionContext } from "./TrinoSqlParser.js";
141
144
  import { RowsPerMatchContext } from "./TrinoSqlParser.js";
@@ -172,7 +175,7 @@ import { TableArgumentTableContext } from "./TrinoSqlParser.js";
172
175
  import { TableArgumentQueryContext } from "./TrinoSqlParser.js";
173
176
  import { DescriptorArgumentContext } from "./TrinoSqlParser.js";
174
177
  import { DescriptorFieldContext } from "./TrinoSqlParser.js";
175
- import { CopartitionTablesContext } from "./TrinoSqlParser.js";
178
+ import { CoPartitionTablesContext } from "./TrinoSqlParser.js";
176
179
  import { ExpressionContext } from "./TrinoSqlParser.js";
177
180
  import { LogicalNotContext } from "./TrinoSqlParser.js";
178
181
  import { PredicatedContext } from "./TrinoSqlParser.js";
@@ -203,6 +206,7 @@ import { TrimContext } from "./TrinoSqlParser.js";
203
206
  import { ParameterContext } from "./TrinoSqlParser.js";
204
207
  import { NormalizeContext } from "./TrinoSqlParser.js";
205
208
  import { LocalTimestampContext } from "./TrinoSqlParser.js";
209
+ import { ListAggContext } from "./TrinoSqlParser.js";
206
210
  import { JsonObjectContext } from "./TrinoSqlParser.js";
207
211
  import { IntervalLiteralContext } from "./TrinoSqlParser.js";
208
212
  import { NumericLiteralContext } from "./TrinoSqlParser.js";
@@ -230,7 +234,6 @@ import { CurrentTimestampContext } from "./TrinoSqlParser.js";
230
234
  import { CurrentSchemaContext } from "./TrinoSqlParser.js";
231
235
  import { ExistsContext } from "./TrinoSqlParser.js";
232
236
  import { PositionContext } from "./TrinoSqlParser.js";
233
- import { ListaggContext } from "./TrinoSqlParser.js";
234
237
  import { SearchedCaseContext } from "./TrinoSqlParser.js";
235
238
  import { CurrentCatalogContext } from "./TrinoSqlParser.js";
236
239
  import { GroupingOperationContext } from "./TrinoSqlParser.js";
@@ -347,6 +350,7 @@ import { CatalogNameCreateContext } from "./TrinoSqlParser.js";
347
350
  import { FunctionNameContext } from "./TrinoSqlParser.js";
348
351
  import { FunctionNameCreateContext } from "./TrinoSqlParser.js";
349
352
  import { ColumnRefContext } from "./TrinoSqlParser.js";
353
+ import { ColumnNameContext } from "./TrinoSqlParser.js";
350
354
  import { ColumnNameCreateContext } from "./TrinoSqlParser.js";
351
355
  import { QualifiedNameContext } from "./TrinoSqlParser.js";
352
356
  import { QueryPeriodContext } from "./TrinoSqlParser.js";
@@ -1160,12 +1164,30 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1160
1164
  * @return the visitor result
1161
1165
  */
1162
1166
  visitQuerySpecification?: (ctx: QuerySpecificationContext) => Result;
1167
+ /**
1168
+ * Visit a parse tree produced by `TrinoSqlParser.whereClause`.
1169
+ * @param ctx the parse tree
1170
+ * @return the visitor result
1171
+ */
1172
+ visitWhereClause?: (ctx: WhereClauseContext) => Result;
1173
+ /**
1174
+ * Visit a parse tree produced by `TrinoSqlParser.havingClause`.
1175
+ * @param ctx the parse tree
1176
+ * @return the visitor result
1177
+ */
1178
+ visitHavingClause?: (ctx: HavingClauseContext) => Result;
1163
1179
  /**
1164
1180
  * Visit a parse tree produced by `TrinoSqlParser.groupBy`.
1165
1181
  * @param ctx the parse tree
1166
1182
  * @return the visitor result
1167
1183
  */
1168
1184
  visitGroupBy?: (ctx: GroupByContext) => Result;
1185
+ /**
1186
+ * Visit a parse tree produced by `TrinoSqlParser.partitionBy`.
1187
+ * @param ctx the parse tree
1188
+ * @return the visitor result
1189
+ */
1190
+ visitPartitionBy?: (ctx: PartitionByContext) => Result;
1169
1191
  /**
1170
1192
  * Visit a parse tree produced by the `singleGroupingSet`
1171
1193
  * labeled alternative in `TrinoSqlParser.groupingElement`.
@@ -1295,11 +1317,11 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1295
1317
  */
1296
1318
  visitListAggOverflowBehavior?: (ctx: ListAggOverflowBehaviorContext) => Result;
1297
1319
  /**
1298
- * Visit a parse tree produced by `TrinoSqlParser.listaggCountIndication`.
1320
+ * Visit a parse tree produced by `TrinoSqlParser.listAggCountIndication`.
1299
1321
  * @param ctx the parse tree
1300
1322
  * @return the visitor result
1301
1323
  */
1302
- visitListaggCountIndication?: (ctx: ListaggCountIndicationContext) => Result;
1324
+ visitListAggCountIndication?: (ctx: ListAggCountIndicationContext) => Result;
1303
1325
  /**
1304
1326
  * Visit a parse tree produced by `TrinoSqlParser.patternRecognition`.
1305
1327
  * @param ctx the parse tree
@@ -1534,11 +1556,11 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1534
1556
  */
1535
1557
  visitDescriptorField?: (ctx: DescriptorFieldContext) => Result;
1536
1558
  /**
1537
- * Visit a parse tree produced by `TrinoSqlParser.copartitionTables`.
1559
+ * Visit a parse tree produced by `TrinoSqlParser.coPartitionTables`.
1538
1560
  * @param ctx the parse tree
1539
1561
  * @return the visitor result
1540
1562
  */
1541
- visitCopartitionTables?: (ctx: CopartitionTablesContext) => Result;
1563
+ visitCoPartitionTables?: (ctx: CoPartitionTablesContext) => Result;
1542
1564
  /**
1543
1565
  * Visit a parse tree produced by `TrinoSqlParser.expression`.
1544
1566
  * @param ctx the parse tree
@@ -1748,6 +1770,13 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1748
1770
  * @return the visitor result
1749
1771
  */
1750
1772
  visitLocalTimestamp?: (ctx: LocalTimestampContext) => Result;
1773
+ /**
1774
+ * Visit a parse tree produced by the `listAgg`
1775
+ * labeled alternative in `TrinoSqlParser.primaryExpression`.
1776
+ * @param ctx the parse tree
1777
+ * @return the visitor result
1778
+ */
1779
+ visitListAgg?: (ctx: ListAggContext) => Result;
1751
1780
  /**
1752
1781
  * Visit a parse tree produced by the `jsonObject`
1753
1782
  * labeled alternative in `TrinoSqlParser.primaryExpression`.
@@ -1937,13 +1966,6 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1937
1966
  * @return the visitor result
1938
1967
  */
1939
1968
  visitPosition?: (ctx: PositionContext) => Result;
1940
- /**
1941
- * Visit a parse tree produced by the `listagg`
1942
- * labeled alternative in `TrinoSqlParser.primaryExpression`.
1943
- * @param ctx the parse tree
1944
- * @return the visitor result
1945
- */
1946
- visitListagg?: (ctx: ListaggContext) => Result;
1947
1969
  /**
1948
1970
  * Visit a parse tree produced by the `searchedCase`
1949
1971
  * labeled alternative in `TrinoSqlParser.primaryExpression`.
@@ -2705,6 +2727,12 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
2705
2727
  * @return the visitor result
2706
2728
  */
2707
2729
  visitColumnRef?: (ctx: ColumnRefContext) => Result;
2730
+ /**
2731
+ * Visit a parse tree produced by `TrinoSqlParser.columnName`.
2732
+ * @param ctx the parse tree
2733
+ * @return the visitor result
2734
+ */
2735
+ visitColumnName?: (ctx: ColumnNameContext) => Result;
2708
2736
  /**
2709
2737
  * Visit a parse tree produced by `TrinoSqlParser.columnNameCreate`.
2710
2738
  * @param ctx the parse tree
@@ -1,12 +1,14 @@
1
- import { Lexer, Token, CommonTokenStream, CharStream, ParserRuleContext, ParseTreeListener, ANTLRErrorListener } from 'antlr4ng';
1
+ import { Lexer, Token, CommonTokenStream, CharStream, ParserRuleContext, ParseTreeListener, ANTLRErrorListener, Parser } from 'antlr4ng';
2
2
  import { CandidatesCollection } from 'antlr4-c3';
3
3
  import { SQLParserBase } from '../../lib/SQLParserBase';
4
4
  import { TextSlice } from './textAndWord';
5
- import { CaretPosition, LOCALE_TYPE, Suggestions } from './types';
5
+ import { CaretPosition, LOCALE_TYPE, SemanticCollectOptions, Suggestions } from './types';
6
6
  import { ParseError, ErrorListener } from './parseErrorListener';
7
7
  import type { SplitListener } from './splitListener';
8
8
  import type { EntityCollector } from './entityCollector';
9
9
  import { EntityContext } from './entityCollector';
10
+ import SemanticContextCollector from './semanticContextCollector';
11
+ export declare const SQL_SPLIT_SYMBOL_TEXT = ";";
10
12
  /**
11
13
  * Basic SQL class, every sql needs extends it.
12
14
  */
@@ -38,11 +40,10 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
38
40
  /**
39
41
  * Convert candidates to suggestions
40
42
  * @param candidates candidate list
41
- * @param allTokens all tokens from input
43
+ * @param allTokens slice all tokens from input by tokenIndexOffset
42
44
  * @param caretTokenIndex tokenIndex of caretPosition
43
- * @param tokenIndexOffset offset of the tokenIndex in the candidates compared to the tokenIndex in allTokens
44
45
  */
45
- protected abstract processCandidates(candidates: CandidatesCollection, allTokens: Token[], caretTokenIndex: number, tokenIndexOffset: number): Suggestions<Token>;
46
+ protected abstract processCandidates(candidates: CandidatesCollection, allTokens: Token[], caretTokenIndex: number): Suggestions<Token>;
46
47
  /**
47
48
  * Get a new splitListener instance.
48
49
  */
@@ -56,6 +57,10 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
56
57
  */
57
58
  protected abstract createEntityCollector(input: string, allTokens?: Token[], caretTokenIndex?: number): EntityCollector;
58
59
  locale: LOCALE_TYPE;
60
+ /**
61
+ * Get a new semanticContextCollector instance.
62
+ */
63
+ protected abstract createSemanticContextCollector(input: string, caretPosition: CaretPosition, allTokens: Token[], options?: SemanticCollectOptions): SemanticContextCollector;
59
64
  /**
60
65
  * Create an antlr4 lexer from input.
61
66
  * @param input string
@@ -116,14 +121,35 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
116
121
  */
117
122
  splitSQLByStatement(input: string): TextSlice[] | null;
118
123
  /**
119
- * Get a minimum boundary parser near tokenIndex.
124
+ * Get the smaller range of input
125
+ * @param input string
126
+ * @param allTokens all tokens from input
127
+ * @param tokenIndexOffset offset of the tokenIndex in the range of input
128
+ * @param caretTokenIndex tokenIndex of caretPosition
129
+ * @returns inputSlice: string, caretTokenIndex: number
130
+ */
131
+ private splitInputBySymbolText;
132
+ /**
133
+ * Get the minimum input string that can be parsed successfully by c3.
134
+ * @param input source string
135
+ * @param caretTokenIndex tokenIndex of caretPosition
136
+ * @param originParseTree origin parseTree
137
+ * @returns MinimumInputInfo
138
+ */
139
+ getMinimumInputInfo(input: string, caretTokenIndex: number, originParseTree: ParserRuleContext | undefined): {
140
+ input: string;
141
+ tokenIndexOffset: number;
142
+ statementCount: number;
143
+ } | null;
144
+ /**
145
+ * Get a minimum boundary parser near caretTokenIndex.
120
146
  * @param input source string.
121
- * @param tokenIndex start from which index to minimize the boundary.
147
+ * @param caretTokenIndex start from which index to minimize the boundary.
122
148
  * @param originParseTree the parse tree need to be minimized, default value is the result of parsing `input`.
123
149
  * @returns minimum parser info
124
150
  */
125
- getMinimumParserInfo(input: string, tokenIndex: number, originParseTree?: ParserRuleContext | null): {
126
- parser: P;
151
+ getMinimumParserInfo(input: string, caretTokenIndex: number, originParseTree: ParserRuleContext | undefined): {
152
+ parser: Parser;
127
153
  parseTree: ParserRuleContext;
128
154
  tokenIndexOffset: number;
129
155
  newTokenIndex: number;
@@ -136,4 +162,12 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
136
162
  */
137
163
  getSuggestionAtCaretPosition(input: string, caretPosition: CaretPosition): Suggestions | null;
138
164
  getAllEntities(input: string, caretPosition?: CaretPosition): EntityContext[] | null;
165
+ /**
166
+ * Get semantic context infos
167
+ * @param input source string
168
+ * @param caretPosition caret position, such as cursor position
169
+ * @param options semantic context options
170
+ * @returns analyzed semantic context
171
+ */
172
+ getSemanticContextAtCaretPosition(input: string, caretPosition: CaretPosition, options?: SemanticCollectOptions): import("./types").SemanticContext;
139
173
  }
@@ -3,6 +3,7 @@ import { CodeCompletionCore } from 'antlr4-c3';
3
3
  import { findCaretTokenIndex } from './findCaretTokenIndex';
4
4
  import { ctxToText, tokenToWord } from './textAndWord';
5
5
  import { ErrorStrategy } from './errorStrategy';
6
+ export const SQL_SPLIT_SYMBOL_TEXT = ';';
6
7
  /**
7
8
  * Basic SQL class, every sql needs extends it.
8
9
  */
@@ -155,31 +156,83 @@ export class BasicSQL {
155
156
  return res;
156
157
  }
157
158
  /**
158
- * Get a minimum boundary parser near tokenIndex.
159
- * @param input source string.
160
- * @param tokenIndex start from which index to minimize the boundary.
161
- * @param originParseTree the parse tree need to be minimized, default value is the result of parsing `input`.
162
- * @returns minimum parser info
159
+ * Get the smaller range of input
160
+ * @param input string
161
+ * @param allTokens all tokens from input
162
+ * @param tokenIndexOffset offset of the tokenIndex in the range of input
163
+ * @param caretTokenIndex tokenIndex of caretPosition
164
+ * @returns inputSlice: string, caretTokenIndex: number
163
165
  */
164
- getMinimumParserInfo(input, tokenIndex, originParseTree) {
165
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
166
- if (arguments.length <= 2) {
167
- this.parseWithCache(input);
168
- originParseTree = this._parseTree;
166
+ splitInputBySymbolText(input, allTokens, tokenIndexOffset, caretTokenIndex) {
167
+ const tokens = allTokens.slice(tokenIndexOffset);
168
+ /**
169
+ * Set startToken
170
+ */
171
+ let startToken = null;
172
+ for (let tokenIndex = caretTokenIndex - tokenIndexOffset; tokenIndex >= 0; tokenIndex--) {
173
+ const token = tokens[tokenIndex];
174
+ if ((token === null || token === void 0 ? void 0 : token.text) === SQL_SPLIT_SYMBOL_TEXT) {
175
+ startToken = tokens[tokenIndex + 1];
176
+ break;
177
+ }
178
+ }
179
+ if (startToken === null) {
180
+ startToken = tokens[0];
169
181
  }
182
+ /**
183
+ * Set stopToken
184
+ */
185
+ let stopToken = null;
186
+ for (let tokenIndex = caretTokenIndex - tokenIndexOffset; tokenIndex < tokens.length; tokenIndex++) {
187
+ const token = tokens[tokenIndex];
188
+ if ((token === null || token === void 0 ? void 0 : token.text) === SQL_SPLIT_SYMBOL_TEXT) {
189
+ stopToken = token;
190
+ break;
191
+ }
192
+ }
193
+ if (stopToken === null) {
194
+ stopToken = tokens[tokens.length - 1];
195
+ }
196
+ const indexOffset = tokens[0].start;
197
+ let startIndex = startToken.start - indexOffset;
198
+ let stopIndex = stopToken.stop + 1 - indexOffset;
199
+ /**
200
+ * Save offset of the tokenIndex in the range of input
201
+ * compared to the tokenIndex in the whole input
202
+ */
203
+ const _tokenIndexOffset = startToken.tokenIndex;
204
+ const _caretTokenIndex = caretTokenIndex - _tokenIndexOffset;
205
+ /**
206
+ * Get the smaller range of _input
207
+ */
208
+ const _input = input.slice(startIndex, stopIndex);
209
+ return {
210
+ inputSlice: _input,
211
+ allTokens: allTokens.slice(_tokenIndexOffset),
212
+ caretTokenIndex: _caretTokenIndex,
213
+ };
214
+ }
215
+ /**
216
+ * Get the minimum input string that can be parsed successfully by c3.
217
+ * @param input source string
218
+ * @param caretTokenIndex tokenIndex of caretPosition
219
+ * @param originParseTree origin parseTree
220
+ * @returns MinimumInputInfo
221
+ */
222
+ getMinimumInputInfo(input, caretTokenIndex, originParseTree) {
223
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
170
224
  if (!originParseTree || !(input === null || input === void 0 ? void 0 : input.length))
171
225
  return null;
172
- const splitListener = this.splitListener;
226
+ let inputSlice = input;
173
227
  /**
174
228
  * Split sql by statement.
175
229
  * Try to collect candidates in as small a range as possible.
176
230
  */
231
+ const splitListener = this.splitListener;
177
232
  this.listen(splitListener, originParseTree);
178
233
  const statementCount = (_a = splitListener.statementsContext) === null || _a === void 0 ? void 0 : _a.length;
179
234
  const statementsContext = splitListener.statementsContext;
180
235
  let tokenIndexOffset = 0;
181
- let sqlParserIns = this._parser;
182
- let parseTree = originParseTree;
183
236
  // If there are multiple statements.
184
237
  if (statementCount > 1) {
185
238
  /**
@@ -200,12 +253,12 @@ export class BasicSQL {
200
253
  */
201
254
  const isPrevCtxValid = index === 0 || !((_b = statementsContext[index - 1]) === null || _b === void 0 ? void 0 : _b.exception);
202
255
  const isNextCtxValid = index === statementCount - 1 || !((_c = statementsContext[index + 1]) === null || _c === void 0 ? void 0 : _c.exception);
203
- if (ctx.stop && ctx.stop.tokenIndex < tokenIndex && isPrevCtxValid) {
256
+ if (ctx.stop && ctx.stop.tokenIndex < caretTokenIndex && isPrevCtxValid) {
204
257
  startStatement = ctx;
205
258
  }
206
259
  if (ctx.start &&
207
260
  !stopStatement &&
208
- ctx.start.tokenIndex > tokenIndex &&
261
+ ctx.start.tokenIndex > caretTokenIndex &&
209
262
  isNextCtxValid) {
210
263
  stopStatement = ctx;
211
264
  break;
@@ -213,35 +266,50 @@ export class BasicSQL {
213
266
  }
214
267
  // A boundary consisting of the index of the input.
215
268
  const startIndex = (_e = (_d = startStatement === null || startStatement === void 0 ? void 0 : startStatement.start) === null || _d === void 0 ? void 0 : _d.start) !== null && _e !== void 0 ? _e : 0;
216
- const stopIndex = (_g = (_f = stopStatement === null || stopStatement === void 0 ? void 0 : stopStatement.stop) === null || _f === void 0 ? void 0 : _f.stop) !== null && _g !== void 0 ? _g : input.length - 1;
269
+ const stopIndex = (_g = (_f = stopStatement === null || stopStatement === void 0 ? void 0 : stopStatement.stop) === null || _f === void 0 ? void 0 : _f.stop) !== null && _g !== void 0 ? _g : inputSlice.length - 1;
217
270
  /**
218
271
  * Save offset of the tokenIndex in the range of input
219
272
  * compared to the tokenIndex in the whole input
220
273
  */
221
274
  tokenIndexOffset = (_j = (_h = startStatement === null || startStatement === void 0 ? void 0 : startStatement.start) === null || _h === void 0 ? void 0 : _h.tokenIndex) !== null && _j !== void 0 ? _j : 0;
222
- tokenIndex = tokenIndex - tokenIndexOffset;
223
- /**
224
- * Reparse the input fragment,
225
- * and c3 will collect candidates in the newly generated parseTree.
226
- */
227
- const inputSlice = input.slice(startIndex, stopIndex);
228
- const lexer = this.createLexer(inputSlice);
229
- lexer.removeErrorListeners();
230
- const tokenStream = new CommonTokenStream(lexer);
231
- tokenStream.fill();
232
- const parser = this.createParserFromTokenStream(tokenStream);
233
- parser.interpreter.predictionMode = PredictionMode.SLL;
234
- parser.removeErrorListeners();
235
- parser.buildParseTrees = true;
236
- parser.errorHandler = new ErrorStrategy();
237
- sqlParserIns = parser;
238
- parseTree = parser.program();
275
+ inputSlice = inputSlice.slice(startIndex, stopIndex);
276
+ }
277
+ return {
278
+ input: inputSlice,
279
+ tokenIndexOffset,
280
+ statementCount,
281
+ };
282
+ }
283
+ /**
284
+ * Get a minimum boundary parser near caretTokenIndex.
285
+ * @param input source string.
286
+ * @param caretTokenIndex start from which index to minimize the boundary.
287
+ * @param originParseTree the parse tree need to be minimized, default value is the result of parsing `input`.
288
+ * @returns minimum parser info
289
+ */
290
+ getMinimumParserInfo(input, caretTokenIndex, originParseTree) {
291
+ if (!originParseTree || !(input === null || input === void 0 ? void 0 : input.length))
292
+ return null;
293
+ const inputInfo = this.getMinimumInputInfo(input, caretTokenIndex, originParseTree);
294
+ if (!inputInfo)
295
+ return null;
296
+ const { input: inputSlice, tokenIndexOffset } = inputInfo;
297
+ caretTokenIndex = caretTokenIndex - tokenIndexOffset;
298
+ let sqlParserIns = this._parser;
299
+ let parseTree = originParseTree;
300
+ /**
301
+ * Reparse the input fragment,
302
+ * and c3 will collect candidates in the newly generated parseTree when input changed.
303
+ */
304
+ if (inputSlice !== input) {
305
+ sqlParserIns = this.createParser(inputSlice);
306
+ parseTree = sqlParserIns.program();
239
307
  }
240
308
  return {
241
309
  parser: sqlParserIns,
242
310
  parseTree,
243
311
  tokenIndexOffset,
244
- newTokenIndex: tokenIndex,
312
+ newTokenIndex: caretTokenIndex,
245
313
  };
246
314
  }
247
315
  /**
@@ -254,18 +322,43 @@ export class BasicSQL {
254
322
  this.parseWithCache(input);
255
323
  if (!this._parseTree)
256
324
  return null;
257
- const allTokens = this.getAllTokens(input);
325
+ let allTokens = this.getAllTokens(input);
258
326
  let caretTokenIndex = findCaretTokenIndex(caretPosition, allTokens);
259
327
  if (!caretTokenIndex && caretTokenIndex !== 0)
260
328
  return null;
261
- const minimumParser = this.getMinimumParserInfo(input, caretTokenIndex);
262
- if (!minimumParser)
329
+ const inputInfo = this.getMinimumInputInfo(input, caretTokenIndex, this._parseTree);
330
+ if (!inputInfo)
263
331
  return null;
264
- const { parser: sqlParserIns, tokenIndexOffset, newTokenIndex, parseTree: c3Context, } = minimumParser;
332
+ const { input: _input, tokenIndexOffset, statementCount } = inputInfo;
333
+ let inputSlice = _input;
334
+ /**
335
+ * Split the inputSlice by separator to get the smaller range of inputSlice.
336
+ */
337
+ if (inputSlice.includes(SQL_SPLIT_SYMBOL_TEXT)) {
338
+ const { inputSlice: _inputSlice, allTokens: _allTokens, caretTokenIndex: _caretTokenIndex, } = this.splitInputBySymbolText(inputSlice, allTokens, tokenIndexOffset, caretTokenIndex);
339
+ allTokens = _allTokens;
340
+ caretTokenIndex = _caretTokenIndex;
341
+ inputSlice = _inputSlice;
342
+ }
343
+ else {
344
+ if (statementCount > 1) {
345
+ caretTokenIndex = caretTokenIndex - tokenIndexOffset;
346
+ }
347
+ }
348
+ let sqlParserIns = this._parser;
349
+ let parseTree = this._parseTree;
350
+ /**
351
+ * Reparse the input fragment,
352
+ * and c3 will collect candidates in the newly generated parseTree when input changed.
353
+ */
354
+ if (inputSlice !== input) {
355
+ sqlParserIns = this.createParser(inputSlice);
356
+ parseTree = sqlParserIns.program();
357
+ }
265
358
  const core = new CodeCompletionCore(sqlParserIns);
266
359
  core.preferredRules = this.preferredRules;
267
- const candidates = core.collectCandidates(newTokenIndex, c3Context);
268
- const originalSuggestions = this.processCandidates(candidates, allTokens, newTokenIndex, tokenIndexOffset);
360
+ const candidates = core.collectCandidates(caretTokenIndex, parseTree);
361
+ const originalSuggestions = this.processCandidates(candidates, allTokens, caretTokenIndex);
269
362
  const syntaxSuggestions = originalSuggestions.syntax.map((syntaxCtx) => {
270
363
  const wordRanges = syntaxCtx.wordRanges.map((token) => {
271
364
  return tokenToWord(token, this._parsedInput);
@@ -300,4 +393,18 @@ export class BasicSQL {
300
393
  // parser.entityCollecting = false;
301
394
  return collectListener.getEntities();
302
395
  }
396
+ /**
397
+ * Get semantic context infos
398
+ * @param input source string
399
+ * @param caretPosition caret position, such as cursor position
400
+ * @param options semantic context options
401
+ * @returns analyzed semantic context
402
+ */
403
+ getSemanticContextAtCaretPosition(input, caretPosition, options) {
404
+ const allTokens = this.getAllTokens(input);
405
+ const parseTree = this.parseWithCache(input);
406
+ const statementContextListener = this.createSemanticContextCollector(input, caretPosition, allTokens, options);
407
+ this.listen(statementContextListener, parseTree);
408
+ return statementContextListener.semanticContext;
409
+ }
303
410
  }
@@ -0,0 +1,50 @@
1
+ import { ErrorNode, ParserRuleContext, TerminalNode, Token } from 'antlr4ng';
2
+ import { CaretPosition, SemanticCollectOptions, SemanticContext } from '../common/types';
3
+ declare abstract class SemanticContextCollector {
4
+ constructor(_input: string, caretPosition: CaretPosition, allTokens: Token[], options?: SemanticCollectOptions);
5
+ readonly options: SemanticCollectOptions;
6
+ private _tokenIndex;
7
+ private _allTokens;
8
+ /**
9
+ * If current caret position is in a beginning of statement semantics, it needs to follow some cases:
10
+ * @case1 there is no statement node with an error before the current statement in the parse tree;
11
+ *
12
+ * @case2 if it is an uncomplete keyword, it will be parsed as an `ErrorNode`
13
+ * and need be a direct child node of `program`;
14
+ *
15
+ * @case3 if it is a complete keyword, the parsed TerminalNode or ErrorNode should be
16
+ * the first leaf node of current statement rule;
17
+ *
18
+ * @case4 if it is whiteSpace in caret position, we can't visit it in antlr4 listener,
19
+ * so we find the first unhidden token before the whiteSpace token, and the unhidden token
20
+ * should be the last leaf node of statement its belongs to;
21
+ *
22
+ * @case5 if the previous token is split symbol like `;`, ignore case1 and forcefully judged as beginning of statement.
23
+ */
24
+ private _isStatementBeginning;
25
+ /**
26
+ * Prev tokenIndex that not white space before current tokenIndex or caret position
27
+ */
28
+ private _prevTokenIndex;
29
+ get semanticContext(): SemanticContext;
30
+ abstract getWhiteSpaceRuleType(): number;
31
+ abstract getStatementRuleType(): number;
32
+ private prevStatementHasError;
33
+ /**
34
+ * Most root rule is `program`.
35
+ */
36
+ private isRootRule;
37
+ /**
38
+ * link to @case4
39
+ * It should be called in each language's own `enterStatement`.
40
+ */
41
+ protected visitStatement(ctx: ParserRuleContext): void;
42
+ /**
43
+ * Uncomplete keyword will be error node
44
+ */
45
+ visitErrorNode(node: ErrorNode): void;
46
+ visitTerminal(node: TerminalNode): void;
47
+ enterEveryRule(_node: ParserRuleContext): void;
48
+ exitEveryRule(_node: ParserRuleContext): void;
49
+ }
50
+ export default SemanticContextCollector;