search-input-query-parser 0.1.4 → 0.2.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.
@@ -1,5 +1,9 @@
1
1
  import { StringLiteral, WildcardPattern } from "./first-pass-parser";
2
- import { ValidationError, reservedWords } from "./validator";
2
+ import {
3
+ ValidationError,
4
+ reservedWords,
5
+ SearchQueryErrorCode,
6
+ } from "./validator";
3
7
  import { validateWildcard } from "./validate-wildcard";
4
8
 
5
9
  // Validate individual strings (field:value pairs or plain terms)
@@ -20,6 +24,7 @@ export const validateString = (
20
24
  if (expr.value.endsWith(":")) {
21
25
  errors.push({
22
26
  message: "Expected field value",
27
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
23
28
  position: expr.position,
24
29
  length: expr.length,
25
30
  });
@@ -30,6 +35,7 @@ export const validateString = (
30
35
  if (expr.value.startsWith(":")) {
31
36
  errors.push({
32
37
  message: "Missing field name",
38
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
33
39
  position: expr.position,
34
40
  length: expr.length,
35
41
  });
@@ -44,6 +50,8 @@ export const validateString = (
44
50
  if (reservedWords.has(fieldName.toUpperCase())) {
45
51
  errors.push({
46
52
  message: `${fieldName} is a reserved word`,
53
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
54
+ value: fieldName,
47
55
  position: expr.position,
48
56
  length: fieldName.length,
49
57
  });
@@ -54,6 +62,7 @@ export const validateString = (
54
62
  if (!/^[a-zA-Z0-9_-]+$/.test(fieldName)) {
55
63
  errors.push({
56
64
  message: "Invalid characters in field name",
65
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
57
66
  position: expr.position,
58
67
  length: fieldName.length,
59
68
  });
@@ -66,6 +75,8 @@ export const validateString = (
66
75
  reservedWords.has(expr.value.toUpperCase())) {
67
76
  errors.push({
68
77
  message: `${expr.value} is a reserved word`,
78
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
79
+ value: expr.value,
69
80
  position: expr.position,
70
81
  length: expr.length,
71
82
  });
@@ -1,5 +1,5 @@
1
1
  import { StringLiteral, WildcardPattern } from "./first-pass-parser";
2
- import { ValidationError } from "./validator";
2
+ import { ValidationError, SearchQueryErrorCode } from "./validator";
3
3
 
4
4
  // Validates wildcard patterns
5
5
 
@@ -18,6 +18,7 @@ export const validateWildcard = (
18
18
  const secondStar = value.indexOf("*", firstStar + 1);
19
19
  errors.push({
20
20
  message: "Only one trailing wildcard (*) is allowed",
21
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
21
22
  position: expr.position + secondStar,
22
23
  length: 1,
23
24
  });
@@ -25,6 +26,7 @@ export const validateWildcard = (
25
26
  if ((firstStar !== -1 && firstStar !== value.length - 1) && !value.endsWith("**")) {
26
27
  errors.push({
27
28
  message: "Wildcard (*) can only appear at the end of a term",
29
+ code: SearchQueryErrorCode.INVALID_WILDCARD_POSITION,
28
30
  position: expr.position + firstStar,
29
31
  length: 1,
30
32
  });
@@ -37,6 +39,7 @@ export const validateWildcard = (
37
39
  if (value.endsWith("**")) {
38
40
  errors.push({
39
41
  message: "Only one trailing wildcard (*) is allowed",
42
+ code: SearchQueryErrorCode.MULTIPLE_WILDCARDS,
40
43
  position: expr.position + value.length - 1,
41
44
  length: 1,
42
45
  });
@@ -1,5 +1,9 @@
1
1
  import { describe, expect, test } from "@jest/globals";
2
- import { validateSearchQuery, ValidationError } from "./validator";
2
+ import {
3
+ validateSearchQuery,
4
+ ValidationError,
5
+ SearchQueryErrorCode
6
+ } from "./validator";
3
7
  import { tokenize, createStream } from "./lexer";
4
8
  import { parseExpression } from "./first-pass-parser";
5
9
 
@@ -23,6 +27,7 @@ describe("Search Query Validator", () => {
23
27
  expect(validateQuery("special@field:value")).toEqual([
24
28
  {
25
29
  message: "Invalid characters in field name",
30
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
26
31
  position: 0,
27
32
  length: 13,
28
33
  },
@@ -33,6 +38,7 @@ describe("Search Query Validator", () => {
33
38
  expect(validateQuery("valid:value special!:value")).toEqual([
34
39
  {
35
40
  message: "Invalid characters in field name",
41
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
36
42
  position: 12,
37
43
  length: 8,
38
44
  },
@@ -45,6 +51,7 @@ describe("Search Query Validator", () => {
45
51
  expect(validateQuery("field:")).toEqual([
46
52
  {
47
53
  message: "Expected field value",
54
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
48
55
  position: 0,
49
56
  length: 6,
50
57
  },
@@ -60,6 +67,7 @@ describe("Search Query Validator", () => {
60
67
  expect(validateQuery(":value")).toEqual([
61
68
  {
62
69
  message: "Missing field name",
70
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
63
71
  position: 0,
64
72
  length: 6,
65
73
  },
@@ -72,6 +80,8 @@ describe("Search Query Validator", () => {
72
80
  expect(validateQuery("AND:value")).toEqual([
73
81
  {
74
82
  message: "AND is a reserved word",
83
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
84
+ value: "AND",
75
85
  position: 0,
76
86
  length: 3,
77
87
  },
@@ -80,6 +90,8 @@ describe("Search Query Validator", () => {
80
90
  expect(validateQuery("OR:value")).toEqual([
81
91
  {
82
92
  message: "OR is a reserved word",
93
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
94
+ value: "OR",
83
95
  position: 0,
84
96
  length: 2,
85
97
  },
@@ -104,6 +116,7 @@ describe("Search Query Validator", () => {
104
116
  expect(validateQuery("(field:value AND invalid!:value)")).toEqual([
105
117
  {
106
118
  message: "Invalid characters in field name",
119
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
107
120
  position: 17,
108
121
  length: 8,
109
122
  },
@@ -114,11 +127,14 @@ describe("Search Query Validator", () => {
114
127
  expect(validateQuery("AND:test OR invalid!:value")).toEqual([
115
128
  {
116
129
  message: "AND is a reserved word",
130
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
131
+ value: "AND",
117
132
  position: 0,
118
133
  length: 3,
119
134
  },
120
135
  {
121
136
  message: "Invalid characters in field name",
137
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
122
138
  position: 12,
123
139
  length: 8,
124
140
  },
@@ -131,6 +147,8 @@ describe("Search Query Validator", () => {
131
147
  ).toEqual([
132
148
  {
133
149
  message: "OR is a reserved word",
150
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
151
+ value: "OR",
134
152
  position: 18,
135
153
  length: 2,
136
154
  },
@@ -151,11 +169,13 @@ describe("Search Query Validator", () => {
151
169
  expect(validateQuery("field::value")).toEqual([
152
170
  {
153
171
  message: "Expected field value",
172
+ code: SearchQueryErrorCode.EXPECTED_FIELD_VALUE,
154
173
  position: 0,
155
174
  length: 6,
156
175
  },
157
176
  {
158
177
  message: "Missing field name",
178
+ code: SearchQueryErrorCode.MISSING_FIELD_NAME,
159
179
  position: 6,
160
180
  length: 6,
161
181
  }
@@ -166,6 +186,7 @@ describe("Search Query Validator", () => {
166
186
  expect(validateQuery("@#$:value")).toEqual([
167
187
  {
168
188
  message: "Invalid characters in field name",
189
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
169
190
  position: 0,
170
191
  length: 3,
171
192
  },
@@ -178,11 +199,14 @@ describe("Search Query Validator", () => {
178
199
  expect(validateQuery(complexQuery)).toEqual([
179
200
  {
180
201
  message: "Invalid characters in field name",
202
+ code: SearchQueryErrorCode.INVALID_FIELD_CHARS,
181
203
  position: 32,
182
204
  length: 8,
183
205
  },
184
206
  {
185
207
  message: "OR is a reserved word",
208
+ code: SearchQueryErrorCode.RESERVED_WORD_AS_FIELD,
209
+ value: "OR",
186
210
  position: 51,
187
211
  length: 2,
188
212
  },
package/src/validator.ts CHANGED
@@ -6,9 +6,51 @@ import { FieldSchema } from "./parser";
6
6
  import { validateInExpression } from "./validate-in-expression";
7
7
  import { validateString } from "./validate-string";
8
8
 
9
+ export enum SearchQueryErrorCode {
10
+ UNKNOWN_ERROR = 0,
11
+
12
+ // Syntax Errors (1000-1999)
13
+ UNTERMINATED_QUOTED_STRING = 1001,
14
+ EXPECTED_FIELD_VALUE = 1002,
15
+ MISSING_FIELD_NAME = 1003,
16
+ MISSING_FIELD_VALUE = 1004,
17
+ UNEXPECTED_RIGHT_PAREN = 1005,
18
+ EXPECTED_RIGHT_PAREN = 1006,
19
+ UNEXPECTED_TOKEN = 1007,
20
+ EXPECTED_TOKEN = 1008,
21
+ MISSING_OPERATOR_OR_WHITESPACE = 1009,
22
+ RESERVED_WORD = 1010,
23
+
24
+ // Field Validation Errors (2000-2999)
25
+ INVALID_FIELD_NAME = 2001,
26
+ INVALID_FIELD_CHARS = 2002,
27
+ RESERVED_WORD_AS_FIELD = 2003,
28
+
29
+ // Value Validation Errors (3000-3999)
30
+ INVALID_NUMERIC_VALUE = 3001,
31
+ INVALID_DATE_FORMAT = 3002,
32
+ INVALID_RANGE_FORMAT = 3003,
33
+ INVALID_RANGE_OPERATOR = 3004,
34
+ EXPECTED_RANGE_VALUE = 3005,
35
+ RANGE_START_GREATER_THAN_END = 3006,
36
+ WILDCARD_NOT_ALLOWED = 3007,
37
+
38
+ // Wildcard Errors (4000-4999)
39
+ INVALID_WILDCARD_POSITION = 4001,
40
+ MULTIPLE_WILDCARDS = 4002,
41
+
42
+ // IN Expression Errors (5000-5999)
43
+ EMPTY_IN_LIST = 5001,
44
+ INVALID_IN_VALUE = 5002,
45
+ EXPECTED_IN_SEPARATOR = 5003,
46
+ EXPECTED_LPAREN_AFTER_IN = 5004,
47
+ }
48
+
9
49
  // Validation error type
10
50
  export type ValidationError = {
11
51
  message: string;
52
+ code: SearchQueryErrorCode;
53
+ value?: string;
12
54
  position: number;
13
55
  length: number;
14
56
  };