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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseExpression = void 0;
4
4
  const lexer_1 = require("./lexer");
5
5
  const parse_primary_1 = require("./parse-primary");
6
+ const validator_1 = require("./validator");
6
7
  const getOperatorPrecedence = (type) => type === lexer_1.TokenType.AND ? 2 : type === lexer_1.TokenType.OR ? 1 : 0;
7
8
  const parseExpression = (stream, minPrecedence = 0) => {
8
9
  const token = (0, lexer_1.currentToken)(stream);
@@ -33,6 +34,8 @@ const parseExpression = (stream, minPrecedence = 0) => {
33
34
  if (nextToken.type === lexer_1.TokenType.EOF) {
34
35
  throw {
35
36
  message: `Unexpected token: ${token.value}`,
37
+ code: validator_1.SearchQueryErrorCode.UNEXPECTED_TOKEN,
38
+ value: token.value,
36
39
  position: token.position,
37
40
  length: token.length,
38
41
  };
package/dist/cjs/lexer.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tokenize = exports.advanceStream = exports.currentToken = exports.createStream = exports.TokenType = void 0;
4
+ const validator_1 = require("./validator");
4
5
  // Token types and data structures
5
6
  var TokenType;
6
7
  (function (TokenType) {
@@ -96,7 +97,12 @@ const tokenizeQuotedString = (input, position) => {
96
97
  pos++;
97
98
  }
98
99
  }
99
- throw { message: "Unterminated quoted string", position, length };
100
+ throw {
101
+ message: "Unterminated quoted string",
102
+ code: validator_1.SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
103
+ position,
104
+ length,
105
+ };
100
106
  };
101
107
  const tokenizeString = (input, position) => {
102
108
  let pos = position;
@@ -260,6 +266,7 @@ const tokenize = (input) => {
260
266
  prevToken.type === TokenType.STRING)) {
261
267
  throw {
262
268
  message: "Invalid syntax: Missing operator or whitespace between terms",
269
+ code: validator_1.SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
263
270
  position: position,
264
271
  length: 1,
265
272
  };
@@ -272,6 +279,7 @@ const tokenize = (input) => {
272
279
  !isSpecialChar(input[newPos])) {
273
280
  throw {
274
281
  message: "Invalid syntax: Missing operator or whitespace between terms",
282
+ code: validator_1.SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
275
283
  position: newPos,
276
284
  length: 1,
277
285
  };
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseInValues = void 0;
4
4
  const lexer_1 = require("./lexer");
5
+ const validator_1 = require("./validator");
5
6
  const parseInValues = (stream, inValuePosition) => {
6
7
  const values = [];
7
8
  let currentStream = stream;
@@ -9,6 +10,7 @@ const parseInValues = (stream, inValuePosition) => {
9
10
  if ((0, lexer_1.currentToken)(currentStream).type !== lexer_1.TokenType.LPAREN) {
10
11
  throw {
11
12
  message: "Expected '(' after IN",
13
+ code: validator_1.SearchQueryErrorCode.EXPECTED_LPAREN_AFTER_IN,
12
14
  position: inValuePosition, // Use the position passed from the caller
13
15
  length: 1,
14
16
  };
@@ -20,6 +22,7 @@ const parseInValues = (stream, inValuePosition) => {
20
22
  if (values.length === 0) {
21
23
  throw {
22
24
  message: "IN operator requires at least one value",
25
+ code: validator_1.SearchQueryErrorCode.EMPTY_IN_LIST,
23
26
  position: token.position,
24
27
  length: 1,
25
28
  };
@@ -36,6 +39,7 @@ const parseInValues = (stream, inValuePosition) => {
36
39
  token.type !== lexer_1.TokenType.COMMA)) {
37
40
  throw {
38
41
  message: "Expected ',' or ')' after IN value",
42
+ code: validator_1.SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
39
43
  position: token.position,
40
44
  length: 1,
41
45
  };
@@ -55,6 +59,7 @@ const parseInValues = (stream, inValuePosition) => {
55
59
  }
56
60
  throw {
57
61
  message: "Expected ',' or ')' after IN value",
62
+ code: validator_1.SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
58
63
  position: nextToken.position,
59
64
  length: 1,
60
65
  };
@@ -4,11 +4,14 @@ exports.parsePrimary = exports.extractFieldValue = exports.isFieldValuePattern =
4
4
  const first_pass_parser_1 = require("./first-pass-parser");
5
5
  const parse_in_values_1 = require("./parse-in-values");
6
6
  const lexer_1 = require("./lexer");
7
+ const validator_1 = require("./validator");
7
8
  const expectToken = (stream, type, message) => {
8
9
  const token = (0, lexer_1.currentToken)(stream);
9
10
  if (token.type !== type) {
10
11
  throw {
11
12
  message: message ? message : `Expected ${type}`,
13
+ code: validator_1.SearchQueryErrorCode.EXPECTED_TOKEN,
14
+ value: type,
12
15
  position: token.position,
13
16
  length: token.length,
14
17
  };
@@ -134,18 +137,22 @@ const parsePrimary = (stream) => {
134
137
  case lexer_1.TokenType.OR:
135
138
  throw {
136
139
  message: `${token.value} is a reserved word`,
140
+ code: validator_1.SearchQueryErrorCode.RESERVED_WORD,
141
+ value: token.value,
137
142
  position: token.position,
138
143
  length: token.length,
139
144
  };
140
145
  case lexer_1.TokenType.RPAREN:
141
146
  throw {
142
147
  message: 'Unexpected ")"',
148
+ code: validator_1.SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
143
149
  position: token.position,
144
150
  length: token.length,
145
151
  };
146
152
  default:
147
153
  throw {
148
154
  message: "Unexpected token",
155
+ code: validator_1.SearchQueryErrorCode.UNEXPECTED_TOKEN,
149
156
  position: token.position,
150
157
  length: token.length,
151
158
  };
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stringify = exports.parseSearchInputQuery = void 0;
3
+ exports.stringify = exports.SearchQueryErrorCode = exports.parseSearchInputQuery = void 0;
4
4
  const lexer_1 = require("./lexer");
5
5
  const first_pass_parser_1 = require("./first-pass-parser");
6
6
  const validator_1 = require("./validator");
7
+ Object.defineProperty(exports, "SearchQueryErrorCode", { enumerable: true, get: function () { return validator_1.SearchQueryErrorCode; } });
7
8
  const validate_expression_fields_1 = require("./validate-expression-fields");
8
9
  const transform_to_expression_1 = require("./transform-to-expression");
9
10
  // Helper function to stringify expressions
@@ -47,6 +48,7 @@ const parseSearchInputQuery = (input, fieldSchemas = []) => {
47
48
  if (finalToken.type !== lexer_1.TokenType.EOF) {
48
49
  throw {
49
50
  message: 'Unexpected ")"',
51
+ code: validator_1.SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
50
52
  position: finalToken.position,
51
53
  length: finalToken.length,
52
54
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateExpressionFields = void 0;
4
+ const validator_1 = require("./validator");
4
5
  // Helper to validate numeric values
5
6
  const validateNumber = (value, position, errors) => {
6
7
  if (value === "")
@@ -8,6 +9,7 @@ const validateNumber = (value, position, errors) => {
8
9
  if (isNaN(Number(value))) {
9
10
  errors.push({
10
11
  message: "Invalid numeric value",
12
+ code: validator_1.SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
11
13
  position,
12
14
  length: value.length,
13
15
  });
@@ -32,6 +34,7 @@ const validateNumericRange = (start, end, basePosition, errors) => {
32
34
  if (startNum > endNum) {
33
35
  errors.push({
34
36
  message: "Range start must be less than or equal to range end",
37
+ code: validator_1.SearchQueryErrorCode.RANGE_START_GREATER_THAN_END,
35
38
  position: basePosition,
36
39
  length: start.length + 2 + end.length,
37
40
  });
@@ -52,6 +55,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
52
55
  if (!allowedFields.has(expr.field.toLowerCase())) {
53
56
  errors.push({
54
57
  message: `Invalid field: "${expr.field}"`,
58
+ code: validator_1.SearchQueryErrorCode.INVALID_FIELD_NAME,
59
+ value: expr.field,
55
60
  position: expr.position,
56
61
  length: expr.field.length,
57
62
  });
@@ -65,6 +70,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
65
70
  if (isNaN(Number(value))) {
66
71
  errors.push({
67
72
  message: "Invalid numeric value",
73
+ code: validator_1.SearchQueryErrorCode.INVALID_NUMERIC_VALUE,
68
74
  position: expr.position +
69
75
  expr.field.length +
70
76
  4 +
@@ -77,6 +83,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
77
83
  if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
78
84
  errors.push({
79
85
  message: "Invalid date format",
86
+ code: validator_1.SearchQueryErrorCode.INVALID_DATE_FORMAT,
80
87
  position: expr.position +
81
88
  expr.field.length +
82
89
  3 +
@@ -95,6 +102,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
95
102
  const schema = schemas.get(expr.prefix.toLowerCase());
96
103
  if ((schema === null || schema === void 0 ? void 0 : schema.type) === "number" || (schema === null || schema === void 0 ? void 0 : schema.type) === "date") {
97
104
  errors.push({
105
+ code: validator_1.SearchQueryErrorCode.WILDCARD_NOT_ALLOWED,
106
+ value: schema.type,
98
107
  message: `Wildcards are not allowed for ${schema.type} fields`,
99
108
  position: expr.position,
100
109
  length: expr.length,
@@ -111,6 +120,8 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
111
120
  if (!allowedFields.has(fieldName.toLowerCase()) && colonIndex > 0) {
112
121
  errors.push({
113
122
  message: `Invalid field: "${fieldName}"`,
123
+ code: validator_1.SearchQueryErrorCode.INVALID_FIELD_NAME,
124
+ value: fieldName,
114
125
  position: expr.position,
115
126
  length: colonIndex,
116
127
  });
@@ -118,6 +129,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
118
129
  if (!value) {
119
130
  errors.push({
120
131
  message: "Expected field value",
132
+ code: validator_1.SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
121
133
  position: expr.position,
122
134
  length: colonIndex + 1,
123
135
  });
@@ -126,6 +138,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
126
138
  if (value.startsWith(":")) {
127
139
  errors.push({
128
140
  message: "Missing field name",
141
+ code: validator_1.SearchQueryErrorCode.MISSING_FIELD_NAME,
129
142
  position: expr.position,
130
143
  length: value.length + colonIndex + 1,
131
144
  });
@@ -140,6 +153,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
140
153
  if (value === ".." || value.includes("...")) {
141
154
  errors.push({
142
155
  message: "Invalid range format",
156
+ code: validator_1.SearchQueryErrorCode.INVALID_RANGE_FORMAT,
143
157
  position: valueStartPosition,
144
158
  length: value.length,
145
159
  });
@@ -156,6 +170,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
156
170
  if (invalidOp.test(value)) {
157
171
  errors.push({
158
172
  message: "Invalid range operator",
173
+ code: validator_1.SearchQueryErrorCode.INVALID_RANGE_OPERATOR,
159
174
  position: valueStartPosition,
160
175
  length: 3,
161
176
  });
@@ -164,6 +179,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
164
179
  if (!compValue) {
165
180
  errors.push({
166
181
  message: "Expected range value",
182
+ code: validator_1.SearchQueryErrorCode.EXPECTED_RANGE_VALUE,
167
183
  position: valueStartPosition + operator.length,
168
184
  length: 0,
169
185
  });
@@ -191,6 +207,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
191
207
  if (!dateValidator(start) || !dateValidator(end)) {
192
208
  errors.push({
193
209
  message: "Invalid date format",
210
+ code: validator_1.SearchQueryErrorCode.INVALID_DATE_FORMAT,
194
211
  position: valueStartPosition,
195
212
  length: value.length,
196
213
  });
@@ -204,6 +221,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
204
221
  if (!dateValidator(dateStr)) {
205
222
  errors.push({
206
223
  message: "Invalid date format",
224
+ code: validator_1.SearchQueryErrorCode.INVALID_DATE_FORMAT,
207
225
  position: valueStartPosition,
208
226
  length: value.length,
209
227
  });
@@ -213,6 +231,7 @@ const validateFieldValue = (expr, allowedFields, errors, schemas) => {
213
231
  else if (!dateValidator(value)) {
214
232
  errors.push({
215
233
  message: "Invalid date format",
234
+ code: validator_1.SearchQueryErrorCode.INVALID_DATE_FORMAT,
216
235
  position: valueStartPosition,
217
236
  length: value.length,
218
237
  });
@@ -7,6 +7,7 @@ const validateInExpression = (expr, errors) => {
7
7
  if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(expr.field)) {
8
8
  errors.push({
9
9
  message: "Invalid characters in field name",
10
+ code: validator_1.SearchQueryErrorCode.INVALID_FIELD_CHARS,
10
11
  position: expr.position,
11
12
  length: expr.field.length,
12
13
  });
@@ -15,6 +16,8 @@ const validateInExpression = (expr, errors) => {
15
16
  if (validator_1.reservedWords.has(expr.field.toUpperCase())) {
16
17
  errors.push({
17
18
  message: `${expr.field} is a reserved word`,
19
+ code: validator_1.SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
20
+ value: expr.field,
18
21
  position: expr.position,
19
22
  length: expr.field.length,
20
23
  });
@@ -24,6 +27,7 @@ const validateInExpression = (expr, errors) => {
24
27
  if (value.includes(",")) {
25
28
  errors.push({
26
29
  message: "Invalid character in IN value",
30
+ code: validator_1.SearchQueryErrorCode.INVALID_IN_VALUE,
27
31
  position: expr.position + expr.field.length + 3 + index * (value.length + 1),
28
32
  length: value.length,
29
33
  });
@@ -16,6 +16,7 @@ const validateString = (expr, errors) => {
16
16
  if (expr.value.endsWith(":")) {
17
17
  errors.push({
18
18
  message: "Expected field value",
19
+ code: validator_1.SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
19
20
  position: expr.position,
20
21
  length: expr.length,
21
22
  });
@@ -25,6 +26,7 @@ const validateString = (expr, errors) => {
25
26
  if (expr.value.startsWith(":")) {
26
27
  errors.push({
27
28
  message: "Missing field name",
29
+ code: validator_1.SearchQueryErrorCode.MISSING_FIELD_NAME,
28
30
  position: expr.position,
29
31
  length: expr.length,
30
32
  });
@@ -37,6 +39,8 @@ const validateString = (expr, errors) => {
37
39
  if (validator_1.reservedWords.has(fieldName.toUpperCase())) {
38
40
  errors.push({
39
41
  message: `${fieldName} is a reserved word`,
42
+ code: validator_1.SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
43
+ value: fieldName,
40
44
  position: expr.position,
41
45
  length: fieldName.length,
42
46
  });
@@ -46,6 +50,7 @@ const validateString = (expr, errors) => {
46
50
  if (!/^[a-zA-Z0-9_-]+$/.test(fieldName)) {
47
51
  errors.push({
48
52
  message: "Invalid characters in field name",
53
+ code: validator_1.SearchQueryErrorCode.INVALID_FIELD_CHARS,
49
54
  position: expr.position,
50
55
  length: fieldName.length,
51
56
  });
@@ -57,6 +62,8 @@ const validateString = (expr, errors) => {
57
62
  validator_1.reservedWords.has(expr.value.toUpperCase())) {
58
63
  errors.push({
59
64
  message: `${expr.value} is a reserved word`,
65
+ code: validator_1.SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
66
+ value: expr.value,
60
67
  position: expr.position,
61
68
  length: expr.length,
62
69
  });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateWildcard = void 0;
4
+ const validator_1 = require("./validator");
4
5
  // Validates wildcard patterns
5
6
  const validateWildcard = (expr, errors) => {
6
7
  const value = expr.type === "STRING" ? expr.value : expr.prefix + "*";
@@ -13,6 +14,7 @@ const validateWildcard = (expr, errors) => {
13
14
  const secondStar = value.indexOf("*", firstStar + 1);
14
15
  errors.push({
15
16
  message: "Only one trailing wildcard (*) is allowed",
17
+ code: validator_1.SearchQueryErrorCode.MULTIPLE_WILDCARDS,
16
18
  position: expr.position + secondStar,
17
19
  length: 1,
18
20
  });
@@ -20,6 +22,7 @@ const validateWildcard = (expr, errors) => {
20
22
  if ((firstStar !== -1 && firstStar !== value.length - 1) && !value.endsWith("**")) {
21
23
  errors.push({
22
24
  message: "Wildcard (*) can only appear at the end of a term",
25
+ code: validator_1.SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
23
26
  position: expr.position + firstStar,
24
27
  length: 1,
25
28
  });
@@ -31,6 +34,7 @@ const validateWildcard = (expr, errors) => {
31
34
  if (value.endsWith("**")) {
32
35
  errors.push({
33
36
  message: "Only one trailing wildcard (*) is allowed",
37
+ code: validator_1.SearchQueryErrorCode.MULTIPLE_WILDCARDS,
34
38
  position: expr.position + value.length - 1,
35
39
  length: 1,
36
40
  });
@@ -1,8 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateSearchQuery = exports.reservedWords = void 0;
3
+ exports.validateSearchQuery = exports.reservedWords = exports.SearchQueryErrorCode = void 0;
4
4
  const validate_in_expression_1 = require("./validate-in-expression");
5
5
  const validate_string_1 = require("./validate-string");
6
+ var SearchQueryErrorCode;
7
+ (function (SearchQueryErrorCode) {
8
+ // Syntax Errors (1000-1999)
9
+ SearchQueryErrorCode[SearchQueryErrorCode["UNTERMINATED_QUOTED_STRING"] = 1001] = "UNTERMINATED_QUOTED_STRING";
10
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_FIELD_VALUE"] = 1002] = "EXPECTED_FIELD_VALUE";
11
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_FIELD_NAME"] = 1003] = "MISSING_FIELD_NAME";
12
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_FIELD_VALUE"] = 1004] = "MISSING_FIELD_VALUE";
13
+ SearchQueryErrorCode[SearchQueryErrorCode["UNEXPECTED_RIGHT_PAREN"] = 1005] = "UNEXPECTED_RIGHT_PAREN";
14
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_RIGHT_PAREN"] = 1006] = "EXPECTED_RIGHT_PAREN";
15
+ SearchQueryErrorCode[SearchQueryErrorCode["UNEXPECTED_TOKEN"] = 1007] = "UNEXPECTED_TOKEN";
16
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_TOKEN"] = 1008] = "EXPECTED_TOKEN";
17
+ SearchQueryErrorCode[SearchQueryErrorCode["MISSING_OPERATOR_OR_WHITESPACE"] = 1009] = "MISSING_OPERATOR_OR_WHITESPACE";
18
+ SearchQueryErrorCode[SearchQueryErrorCode["RESERVED_WORD"] = 1010] = "RESERVED_WORD";
19
+ // Field Validation Errors (2000-2999)
20
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_FIELD_NAME"] = 2001] = "INVALID_FIELD_NAME";
21
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_FIELD_CHARS"] = 2002] = "INVALID_FIELD_CHARS";
22
+ SearchQueryErrorCode[SearchQueryErrorCode["RESERVED_WORD_AS_FIELD"] = 2003] = "RESERVED_WORD_AS_FIELD";
23
+ // Value Validation Errors (3000-3999)
24
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_NUMERIC_VALUE"] = 3001] = "INVALID_NUMERIC_VALUE";
25
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_DATE_FORMAT"] = 3002] = "INVALID_DATE_FORMAT";
26
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_RANGE_FORMAT"] = 3003] = "INVALID_RANGE_FORMAT";
27
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_RANGE_OPERATOR"] = 3004] = "INVALID_RANGE_OPERATOR";
28
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_RANGE_VALUE"] = 3005] = "EXPECTED_RANGE_VALUE";
29
+ SearchQueryErrorCode[SearchQueryErrorCode["RANGE_START_GREATER_THAN_END"] = 3006] = "RANGE_START_GREATER_THAN_END";
30
+ SearchQueryErrorCode[SearchQueryErrorCode["WILDCARD_NOT_ALLOWED"] = 3007] = "WILDCARD_NOT_ALLOWED";
31
+ // Wildcard Errors (4000-4999)
32
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_WILDCARD_POSITION"] = 4001] = "INVALID_WILDCARD_POSITION";
33
+ SearchQueryErrorCode[SearchQueryErrorCode["MULTIPLE_WILDCARDS"] = 4002] = "MULTIPLE_WILDCARDS";
34
+ // IN Expression Errors (5000-5999)
35
+ SearchQueryErrorCode[SearchQueryErrorCode["EMPTY_IN_LIST"] = 5001] = "EMPTY_IN_LIST";
36
+ SearchQueryErrorCode[SearchQueryErrorCode["INVALID_IN_VALUE"] = 5002] = "INVALID_IN_VALUE";
37
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_IN_SEPARATOR"] = 5003] = "EXPECTED_IN_SEPARATOR";
38
+ SearchQueryErrorCode[SearchQueryErrorCode["EXPECTED_LPAREN_AFTER_IN"] = 5004] = "EXPECTED_LPAREN_AFTER_IN";
39
+ })(SearchQueryErrorCode || (exports.SearchQueryErrorCode = SearchQueryErrorCode = {}));
6
40
  exports.reservedWords = new Set(["AND", "OR"]);
7
41
  const walkExpression = (expr, errors) => {
8
42
  switch (expr.type) {
@@ -1,5 +1,6 @@
1
1
  import { TokenType, currentToken, advanceStream } from "./lexer";
2
2
  import { parsePrimary } from "./parse-primary";
3
+ import { SearchQueryErrorCode } from "./validator";
3
4
  const getOperatorPrecedence = (type) => type === TokenType.AND ? 2 : type === TokenType.OR ? 1 : 0;
4
5
  export const parseExpression = (stream, minPrecedence = 0) => {
5
6
  const token = currentToken(stream);
@@ -30,6 +31,8 @@ export const parseExpression = (stream, minPrecedence = 0) => {
30
31
  if (nextToken.type === TokenType.EOF) {
31
32
  throw {
32
33
  message: `Unexpected token: ${token.value}`,
34
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
35
+ value: token.value,
33
36
  position: token.position,
34
37
  length: token.length,
35
38
  };
package/dist/esm/lexer.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { SearchQueryErrorCode } from "./validator";
1
2
  // Token types and data structures
2
3
  export var TokenType;
3
4
  (function (TokenType) {
@@ -90,7 +91,12 @@ const tokenizeQuotedString = (input, position) => {
90
91
  pos++;
91
92
  }
92
93
  }
93
- throw { message: "Unterminated quoted string", position, length };
94
+ throw {
95
+ message: "Unterminated quoted string",
96
+ code: SearchQueryErrorCode.UNTERMINATED_QUOTED_STRING,
97
+ position,
98
+ length,
99
+ };
94
100
  };
95
101
  const tokenizeString = (input, position) => {
96
102
  let pos = position;
@@ -254,6 +260,7 @@ export const tokenize = (input) => {
254
260
  prevToken.type === TokenType.STRING)) {
255
261
  throw {
256
262
  message: "Invalid syntax: Missing operator or whitespace between terms",
263
+ code: SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
257
264
  position: position,
258
265
  length: 1,
259
266
  };
@@ -266,6 +273,7 @@ export const tokenize = (input) => {
266
273
  !isSpecialChar(input[newPos])) {
267
274
  throw {
268
275
  message: "Invalid syntax: Missing operator or whitespace between terms",
276
+ code: SearchQueryErrorCode.MISSING_OPERATOR_OR_WHITESPACE,
269
277
  position: newPos,
270
278
  length: 1,
271
279
  };
@@ -1,4 +1,5 @@
1
1
  import { currentToken, TokenType, advanceStream } from "./lexer";
2
+ import { SearchQueryErrorCode } from "./validator";
2
3
  export const parseInValues = (stream, inValuePosition) => {
3
4
  const values = [];
4
5
  let currentStream = stream;
@@ -6,6 +7,7 @@ export const parseInValues = (stream, inValuePosition) => {
6
7
  if (currentToken(currentStream).type !== TokenType.LPAREN) {
7
8
  throw {
8
9
  message: "Expected '(' after IN",
10
+ code: SearchQueryErrorCode.EXPECTED_LPAREN_AFTER_IN,
9
11
  position: inValuePosition, // Use the position passed from the caller
10
12
  length: 1,
11
13
  };
@@ -17,6 +19,7 @@ export const parseInValues = (stream, inValuePosition) => {
17
19
  if (values.length === 0) {
18
20
  throw {
19
21
  message: "IN operator requires at least one value",
22
+ code: SearchQueryErrorCode.EMPTY_IN_LIST,
20
23
  position: token.position,
21
24
  length: 1,
22
25
  };
@@ -33,6 +36,7 @@ export const parseInValues = (stream, inValuePosition) => {
33
36
  token.type !== TokenType.COMMA)) {
34
37
  throw {
35
38
  message: "Expected ',' or ')' after IN value",
39
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
36
40
  position: token.position,
37
41
  length: 1,
38
42
  };
@@ -52,6 +56,7 @@ export const parseInValues = (stream, inValuePosition) => {
52
56
  }
53
57
  throw {
54
58
  message: "Expected ',' or ')' after IN value",
59
+ code: SearchQueryErrorCode.EXPECTED_IN_SEPARATOR,
55
60
  position: nextToken.position,
56
61
  length: 1,
57
62
  };
@@ -1,11 +1,14 @@
1
1
  import { parseExpression } from "./first-pass-parser";
2
2
  import { parseInValues } from "./parse-in-values";
3
3
  import { currentToken, TokenType, advanceStream } from "./lexer";
4
+ import { SearchQueryErrorCode } from "./validator";
4
5
  export const expectToken = (stream, type, message) => {
5
6
  const token = currentToken(stream);
6
7
  if (token.type !== type) {
7
8
  throw {
8
9
  message: message ? message : `Expected ${type}`,
10
+ code: SearchQueryErrorCode.EXPECTED_TOKEN,
11
+ value: type,
9
12
  position: token.position,
10
13
  length: token.length,
11
14
  };
@@ -128,18 +131,22 @@ export const parsePrimary = (stream) => {
128
131
  case TokenType.OR:
129
132
  throw {
130
133
  message: `${token.value} is a reserved word`,
134
+ code: SearchQueryErrorCode.RESERVED_WORD,
135
+ value: token.value,
131
136
  position: token.position,
132
137
  length: token.length,
133
138
  };
134
139
  case TokenType.RPAREN:
135
140
  throw {
136
141
  message: 'Unexpected ")"',
142
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
137
143
  position: token.position,
138
144
  length: token.length,
139
145
  };
140
146
  default:
141
147
  throw {
142
148
  message: "Unexpected token",
149
+ code: SearchQueryErrorCode.UNEXPECTED_TOKEN,
143
150
  position: token.position,
144
151
  length: token.length,
145
152
  };
@@ -1,6 +1,6 @@
1
1
  import { tokenize, createStream, currentToken, TokenType } from "./lexer";
2
2
  import { parseExpression, } from "./first-pass-parser";
3
- import { validateSearchQuery } from "./validator";
3
+ import { validateSearchQuery, SearchQueryErrorCode, } from "./validator";
4
4
  import { validateExpressionFields } from "./validate-expression-fields";
5
5
  import { transformToExpression } from "./transform-to-expression";
6
6
  // Helper function to stringify expressions
@@ -43,6 +43,7 @@ export const parseSearchInputQuery = (input, fieldSchemas = []) => {
43
43
  if (finalToken.type !== TokenType.EOF) {
44
44
  throw {
45
45
  message: 'Unexpected ")"',
46
+ code: SearchQueryErrorCode.UNEXPECTED_RIGHT_PAREN,
46
47
  position: finalToken.position,
47
48
  length: finalToken.length,
48
49
  };
@@ -78,4 +79,4 @@ export const parseSearchInputQuery = (input, fieldSchemas = []) => {
78
79
  };
79
80
  }
80
81
  };
81
- export { stringify, };
82
+ export { SearchQueryErrorCode, stringify, };