qast 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +428 -0
  3. package/dist/adapters/prisma.d.ts +12 -0
  4. package/dist/adapters/prisma.d.ts.map +1 -0
  5. package/dist/adapters/prisma.js +132 -0
  6. package/dist/adapters/prisma.js.map +1 -0
  7. package/dist/adapters/sequelize.d.ts +37 -0
  8. package/dist/adapters/sequelize.d.ts.map +1 -0
  9. package/dist/adapters/sequelize.js +166 -0
  10. package/dist/adapters/sequelize.js.map +1 -0
  11. package/dist/adapters/typeorm.d.ts +18 -0
  12. package/dist/adapters/typeorm.d.ts.map +1 -0
  13. package/dist/adapters/typeorm.js +112 -0
  14. package/dist/adapters/typeorm.js.map +1 -0
  15. package/dist/errors.d.ts +35 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +61 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.d.ts +38 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +78 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/parser/parser.d.ts +49 -0
  24. package/dist/parser/parser.d.ts.map +1 -0
  25. package/dist/parser/parser.js +148 -0
  26. package/dist/parser/parser.js.map +1 -0
  27. package/dist/parser/tokenizer.d.ts +73 -0
  28. package/dist/parser/tokenizer.d.ts.map +1 -0
  29. package/dist/parser/tokenizer.js +352 -0
  30. package/dist/parser/tokenizer.js.map +1 -0
  31. package/dist/parser/validator.d.ts +14 -0
  32. package/dist/parser/validator.d.ts.map +1 -0
  33. package/dist/parser/validator.js +94 -0
  34. package/dist/parser/validator.js.map +1 -0
  35. package/dist/types/ast.d.ts +72 -0
  36. package/dist/types/ast.d.ts.map +1 -0
  37. package/dist/types/ast.js +17 -0
  38. package/dist/types/ast.js.map +1 -0
  39. package/package.json +72 -0
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toSequelizeFilter = toSequelizeFilter;
4
+ const ast_1 = require("../types/ast");
5
+ /**
6
+ * Transform a QAST AST node to a Sequelize filter
7
+ *
8
+ * IMPORTANT: Sequelize uses the Op object from 'sequelize', not $ operators.
9
+ * This adapter returns a structure with metadata that you need to transform.
10
+ *
11
+ * Example usage:
12
+ * ```ts
13
+ * import { Op } from 'sequelize';
14
+ * import { toSequelizeFilter } from 'qast';
15
+ *
16
+ * const filter = toSequelizeFilter(ast);
17
+ * // Returns a structure like:
18
+ * // { age: { __qast_operator__: 'gt', value: 25 } }
19
+ * // You need to transform it:
20
+ * // { age: { [Op.gt]: 25 } }
21
+ * ```
22
+ *
23
+ * For simple equality (eq operator), you can use plain values directly.
24
+ */
25
+ function toSequelizeFilter(ast) {
26
+ return transformNode(ast);
27
+ }
28
+ /**
29
+ * Transform a node to Sequelize format
30
+ */
31
+ function transformNode(node) {
32
+ if ((0, ast_1.isComparisonNode)(node)) {
33
+ return transformComparisonNode(node);
34
+ }
35
+ else if ((0, ast_1.isLogicalNode)(node)) {
36
+ return transformLogicalNode(node);
37
+ }
38
+ throw new Error('Invalid node type');
39
+ }
40
+ /**
41
+ * Transform a comparison node to Sequelize format
42
+ *
43
+ * Sequelize uses Op operators from 'sequelize' package.
44
+ * Since we cannot import Op (optional peer dependency), we return metadata
45
+ * that users can transform to use Op operators.
46
+ *
47
+ * For equality (eq), Sequelize accepts plain values, so we return them directly.
48
+ * For other operators, we return metadata that indicates the operator type.
49
+ */
50
+ function transformComparisonNode(node) {
51
+ const { field, op, value } = node;
52
+ // For equality, Sequelize accepts plain values
53
+ if (op === 'eq') {
54
+ return { [field]: value };
55
+ }
56
+ // For other operators, return metadata that can be transformed to use Op
57
+ // Users need to import Op from 'sequelize' and transform:
58
+ // { __qast_operator__: 'gt', value: 25 } -> { [Op.gt]: 25 }
59
+ switch (op) {
60
+ case 'ne':
61
+ return { [field]: { __qast_operator__: 'ne', value } };
62
+ case 'gt':
63
+ return { [field]: { __qast_operator__: 'gt', value } };
64
+ case 'lt':
65
+ return { [field]: { __qast_operator__: 'lt', value } };
66
+ case 'gte':
67
+ return { [field]: { __qast_operator__: 'gte', value } };
68
+ case 'lte':
69
+ return { [field]: { __qast_operator__: 'lte', value } };
70
+ case 'in':
71
+ return { [field]: { __qast_operator__: 'in', value } };
72
+ case 'contains':
73
+ // Sequelize uses Op.like for contains with wildcards
74
+ return { [field]: { __qast_operator__: 'contains', value } };
75
+ default:
76
+ throw new Error(`Unsupported operator: ${op}`);
77
+ }
78
+ }
79
+ /**
80
+ * Transform a logical node to Sequelize format
81
+ *
82
+ * Sequelize uses Op.and and Op.or for logical operations.
83
+ * Since we cannot import Op, we return metadata that indicates the logical operation.
84
+ *
85
+ * Users need to transform: { __qast_logical__: 'and', conditions: [...] }
86
+ * to: { [Op.and]: [...] }
87
+ */
88
+ function transformLogicalNode(node) {
89
+ const leftFilter = transformNode(node.left);
90
+ const rightFilter = transformNode(node.right);
91
+ // Handle nested logical operations
92
+ // Check if either side already has logical operation metadata
93
+ const leftLogical = leftFilter.__qast_logical__;
94
+ const rightLogical = rightFilter.__qast_logical__;
95
+ if (node.type === 'AND') {
96
+ // For AND, combine conditions
97
+ if (leftLogical === 'and' && rightLogical === 'and') {
98
+ // Both have AND, merge their conditions
99
+ const leftConditions = leftFilter.conditions;
100
+ const rightConditions = rightFilter.conditions;
101
+ return {
102
+ __qast_logical__: 'and',
103
+ conditions: [...leftConditions, ...rightConditions],
104
+ };
105
+ }
106
+ else if (leftLogical === 'and') {
107
+ // Left has AND, add right to it
108
+ const leftConditions = leftFilter.conditions;
109
+ return {
110
+ __qast_logical__: 'and',
111
+ conditions: [...leftConditions, rightFilter],
112
+ };
113
+ }
114
+ else if (rightLogical === 'and') {
115
+ // Right has AND, add left to it
116
+ const rightConditions = rightFilter.conditions;
117
+ return {
118
+ __qast_logical__: 'and',
119
+ conditions: [leftFilter, ...rightConditions],
120
+ };
121
+ }
122
+ else {
123
+ // Neither has AND, create new AND array
124
+ return {
125
+ __qast_logical__: 'and',
126
+ conditions: [leftFilter, rightFilter],
127
+ };
128
+ }
129
+ }
130
+ else {
131
+ // For OR, combine conditions
132
+ if (leftLogical === 'or' && rightLogical === 'or') {
133
+ // Both have OR, merge their conditions
134
+ const leftConditions = leftFilter.conditions;
135
+ const rightConditions = rightFilter.conditions;
136
+ return {
137
+ __qast_logical__: 'or',
138
+ conditions: [...leftConditions, ...rightConditions],
139
+ };
140
+ }
141
+ else if (leftLogical === 'or') {
142
+ // Left has OR, add right to it
143
+ const leftConditions = leftFilter.conditions;
144
+ return {
145
+ __qast_logical__: 'or',
146
+ conditions: [...leftConditions, rightFilter],
147
+ };
148
+ }
149
+ else if (rightLogical === 'or') {
150
+ // Right has OR, add left to it
151
+ const rightConditions = rightFilter.conditions;
152
+ return {
153
+ __qast_logical__: 'or',
154
+ conditions: [leftFilter, ...rightConditions],
155
+ };
156
+ }
157
+ else {
158
+ // Neither has OR, create new OR array
159
+ return {
160
+ __qast_logical__: 'or',
161
+ conditions: [leftFilter, rightFilter],
162
+ };
163
+ }
164
+ }
165
+ }
166
+ //# sourceMappingURL=sequelize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sequelize.js","sourceRoot":"","sources":["../../src/adapters/sequelize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { QastNode } from '../types/ast';
2
+ /**
3
+ * TypeORM filter type
4
+ * Note: This returns a plain object that can be used with TypeORM's FindOptions
5
+ * In practice, TypeORM users may need to import operators from 'typeorm'
6
+ */
7
+ export type TypeORMFilter = {
8
+ where: Record<string, any> | Array<Record<string, any>>;
9
+ };
10
+ /**
11
+ * Transform a QAST AST node to a TypeORM filter
12
+ *
13
+ * Note: TypeORM uses operator functions like MoreThan(), LessThan(), etc.
14
+ * This adapter returns a structure that can be used with TypeORM's FindOptions.
15
+ * For production use, users may need to wrap values with TypeORM operators.
16
+ */
17
+ export declare function toTypeORMFilter(ast: QastNode): TypeORMFilter;
18
+ //# sourceMappingURL=typeorm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeorm.d.ts","sourceRoot":"","sources":["../../src/adapters/typeorm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgE,MAAM,cAAc,CAAC;AAEtG;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;CACzD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,aAAa,CAG5D"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toTypeORMFilter = toTypeORMFilter;
4
+ const ast_1 = require("../types/ast");
5
+ /**
6
+ * Transform a QAST AST node to a TypeORM filter
7
+ *
8
+ * Note: TypeORM uses operator functions like MoreThan(), LessThan(), etc.
9
+ * This adapter returns a structure that can be used with TypeORM's FindOptions.
10
+ * For production use, users may need to wrap values with TypeORM operators.
11
+ */
12
+ function toTypeORMFilter(ast) {
13
+ const where = transformNode(ast);
14
+ return { where };
15
+ }
16
+ /**
17
+ * Transform a node to TypeORM format
18
+ */
19
+ function transformNode(node) {
20
+ if ((0, ast_1.isComparisonNode)(node)) {
21
+ return transformComparisonNode(node);
22
+ }
23
+ else if ((0, ast_1.isLogicalNode)(node)) {
24
+ return transformLogicalNode(node);
25
+ }
26
+ throw new Error('Invalid node type');
27
+ }
28
+ /**
29
+ * Transform a comparison node to TypeORM format
30
+ *
31
+ * TypeORM uses operator functions from 'typeorm' package.
32
+ * Since we don't want to import TypeORM directly (optional peer dependency),
33
+ * we return a structure with metadata that can be used to build TypeORM FindOptions.
34
+ *
35
+ * For simple equality (eq), TypeORM accepts plain values.
36
+ * For other operators, users should use TypeORM operators like MoreThan(), LessThan(), etc.
37
+ *
38
+ * This function returns an object with an __qast_operator__ property that indicates
39
+ * the operator type. Users can transform this to use TypeORM operators.
40
+ */
41
+ function transformComparisonNode(node) {
42
+ const { field, op, value } = node;
43
+ // Map operators to TypeORM-compatible format
44
+ // For eq, use direct value (TypeORM supports this)
45
+ // For other operators, include metadata for transformation
46
+ switch (op) {
47
+ case 'eq':
48
+ // Direct equality - TypeORM accepts this
49
+ return { [field]: value };
50
+ case 'ne':
51
+ // Not equal - requires Not(Equal(value)) from TypeORM
52
+ return { [field]: { __qast_operator__: 'ne', value } };
53
+ case 'gt':
54
+ // More than - requires MoreThan(value) from TypeORM
55
+ return { [field]: { __qast_operator__: 'gt', value } };
56
+ case 'lt':
57
+ // Less than - requires LessThan(value) from TypeORM
58
+ return { [field]: { __qast_operator__: 'lt', value } };
59
+ case 'gte':
60
+ // More than or equal - requires MoreThanOrEqual(value) from TypeORM
61
+ return { [field]: { __qast_operator__: 'gte', value } };
62
+ case 'lte':
63
+ // Less than or equal - requires LessThanOrEqual(value) from TypeORM
64
+ return { [field]: { __qast_operator__: 'lte', value } };
65
+ case 'in':
66
+ // In array - requires In(value) from TypeORM
67
+ return { [field]: { __qast_operator__: 'in', value } };
68
+ case 'contains':
69
+ // Contains (like) - requires Like(`%${value}%`) from TypeORM
70
+ return { [field]: { __qast_operator__: 'contains', value } };
71
+ default:
72
+ throw new Error(`Unsupported operator: ${op}`);
73
+ }
74
+ }
75
+ /**
76
+ * Transform a logical node to TypeORM format
77
+ *
78
+ * TypeORM handles AND/OR differently:
79
+ * - AND: Multiple conditions in same object (merged)
80
+ * - OR: Array of condition objects
81
+ */
82
+ function transformLogicalNode(node) {
83
+ const leftFilter = transformNode(node.left);
84
+ const rightFilter = transformNode(node.right);
85
+ if (node.type === 'AND') {
86
+ // For AND, merge the filters into a single object
87
+ return mergeFilters(leftFilter, rightFilter);
88
+ }
89
+ else {
90
+ // For OR, create an array of conditions
91
+ const leftArray = Array.isArray(leftFilter) ? leftFilter : [leftFilter];
92
+ const rightArray = Array.isArray(rightFilter) ? rightFilter : [rightFilter];
93
+ return [...leftArray, ...rightArray];
94
+ }
95
+ }
96
+ /**
97
+ * Merge two TypeORM filters (for AND operations)
98
+ */
99
+ function mergeFilters(left, right) {
100
+ // If either is an array, we need to flatten
101
+ // For AND operations in TypeORM, we merge objects
102
+ if (Array.isArray(left) || Array.isArray(right)) {
103
+ // If we have arrays in AND, we need to create a cartesian product
104
+ // For simplicity, we'll flatten and merge
105
+ const leftObj = Array.isArray(left) ? Object.assign({}, ...left) : left;
106
+ const rightObj = Array.isArray(right) ? Object.assign({}, ...right) : right;
107
+ return { ...leftObj, ...rightObj };
108
+ }
109
+ // Both are objects, merge them
110
+ return { ...left, ...right };
111
+ }
112
+ //# sourceMappingURL=typeorm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeorm.js","sourceRoot":"","sources":["../../src/adapters/typeorm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Base error class for QAST library
3
+ */
4
+ export declare class QastError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ /**
8
+ * Error thrown during tokenization when an invalid token is encountered
9
+ */
10
+ export declare class TokenizationError extends QastError {
11
+ readonly position: number;
12
+ readonly query: string;
13
+ constructor(message: string, position: number, query: string);
14
+ /**
15
+ * Get a snippet of the query around the error position
16
+ */
17
+ getSnippet(): string;
18
+ }
19
+ /**
20
+ * Error thrown during parsing when the query syntax is invalid
21
+ */
22
+ export declare class ParseError extends QastError {
23
+ readonly position: number;
24
+ readonly query: string;
25
+ constructor(message: string, position?: number, query?: string);
26
+ }
27
+ /**
28
+ * Error thrown during validation when a field or operator is not allowed
29
+ */
30
+ export declare class ValidationError extends QastError {
31
+ readonly field?: string;
32
+ readonly operator?: string;
33
+ constructor(message: string, field?: string, operator?: string);
34
+ }
35
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC9C,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,KAAK,EAAE,MAAM,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAO5D;;OAEG;IACH,UAAU,IAAI,MAAM;CAOrB;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,KAAK,EAAE,MAAM,CAAC;gBAElB,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;CAM/D;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS;IAC5C,SAAgB,KAAK,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAgB,QAAQ,CAAC,EAAE,MAAM,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAM/D"}
package/dist/errors.js ADDED
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationError = exports.ParseError = exports.TokenizationError = exports.QastError = void 0;
4
+ /**
5
+ * Base error class for QAST library
6
+ */
7
+ class QastError extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = this.constructor.name;
11
+ Error.captureStackTrace(this, this.constructor);
12
+ }
13
+ }
14
+ exports.QastError = QastError;
15
+ /**
16
+ * Error thrown during tokenization when an invalid token is encountered
17
+ */
18
+ class TokenizationError extends QastError {
19
+ constructor(message, position, query) {
20
+ super(`${message} at position ${position}`);
21
+ this.position = position;
22
+ this.query = query;
23
+ this.name = 'TokenizationError';
24
+ }
25
+ /**
26
+ * Get a snippet of the query around the error position
27
+ */
28
+ getSnippet() {
29
+ const start = Math.max(0, this.position - 10);
30
+ const end = Math.min(this.query.length, this.position + 10);
31
+ const before = this.query.substring(start, this.position);
32
+ const after = this.query.substring(this.position, end);
33
+ return `${before}[ERROR]${after}`;
34
+ }
35
+ }
36
+ exports.TokenizationError = TokenizationError;
37
+ /**
38
+ * Error thrown during parsing when the query syntax is invalid
39
+ */
40
+ class ParseError extends QastError {
41
+ constructor(message, position, query) {
42
+ super(message);
43
+ this.position = position ?? -1;
44
+ this.query = query ?? '';
45
+ this.name = 'ParseError';
46
+ }
47
+ }
48
+ exports.ParseError = ParseError;
49
+ /**
50
+ * Error thrown during validation when a field or operator is not allowed
51
+ */
52
+ class ValidationError extends QastError {
53
+ constructor(message, field, operator) {
54
+ super(message);
55
+ this.field = field;
56
+ this.operator = operator;
57
+ this.name = 'ValidationError';
58
+ }
59
+ }
60
+ exports.ValidationError = ValidationError;
61
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAND,8BAMC;AAED;;GAEG;AACH,MAAa,iBAAkB,SAAQ,SAAS;IAI9C,YAAY,OAAe,EAAE,QAAgB,EAAE,KAAa;QAC1D,KAAK,CAAC,GAAG,OAAO,gBAAgB,QAAQ,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,UAAU;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACvD,OAAO,GAAG,MAAM,UAAU,KAAK,EAAE,CAAC;IACpC,CAAC;CACF;AArBD,8CAqBC;AAED;;GAEG;AACH,MAAa,UAAW,SAAQ,SAAS;IAIvC,YAAY,OAAe,EAAE,QAAiB,EAAE,KAAc;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAVD,gCAUC;AAED;;GAEG;AACH,MAAa,eAAgB,SAAQ,SAAS;IAI5C,YAAY,OAAe,EAAE,KAAc,EAAE,QAAiB;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAVD,0CAUC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * QAST - Query to AST to ORM
3
+ *
4
+ * A library that parses human-readable query strings into ASTs
5
+ * and transforms them into ORM-compatible filter objects.
6
+ */
7
+ export { parseQueryString } from './parser/parser';
8
+ export { Tokenizer, Token, TokenType } from './parser/tokenizer';
9
+ export { validateQuery, extractFields, extractOperators } from './parser/validator';
10
+ export { toPrismaFilter, PrismaFilter } from './adapters/prisma';
11
+ export { toTypeORMFilter, TypeORMFilter } from './adapters/typeorm';
12
+ export { toSequelizeFilter, SequelizeFilter } from './adapters/sequelize';
13
+ export { QastNode, ComparisonNode, LogicalNode, LogicalOperator, Operator, QastValue, ParseOptions, WhitelistOptions, isComparisonNode, isLogicalNode, } from './types/ast';
14
+ export { QastError, ParseError, ValidationError, TokenizationError, } from './errors';
15
+ import { ParseOptions, QastNode } from './types/ast';
16
+ /**
17
+ * Parse a query string into an AST
18
+ *
19
+ * @param query - The query string to parse (e.g., 'age gt 25 and name eq "John"')
20
+ * @param options - Optional parsing options (whitelisting, validation)
21
+ * @returns The parsed AST node
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const ast = parseQuery('age gt 25 and name eq "John"');
26
+ * ```
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const ast = parseQuery('age gt 25', {
31
+ * allowedFields: ['age', 'name'],
32
+ * allowedOperators: ['gt', 'eq'],
33
+ * validate: true,
34
+ * });
35
+ * ```
36
+ */
37
+ export declare function parseQuery(query: string, options?: ParseOptions): QastNode;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGjE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG1E,OAAO,EACL,QAAQ,EACR,cAAc,EACd,WAAW,EACX,eAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,SAAS,EACT,UAAU,EACV,eAAe,EACf,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAKlB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAoB,MAAM,aAAa,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,QAAQ,CAiB1E"}
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * QAST - Query to AST to ORM
4
+ *
5
+ * A library that parses human-readable query strings into ASTs
6
+ * and transforms them into ORM-compatible filter objects.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TokenizationError = exports.ValidationError = exports.ParseError = exports.QastError = exports.isLogicalNode = exports.isComparisonNode = exports.toSequelizeFilter = exports.toTypeORMFilter = exports.toPrismaFilter = exports.extractOperators = exports.extractFields = exports.validateQuery = exports.TokenType = exports.Tokenizer = exports.parseQueryString = void 0;
10
+ exports.parseQuery = parseQuery;
11
+ // Export parser
12
+ var parser_1 = require("./parser/parser");
13
+ Object.defineProperty(exports, "parseQueryString", { enumerable: true, get: function () { return parser_1.parseQueryString; } });
14
+ var tokenizer_1 = require("./parser/tokenizer");
15
+ Object.defineProperty(exports, "Tokenizer", { enumerable: true, get: function () { return tokenizer_1.Tokenizer; } });
16
+ Object.defineProperty(exports, "TokenType", { enumerable: true, get: function () { return tokenizer_1.TokenType; } });
17
+ // Export validators
18
+ var validator_1 = require("./parser/validator");
19
+ Object.defineProperty(exports, "validateQuery", { enumerable: true, get: function () { return validator_1.validateQuery; } });
20
+ Object.defineProperty(exports, "extractFields", { enumerable: true, get: function () { return validator_1.extractFields; } });
21
+ Object.defineProperty(exports, "extractOperators", { enumerable: true, get: function () { return validator_1.extractOperators; } });
22
+ // Export adapters
23
+ var prisma_1 = require("./adapters/prisma");
24
+ Object.defineProperty(exports, "toPrismaFilter", { enumerable: true, get: function () { return prisma_1.toPrismaFilter; } });
25
+ var typeorm_1 = require("./adapters/typeorm");
26
+ Object.defineProperty(exports, "toTypeORMFilter", { enumerable: true, get: function () { return typeorm_1.toTypeORMFilter; } });
27
+ var sequelize_1 = require("./adapters/sequelize");
28
+ Object.defineProperty(exports, "toSequelizeFilter", { enumerable: true, get: function () { return sequelize_1.toSequelizeFilter; } });
29
+ // Export types
30
+ var ast_1 = require("./types/ast");
31
+ Object.defineProperty(exports, "isComparisonNode", { enumerable: true, get: function () { return ast_1.isComparisonNode; } });
32
+ Object.defineProperty(exports, "isLogicalNode", { enumerable: true, get: function () { return ast_1.isLogicalNode; } });
33
+ // Export errors
34
+ var errors_1 = require("./errors");
35
+ Object.defineProperty(exports, "QastError", { enumerable: true, get: function () { return errors_1.QastError; } });
36
+ Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return errors_1.ParseError; } });
37
+ Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_1.ValidationError; } });
38
+ Object.defineProperty(exports, "TokenizationError", { enumerable: true, get: function () { return errors_1.TokenizationError; } });
39
+ // Main parse function with options
40
+ const parser_2 = require("./parser/parser");
41
+ const validator_2 = require("./parser/validator");
42
+ /**
43
+ * Parse a query string into an AST
44
+ *
45
+ * @param query - The query string to parse (e.g., 'age gt 25 and name eq "John"')
46
+ * @param options - Optional parsing options (whitelisting, validation)
47
+ * @returns The parsed AST node
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const ast = parseQuery('age gt 25 and name eq "John"');
52
+ * ```
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const ast = parseQuery('age gt 25', {
57
+ * allowedFields: ['age', 'name'],
58
+ * allowedOperators: ['gt', 'eq'],
59
+ * validate: true,
60
+ * });
61
+ * ```
62
+ */
63
+ function parseQuery(query, options) {
64
+ const ast = (0, parser_2.parseQueryString)(query);
65
+ // Validate if options are provided and validation is enabled
66
+ if (options && options.validate !== false) {
67
+ const whitelist = {
68
+ allowedFields: options.allowedFields,
69
+ allowedOperators: options.allowedOperators,
70
+ };
71
+ // Only validate if whitelists are provided
72
+ if (whitelist.allowedFields || whitelist.allowedOperators) {
73
+ (0, validator_2.validateQuery)(ast, whitelist);
74
+ }
75
+ }
76
+ return ast;
77
+ }
78
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA8DH,gCAiBC;AA7ED,gBAAgB;AAChB,0CAAmD;AAA1C,0GAAA,gBAAgB,OAAA;AACzB,gDAAiE;AAAxD,sGAAA,SAAS,OAAA;AAAS,sGAAA,SAAS,OAAA;AAEpC,oBAAoB;AACpB,gDAAoF;AAA3E,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAEvD,kBAAkB;AAClB,4CAAiE;AAAxD,wGAAA,cAAc,OAAA;AACvB,8CAAoE;AAA3D,0GAAA,eAAe,OAAA;AACxB,kDAA0E;AAAjE,8GAAA,iBAAiB,OAAA;AAE1B,eAAe;AACf,mCAWqB;AAFnB,uGAAA,gBAAgB,OAAA;AAChB,oGAAA,aAAa,OAAA;AAGf,gBAAgB;AAChB,mCAKkB;AAJhB,mGAAA,SAAS,OAAA;AACT,oGAAA,UAAU,OAAA;AACV,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AAGnB,mCAAmC;AACnC,4CAAmD;AACnD,kDAAmD;AAGnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,UAAU,CAAC,KAAa,EAAE,OAAsB;IAC9D,MAAM,GAAG,GAAG,IAAA,yBAAgB,EAAC,KAAK,CAAC,CAAC;IAEpC,6DAA6D;IAC7D,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAqB;YAClC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;SAC3C,CAAC;QAEF,2CAA2C;QAC3C,IAAI,SAAS,CAAC,aAAa,IAAI,SAAS,CAAC,gBAAgB,EAAE,CAAC;YAC1D,IAAA,yBAAa,EAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { Token } from './tokenizer';
2
+ import { QastNode } from '../types/ast';
3
+ /**
4
+ * Parser for QAST query strings
5
+ * Grammar:
6
+ * expression -> term (("and" | "or") term)*
7
+ * term -> factor | "(" expression ")"
8
+ * factor -> IDENTIFIER OPERATOR VALUE
9
+ */
10
+ export declare class Parser {
11
+ private tokens;
12
+ private position;
13
+ private currentToken;
14
+ constructor(tokens: Token[]);
15
+ /**
16
+ * Advance to the next token
17
+ */
18
+ private advance;
19
+ /**
20
+ * Expect a token of a specific type, throw error if not found
21
+ */
22
+ private expect;
23
+ /**
24
+ * Check if current token matches a type
25
+ */
26
+ private check;
27
+ /**
28
+ * Parse a factor: IDENTIFIER OPERATOR VALUE
29
+ */
30
+ private parseFactor;
31
+ /**
32
+ * Parse a term: factor | "(" expression ")"
33
+ */
34
+ private parseTerm;
35
+ /**
36
+ * Parse an expression: term (("and" | "or") term)*
37
+ * Left-associative: a and b or c is parsed as (a and b) or c
38
+ */
39
+ private parseExpression;
40
+ /**
41
+ * Parse the query and return the AST
42
+ */
43
+ parse(): QastNode;
44
+ }
45
+ /**
46
+ * Parse a query string into an AST
47
+ */
48
+ export declare function parseQueryString(query: string): QastNode;
49
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,EAAa,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAA4B,MAAM,cAAc,CAAC;AAGlE;;;;;;GAMG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAQ;gBAEhB,MAAM,EAAE,KAAK,EAAE;IAM3B;;OAEG;IACH,OAAO,CAAC,OAAO;IASf;;OAEG;IACH,OAAO,CAAC,MAAM;IAYd;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,OAAO,CAAC,WAAW;IAoCnB;;OAEG;IACH,OAAO,CAAC,SAAS;IAajB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAyBvB;;OAEG;IACI,KAAK,IAAI,QAAQ;CAmBzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAYxD"}