@witchcraft/expressit 0.0.3 → 0.1.1

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 (119) hide show
  1. package/README.md +3 -1
  2. package/dist/Lexer.d.ts +146 -0
  3. package/dist/Lexer.d.ts.map +1 -0
  4. package/dist/Lexer.js +960 -0
  5. package/dist/Parser.d.ts +211 -0
  6. package/dist/Parser.d.ts.map +1 -0
  7. package/dist/Parser.js +1476 -0
  8. package/dist/ast/builders/token.js +1 -1
  9. package/dist/ast/handlers.d.ts +3 -3
  10. package/dist/ast/handlers.d.ts.map +1 -1
  11. package/dist/examples/shortcutContextParser.d.ts +1 -1
  12. package/dist/examples/shortcutContextParser.js +1 -1
  13. package/dist/helpers/errors.js +3 -3
  14. package/dist/helpers/parser/checkParserOpts.js +2 -2
  15. package/dist/helpers/parser/extractPosition.d.ts +2 -6
  16. package/dist/helpers/parser/extractPosition.d.ts.map +1 -1
  17. package/dist/helpers/parser/extractPosition.js +3 -3
  18. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts +2 -3
  19. package/dist/helpers/parser/getUnclosedRightParenCount.d.ts.map +1 -1
  20. package/dist/helpers/parser/getUnclosedRightParenCount.js +4 -4
  21. package/dist/index.d.ts +1 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3 -5
  24. package/dist/package.json.js +27 -41
  25. package/dist/types/ast.d.ts +1 -7
  26. package/dist/types/ast.d.ts.map +1 -1
  27. package/dist/types/errors.d.ts +5 -17
  28. package/dist/types/errors.d.ts.map +1 -1
  29. package/dist/types/errors.js +0 -1
  30. package/dist/types/parser.d.ts.map +1 -1
  31. package/dist/utils/extractTokens.js +1 -1
  32. package/dist/utils/getCursorInfo.d.ts +2 -2
  33. package/dist/utils/getCursorInfo.d.ts.map +1 -1
  34. package/dist/utils/getCursorInfo.js +3 -6
  35. package/dist/utils/getOppositeDelimiter.d.ts.map +1 -1
  36. package/dist/utils/getOppositeDelimiter.js +1 -1
  37. package/dist/utils/prettyAst.js +7 -6
  38. package/package.json +25 -41
  39. package/src/Lexer.ts +704 -0
  40. package/src/Parser.ts +2014 -0
  41. package/src/ast/builders/array.ts +1 -1
  42. package/src/ast/builders/condition.ts +1 -1
  43. package/src/ast/builders/expression.ts +1 -1
  44. package/src/ast/builders/group.ts +1 -1
  45. package/src/ast/builders/pos.ts +1 -1
  46. package/src/ast/builders/token.ts +2 -2
  47. package/src/ast/builders/type.ts +1 -1
  48. package/src/ast/builders/variable.ts +1 -1
  49. package/src/ast/classes/ConditionNode.ts +1 -1
  50. package/src/ast/classes/ErrorToken.ts +1 -1
  51. package/src/ast/classes/ValidToken.ts +2 -2
  52. package/src/ast/handlers.ts +6 -6
  53. package/src/examples/shortcutContextParser.ts +2 -2
  54. package/src/helpers/errors.ts +4 -4
  55. package/src/helpers/general/defaultConditionNormalizer.ts +1 -1
  56. package/src/helpers/parser/checkParserOpts.ts +12 -12
  57. package/src/helpers/parser/extractPosition.ts +4 -8
  58. package/src/helpers/parser/getUnclosedRightParenCount.ts +6 -6
  59. package/src/helpers/parser/parseParserOptions.ts +1 -1
  60. package/src/index.ts +1 -2
  61. package/src/types/ast.ts +1 -8
  62. package/src/types/errors.ts +12 -22
  63. package/src/types/parser.ts +0 -1
  64. package/src/utils/extractTokens.ts +1 -1
  65. package/src/utils/getCursorInfo.ts +6 -5
  66. package/src/utils/getOppositeDelimiter.ts +5 -2
  67. package/src/utils/prettyAst.ts +4 -4
  68. package/dist/grammar/ParserBase.d.ts +0 -51
  69. package/dist/grammar/ParserBase.d.ts.map +0 -1
  70. package/dist/grammar/ParserBase.js +0 -517
  71. package/dist/grammar/createTokens.d.ts +0 -56
  72. package/dist/grammar/createTokens.d.ts.map +0 -1
  73. package/dist/grammar/createTokens.js +0 -844
  74. package/dist/grammar/index.d.ts +0 -3
  75. package/dist/grammar/index.d.ts.map +0 -1
  76. package/dist/grammar/index.js +0 -6
  77. package/dist/methods/autocomplete.d.ts +0 -18
  78. package/dist/methods/autocomplete.d.ts.map +0 -1
  79. package/dist/methods/autocomplete.js +0 -109
  80. package/dist/methods/autoreplace.d.ts +0 -13
  81. package/dist/methods/autoreplace.d.ts.map +0 -1
  82. package/dist/methods/autoreplace.js +0 -36
  83. package/dist/methods/autosuggest.d.ts +0 -28
  84. package/dist/methods/autosuggest.d.ts.map +0 -1
  85. package/dist/methods/autosuggest.js +0 -371
  86. package/dist/methods/evaluate.d.ts +0 -11
  87. package/dist/methods/evaluate.d.ts.map +0 -1
  88. package/dist/methods/evaluate.js +0 -32
  89. package/dist/methods/getBestIndex.d.ts +0 -19
  90. package/dist/methods/getBestIndex.d.ts.map +0 -1
  91. package/dist/methods/getBestIndex.js +0 -53
  92. package/dist/methods/getIndexes.d.ts +0 -17
  93. package/dist/methods/getIndexes.d.ts.map +0 -1
  94. package/dist/methods/getIndexes.js +0 -98
  95. package/dist/methods/index.d.ts +0 -9
  96. package/dist/methods/index.d.ts.map +0 -1
  97. package/dist/methods/index.js +0 -18
  98. package/dist/methods/normalize.d.ts +0 -10
  99. package/dist/methods/normalize.d.ts.map +0 -1
  100. package/dist/methods/normalize.js +0 -98
  101. package/dist/methods/validate.d.ts +0 -11
  102. package/dist/methods/validate.d.ts.map +0 -1
  103. package/dist/methods/validate.js +0 -112
  104. package/dist/parser.d.ts +0 -58
  105. package/dist/parser.d.ts.map +0 -1
  106. package/dist/parser.js +0 -137
  107. package/src/grammar/ParserBase.ts +0 -716
  108. package/src/grammar/createTokens.ts +0 -513
  109. package/src/grammar/index.ts +0 -4
  110. package/src/methods/autocomplete.ts +0 -128
  111. package/src/methods/autoreplace.ts +0 -46
  112. package/src/methods/autosuggest.ts +0 -543
  113. package/src/methods/evaluate.ts +0 -39
  114. package/src/methods/getBestIndex.ts +0 -53
  115. package/src/methods/getIndexes.ts +0 -100
  116. package/src/methods/index.ts +0 -10
  117. package/src/methods/normalize.ts +0 -137
  118. package/src/methods/validate.ts +0 -143
  119. package/src/parser.ts +0 -184
package/dist/Parser.js ADDED
@@ -0,0 +1,1476 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { get } from "@alanscodelog/utils/get.js";
8
+ import { insert } from "@alanscodelog/utils/insert.js";
9
+ import { isArray } from "@alanscodelog/utils/isArray.js";
10
+ import { isWhitespace } from "@alanscodelog/utils/isWhitespace.js";
11
+ import { setReadOnly } from "@alanscodelog/utils/setReadOnly.js";
12
+ import { unreachable } from "@alanscodelog/utils/unreachable.js";
13
+ import { pos } from "./ast/builders/pos.js";
14
+ import { ArrayNode } from "./ast/classes/ArrayNode.js";
15
+ import { ConditionNode } from "./ast/classes/ConditionNode.js";
16
+ import { ErrorToken } from "./ast/classes/ErrorToken.js";
17
+ import { ExpressionNode } from "./ast/classes/ExpressionNode.js";
18
+ import { GroupNode } from "./ast/classes/GroupNode.js";
19
+ import { Condition } from "./ast/classes/Condition.js";
20
+ import { Expression } from "./ast/classes/Expression.js";
21
+ import "@alanscodelog/utils/crop.js";
22
+ import "@alanscodelog/utils/indent.js";
23
+ import "@alanscodelog/utils/pretty.js";
24
+ import { ValidToken } from "./ast/classes/ValidToken.js";
25
+ import { VariableNode } from "./ast/classes/VariableNode.js";
26
+ import { token, operator, expression, variable, condition, group, array, delimiter } from "./ast/handlers.js";
27
+ import { applyBoolean } from "./helpers/general/applyBoolean.js";
28
+ import { applyPrefix } from "./helpers/general/applyPrefix.js";
29
+ import { checkParserOpts } from "./helpers/parser/checkParserOpts.js";
30
+ import { extractPosition } from "./helpers/parser/extractPosition.js";
31
+ import { getUnclosedRightParenCount } from "./helpers/parser/getUnclosedRightParenCount.js";
32
+ import { parseParserOptions } from "./helpers/parser/parseParserOptions.js";
33
+ import { seal } from "./helpers/parser/seal.js";
34
+ import { Lexer, $C, $T } from "./Lexer.js";
35
+ import { TOKEN_TYPE } from "./types/ast.js";
36
+ import { SUGGESTION_TYPE } from "./types/autocomplete.js";
37
+ import { extractTokens } from "./utils/extractTokens.js";
38
+ import { getCursorInfo } from "./utils/getCursorInfo.js";
39
+ import { getSurroundingErrors } from "./utils/getSurroundingErrors.js";
40
+ const OPPOSITE = {
41
+ [TOKEN_TYPE.AND]: TOKEN_TYPE.OR,
42
+ [TOKEN_TYPE.OR]: TOKEN_TYPE.AND
43
+ };
44
+ function isEqualSet(setA, setB) {
45
+ if (setA.size !== setB.size)
46
+ return false;
47
+ for (const key of setA) {
48
+ if (!setB.has(key))
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ const defaultNodeDirs = {
54
+ before: false,
55
+ after: false
56
+ };
57
+ const createDefaultRequires = (partial = {}) => ({
58
+ whitespace: {
59
+ ...defaultNodeDirs,
60
+ ...partial.whitespace ? partial.whitespace : {}
61
+ },
62
+ group: partial.group ?? false,
63
+ prefix: partial.prefix ?? false
64
+ });
65
+ const tokenRequiresWhitespace = (validToken, whitespace, wordOps) => {
66
+ if (whitespace || validToken === void 0)
67
+ return false;
68
+ return validToken.type === TOKEN_TYPE.VALUE || [TOKEN_TYPE.AND, TOKEN_TYPE.OR, TOKEN_TYPE.NOT].includes(validToken.type) && wordOps.find((_) => _.value === validToken.value) !== void 0;
69
+ };
70
+ const tokenVariable = [TOKEN_TYPE.BACKTICK, TOKEN_TYPE.DOUBLEQUOTE, TOKEN_TYPE.SINGLEQUOTE, TOKEN_TYPE.VALUE, TOKEN_TYPE.REGEX];
71
+ class Parser {
72
+ constructor(options) {
73
+ // needed for evaluate and validate so they are only checked on demand
74
+ __publicField(this, "evaluationOptionsChecked", false);
75
+ __publicField(this, "validationOptionsChecked", false);
76
+ __publicField(this, "options");
77
+ __publicField(this, "lexer");
78
+ __publicField(this, "$");
79
+ __publicField(this, "$categories");
80
+ __publicField(this, "info");
81
+ __publicField(this, "state", {
82
+ rawInput: "",
83
+ lexedTokens: [],
84
+ index: 0,
85
+ shift: 0
86
+ });
87
+ __publicField(this, "subParserOne");
88
+ __publicField(this, "subParserTwo");
89
+ const opts = parseParserOptions(options ?? {});
90
+ checkParserOpts(opts);
91
+ this.options = opts;
92
+ this.lexer = new Lexer(opts);
93
+ this.$ = this.lexer.$;
94
+ this.$categories = this.lexer.$categories;
95
+ this.info = {
96
+ expandedSepAlsoCustom: this.lexer.symbols.expandedSepAlsoCustom,
97
+ customOpAlsoNegation: this.lexer.symbols.customOpAlsoNegation
98
+ };
99
+ }
100
+ // eslint-disable-next-line @typescript-eslint/naming-convention
101
+ _checkEvaluationOptions() {
102
+ if (!this.evaluationOptionsChecked) {
103
+ checkParserOpts(this.options, true);
104
+ this.evaluationOptionsChecked = true;
105
+ }
106
+ }
107
+ // eslint-disable-next-line @typescript-eslint/naming-convention
108
+ _checkValidationOptions() {
109
+ if (!this.validationOptionsChecked) {
110
+ checkParserOpts(this.options, false, true);
111
+ this.validationOptionsChecked = true;
112
+ }
113
+ }
114
+ /**
115
+ * This is exposed mainly for debugging purposes. Use parse directly instead.
116
+ */
117
+ lex(input) {
118
+ if (isWhitespace(input)) {
119
+ return { tokens: [], shift: 0, rawInput: input };
120
+ }
121
+ let lexed = this.lexer.tokenize(input);
122
+ const shift = getUnclosedRightParenCount(lexed);
123
+ const rawInput = input;
124
+ if (shift) {
125
+ input = "(".repeat(shift) + input;
126
+ lexed = this.lexer.tokenize(input);
127
+ }
128
+ const lexedTokens = lexed.filter((token2) => {
129
+ const tokenType = this.getTokenType(token2.type);
130
+ if (tokenType) {
131
+ return !tokenType.skip;
132
+ } else {
133
+ throw new Error(`Unknown token type ${token2.type}`);
134
+ }
135
+ });
136
+ return { tokens: lexedTokens, shift, rawInput };
137
+ }
138
+ /**
139
+ * Parse an input string into an AST.
140
+ * It can also parse the result from `lex`, but that is really only for internal use.
141
+ */
142
+ parse(input) {
143
+ var _a;
144
+ const doSeal = ((_a = arguments[1]) == null ? void 0 : _a.seal) ?? true;
145
+ if (typeof input === "string" && isWhitespace(input)) {
146
+ return token.value(void 0, { start: 0, end: 0 });
147
+ }
148
+ const { tokens: lexedTokens, shift, rawInput } = typeof input === "string" ? this.lex(input) : input;
149
+ this.state = {
150
+ rawInput,
151
+ shift,
152
+ index: -1,
153
+ lexedTokens
154
+ };
155
+ const res = this.ruleMain();
156
+ if (doSeal) {
157
+ seal(res);
158
+ }
159
+ this.state = {
160
+ rawInput: "",
161
+ shift: 0,
162
+ index: -1,
163
+ lexedTokens: []
164
+ };
165
+ return res;
166
+ }
167
+ createSubParserIfNotExists(opts, which = "One") {
168
+ if (this[`subParser${which}`] === void 0) {
169
+ this[`subParser${which}`] = new Parser(opts);
170
+ }
171
+ return this[`subParser${which}`];
172
+ }
173
+ transformCategoryToken(token2, categoryToken) {
174
+ return {
175
+ ...token2,
176
+ type: categoryToken.type
177
+ };
178
+ }
179
+ getCategoryTokens(type) {
180
+ var _a;
181
+ return (_a = this.$categories[type]) == null ? void 0 : _a.entries;
182
+ }
183
+ getTokenType(type) {
184
+ return this.$[type];
185
+ }
186
+ isExactType(token2, type) {
187
+ if (this.$[type]) {
188
+ return this.isType(token2, type);
189
+ }
190
+ return false;
191
+ }
192
+ isType(token2, type) {
193
+ if (token2 === void 0)
194
+ return false;
195
+ if (token2.type === type)
196
+ return true;
197
+ const tokenType = this.getTokenType(token2.type);
198
+ if ((tokenType == null ? void 0 : tokenType.type) === type)
199
+ return true;
200
+ const category = this.$categories[type];
201
+ if ((category == null ? void 0 : category.entries[token2.type]) !== void 0) {
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+ createErrorToken(type, index) {
207
+ return {
208
+ type,
209
+ value: "",
210
+ startOffset: index ?? this.state.index,
211
+ endOffset: index ?? this.state.index,
212
+ isError: true
213
+ };
214
+ }
215
+ processToken(token2) {
216
+ if (token2 === void 0) {
217
+ return [void 0, extractPosition({ startOffset: 0, endOffset: 0 }, this.state.shift)];
218
+ } else {
219
+ return [token2.value, extractPosition(token2, this.state.shift)];
220
+ }
221
+ }
222
+ peek(n = 1) {
223
+ return this.state.lexedTokens[this.state.index + n];
224
+ }
225
+ nextIsEof() {
226
+ return this.peek(1) === void 0;
227
+ }
228
+ consumeAny() {
229
+ var _a;
230
+ return this.consume((_a = this.peek(1)) == null ? void 0 : _a.type);
231
+ }
232
+ consume(type) {
233
+ if (type === void 0) {
234
+ throw new Error("type is undefined");
235
+ }
236
+ const nextToken = this.peek(1);
237
+ if (nextToken === void 0) {
238
+ throw new Error(`Reached end of input without consuming a token of type ${type}`);
239
+ }
240
+ if (this.$categories[type] !== void 0) {
241
+ const categoryToken = this.$categories[type];
242
+ const tokenType = categoryToken == null ? void 0 : categoryToken.entries[nextToken.type];
243
+ if (categoryToken && tokenType) {
244
+ this.state.index++;
245
+ return this.transformCategoryToken(nextToken, categoryToken);
246
+ } else {
247
+ throw new Error("here");
248
+ }
249
+ } else {
250
+ const tokenType = this.getTokenType(type);
251
+ if (tokenType !== void 0) {
252
+ if ((nextToken == null ? void 0 : nextToken.type) === tokenType.type) {
253
+ this.state.index++;
254
+ return nextToken;
255
+ } else {
256
+ throw new Error(`Expected token type ${tokenType.type}, got ${nextToken == null ? void 0 : nextToken.type}`);
257
+ }
258
+ }
259
+ }
260
+ throw new Error(`Unknown token type ${type}`);
261
+ }
262
+ saveState() {
263
+ return { ...this.state };
264
+ }
265
+ restoreState(state) {
266
+ this.state = state;
267
+ }
268
+ ruleMain() {
269
+ const res = this.ruleBool("OR");
270
+ if (res === void 0) {
271
+ const error = token.value(void 0, { start: 0, end: 0 });
272
+ return error;
273
+ }
274
+ return res;
275
+ }
276
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
277
+ ruleBool(type) {
278
+ var _a;
279
+ const OP_TYPE = type === "AND" ? $C.OPERATOR_AND : $C.OPERATOR_OR;
280
+ const pairs = [];
281
+ let next = this.peek(1);
282
+ while (pairs.length < 1 || ((_a = pairs[pairs.length - 1]) == null ? void 0 : _a[1]) !== void 0) {
283
+ const exp = type === "AND" ? this.ruleCondition() : this.ruleBool("AND");
284
+ next = this.peek(1);
285
+ const canAttemptErrorRecovery = type === "AND" ? ["error", "and"].includes(this.options.onMissingBooleanOperator) : this.options.onMissingBooleanOperator === "or";
286
+ const extras = [];
287
+ if (canAttemptErrorRecovery && (this.isType(next, $C.VALUE) || this.isType(next, $C.QUOTE_ANY) || this.isType(next, $T.PAREN_L) || this.isType(next, $T.EXP_PROP_OP) || this.isType(next, $T.REGEX_START) || this.isType(next, $T.CUSTOM_PROP_OP))) {
288
+ let state = this.saveState();
289
+ let cond = this.ruleCondition();
290
+ if (type === "AND") {
291
+ let dummyOp;
292
+ while (cond !== void 0) {
293
+ if (this.options.onMissingBooleanOperator === "and") {
294
+ const prev = this.peek(-1);
295
+ const start = prev.endOffset + 1;
296
+ dummyOp = operator.and("", pos({ start }, { fill: true }));
297
+ }
298
+ extras.push([dummyOp, cond]);
299
+ state = this.saveState();
300
+ cond = this.ruleCondition();
301
+ }
302
+ this.restoreState(state);
303
+ } else {
304
+ const prev = this.peek(-1);
305
+ const start = prev.endOffset + 1;
306
+ const dummyOp = operator.or("", pos({ start }, { fill: true }));
307
+ extras.push([dummyOp, cond]);
308
+ }
309
+ next = this.peek(1);
310
+ }
311
+ const sepToken = this.isType(next, OP_TYPE) && next ? type === "AND" ? operator.and(...this.processToken(this.consume(next.type))) : operator.or(...this.processToken(this.consume(next.type))) : void 0;
312
+ pairs.push([
313
+ exp,
314
+ sepToken
315
+ ]);
316
+ next = this.peek(1);
317
+ for (const extra of extras) {
318
+ pairs[pairs.length - 1].splice(1, 1, extra[0]);
319
+ pairs.push([extra[1]]);
320
+ }
321
+ }
322
+ if (pairs.length === 0 && this.isType(this.peek(1), OP_TYPE)) {
323
+ next = this.peek(-1);
324
+ let state = this.saveState();
325
+ while (this.isType(next, $C.OPERATOR_AND)) {
326
+ const token2 = this.consume($C.OPERATOR_AND);
327
+ pairs.push([
328
+ void 0,
329
+ type === "AND" ? operator.and(...this.processToken(token2)) : operator.or(...this.processToken(token2))
330
+ ]);
331
+ next = this.peek(-1);
332
+ while (this.isType(next, $C.VALUE) || this.isType(next, $C.QUOTE_ANY) || this.isType(next, $T.PAREN_L)) {
333
+ pairs.push([this.ruleCondition()]);
334
+ next = this.peek(-1);
335
+ }
336
+ state = this.saveState();
337
+ }
338
+ this.restoreState(state);
339
+ }
340
+ if (type === "AND" && pairs.length === 0)
341
+ return void 0;
342
+ let res = pairs[pairs.length - 1][0];
343
+ for (let i = pairs.length - 1; i > 0; i--) {
344
+ const before = pairs[i - 1];
345
+ if (type === "OR" && res === void 0 && before === void 0)
346
+ return void 0;
347
+ res = expression(before[0], before[1], res);
348
+ }
349
+ return res;
350
+ }
351
+ ruleCondition() {
352
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
353
+ const not = this.ruleNot();
354
+ const property = this.ruleConditionProperty();
355
+ const propVal = ((_a = property == null ? void 0 : property.prop) == null ? void 0 : _a.value) === void 0 ? void 0 : property.prop.value instanceof ErrorToken ? "" : property.prop.value.value;
356
+ const propOpVal = ((_b = property == null ? void 0 : property.rest) == null ? void 0 : _b.propertyOperator) === void 0 ? void 0 : property.rest.propertyOperator instanceof ErrorToken ? "" : (_c = property.rest.propertyOperator) == null ? void 0 : _c.value;
357
+ const isExpanded = (((_d = property == null ? void 0 : property.rest) == null ? void 0 : _d.sepL) ?? ((_e = property == null ? void 0 : property.rest) == null ? void 0 : _e.sepR)) !== void 0;
358
+ const convertRegexValues = typeof this.options.regexValues === "function" && !this.options.regexValues(propVal, propOpVal, isExpanded);
359
+ const convertArrayValues = typeof this.options.arrayValues === "function" && !this.options.arrayValues(propVal, propOpVal, isExpanded);
360
+ let value = this.ruleConditionValue(property, { convertRegexValues, convertArrayValues });
361
+ let group$1;
362
+ if (!(value instanceof ArrayNode) && !isArray(value) && (!value || this.options.prefixableGroups) && this.isType(this.peek(1), $T.PAREN_L)) {
363
+ group$1 = this.rulePlainGroup({ onlyValues: property !== void 0, convertRegexValues, convertArrayValues });
364
+ }
365
+ if (isArray(value)) {
366
+ group$1 = value;
367
+ value = void 0;
368
+ }
369
+ if (convertRegexValues && value instanceof VariableNode && ((_f = value.quote) == null ? void 0 : _f.left.type) === TOKEN_TYPE.REGEX) {
370
+ value = variable(void 0, void 0, token.value(
371
+ (((_h = (_g = value.quote) == null ? void 0 : _g.left) == null ? void 0 : _h.value) ?? "") + (value.value.value ?? "") + (((_j = (_i = value.quote) == null ? void 0 : _i.right) == null ? void 0 : _j.value) ?? ""),
372
+ pos(value)
373
+ ), void 0);
374
+ }
375
+ if (group$1) {
376
+ if (property) {
377
+ return condition(not, property == null ? void 0 : property.prop, property == null ? void 0 : property.rest, group(void 0, void 0, ...group$1));
378
+ }
379
+ if (value) {
380
+ return group(void 0, condition(not, void 0, void 0, value), ...group$1);
381
+ }
382
+ return group(not, value, ...group$1);
383
+ }
384
+ if ([not, property, value].every((_) => _ === void 0))
385
+ return void 0;
386
+ return condition(not, property == null ? void 0 : property.prop, property == null ? void 0 : property.rest, value);
387
+ }
388
+ ruleConditionValue(property, { convertRegexValues = false, convertArrayValues = false } = {}) {
389
+ const next = this.peek(1);
390
+ const next2 = this.peek(2);
391
+ const next3 = this.peek(3);
392
+ const next4 = this.peek(4);
393
+ if (this.options.prefixableGroups && property === void 0 && (next == null ? void 0 : next.type) !== $T.PAREN_L && (this.isType(next, $C.VALUE) && (this.isType(next2, $T.PAREN_L) || this.isType(next2, $C.QUOTE_ANY) && this.isType(next3, $T.PAREN_L)) || this.isType(next, $C.QUOTE_ANY) && (this.isType(next2, $T.PAREN_L) || this.isType(next2, $C.VALUE) && (this.isType(next3, $T.PAREN_L) || // "a(
394
+ this.isType(next3, $C.QUOTE_ANY) && this.isType(next4, $T.PAREN_L))))) {
395
+ const res = this.ruleVariable({ unprefixed: true });
396
+ if (res)
397
+ return res;
398
+ }
399
+ if (!this.isType(next, $T.PAREN_L)) {
400
+ const res = this.ruleVariable({ unprefixed: false });
401
+ if (res)
402
+ return res;
403
+ }
404
+ if (this.isType(next, $T.PAREN_L)) {
405
+ const res = this.rulePlainGroup({ onlyValues: property !== void 0, convertRegexValues, convertArrayValues });
406
+ if (res)
407
+ return res;
408
+ }
409
+ if (this.isType(next, $T.BRACKET_L)) {
410
+ const res = this.rulePlainBracketGroup({ convertArrayValues });
411
+ if (res)
412
+ return res;
413
+ }
414
+ return void 0;
415
+ }
416
+ rulePlainGroup({ onlyValues = false, convertRegexValues = false, convertArrayValues = false } = {}) {
417
+ const parenL = this.ruleParenL();
418
+ let parenLeftCount = 0;
419
+ let start;
420
+ let end;
421
+ const condition2 = !onlyValues ? this.ruleBool("OR") : void 0;
422
+ if (onlyValues && !this.nextIsEof()) {
423
+ while (!this.nextIsEof() && (!this.isType(this.peek(1), $T.PAREN_R) || parenLeftCount !== 0)) {
424
+ const token2 = this.consumeAny();
425
+ start ?? (start = extractPosition(token2, this.state.shift).start);
426
+ if (token2.type === $T.PAREN_L) {
427
+ parenLeftCount++;
428
+ }
429
+ if (token2.type === $T.PAREN_R) {
430
+ parenLeftCount--;
431
+ }
432
+ }
433
+ }
434
+ if (start !== void 0) {
435
+ end ?? (end = extractPosition(this.peek(0), this.state.shift).end);
436
+ }
437
+ const parenR = this.isType(this.peek(1), $T.PAREN_R) ? this.ruleParenR() : void 0;
438
+ if (start !== void 0) {
439
+ const subInput = this.state.rawInput.slice(start, end);
440
+ this.createSubParserIfNotExists({
441
+ ...this.options,
442
+ customPropertyOperators: [],
443
+ expandedPropertySeparator: void 0,
444
+ regexValues: convertRegexValues,
445
+ arrayValues: convertArrayValues
446
+ }, "One");
447
+ const parsed = this.subParserOne.parse(" ".repeat(start) + subInput, { seal: false });
448
+ return [parenL, parsed, parenR];
449
+ }
450
+ return [parenL, condition2, parenR];
451
+ }
452
+ rulePlainBracketGroup({ convertArrayValues = false } = {}) {
453
+ const bracketL = this.ruleBracketL();
454
+ const values = [];
455
+ if (!convertArrayValues) {
456
+ let state = this.saveState();
457
+ let variable2 = this.ruleVariable({ unprefixed: false });
458
+ while (variable2 !== void 0) {
459
+ values.push(variable2);
460
+ state = this.saveState();
461
+ variable2 = this.ruleVariable({ unprefixed: false });
462
+ }
463
+ this.restoreState(state);
464
+ } else if (convertArrayValues && !this.nextIsEof()) {
465
+ while (!this.nextIsEof() && !this.isType(this.peek(1), $T.BRACKET_R)) {
466
+ this.consumeAny();
467
+ }
468
+ }
469
+ const bracketR = this.isType(this.peek(1), $T.BRACKET_R) ? this.ruleBracketR() : void 0;
470
+ if (bracketL === void 0)
471
+ throw new Error("bracketL is undefined, peek before using rule.");
472
+ if (!convertArrayValues) {
473
+ return array(bracketL, values, bracketR);
474
+ }
475
+ const start = bracketL.start;
476
+ const end = bracketR == null ? void 0 : bracketR.end;
477
+ const subInput = this.state.rawInput.slice(start, end);
478
+ this.createSubParserIfNotExists({
479
+ ...this.options,
480
+ customPropertyOperators: [],
481
+ expandedPropertySeparator: void 0,
482
+ arrayValues: false
483
+ }, "Two");
484
+ const parsed = this.subParserTwo.parse(" ".repeat(start) + subInput, { seal: false });
485
+ if (parsed instanceof ConditionNode) {
486
+ return parsed.value;
487
+ }
488
+ if (parsed instanceof ErrorToken || parsed instanceof ExpressionNode || parsed instanceof GroupNode) {
489
+ unreachable("parsed.value should not be an ErrorToken, ExpressionNode, or GroupNode.");
490
+ }
491
+ return parsed;
492
+ }
493
+ ruleConditionProperty() {
494
+ const current = this.peek(0);
495
+ const next = this.peek(1);
496
+ const next2 = this.peek(2);
497
+ if (this.isType(next, $T.EXP_PROP_OP) || this.isType(next, $T.CUSTOM_PROP_OP) || this.isType(next, $T.VALUE_UNQUOTED) && (this.isType(next2, $T.EXP_PROP_OP) || this.isType(next2, $T.CUSTOM_PROP_OP)) || this.info.customOpAlsoNegation && (this.isType(next2, $T.SYM_NOT) || this.isType(current, $T.SYM_NOT) && this.isType(next, $T.SYM_NOT))) {
498
+ return this.ruleProperty();
499
+ }
500
+ return void 0;
501
+ }
502
+ ruleProperty() {
503
+ const prop = this.ruleVariable({ unprefixed: true });
504
+ const next = this.peek(1);
505
+ let rest = {};
506
+ if (this.isType(next, $T.EXP_PROP_OP)) {
507
+ const sepL = token.sep(...this.processToken(this.consume($T.EXP_PROP_OP)));
508
+ const op = this.isType(this.peek(1), $T.VALUE_UNQUOTED) ? token.value(...this.processToken(this.consume($T.VALUE_UNQUOTED))) : void 0;
509
+ const sepR = this.isType(this.peek(1), $T.EXP_PROP_OP) ? token.sep(...this.processToken(this.consume($T.EXP_PROP_OP))) : void 0;
510
+ if (this.info.expandedSepAlsoCustom && op === void 0 && sepR === void 0) {
511
+ setReadOnly(sepL, "type", TOKEN_TYPE.OP_CUSTOM);
512
+ rest = {
513
+ sepL: void 0,
514
+ sepR,
515
+ propertyOperator: sepL
516
+ };
517
+ } else {
518
+ rest = { sepL, sepR, propertyOperator: op };
519
+ }
520
+ } else if (this.isType(next, $T.CUSTOM_PROP_OP)) {
521
+ const op = token.custom(...this.processToken(this.consume($T.CUSTOM_PROP_OP)));
522
+ rest = { propertyOperator: op };
523
+ } else if (this.info.customOpAlsoNegation && this.isType(next, $T.SYM_NOT)) {
524
+ const op = token.custom(...this.processToken(this.consume($T.SYM_NOT)));
525
+ rest = { propertyOperator: op };
526
+ }
527
+ return { prop, rest };
528
+ }
529
+ ruleVariable({
530
+ unprefixed = false
531
+ } = {}) {
532
+ const prefix = this.ruleVariablePrefix({ onlyToken: true, unprefixed });
533
+ const next = this.peek(1);
534
+ const next2 = this.peek(2);
535
+ const next3 = this.peek(3);
536
+ if (next && (this.isExactType(next, $T.QUOTE_DOUBLE) || this.isExactType(next, $T.QUOTE_SINGLE) || this.isExactType(next, $T.QUOTE_BACKTICK))) {
537
+ const quoteType = next.type;
538
+ if ((next2 == null ? void 0 : next2.type) === quoteType) {
539
+ const quoteL = this.ruleQuote(quoteType);
540
+ const quoteR = this.ruleQuote(quoteType);
541
+ return variable(void 0, quoteL, void 0, quoteR);
542
+ }
543
+ if ((next3 == null ? void 0 : next3.type) === next.type) {
544
+ const quoteL = this.ruleQuote(quoteType);
545
+ const value = this.isType(next2, $T.VALUE_UNQUOTED) ? this.ruleValueUnquoted({}) : this.ruleValueNot(quoteType);
546
+ const quoteR = this.ruleQuote(quoteType);
547
+ const prefixToken = prefix ? token.value(...this.processToken(prefix)) : void 0;
548
+ return variable(prefixToken, quoteL, value, quoteR);
549
+ }
550
+ }
551
+ if (this.isType(next, $C.REGEX_ANY)) {
552
+ const quoteL = this.ruleRegexAny();
553
+ const maybeValue = this.peek(1);
554
+ const value = this.isType(maybeValue, $T.VALUE_REGEX) ? this.ruleValueNot($C.REGEX_ANY) : void 0;
555
+ const quoteR = this.isType(this.peek(1), $C.REGEX_ANY) ? this.ruleRegexAny() : void 0;
556
+ const args = isArray(quoteR) ? quoteR : [quoteR, void 0];
557
+ return variable(void 0, quoteL, value, args[0], args[1]);
558
+ }
559
+ if (this.isType(next, $T.VALUE_UNQUOTED) && this.isType(next2, $C.QUOTE_ANY)) {
560
+ const value = this.ruleValueUnquoted();
561
+ const quoteR = this.ruleValueDelimAny();
562
+ return variable(void 0, void 0, value, quoteR);
563
+ }
564
+ if (this.isType(next, $C.QUOTE_ANY)) {
565
+ const quoteToken = next;
566
+ const quoteL = this.ruleValueDelimAny();
567
+ const maybeValue = this.peek(1);
568
+ const value = !quoteL && this.isType(maybeValue, $T.VALUE_UNQUOTED) ? this.ruleValueUnquoted() : quoteL && this.isType(maybeValue, quoteToken.type.replace("QUOTE", "VALUE_FOR")) ? this.ruleValueNot(quoteToken.type) : void 0;
569
+ return variable(void 0, quoteL, value, void 0);
570
+ }
571
+ if (this.isType(next, $T.VALUE_UNQUOTED)) {
572
+ const value = this.ruleValueUnquoted();
573
+ return variable(void 0, void 0, value, void 0);
574
+ }
575
+ return void 0;
576
+ }
577
+ ruleValueDelimAny() {
578
+ const next = this.peek(1);
579
+ if (this.isType(next, $C.QUOTE_ANY)) {
580
+ const type = next.value === `"` ? "double" : next.value === "'" ? "single" : next.value === "`" ? "tick" : "regex";
581
+ return delimiter[type](...this.processToken(this.consume($C.QUOTE_ANY)));
582
+ }
583
+ return void 0;
584
+ }
585
+ ruleRegexAny() {
586
+ const value = this.consume($C.REGEX_ANY);
587
+ if (value.value.length > 1) {
588
+ const delim = {
589
+ value: "/",
590
+ startOffset: value.startOffset,
591
+ endOffset: value.startOffset
592
+ };
593
+ const flags = {
594
+ value: value.value.slice(1),
595
+ startOffset: value.startOffset + 1,
596
+ endOffset: value.endOffset
597
+ };
598
+ return [
599
+ // why the ! ??? todo
600
+ delimiter.regex(...this.processToken(delim)),
601
+ token.value(...this.processToken(flags))
602
+ ];
603
+ }
604
+ return delimiter.regex(...this.processToken(value));
605
+ }
606
+ ruleValueNot(type) {
607
+ const realType = {
608
+ [$T.QUOTE_SINGLE]: $C.VALUE_FOR_SINGLE,
609
+ [$T.QUOTE_DOUBLE]: $C.VALUE_FOR_DOUBLE,
610
+ [$T.QUOTE_BACKTICK]: $C.VALUE_FOR_BACKTICK,
611
+ [$C.REGEX_ANY]: $T.VALUE_REGEX
612
+ }[type];
613
+ if (realType === void 0) {
614
+ unreachable(`Unknown quote/regex type ${type}`);
615
+ }
616
+ const value = this.consume(realType);
617
+ if (realType !== value.type) {
618
+ unreachable(`Expected value type ${realType}, got ${value.type}`);
619
+ }
620
+ return token.value(...this.processToken(value));
621
+ }
622
+ ruleQuote(type) {
623
+ const quote = this.peek(1);
624
+ if (type !== (quote == null ? void 0 : quote.type)) {
625
+ throw new Error(`Expected quote type ${type}, got ${quote == null ? void 0 : quote.type}`);
626
+ }
627
+ switch (type) {
628
+ case $T.QUOTE_SINGLE:
629
+ return delimiter.single(
630
+ ...this.processToken(this.consume($T.QUOTE_SINGLE))
631
+ );
632
+ case $T.QUOTE_DOUBLE:
633
+ return delimiter.double(
634
+ ...this.processToken(this.consume($T.QUOTE_DOUBLE))
635
+ );
636
+ case $T.QUOTE_BACKTICK:
637
+ return delimiter.tick(
638
+ ...this.processToken(this.consume($T.QUOTE_BACKTICK))
639
+ );
640
+ }
641
+ throw new Error(`Expected quote type ${type}`);
642
+ }
643
+ ruleVariablePrefix({
644
+ onlyToken = false,
645
+ unprefixed = false
646
+ } = {}) {
647
+ const next = this.peek(1);
648
+ const next2 = this.peek(2);
649
+ const next4 = this.peek(4);
650
+ if (!unprefixed && this.options.prefixableStrings !== void 0 && this.isType(next2, $C.QUOTE_ANY) && next2 && this.isType(next4, next2.type) && next && this.options.prefixableStrings.includes(next.value)) {
651
+ return this.ruleValueUnquoted({ onlyToken });
652
+ }
653
+ if (onlyToken)
654
+ return void 0;
655
+ return token.value(...this.processToken());
656
+ }
657
+ ruleValueUnquoted({
658
+ onlyToken = false
659
+ } = {}) {
660
+ const t = this.consume($T.VALUE_UNQUOTED);
661
+ const res = onlyToken ? t : token.value(...this.processToken(t));
662
+ return res;
663
+ }
664
+ ruleParenL() {
665
+ const next = this.peek(1);
666
+ const value = (next == null ? void 0 : next.type) === $T.PAREN_L ? this.consume($T.PAREN_L) : this.createErrorToken($T.PAREN_L);
667
+ const loc = extractPosition(value, this.state.shift);
668
+ return this.state.shift === 0 || loc.start > 0 ? delimiter.parenL(value.isError ? void 0 : value.value, loc) : void 0;
669
+ }
670
+ ruleParenR() {
671
+ const value = this.consume($T.PAREN_R);
672
+ return delimiter.parenR(...this.processToken(value));
673
+ }
674
+ ruleBracketL() {
675
+ const next = this.peek(1);
676
+ const value = (next == null ? void 0 : next.type) === $T.BRACKET_L ? this.consume($T.BRACKET_L) : this.createErrorToken($T.BRACKET_L);
677
+ const loc = extractPosition(value, this.state.shift);
678
+ return this.state.shift === 0 || loc.start > 0 ? delimiter.bracketL(value.isError ? void 0 : value.value, loc) : void 0;
679
+ }
680
+ ruleBracketR() {
681
+ const value = this.consume($T.BRACKET_R);
682
+ return delimiter.bracketR(...this.processToken(value));
683
+ }
684
+ ruleNot() {
685
+ if (this.isType(this.peek(1), $C.OPERATOR_NOT)) {
686
+ const op = this.consume($C.OPERATOR_NOT);
687
+ return operator.not(...this.processToken(op));
688
+ }
689
+ return void 0;
690
+ }
691
+ /**
692
+ * Given a list of @see Suggestion entries, the parser options, and a list of variables, prefixes, operators, etc, and the preferred quote type, returns a list of @see Completion entries.
693
+ *
694
+ * It takes care of suggesting the correct delimiters for fixes, quoting variables/prefixes if it would not be possible to parse them unquoted, and separating symbol from non-symbol (word) operators.
695
+ *
696
+ * Does not add whitespace or group requirements. The suggestion information is still in the completion if you wish to show these. But they should not be added to the completion value if using @see autoreplace which will take care of it.
697
+ *
698
+ * Is not aware of existing values. You will have to use @see getCursorInfo to understand the context in which the suggestion was made, so that, for example, you could filter out used regex flags.
699
+ */
700
+ autocomplete(suggestions, {
701
+ values = [],
702
+ arrayValues = [],
703
+ variables = [],
704
+ prefixes = [],
705
+ properties = [],
706
+ expandedPropertyOperators = [],
707
+ customPropertyOperators = this.options.customPropertyOperators ?? [],
708
+ keywords = this.options.keywords,
709
+ regexFlags = ["i", "m", "u"],
710
+ quote = '"'
711
+ } = {}) {
712
+ const self = this;
713
+ return suggestions.map((suggestion) => {
714
+ const type = suggestion.type;
715
+ switch (type) {
716
+ case SUGGESTION_TYPE.BACKTICK:
717
+ return [{ suggestion, value: "`" }];
718
+ case SUGGESTION_TYPE.DOUBLEQUOTE:
719
+ return [{ suggestion, value: '"' }];
720
+ case SUGGESTION_TYPE.SINGLEQUOTE:
721
+ return [{ suggestion, value: "'" }];
722
+ case SUGGESTION_TYPE.PARENL:
723
+ return [{ suggestion, value: "(" }];
724
+ case SUGGESTION_TYPE.PARENR:
725
+ return [{ suggestion, value: ")" }];
726
+ case SUGGESTION_TYPE.BRAKCETR:
727
+ return [{ suggestion, value: "]" }];
728
+ case SUGGESTION_TYPE.REGEX:
729
+ return [{ suggestion, value: "/" }];
730
+ case SUGGESTION_TYPE.REGEX_FLAGS:
731
+ return regexFlags.map((value) => ({ suggestion, value })).filter((completion) => {
732
+ var _a, _b, _c, _d, _e, _f, _g;
733
+ const { suggestion: suggestion2, value } = completion;
734
+ if (suggestion2.type !== SUGGESTION_TYPE.REGEX_FLAGS) {
735
+ return true;
736
+ }
737
+ const token2 = suggestion2.cursorInfo;
738
+ const flags = token2.at && ((_b = (_a = token2.at.parent) == null ? void 0 : _a.quote) == null ? void 0 : _b.flags) === suggestion2.cursorInfo.at ? token2.at : token2.next && ((_d = (_c = token2.next.parent) == null ? void 0 : _c.quote) == null ? void 0 : _d.flags) === suggestion2.cursorInfo.next ? token2.next : token2.prev && ((_f = (_e = token2.prev.parent) == null ? void 0 : _e.quote) == null ? void 0 : _f.flags) === suggestion2.cursorInfo.prev ? token2.prev : void 0;
739
+ if ((_g = flags == null ? void 0 : flags.value) == null ? void 0 : _g.includes(value)) {
740
+ return false;
741
+ }
742
+ return true;
743
+ });
744
+ case SUGGESTION_TYPE.PROPERTY: {
745
+ return properties.map((value) => ({ suggestion, value }));
746
+ }
747
+ case SUGGESTION_TYPE.PROPERTY_SEP: {
748
+ return [{ suggestion, value: self.options.expandedPropertySeparator }];
749
+ }
750
+ case SUGGESTION_TYPE.EXPANDED_PROPERTY_OPERATOR: {
751
+ return expandedPropertyOperators.map((value) => ({ suggestion, value }));
752
+ }
753
+ case SUGGESTION_TYPE.CUSTOM_PROPERTY_OPERATOR: {
754
+ return customPropertyOperators.map((value) => ({ suggestion, value }));
755
+ }
756
+ case SUGGESTION_TYPE.BOOLEAN_SYMBOL_OP: {
757
+ const keywordsList = [...keywords.and, ...keywords.or];
758
+ const symOpts = keywordsList.filter((_) => _.isSymbol);
759
+ return symOpts.map(({ value }) => ({ suggestion, value }));
760
+ }
761
+ case SUGGESTION_TYPE.BOOLEAN_WORD_OP: {
762
+ const keywordsList = [...keywords.and, ...keywords.or];
763
+ const wordOpts = keywordsList.filter((_) => !_.isSymbol);
764
+ return wordOpts.map(({ value }) => ({ suggestion, value }));
765
+ }
766
+ case SUGGESTION_TYPE.VALUE:
767
+ case SUGGESTION_TYPE.ARRAY_VALUE:
768
+ case SUGGESTION_TYPE.VARIABLE: {
769
+ const arr = type === SUGGESTION_TYPE.VARIABLE ? variables : type === SUGGESTION_TYPE.ARRAY_VALUE ? arrayValues : type === SUGGESTION_TYPE.VALUE ? values : unreachable();
770
+ return arr.map((variable2) => {
771
+ const res = self.parse(variable2);
772
+ if (res instanceof ConditionNode && res.operator === void 0 && res.value instanceof VariableNode && res.value.quote === void 0) {
773
+ return { suggestion, value: res.value.value.value };
774
+ } else {
775
+ return { suggestion, value: quote + variable2.replace(new RegExp(quote, "g"), `\\${quote}`) + quote };
776
+ }
777
+ });
778
+ }
779
+ case SUGGESTION_TYPE.PREFIX:
780
+ return prefixes.map((prefix) => {
781
+ const res = self.parse(prefix);
782
+ if (res instanceof ConditionNode && res.operator === void 0 && res.value instanceof VariableNode && res.value.quote === void 0) {
783
+ return { suggestion, value: res.value.value.value };
784
+ } else {
785
+ return { suggestion, value: quote + prefix.replace(new RegExp(quote, "g"), `\\${quote}`) + quote };
786
+ }
787
+ });
788
+ }
789
+ }).flat();
790
+ }
791
+ /**
792
+ * Given the input string and a @see Completion consisting of the value of the replacement and a @see Suggestion entry, returns the replacement string and the new position of the cursor.
793
+ *
794
+ * The value passed should be escaped if it's needed (or quoted). @see autocomplete already takes care of quoting variables if you're using it.
795
+ */
796
+ autoreplace(input, { value, suggestion }) {
797
+ const isQuotedLeft = ['"', "'", "`"].includes(value[0]);
798
+ const isQuotedRight = ['"', "'", "`"].includes(value[value.length - 1]);
799
+ if (isQuotedLeft && !isQuotedRight || !isQuotedLeft && isQuotedRight) {
800
+ throw new Error(`Completion value must either be entirely quoted or entirely unquoted. But the left side is ${isQuotedLeft ? "quoted" : "unquoted"} and the right side is ${isQuotedRight ? "quoted" : "unquoted"}.`);
801
+ }
802
+ let cursor = suggestion.range.start + value.length;
803
+ if (suggestion.requires.prefix) {
804
+ value = suggestion.requires.prefix + (isQuotedLeft ? "" : '"') + value + (isQuotedRight ? "" : '"');
805
+ cursor += suggestion.requires.prefix.length + Number(!isQuotedLeft) + Number(!isQuotedRight);
806
+ }
807
+ if (suggestion.requires.group) {
808
+ value += "()";
809
+ cursor++;
810
+ }
811
+ if (suggestion.requires.whitespace.before) {
812
+ value = ` ${value}`;
813
+ cursor++;
814
+ }
815
+ if (suggestion.requires.whitespace.after) {
816
+ value = `${value} `;
817
+ }
818
+ const replacement = insert(value, input, [suggestion.range.start, suggestion.range.end]);
819
+ return { replacement, cursor };
820
+ }
821
+ /**
822
+ * Returns a list of suggestions ( @see Suggestion ). These are not a list of autocomplete entries (with values), but more a list of entries describing possible suggestions. This list can then be passed to @see Parser["autocomplete"] to build a list to show users, from which you can then pick an entry to pass to @see Parser["autoreplace"] .
823
+ *
824
+ * The list returned is "unsorted", but there is still some logic to the order. Fixes for errors are suggested first, in the order returned by @see getSurroundingErrors. Regular suggestions come after in the following order: prefixes if enabled, variables, boolean symbol operators, then boolean word operators.
825
+ *
826
+ * When the cursor is between two tokens that have possible suggestions, only suggestion types for the token before are returned. For example:
827
+ *
828
+ * ```js
829
+ * prop="val"
830
+ * prop|="val" //returns a property suggestions to replace `prop`
831
+ * prop=|"val" //returns a custom operator suggestion to replace `=`
832
+ * prop="|val" //returns a value suggestion
833
+ * ```
834
+ *
835
+ * And if there are no suggestions for the previous token but there are for the next ones, they are suggested:
836
+ * ```js
837
+ * prop:op:"val"
838
+ * prop:op|:"val" // returns an operator suggestion
839
+ * prop:op:|"val" // returns a value suggestion
840
+ * prop:op|"val" // returns a suggestion for the missing separator
841
+ * ```
842
+ */
843
+ autosuggest(input, ast, index) {
844
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L;
845
+ const opts = this.options;
846
+ const tokens = extractTokens(ast);
847
+ const token2 = getCursorInfo(input, tokens, index);
848
+ const wordOps = [...opts.keywords.and, ...opts.keywords.or, ...opts.keywords.not].filter((op) => !op.isSymbol);
849
+ const canSuggestOpAfterPrev = token2.valid.prev && tokenVariable.includes((_a = token2.valid.prev) == null ? void 0 : _a.type) && (token2.whitespace.prev || token2.valid.prev.type === TOKEN_TYPE.PARENR) && !token2.at && token2.valid.next === void 0;
850
+ const canSuggestOpBeforeNext = token2.valid.next && tokenVariable.includes((_b = token2.valid.next) == null ? void 0 : _b.type) && token2.whitespace.next && // no parenL allowed since check since there will already be prefix suggestions
851
+ !token2.at && token2.valid.prev === void 0;
852
+ const requiresWhitespacePrev = tokenRequiresWhitespace(token2.valid.prev, token2.whitespace.prev, wordOps);
853
+ const requiresWhitespaceNext = tokenRequiresWhitespace(token2.valid.next, token2.whitespace.next, wordOps);
854
+ const requiresWhitespacePrevOp = canSuggestOpAfterPrev ? false : requiresWhitespacePrev;
855
+ const requireWhitespaceNextOp = !canSuggestOpAfterPrev && canSuggestOpBeforeNext ? false : requiresWhitespaceNext;
856
+ const suggestions = [];
857
+ if (ast instanceof ErrorToken) {
858
+ suggestions.push({
859
+ type: SUGGESTION_TYPE.PREFIX,
860
+ requires: createDefaultRequires({ group: true }),
861
+ range: pos({ start: index }, { fill: true }),
862
+ isError: true,
863
+ cursorInfo: token2
864
+ });
865
+ suggestions.push({
866
+ type: SUGGESTION_TYPE.VARIABLE,
867
+ requires: createDefaultRequires(),
868
+ range: pos({ start: index }, { fill: true }),
869
+ isError: true,
870
+ cursorInfo: token2
871
+ });
872
+ } else {
873
+ const surroundingErrors = getSurroundingErrors(tokens, token2);
874
+ const errorTypesHandled = [];
875
+ const errorSuggestion = {
876
+ isError: true,
877
+ cursorInfo: token2
878
+ };
879
+ const baseSuggestion = {
880
+ isError: false,
881
+ cursorInfo: token2
882
+ };
883
+ for (const error of surroundingErrors) {
884
+ for (const type of error.expected) {
885
+ if (errorTypesHandled.includes(type))
886
+ continue;
887
+ errorTypesHandled.push(type);
888
+ switch (type) {
889
+ case TOKEN_TYPE.DOUBLEQUOTE:
890
+ case TOKEN_TYPE.SINGLEQUOTE:
891
+ case TOKEN_TYPE.BACKTICK:
892
+ {
893
+ const isLeft = error.parent.quote.left === error;
894
+ const isRight = error.parent.quote.right === error;
895
+ suggestions.push({
896
+ ...errorSuggestion,
897
+ type,
898
+ requires: createDefaultRequires({
899
+ whitespace: {
900
+ before: isRight ? false : requiresWhitespacePrev,
901
+ after: isLeft ? false : requiresWhitespaceNext
902
+ }
903
+ }),
904
+ range: pos({ start: index }, { fill: true })
905
+ });
906
+ }
907
+ break;
908
+ case TOKEN_TYPE.AND:
909
+ case TOKEN_TYPE.OR:
910
+ suggestions.push({
911
+ ...errorSuggestion,
912
+ type: SUGGESTION_TYPE.BOOLEAN_SYMBOL_OP,
913
+ requires: createDefaultRequires(),
914
+ range: pos({ start: index }, { fill: true })
915
+ });
916
+ suggestions.push({
917
+ ...errorSuggestion,
918
+ type: SUGGESTION_TYPE.BOOLEAN_WORD_OP,
919
+ requires: createDefaultRequires({
920
+ whitespace: {
921
+ before: requiresWhitespacePrevOp,
922
+ after: requireWhitespaceNextOp
923
+ }
924
+ }),
925
+ range: pos({ start: index }, { fill: true })
926
+ });
927
+ if (type === TOKEN_TYPE.AND)
928
+ errorTypesHandled.push(TOKEN_TYPE.OR);
929
+ if (type === TOKEN_TYPE.OR)
930
+ errorTypesHandled.push(TOKEN_TYPE.AND);
931
+ break;
932
+ case TOKEN_TYPE.PARENL:
933
+ case TOKEN_TYPE.PARENR:
934
+ suggestions.push({
935
+ ...errorSuggestion,
936
+ type,
937
+ requires: createDefaultRequires(),
938
+ range: pos({ start: index }, { fill: true })
939
+ });
940
+ break;
941
+ case TOKEN_TYPE.VALUE: {
942
+ const prefixedValue = error.parent instanceof VariableNode ? (_d = (_c = error.parent) == null ? void 0 : _c.prefix) == null ? void 0 : _d.value : false;
943
+ const isRegexValue = error.parent instanceof VariableNode && (((_e = error.parent.quote) == null ? void 0 : _e.left.type) === TOKEN_TYPE.REGEX || ((_f = error.parent.quote) == null ? void 0 : _f.right.type) === TOKEN_TYPE.REGEX);
944
+ if (!isRegexValue) {
945
+ if (!prefixedValue && opts.prefixableGroups) {
946
+ suggestions.push({
947
+ ...errorSuggestion,
948
+ type: SUGGESTION_TYPE.PREFIX,
949
+ requires: createDefaultRequires({
950
+ whitespace: {
951
+ before: requiresWhitespacePrev,
952
+ after: false
953
+ /* parens get inserted */
954
+ },
955
+ group: true
956
+ // is always needed
957
+ }),
958
+ range: pos({ start: index }, { fill: true })
959
+ });
960
+ }
961
+ suggestions.push({
962
+ ...errorSuggestion,
963
+ type: SUGGESTION_TYPE.VARIABLE,
964
+ requires: createDefaultRequires({
965
+ whitespace: {
966
+ before: requiresWhitespacePrev,
967
+ after: requiresWhitespaceNext
968
+ },
969
+ prefix: prefixedValue
970
+ }),
971
+ range: pos({ start: index }, { fill: true })
972
+ });
973
+ }
974
+ break;
975
+ }
976
+ case TOKEN_TYPE.BRACKETR: {
977
+ suggestions.push({
978
+ ...errorSuggestion,
979
+ type: SUGGESTION_TYPE.BRAKCETR,
980
+ requires: createDefaultRequires(),
981
+ range: pos({ start: index }, { fill: true })
982
+ });
983
+ break;
984
+ }
985
+ case TOKEN_TYPE.OP_EXPANDED_SEP:
986
+ suggestions.push({
987
+ ...errorSuggestion,
988
+ type: SUGGESTION_TYPE.PROPERTY_SEP,
989
+ requires: createDefaultRequires(),
990
+ range: pos({ start: index }, { fill: true })
991
+ });
992
+ break;
993
+ case TOKEN_TYPE.REGEX:
994
+ suggestions.push({
995
+ ...errorSuggestion,
996
+ type: SUGGESTION_TYPE.REGEX,
997
+ requires: createDefaultRequires(),
998
+ range: pos({ start: index }, { fill: true })
999
+ });
1000
+ break;
1001
+ case TOKEN_TYPE.OP_CUSTOM:
1002
+ case TOKEN_TYPE.BRACKETL:
1003
+ case TOKEN_TYPE.NOT:
1004
+ unreachable();
1005
+ }
1006
+ }
1007
+ }
1008
+ const prevVar = (_g = token2.valid.prev) == null ? void 0 : _g.parent;
1009
+ const nextVar = (_h = token2.valid.next) == null ? void 0 : _h.parent;
1010
+ const prevCondition = prevVar == null ? void 0 : prevVar.parent;
1011
+ const nextCondition = nextVar == null ? void 0 : nextVar.parent;
1012
+ const atVar = (_i = token2.at) == null ? void 0 : _i.parent;
1013
+ const atCondition = atVar == null ? void 0 : atVar.parent;
1014
+ const isVarPrev = !token2.whitespace.prev && ((_j = token2.valid.prev) == null ? void 0 : _j.type) !== TOKEN_TYPE.REGEX && prevVar instanceof VariableNode && (prevCondition instanceof ConditionNode && prevCondition.value === prevVar && (((_k = prevVar.quote) == null ? void 0 : _k.right) === token2.valid.prev || prevVar.value === token2.valid.prev) || prevCondition instanceof ArrayNode);
1015
+ const isVarNext = !token2.whitespace.next && ((_l = token2.valid.next) == null ? void 0 : _l.type) !== TOKEN_TYPE.REGEX && nextVar instanceof VariableNode && (nextCondition instanceof ConditionNode && nextCondition.value === nextVar && (((_m = nextVar.quote) == null ? void 0 : _m.left) === token2.valid.next || nextVar.value === token2.valid.next) || nextCondition instanceof ArrayNode);
1016
+ const isVarAt = atVar instanceof VariableNode && atCondition instanceof ConditionNode || prevVar instanceof VariableNode && token2.valid.prev === ((_n = prevVar == null ? void 0 : prevVar.quote) == null ? void 0 : _n.left) || nextVar instanceof VariableNode && token2.valid.next === ((_o = nextVar == null ? void 0 : nextVar.quote) == null ? void 0 : _o.right);
1017
+ const isPropertyPrev = prevCondition instanceof ConditionNode && prevVar !== void 0 && prevVar === (prevCondition == null ? void 0 : prevCondition.property);
1018
+ const isPropertyNext = nextCondition instanceof ConditionNode && nextVar !== void 0 && nextVar === (nextCondition == null ? void 0 : nextCondition.property);
1019
+ const isPropertyAt = atCondition instanceof ConditionNode && atVar !== void 0 && atVar === (atCondition == null ? void 0 : atCondition.property);
1020
+ const isPropertyOperatorPrev = prevVar instanceof ConditionNode && token2.valid.prev === (prevVar == null ? void 0 : prevVar.propertyOperator);
1021
+ const isPropertyOperatorNext = nextVar instanceof ConditionNode && token2.valid.next === (nextVar == null ? void 0 : nextVar.propertyOperator);
1022
+ const isPropertyOperatorAt = atVar instanceof ConditionNode && token2.at === (atVar == null ? void 0 : atVar.propertyOperator);
1023
+ const noArrayValuesTarget = ((_p = token2.valid.prev) == null ? void 0 : _p.type) === TOKEN_TYPE.BRACKETL && (token2.valid.next === void 0 || ((_q = token2.valid.next) == null ? void 0 : _q.type) === TOKEN_TYPE.BRACKETR);
1024
+ const target = isVarPrev ? token2.valid.prev : !noArrayValuesTarget && !isPropertyPrev && !isPropertyOperatorPrev && isVarNext ? token2.valid.next : isVarAt ? token2.at : void 0;
1025
+ const propertyTarget = isPropertyPrev ? token2.valid.prev : !noArrayValuesTarget && !isVarPrev && !isPropertyOperatorPrev && isPropertyNext ? token2.valid.next : isPropertyAt ? token2.at : void 0;
1026
+ const propOpTarget = isPropertyOperatorPrev ? token2.valid.prev : !noArrayValuesTarget && !isVarPrev && !isPropertyPrev && isPropertyOperatorNext ? token2.valid.next : isPropertyOperatorAt ? token2.at : void 0;
1027
+ if (target) {
1028
+ const parent = target.parent;
1029
+ if (parent instanceof VariableNode) {
1030
+ const range = pos(parent);
1031
+ const condition2 = parent == null ? void 0 : parent.parent;
1032
+ const isValue = condition2.propertyOperator !== void 0 && condition2.value === parent;
1033
+ const maybeGroup = (_r = parent == null ? void 0 : parent.parent) == null ? void 0 : _r.parent;
1034
+ const isPrefix = maybeGroup instanceof GroupNode && maybeGroup.prefix === condition2;
1035
+ const varStart = getCursorInfo(input, ast, parent.start);
1036
+ const varEnd = getCursorInfo(input, ast, parent.end);
1037
+ const targetRequiresWhitespacePrev = tokenRequiresWhitespace(varStart.valid.prev, varStart.whitespace.prev, wordOps);
1038
+ const targetRequiresWhitespaceNext = tokenRequiresWhitespace(varEnd.valid.next, varEnd.whitespace.next, wordOps);
1039
+ const prefixedValue = target.parent instanceof VariableNode ? (_t = (_s = target.parent) == null ? void 0 : _s.prefix) == null ? void 0 : _t.value : false;
1040
+ const isSepPrev = ((_u = token2.prev) == null ? void 0 : _u.type) === TOKEN_TYPE.OP_EXPANDED_SEP;
1041
+ const arrayValue = ((_v = target.parent) == null ? void 0 : _v.parent) instanceof ArrayNode;
1042
+ const isRegexFlag = target === ((_w = parent.quote) == null ? void 0 : _w.flags);
1043
+ if (!isRegexFlag && !isSepPrev && !isValue && !arrayValue && !prefixedValue && opts.prefixableGroups) {
1044
+ suggestions.push({
1045
+ ...baseSuggestion,
1046
+ type: SUGGESTION_TYPE.PREFIX,
1047
+ requires: createDefaultRequires({
1048
+ group: !isPrefix,
1049
+ whitespace: {
1050
+ before: targetRequiresWhitespacePrev && !isPrefix,
1051
+ after: false
1052
+ // parens exist or get inserted
1053
+ }
1054
+ }),
1055
+ range
1056
+ });
1057
+ }
1058
+ if (!isRegexFlag && !isPrefix) {
1059
+ suggestions.push({
1060
+ ...baseSuggestion,
1061
+ type: arrayValue ? SUGGESTION_TYPE.ARRAY_VALUE : isValue ? SUGGESTION_TYPE.VALUE : SUGGESTION_TYPE.VARIABLE,
1062
+ requires: createDefaultRequires({
1063
+ whitespace: {
1064
+ before: targetRequiresWhitespacePrev,
1065
+ after: targetRequiresWhitespaceNext
1066
+ },
1067
+ prefix: prefixedValue
1068
+ }),
1069
+ range
1070
+ });
1071
+ }
1072
+ }
1073
+ }
1074
+ if (noArrayValuesTarget) {
1075
+ suggestions.push({
1076
+ ...baseSuggestion,
1077
+ type: SUGGESTION_TYPE.ARRAY_VALUE,
1078
+ requires: createDefaultRequires(),
1079
+ range: pos({ start: index }, { fill: true })
1080
+ });
1081
+ }
1082
+ if (propertyTarget) {
1083
+ suggestions.push({
1084
+ ...baseSuggestion,
1085
+ type: SUGGESTION_TYPE.PROPERTY,
1086
+ requires: createDefaultRequires(),
1087
+ range: pos(propertyTarget)
1088
+ });
1089
+ }
1090
+ if (propOpTarget) {
1091
+ suggestions.push({
1092
+ ...baseSuggestion,
1093
+ type: propOpTarget.parent.sep ? SUGGESTION_TYPE.EXPANDED_PROPERTY_OPERATOR : SUGGESTION_TYPE.CUSTOM_PROPERTY_OPERATOR,
1094
+ requires: createDefaultRequires(),
1095
+ range: pos(propOpTarget)
1096
+ });
1097
+ }
1098
+ const canSuggestValue = token2.whitespace.next && (token2.whitespace.prev || ((_x = token2.prev) == null ? void 0 : _x.type) === TOKEN_TYPE.BRACKETL || ((_y = token2.prev) == null ? void 0 : _y.type) === TOKEN_TYPE.PARENL) || token2.whitespace.prev && (token2.whitespace.next || ((_z = token2.next) == null ? void 0 : _z.type) === TOKEN_TYPE.BRACKETR || ((_A = token2.next) == null ? void 0 : _A.type) === TOKEN_TYPE.PARENR);
1099
+ if (canSuggestValue) {
1100
+ const inArrayNode = [nextCondition, prevCondition, nextVar, prevVar].find((_) => _ instanceof ArrayNode) !== void 0;
1101
+ const opsNotNeeded = ["and", "or"].includes(opts.onMissingBooleanOperator);
1102
+ if (inArrayNode || opsNotNeeded) {
1103
+ suggestions.push({
1104
+ type: inArrayNode ? SUGGESTION_TYPE.ARRAY_VALUE : SUGGESTION_TYPE.VARIABLE,
1105
+ requires: createDefaultRequires({}),
1106
+ range: pos({ start: index }, { fill: true }),
1107
+ ...baseSuggestion
1108
+ });
1109
+ }
1110
+ if (!inArrayNode && opsNotNeeded) {
1111
+ suggestions.push({
1112
+ ...baseSuggestion,
1113
+ type: SUGGESTION_TYPE.PREFIX,
1114
+ requires: createDefaultRequires({
1115
+ group: true
1116
+ }),
1117
+ range: pos({ start: index }, { fill: true })
1118
+ });
1119
+ }
1120
+ }
1121
+ const canSuggestRegexFlags = (
1122
+ // has existing flags before/after
1123
+ token2.at && token2.at === ((_D = (_C = (_B = token2.at) == null ? void 0 : _B.parent) == null ? void 0 : _C.quote) == null ? void 0 : _D.flags) || token2.valid.prev && token2.valid.prev === ((_G = (_F = (_E = token2.valid.prev) == null ? void 0 : _E.parent) == null ? void 0 : _F.quote) == null ? void 0 : _G.flags) || token2.valid.next && token2.valid.next === ((_J = (_I = (_H = token2.valid.next) == null ? void 0 : _H.parent) == null ? void 0 : _I.quote) == null ? void 0 : _J.flags) || // no flags
1124
+ ((_K = token2.valid.prev) == null ? void 0 : _K.type) === TOKEN_TYPE.REGEX && token2.valid.prev === ((_L = token2.valid.prev.parent.quote) == null ? void 0 : _L.right)
1125
+ );
1126
+ if (canSuggestRegexFlags) {
1127
+ suggestions.push({
1128
+ ...baseSuggestion,
1129
+ type: SUGGESTION_TYPE.REGEX_FLAGS,
1130
+ requires: createDefaultRequires(),
1131
+ range: pos({ start: index }, { fill: true })
1132
+ });
1133
+ }
1134
+ if (canSuggestOpAfterPrev || canSuggestOpBeforeNext) {
1135
+ const range = pos({ start: index }, { fill: true });
1136
+ suggestions.push({
1137
+ ...baseSuggestion,
1138
+ type: SUGGESTION_TYPE.BOOLEAN_SYMBOL_OP,
1139
+ requires: createDefaultRequires(),
1140
+ range
1141
+ });
1142
+ suggestions.push({
1143
+ ...baseSuggestion,
1144
+ type: SUGGESTION_TYPE.BOOLEAN_WORD_OP,
1145
+ requires: createDefaultRequires({
1146
+ whitespace: {
1147
+ before: requiresWhitespacePrevOp,
1148
+ after: requireWhitespaceNextOp
1149
+ }
1150
+ }),
1151
+ range
1152
+ });
1153
+ }
1154
+ }
1155
+ return suggestions;
1156
+ }
1157
+ /**
1158
+ * Evaluates a {@link Parser.normalize normalized} ast.
1159
+ *
1160
+ * How the ast is evaluated for different operators can be controlled by the {@link ParserOptions.valueComparer valueComparer} option.
1161
+ */
1162
+ evaluate(ast, context) {
1163
+ this._checkEvaluationOptions();
1164
+ const opts = this.options;
1165
+ if (ast instanceof Condition) {
1166
+ const contextValue = get(context, ast.property);
1167
+ const res = opts.valueComparer({ property: ast.property, value: ast.value, operator: ast.operator }, contextValue, context);
1168
+ return ast.negate ? !res : res;
1169
+ }
1170
+ if (ast instanceof Expression) {
1171
+ const left = this.evaluate(ast.left, context);
1172
+ const right = this.evaluate(ast.right, context);
1173
+ return ast.operator === TOKEN_TYPE.AND ? left && right : left || right;
1174
+ }
1175
+ return unreachable();
1176
+ }
1177
+ /**
1178
+ * Given the set of indexes returned by {@link getBestIndex}, the set of existing indexes in a database, and the index to sort by\*, will return a list of the best/shortest sets of indexes.
1179
+ *
1180
+ * For example, given the query `a && b && c`, `getBestIndex` will return `[Set(a), Set(b)]`.
1181
+ *
1182
+ * Suppose we have indexes on all the variables and that the user wants to sort by `c`, this function will return [`Set(c)`].
1183
+ *
1184
+ * Suppose instead we have indexes only on `a` and `b` and that the user wants to sort by `c`, this function will return [`Set(a), Set(b)`]. Either can be picked by some other criteria (e.g. size of the indexes). Sort should then be done in memory.
1185
+ *
1186
+ * And then finally, if we have no existing indexes on any of the variables, the function will return `[]`.
1187
+ *
1188
+ * Note: This is a simple algorithm and is not designed to take into account instances where entries are indexed by two or more properties as their keys (i.e. multicolumn indexes).
1189
+ *
1190
+ * \* If the sort index is not in the list of existing indexes it is not taken into account.
1191
+ */
1192
+ getBestIndexes(indexes, existing, sortIndex = "") {
1193
+ indexes = indexes.filter((set) => {
1194
+ for (const key of set) {
1195
+ if (!existing.has(key))
1196
+ return false;
1197
+ }
1198
+ return true;
1199
+ });
1200
+ let finalIndexes = indexes;
1201
+ if (existing.has(sortIndex)) {
1202
+ const indexesWithSortIndex = indexes.filter((set) => set.has(sortIndex));
1203
+ if (indexesWithSortIndex.length > 0)
1204
+ finalIndexes = indexesWithSortIndex;
1205
+ }
1206
+ let smallest = Infinity;
1207
+ if (existing instanceof Map) {
1208
+ const scores = /* @__PURE__ */ new Map();
1209
+ for (const set of finalIndexes) {
1210
+ let score = 0;
1211
+ for (const key of set) {
1212
+ score += existing.get(key) ?? 0;
1213
+ }
1214
+ scores.set(set, score);
1215
+ smallest = score < smallest ? score : smallest;
1216
+ }
1217
+ return indexes.filter((set) => smallest === Infinity || scores.get(set) === smallest);
1218
+ } else {
1219
+ for (const set of finalIndexes) {
1220
+ smallest = set.size < smallest ? set.size : smallest;
1221
+ }
1222
+ return indexes.filter((set) => smallest === Infinity || set.size === smallest);
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Returns a list of the different sets of keys that need to be indexed to run a normalized query on a database and hit an existing index.
1227
+ *
1228
+ * For example, the expression `a || b` requires both `a` AND `b` be indexed to use an index. The function would return `[Set(a, b)]`.
1229
+ *
1230
+ * On the otherhand, the expression `a && b` only requires `a` OR `b` to be indexed (`[Set(a), Set(b)]`) If at least one is indexed, the rest of the filtering can be done in memory. There is no need to in memory filter the entire database.
1231
+ *
1232
+ * Now take a more complicated query like `(a && b) || (a && c)`. This only requires `a` be indexed, or both `b` AND `c`. (`[Set(a)], [Set(b), Set(c)]`).
1233
+ *
1234
+ * Queries like `(a || b) && (a || c)` would require all the variables to be indexed `[Set(a), Set(b), Set(c)]`.
1235
+ */
1236
+ getIndexes(ast) {
1237
+ if (ast instanceof Condition) {
1238
+ return [new Set(ast.property.join("."))];
1239
+ }
1240
+ if (ast instanceof Expression) {
1241
+ const left = this.getIndexes(ast.left);
1242
+ const right = this.getIndexes(ast.right);
1243
+ if (ast.operator === TOKEN_TYPE.AND) {
1244
+ const sets = [];
1245
+ const allKeys = /* @__PURE__ */ new Set();
1246
+ for (const leftSet of left) {
1247
+ const exists = sets.find((set) => isEqualSet(set, leftSet));
1248
+ if (exists)
1249
+ continue;
1250
+ sets.push(leftSet);
1251
+ for (const key of leftSet) {
1252
+ allKeys.add(key);
1253
+ }
1254
+ }
1255
+ for (const rightSet of right) {
1256
+ const exists = sets.find((set) => isEqualSet(set, rightSet));
1257
+ if (exists)
1258
+ continue;
1259
+ sets.push(rightSet);
1260
+ for (const key of rightSet) {
1261
+ allKeys.add(key);
1262
+ }
1263
+ }
1264
+ const commonKeys = /* @__PURE__ */ new Set();
1265
+ outerCheck:
1266
+ for (const key of allKeys) {
1267
+ for (const set of sets) {
1268
+ if (!set.has(key))
1269
+ continue outerCheck;
1270
+ }
1271
+ commonKeys.add(key);
1272
+ }
1273
+ if (commonKeys.size > 0) {
1274
+ return [commonKeys, allKeys];
1275
+ } else {
1276
+ return sets;
1277
+ }
1278
+ }
1279
+ if (ast.operator === TOKEN_TYPE.OR) {
1280
+ for (const rightSet of right) {
1281
+ for (const leftSet of left) {
1282
+ if (isEqualSet(leftSet, rightSet)) {
1283
+ return [rightSet];
1284
+ }
1285
+ }
1286
+ }
1287
+ const res = /* @__PURE__ */ new Set();
1288
+ for (const leftSet of left) {
1289
+ for (const key of leftSet) {
1290
+ res.add(key);
1291
+ }
1292
+ }
1293
+ for (const rightSet of right) {
1294
+ for (const key of rightSet) {
1295
+ res.add(key);
1296
+ }
1297
+ }
1298
+ return [res];
1299
+ }
1300
+ }
1301
+ return unreachable();
1302
+ }
1303
+ /**
1304
+ * Normalizes the ast by applying {@link GroupNode GroupNodes} and converting {@link ConditionNode ConditionNodes} to {@link NormalizedConditionNode NormalizedConditionNodes}.
1305
+ */
1306
+ normalize(ast) {
1307
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1308
+ this._checkEvaluationOptions();
1309
+ const opts = this.options;
1310
+ if (ast instanceof ErrorToken || !ast.valid) {
1311
+ throw new Error("AST node must be valid.");
1312
+ }
1313
+ const prefix = arguments[1];
1314
+ const groupValue = arguments[2];
1315
+ let operator2 = arguments[3];
1316
+ const self_ = this;
1317
+ if (ast instanceof ConditionNode) {
1318
+ if (!(ast.value instanceof GroupNode)) {
1319
+ const isValue = ast.value instanceof ArrayNode || ((_b = (_a = ast.value) == null ? void 0 : _a.quote) == null ? void 0 : _b.left.type) === TOKEN_TYPE.REGEX;
1320
+ let name = ast.property ? unescape(ast.property.value.value) : isValue ? void 0 : unescape((_c = ast.value) == null ? void 0 : _c.value.value);
1321
+ const isNested = operator2 !== void 0;
1322
+ if (prefix !== void 0 && !isNested) {
1323
+ name = name ? applyPrefix(prefix, name, opts.prefixApplier) : prefix;
1324
+ }
1325
+ let value;
1326
+ if (isNested) {
1327
+ value = name ?? true;
1328
+ name = prefix;
1329
+ } else {
1330
+ value = ast.value instanceof ArrayNode ? ast.value.values.map((val) => unescape(val.value.value)) : ((_e = (_d = ast.value) == null ? void 0 : _d.quote) == null ? void 0 : _e.left.type) === TOKEN_TYPE.REGEX ? ast.value.value.value : ast.property && ast.value instanceof VariableNode ? unescape(ast.value.value.value) : true;
1331
+ }
1332
+ const propertyKeys = name ? opts.keyParser(name) : [];
1333
+ const boolValue = applyBoolean(groupValue, ast.operator === void 0);
1334
+ const valuePrefix = ast.value instanceof VariableNode && ast.value.prefix ? unescape(ast.value.prefix.value) : void 0;
1335
+ operator2 ?? (operator2 = (_f = ast.propertyOperator) == null ? void 0 : _f.value);
1336
+ const isRegex = ((_h = (_g = ast.value) == null ? void 0 : _g.quote) == null ? void 0 : _h.left.type) === TOKEN_TYPE.REGEX;
1337
+ const isQuoted = ((_i = ast.value) == null ? void 0 : _i.quote) !== void 0;
1338
+ const isExpanded = ast.sep !== void 0;
1339
+ const regexFlags = (_l = (_k = (_j = ast.value) == null ? void 0 : _j.quote) == null ? void 0 : _k.flags) == null ? void 0 : _l.value;
1340
+ const query = {
1341
+ value,
1342
+ operator: operator2,
1343
+ prefix: valuePrefix,
1344
+ regexFlags,
1345
+ property: propertyKeys,
1346
+ isRegex,
1347
+ isQuoted,
1348
+ isExpanded,
1349
+ isNegated: !boolValue,
1350
+ condition: ast
1351
+ };
1352
+ const res = opts.conditionNormalizer(query);
1353
+ return new Condition({ property: propertyKeys, ...res });
1354
+ } else {
1355
+ let name = unescape(ast.property.value.value);
1356
+ if (prefix !== void 0) {
1357
+ name = applyPrefix(prefix, name, opts.prefixApplier);
1358
+ }
1359
+ const boolValue = applyBoolean(groupValue, ast.operator === void 0);
1360
+ const operator22 = (_m = ast.propertyOperator) == null ? void 0 : _m.value;
1361
+ return self_.normalize(ast.value, name, boolValue, operator22);
1362
+ }
1363
+ }
1364
+ if (ast instanceof GroupNode) {
1365
+ const _prefix = ast.prefix instanceof ConditionNode && ast.prefix.value instanceof VariableNode ? unescape(ast.prefix.value.value.value) : void 0;
1366
+ const _groupValue = ast.prefix instanceof ConditionNode ? ast.prefix.operator === void 0 : !(ast.prefix instanceof ValidToken);
1367
+ const applied = applyPrefix(prefix, _prefix ?? "", opts.prefixApplier);
1368
+ return self_.normalize(ast.expression, applied, applyBoolean(groupValue, _groupValue), operator2);
1369
+ }
1370
+ if (ast instanceof ExpressionNode) {
1371
+ const left = self_.normalize(ast.left, prefix, groupValue, operator2);
1372
+ const right = self_.normalize(ast.right, prefix, groupValue, operator2);
1373
+ const type = groupValue === false ? OPPOSITE[ast.operator.type] : ast.operator.type;
1374
+ return new Expression({ operator: type, left, right });
1375
+ }
1376
+ return unreachable();
1377
+ }
1378
+ /**
1379
+ * Allows pre-validating ASTs for syntax highlighting purposes.
1380
+ * Works similar to evaluate. Internally it will use the prefixApplier, keyParser, and valueValidator (instead of comparer).
1381
+ *
1382
+ * The context does not need to be passed. If it's not passed, the function will not attempt to get the values (so it will not error) and the contextValue param of the valueValidator will be undefined.
1383
+ */
1384
+ validate(ast, context) {
1385
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1386
+ const self = this;
1387
+ self._checkValidationOptions();
1388
+ const opts = self.options;
1389
+ if (ast instanceof ErrorToken || !ast.valid) {
1390
+ throw new Error("AST node must be valid.");
1391
+ }
1392
+ const prefix = arguments[2];
1393
+ const groupValue = arguments[3];
1394
+ const results = arguments[4] ?? [];
1395
+ const prefixes = arguments[5] ?? [];
1396
+ let operator2 = arguments[6];
1397
+ const self_ = this;
1398
+ if (ast instanceof ConditionNode) {
1399
+ if (!(ast.value instanceof GroupNode)) {
1400
+ const isValue = ast.value instanceof ArrayNode || ((_b = (_a = ast.value) == null ? void 0 : _a.quote) == null ? void 0 : _b.left.type) === TOKEN_TYPE.REGEX;
1401
+ const nameNode = ast.property ? ast.property : isValue ? void 0 : ast.value;
1402
+ let name = nameNode ? unescape(nameNode.value.value) : void 0;
1403
+ const isNested = operator2 !== void 0;
1404
+ if (prefix !== void 0 && !isNested) {
1405
+ name = name ? applyPrefix(prefix, name, opts.prefixApplier) : prefix;
1406
+ }
1407
+ let value;
1408
+ let propertyNodes = [];
1409
+ if (isNested) {
1410
+ value = name;
1411
+ name = prefix;
1412
+ propertyNodes = [...prefixes];
1413
+ } else {
1414
+ propertyNodes = [...prefixes, ...nameNode ? [nameNode] : []];
1415
+ value = ast.value instanceof ArrayNode ? ast.value.values : ((_d = (_c = ast.value) == null ? void 0 : _c.quote) == null ? void 0 : _d.left.type) === TOKEN_TYPE.REGEX ? ast.value : ast.property && ast.value instanceof VariableNode ? ast.value : true;
1416
+ }
1417
+ const propertyKeys = name ? opts.keyParser(name) : [];
1418
+ const contextValue = context !== void 0 ? get(context, propertyKeys) : void 0;
1419
+ const boolValue = applyBoolean(groupValue, ast.operator === void 0);
1420
+ const valuePrefix = ast.value instanceof VariableNode && ast.value.prefix ? ast.value.prefix : void 0;
1421
+ operator2 ?? (operator2 = ast.propertyOperator);
1422
+ const isRegex = ((_f = (_e = ast.value) == null ? void 0 : _e.quote) == null ? void 0 : _f.left.type) === TOKEN_TYPE.REGEX;
1423
+ const isQuoted = ((_g = ast.value) == null ? void 0 : _g.quote) !== void 0;
1424
+ const isExpanded = ast.sep !== void 0;
1425
+ const regexFlags = (_i = (_h = ast.value) == null ? void 0 : _h.quote) == null ? void 0 : _i.flags;
1426
+ const query = {
1427
+ value,
1428
+ operator: operator2,
1429
+ prefix: valuePrefix,
1430
+ prefixes,
1431
+ property: propertyNodes,
1432
+ propertyKeys,
1433
+ propertyName: name,
1434
+ regexFlags,
1435
+ isRegex,
1436
+ isNegated: !boolValue,
1437
+ isQuoted,
1438
+ isExpanded,
1439
+ condition: ast
1440
+ };
1441
+ const res = opts.valueValidator(contextValue, query, context);
1442
+ if (res && !isArray(res))
1443
+ throw new Error("The valueValidator must return an array or nothing/undefined");
1444
+ if (res) {
1445
+ for (const entry of res)
1446
+ results.push(entry);
1447
+ }
1448
+ } else {
1449
+ let name = unescape(ast.property.value.value);
1450
+ if (prefix !== void 0) {
1451
+ name = applyPrefix(prefix, name, opts.prefixApplier);
1452
+ }
1453
+ const boolValue = applyBoolean(groupValue, ast.operator === void 0);
1454
+ if (ast.property)
1455
+ prefixes.push(ast.property);
1456
+ const operator22 = ast.propertyOperator;
1457
+ self_.validate(ast.value, context, name, boolValue, results, prefixes, operator22);
1458
+ }
1459
+ }
1460
+ if (ast instanceof GroupNode) {
1461
+ const _prefix = ast.prefix instanceof ConditionNode && ast.prefix.value instanceof VariableNode ? ast.prefix.value : void 0;
1462
+ if (_prefix)
1463
+ prefixes.push(_prefix);
1464
+ const _groupValue = ast.prefix instanceof ConditionNode ? ast.prefix.operator === void 0 : !(ast.prefix instanceof ValidToken);
1465
+ self_.validate(ast.expression, context, applyPrefix(prefix, (_prefix == null ? void 0 : _prefix.value.value) ?? "", opts.prefixApplier), applyBoolean(groupValue, _groupValue), results, prefixes, operator2);
1466
+ }
1467
+ if (ast instanceof ExpressionNode) {
1468
+ self_.validate(ast.left, context, prefix, groupValue, results, [...prefixes], operator2);
1469
+ self_.validate(ast.right, context, prefix, groupValue, results, [...prefixes], operator2);
1470
+ }
1471
+ return results;
1472
+ }
1473
+ }
1474
+ export {
1475
+ Parser
1476
+ };