search-input-query-parser 0.1.3 → 0.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.
@@ -1,3 +1,4 @@
1
+ import { SearchQueryErrorCode } from "./validator";
1
2
  // Helper to validate numeric values
2
3
  const validateNumber = (value, position, errors) => {
3
4
  if (value === "")
@@ -5,6 +6,7 @@ const validateNumber = (value, position, errors) => {
5
6
  if (isNaN(Number(value))) {
6
7
  errors.push({
7
8
  message: "Invalid numeric value",
9
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
8
10
  position,
9
11
  length: value.length,
10
12
  });
@@ -29,6 +31,7 @@ const validateNumericRange = (start, end, basePosition, errors) => {
29
31
  if (startNum > endNum) {
30
32
  errors.push({
31
33
  message: "Range start must be less than or equal to range end",
34
+ code: SearchQueryErrorCode.RANGE_START_GREATER_THAN_END,
32
35
  position: basePosition,
33
36
  length: start.length + 2 + end.length,
34
37
  });
@@ -49,6 +52,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
49
52
  if (!allowedFields.has(expr.field.toLowerCase())) {
50
53
  errors.push({
51
54
  message: `Invalid field: "${expr.field}"`,
55
+ code: SearchQueryErrorCode.INVALID_FIELD_NAME,
56
+ value: expr.field,
52
57
  position: expr.position,
53
58
  length: expr.field.length,
54
59
  });
@@ -62,6 +67,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
62
67
  if (isNaN(Number(value))) {
63
68
  errors.push({
64
69
  message: "Invalid numeric value",
70
+ code: SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
65
71
  position: expr.position +
66
72
  expr.field.length +
67
73
  4 +
@@ -74,6 +80,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
74
80
  if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
75
81
  errors.push({
76
82
  message: "Invalid date format",
83
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
77
84
  position: expr.position +
78
85
  expr.field.length +
79
86
  3 +
@@ -92,6 +99,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
92
99
  const schema = schemas.get(expr.prefix.toLowerCase());
93
100
  if ((schema === null || schema === void 0 ? void 0 : schema.type) === "number" || (schema === null || schema === void 0 ? void 0 : schema.type) === "date") {
94
101
  errors.push({
102
+ code: SearchQueryErrorCode.WILDCARD_NOT_ALLOWED,
103
+ value: schema.type,
95
104
  message: `Wildcards are not allowed for ${schema.type} fields`,
96
105
  position: expr.position,
97
106
  length: expr.length,
@@ -108,6 +117,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
108
117
  if (!allowedFields.has(fieldName.toLowerCase()) && colonIndex > 0) {
109
118
  errors.push({
110
119
  message: `Invalid field: "${fieldName}"`,
120
+ code: SearchQueryErrorCode.INVALID_FIELD_NAME,
121
+ value: fieldName,
111
122
  position: expr.position,
112
123
  length: colonIndex,
113
124
  });
@@ -115,6 +126,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
115
126
  if (!value) {
116
127
  errors.push({
117
128
  message: "Expected field value",
129
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
118
130
  position: expr.position,
119
131
  length: colonIndex + 1,
120
132
  });
@@ -123,6 +135,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
123
135
  if (value.startsWith(":")) {
124
136
  errors.push({
125
137
  message: "Missing field name",
138
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
126
139
  position: expr.position,
127
140
  length: value.length + colonIndex + 1,
128
141
  });
@@ -137,6 +150,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
137
150
  if (value === ".." || value.includes("...")) {
138
151
  errors.push({
139
152
  message: "Invalid range format",
153
+ code: SearchQueryErrorCode.INVALID_RANGE_FORMAT,
140
154
  position: valueStartPosition,
141
155
  length: value.length,
142
156
  });
@@ -153,6 +167,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
153
167
  if (invalidOp.test(value)) {
154
168
  errors.push({
155
169
  message: "Invalid range operator",
170
+ code: SearchQueryErrorCode.INVALID_RANGE_OPERATOR,
156
171
  position: valueStartPosition,
157
172
  length: 3,
158
173
  });
@@ -161,6 +176,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
161
176
  if (!compValue) {
162
177
  errors.push({
163
178
  message: "Expected range value",
179
+ code: SearchQueryErrorCode.EXPECTED_RANGE_VALUE,
164
180
  position: valueStartPosition + operator.length,
165
181
  length: 0,
166
182
  });
@@ -188,6 +204,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
188
204
  if (!dateValidator(start) || !dateValidator(end)) {
189
205
  errors.push({
190
206
  message: "Invalid date format",
207
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
191
208
  position: valueStartPosition,
192
209
  length: value.length,
193
210
  });
@@ -201,6 +218,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
201
218
  if (!dateValidator(dateStr)) {
202
219
  errors.push({
203
220
  message: "Invalid date format",
221
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
204
222
  position: valueStartPosition,
205
223
  length: value.length,
206
224
  });
@@ -210,6 +228,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
210
228
  else if (!dateValidator(value)) {
211
229
  errors.push({
212
230
  message: "Invalid date format",
231
+ code: SearchQueryErrorCode.INVALID_DATE_FORMAT,
213
232
  position: valueStartPosition,
214
233
  length: value.length,
215
234
  });
@@ -1,9 +1,10 @@
1
- import { reservedWords } from "./validator";
1
+ import { reservedWords, SearchQueryErrorCode } from "./validator";
2
2
  export const validateInExpression = (expr, errors) => {
3
3
  // Validate field name pattern
4
4
  if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(expr.field)) {
5
5
  errors.push({
6
6
  message: "Invalid characters in field name",
7
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
7
8
  position: expr.position,
8
9
  length: expr.field.length,
9
10
  });
@@ -12,6 +13,8 @@ export const validateInExpression = (expr, errors) => {
12
13
  if (reservedWords.has(expr.field.toUpperCase())) {
13
14
  errors.push({
14
15
  message: `${expr.field} is a reserved word`,
16
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
17
+ value: expr.field,
15
18
  position: expr.position,
16
19
  length: expr.field.length,
17
20
  });
@@ -21,6 +24,7 @@ export const validateInExpression = (expr, errors) => {
21
24
  if (value.includes(",")) {
22
25
  errors.push({
23
26
  message: "Invalid character in IN value",
27
+ code: SearchQueryErrorCode.INVALID_IN_VALUE,
24
28
  position: expr.position + expr.field.length + 3 + index * (value.length + 1),
25
29
  length: value.length,
26
30
  });
@@ -1,4 +1,4 @@
1
- import { reservedWords } from "./validator";
1
+ import { reservedWords, SearchQueryErrorCode, } from "./validator";
2
2
  import { validateWildcard } from "./validate-wildcard";
3
3
  // Validate individual strings (field:value pairs or plain terms)
4
4
  export const validateString = (expr, errors) => {
@@ -13,6 +13,7 @@ export const validateString = (expr, errors) => {
13
13
  if (expr.value.endsWith(":")) {
14
14
  errors.push({
15
15
  message: "Expected field value",
16
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
16
17
  position: expr.position,
17
18
  length: expr.length,
18
19
  });
@@ -22,6 +23,7 @@ export const validateString = (expr, errors) => {
22
23
  if (expr.value.startsWith(":")) {
23
24
  errors.push({
24
25
  message: "Missing field name",
26
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
25
27
  position: expr.position,
26
28
  length: expr.length,
27
29
  });
@@ -34,6 +36,8 @@ export const validateString = (expr, errors) => {
34
36
  if (reservedWords.has(fieldName.toUpperCase())) {
35
37
  errors.push({
36
38
  message: `${fieldName} is a reserved word`,
39
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
40
+ value: fieldName,
37
41
  position: expr.position,
38
42
  length: fieldName.length,
39
43
  });
@@ -43,6 +47,7 @@ export const validateString = (expr, errors) => {
43
47
  if (!/^[a-zA-Z0-9_-]+$/.test(fieldName)) {
44
48
  errors.push({
45
49
  message: "Invalid characters in field name",
50
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
46
51
  position: expr.position,
47
52
  length: fieldName.length,
48
53
  });
@@ -54,6 +59,8 @@ export const validateString = (expr, errors) => {
54
59
  reservedWords.has(expr.value.toUpperCase())) {
55
60
  errors.push({
56
61
  message: `${expr.value} is a reserved word`,
62
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
63
+ value: expr.value,
57
64
  position: expr.position,
58
65
  length: expr.length,
59
66
  });
@@ -1,3 +1,4 @@
1
+ import { SearchQueryErrorCode } from "./validator";
1
2
  // Validates wildcard patterns
2
3
  export const validateWildcard = (expr, errors) => {
3
4
  const value = expr.type === "STRING" ? expr.value : expr.prefix + "*";
@@ -10,6 +11,7 @@ export const validateWildcard = (expr, errors) => {
10
11
  const secondStar = value.indexOf("*", firstStar + 1);
11
12
  errors.push({
12
13
  message: "Only one trailing wildcard (*) is allowed",
14
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
13
15
  position: expr.position + secondStar,
14
16
  length: 1,
15
17
  });
@@ -17,6 +19,7 @@ export const validateWildcard = (expr, errors) => {
17
19
  if ((firstStar !== -1 && firstStar !== value.length - 1) && !value.endsWith("**")) {
18
20
  errors.push({
19
21
  message: "Wildcard (*) can only appear at the end of a term",
22
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
20
23
  position: expr.position + firstStar,
21
24
  length: 1,
22
25
  });
@@ -28,6 +31,7 @@ export const validateWildcard = (expr, errors) => {
28
31
  if (value.endsWith("**")) {
29
32
  errors.push({
30
33
  message: "Only one trailing wildcard (*) is allowed",
34
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
31
35
  position: expr.position + value.length - 1,
32
36
  length: 1,
33
37
  });
@@ -1,5 +1,39 @@
1
1
  import { validateInExpression } from "./validate-in-expression";
2
2
  import { validateString } from "./validate-string";
3
+ export var SearchQueryErrorCode;
4
+ (function (SearchQueryErrorCode) {
5
+ // Syntax Errors (1000-1999)
6
+ SearchQueryErrorCode[SearchQueryErrorCode["UNTERMINATED_QUOTED_STRING"] = 1001] = "UNTERMINATED_QUOTED_STRING";
7
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_FIELD_VALUE"] = 1002] = "EXPECTED_FIELD_VALUE";
8
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_FIELD_NAME"] = 1003] = "MISSING_FIELD_NAME";
9
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_FIELD_VALUE"] = 1004] = "MISSING_FIELD_VALUE";
10
+ SearchQueryErrorCode[SearchQueryErrorCode["UNEXPECTED_RIGHT_PAREN"] = 1005] = "UNEXPECTED_RIGHT_PAREN";
11
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_RIGHT_PAREN"] = 1006] = "EXPECTED_RIGHT_PAREN";
12
+ SearchQueryErrorCode[SearchQueryErrorCode["UNEXPECTED_TOKEN"] = 1007] = "UNEXPECTED_TOKEN";
13
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_TOKEN"] = 1008] = "EXPECTED_TOKEN";
14
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_OPERATOR_OR_WHITESPACE"] = 1009] = "MISSING_OPERATOR_OR_WHITESPACE";
15
+ SearchQueryErrorCode[SearchQueryErrorCode["RESERVED_WORD"] = 1010] = "RESERVED_WORD";
16
+ // Field Validation Errors (2000-2999)
17
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_FIELD_NAME"] = 2001] = "INVALID_FIELD_NAME";
18
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_FIELD_CHARS"] = 2002] = "INVALID_FIELD_CHARS";
19
+ SearchQueryErrorCode[SearchQueryErrorCode["RESERVED_WORD_AS_FIELD"] = 2003] = "RESERVED_WORD_AS_FIELD";
20
+ // Value Validation Errors (3000-3999)
21
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_NUMERIC_VALUE"] = 3001] = "INVALID_NUMERIC_VALUE";
22
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_DATE_FORMAT"] = 3002] = "INVALID_DATE_FORMAT";
23
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_RANGE_FORMAT"] = 3003] = "INVALID_RANGE_FORMAT";
24
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_RANGE_OPERATOR"] = 3004] = "INVALID_RANGE_OPERATOR";
25
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_RANGE_VALUE"] = 3005] = "EXPECTED_RANGE_VALUE";
26
+ SearchQueryErrorCode[SearchQueryErrorCode["RANGE_START_GREATER_THAN_END"] = 3006] = "RANGE_START_GREATER_THAN_END";
27
+ SearchQueryErrorCode[SearchQueryErrorCode["WILDCARD_NOT_ALLOWED"] = 3007] = "WILDCARD_NOT_ALLOWED";
28
+ // Wildcard Errors (4000-4999)
29
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_WILDCARD_POSITION"] = 4001] = "INVALID_WILDCARD_POSITION";
30
+ SearchQueryErrorCode[SearchQueryErrorCode["MULTIPLE_WILDCARDS"] = 4002] = "MULTIPLE_WILDCARDS";
31
+ // IN Expression Errors (5000-5999)
32
+ SearchQueryErrorCode[SearchQueryErrorCode["EMPTY_IN_LIST"] = 5001] = "EMPTY_IN_LIST";
33
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_IN_VALUE"] = 5002] = "INVALID_IN_VALUE";
34
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_IN_SEPARATOR"] = 5003] = "EXPECTED_IN_SEPARATOR";
35
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_LPAREN_AFTER_IN"] = 5004] = "EXPECTED_LPAREN_AFTER_IN";
36
+ })(SearchQueryErrorCode || (SearchQueryErrorCode = {}));
3
37
  export const reservedWords = new Set(["AND", "OR"]);
4
38
  const walkExpression = (expr, errors) => {
5
39
  switch (expr.type) {
@@ -1,5 +1,5 @@
1
1
  import { PositionLength } from "./first-pass-parser";
2
- import { ValidationError } from "./validator";
2
+ import { ValidationError, SearchQueryErrorCode } from "./validator";
3
3
  interface FieldSchema {
4
4
  name: string;
5
5
  type: "string" | "number" | "date" | "boolean";
@@ -65,4 +65,4 @@ type SearchQueryError = {
65
65
  };
66
66
  declare const stringify: (expr: Expression) => string;
67
67
  export declare const parseSearchInputQuery: (input: string, fieldSchemas?: FieldSchema[]) => SearchQuery | SearchQueryError;
68
- export { type SearchQuery, type SearchQueryError, type Expression, type ValidationError, type FieldSchema, type RangeOperator, type RangeExpression, type WildcardPattern, type Value, stringify, };
68
+ export { type SearchQuery, type SearchQueryError, type Expression, type ValidationError, SearchQueryErrorCode, type FieldSchema, type RangeOperator, type RangeExpression, type WildcardPattern, type Value, stringify, };
@@ -1,6 +1,36 @@
1
1
  import { FirstPassExpression } from "./first-pass-parser";
2
+ export declare enum SearchQueryErrorCode {
3
+ UNTERMINATED_QUOTED_STRING = 1001,
4
+ EXPECTED_FIELD_VALUE = 1002,
5
+ MISSING_FIELD_NAME = 1003,
6
+ MISSING_FIELD_VALUE = 1004,
7
+ UNEXPECTED_RIGHT_PAREN = 1005,
8
+ EXPECTED_RIGHT_PAREN = 1006,
9
+ UNEXPECTED_TOKEN = 1007,
10
+ EXPECTED_TOKEN = 1008,
11
+ MISSING_OPERATOR_OR_WHITESPACE = 1009,
12
+ RESERVED_WORD = 1010,
13
+ INVALID_FIELD_NAME = 2001,
14
+ INVALID_FIELD_CHARS = 2002,
15
+ RESERVED_WORD_AS_FIELD = 2003,
16
+ INVALID_NUMERIC_VALUE = 3001,
17
+ INVALID_DATE_FORMAT = 3002,
18
+ INVALID_RANGE_FORMAT = 3003,
19
+ INVALID_RANGE_OPERATOR = 3004,
20
+ EXPECTED_RANGE_VALUE = 3005,
21
+ RANGE_START_GREATER_THAN_END = 3006,
22
+ WILDCARD_NOT_ALLOWED = 3007,
23
+ INVALID_WILDCARD_POSITION = 4001,
24
+ MULTIPLE_WILDCARDS = 4002,
25
+ EMPTY_IN_LIST = 5001,
26
+ INVALID_IN_VALUE = 5002,
27
+ EXPECTED_IN_SEPARATOR = 5003,
28
+ EXPECTED_LPAREN_AFTER_IN = 5004
29
+ }
2
30
  export type ValidationError = {
3
31
  message: string;
32
+ code: SearchQueryErrorCode;
33
+ value?: string;
4
34
  position: number;
5
35
  length: number;
6
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "search-input-query-parser",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "A parser for advanced search query syntax with field:value support",
5
5
  "keywords": [
6
6
  "search",
@@ -54,9 +54,10 @@
54
54
  "license": "ISC",
55
55
  "devDependencies": {
56
56
  "@types/jest": "^29.5.14",
57
- "@types/node": "^20.11.0",
57
+ "@types/node": "^22.10.1",
58
58
  "jest": "^29.7.0",
59
+ "npm-check-updates": "^17.1.11",
59
60
  "ts-jest": "^29.2.5",
60
- "typescript": "^5.3.3"
61
+ "typescript": "^5.7.2"
61
62
  }
62
- }
63
+ }
@@ -1,5 +1,6 @@
1
1
  import { TokenType, TokenStream, currentToken, advanceStream } from "./lexer";
2
2
  import { parsePrimary } from "./parse-primary";
3
+ import { SearchQueryErrorCode } from "./validator";
3
4
 
4
5
  // First Pass AST types (from tokenizer/parser)
5
6
  export type PositionLength = {
@@ -94,6 +95,8 @@ export const parseExpression = (
94
95
  if (nextToken.type === TokenType.EOF) {
95
96
  throw {
96
97
  message: `Unexpected token: ${token.value}`,
98
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
99
+ value: token.value,
97
100
  position: token.position,
98
101
  length: token.length,
99
102
  };
package/src/lexer.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { SearchQueryErrorCode } from "./validator";
2
+
1
3
  // Token types and data structures
2
4
  export enum TokenType {
3
5
  STRING = "STRING",
@@ -123,7 +125,12 @@ const tokenizeQuotedString = (
123
125
  }
124
126
  }
125
127
 
126
- throw { message: "Unterminated quoted string", position, length };
128
+ throw {
129
+ message: "Unterminated quoted string",
130
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
131
+ position,
132
+ length,
133
+ };
127
134
  };
128
135
 
129
136
  const tokenizeString = (input: string, position: number): [Token, number] => {
@@ -317,6 +324,7 @@ export const tokenize = (input: string): Token[] => {
317
324
  throw {
318
325
  message:
319
326
  "Invalid syntax: Missing operator or whitespace between terms",
327
+ code: SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
320
328
  position: position,
321
329
  length: 1,
322
330
  };
@@ -333,6 +341,7 @@ export const tokenize = (input: string): Token[] => {
333
341
  throw {
334
342
  message:
335
343
  "Invalid syntax: Missing operator or whitespace between terms",
344
+ code: SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
336
345
  position: newPos,
337
346
  length: 1,
338
347
  };
@@ -1,6 +1,6 @@
1
1
  import { ParseResult } from "./first-pass-parser";
2
2
  import { TokenStream, currentToken, TokenType, advanceStream } from "./lexer";
3
-
3
+ import { SearchQueryErrorCode } from "./validator";
4
4
 
5
5
  export const parseInValues = (
6
6
  stream: TokenStream,
@@ -13,6 +13,7 @@ export const parseInValues = (
13
13
  if (currentToken(currentStream).type !== TokenType.LPAREN) {
14
14
  throw {
15
15
  message: "Expected '(' after IN",
16
+ code: SearchQueryErrorCode.EXPECTED_LPAREN_AFTER_IN,
16
17
  position: inValuePosition, // Use the position passed from the caller
17
18
  length: 1,
18
19
  };
@@ -26,6 +27,7 @@ export const parseInValues = (
26
27
  if (values.length === 0) {
27
28
  throw {
28
29
  message: "IN operator requires at least one value",
30
+ code: SearchQueryErrorCode.EMPTY_IN_LIST,
29
31
  position: token.position,
30
32
  length: 1,
31
33
  };
@@ -43,6 +45,7 @@ export const parseInValues = (
43
45
  token.type !== TokenType.COMMA)) {
44
46
  throw {
45
47
  message: "Expected ',' or ')' after IN value",
48
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
46
49
  position: token.position,
47
50
  length: 1,
48
51
  };
@@ -64,6 +67,7 @@ export const parseInValues = (
64
67
  }
65
68
  throw {
66
69
  message: "Expected ',' or ')' after IN value",
70
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
67
71
  position: nextToken.position,
68
72
  length: 1,
69
73
  };
@@ -1,6 +1,7 @@
1
1
  import { ParseResult, FirstPassExpression, parseExpression } from "./first-pass-parser";
2
2
  import { parseInValues } from "./parse-in-values";
3
3
  import { TokenStream, currentToken, TokenType, advanceStream } from "./lexer";
4
+ import { SearchQueryErrorCode } from "./validator";
4
5
 
5
6
  export const expectToken = (
6
7
  stream: TokenStream,
@@ -11,6 +12,8 @@ export const expectToken = (
11
12
  if (token.type !== type) {
12
13
  throw {
13
14
  message: message ? message : `Expected ${type}`,
15
+ code: SearchQueryErrorCode.EXPECTED_TOKEN,
16
+ value: type,
14
17
  position: token.position,
15
18
  length: token.length,
16
19
  };
@@ -158,6 +161,8 @@ export const parsePrimary = (
158
161
  case TokenType.OR:
159
162
  throw {
160
163
  message: `${token.value} is a reserved word`,
164
+ code: SearchQueryErrorCode.RESERVED_WORD,
165
+ value: token.value,
161
166
  position: token.position,
162
167
  length: token.length,
163
168
  };
@@ -165,6 +170,7 @@ export const parsePrimary = (
165
170
  case TokenType.RPAREN:
166
171
  throw {
167
172
  message: 'Unexpected ")"',
173
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
168
174
  position: token.position,
169
175
  length: token.length,
170
176
  };
@@ -172,6 +178,7 @@ export const parsePrimary = (
172
178
  default:
173
179
  throw {
174
180
  message: "Unexpected token",
181
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
175
182
  position: token.position,
176
183
  length: token.length,
177
184
  };