@routier/core 0.2.1 → 0.4.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 (161) hide show
  1. package/LICENSE +21 -0
  2. package/{readme.md → README.md} +3 -3
  3. package/dist/assertions/index.cjs +191 -0
  4. package/dist/assertions/index.cjs.map +1 -0
  5. package/dist/assertions/index.js +43 -63
  6. package/dist/assertions/index.js.map +1 -1
  7. package/dist/capabilities/index.cjs +820 -0
  8. package/dist/capabilities/index.cjs.map +1 -0
  9. package/dist/capabilities/index.js +584 -558
  10. package/dist/capabilities/index.js.map +1 -1
  11. package/dist/codegen/handlers/CloneHandlerBuilder.d.ts +10 -1
  12. package/dist/codegen/handlers/clone/CloneArrayHandler.d.ts +3 -0
  13. package/dist/codegen/handlers/clone/CloneDateHandler.d.ts +13 -0
  14. package/dist/codegen/handlers/clone/CloneValueHandler.d.ts +16 -0
  15. package/dist/codegen/handlers/compare/CompareComputedHandler.d.ts +10 -0
  16. package/dist/codegen/handlers/compare/CompareFunctionHandler.d.ts +10 -0
  17. package/dist/codegen/handlers/deserialize/DeserializeArrayHandler.d.ts +14 -0
  18. package/dist/codegen/handlers/enableChangeTracking/EnableChangeTrackingArrayHandler.d.ts +11 -0
  19. package/dist/codegen/handlers/enrichment/EnrichmentArrayHandler.d.ts +11 -0
  20. package/dist/codegen/handlers/freeze/FreezeArrayHandler.d.ts +6 -0
  21. package/dist/codegen/handlers/hash/HashArrayHandler.d.ts +10 -0
  22. package/dist/codegen/handlers/hash/HashFileHandler.d.ts +24 -0
  23. package/dist/codegen/handlers/hash/HashObjectHandler.d.ts +10 -0
  24. package/dist/codegen/handlers/hash/HashTransformHandler.d.ts +23 -0
  25. package/dist/codegen/handlers/merge/MergeArrayHandler.d.ts +20 -0
  26. package/dist/codegen/handlers/merge/MergeObjectHandler.d.ts +10 -0
  27. package/dist/codegen/handlers/serialize/SerializeArrayHandler.d.ts +19 -0
  28. package/dist/codegen/handlers/strip/StripComputedHandler.d.ts +10 -0
  29. package/dist/codegen/handlers/strip/StripFunctionHandler.d.ts +9 -0
  30. package/dist/codegen/handlers/types.d.ts +55 -1
  31. package/dist/codegen/index.cjs +618 -0
  32. package/dist/codegen/index.cjs.map +1 -0
  33. package/dist/codegen/index.js +99 -127
  34. package/dist/codegen/index.js.map +1 -1
  35. package/dist/collections/MemoryDataCollection.d.ts +15 -1
  36. package/dist/collections/TagCollection.d.ts +0 -1
  37. package/dist/collections/index.cjs +702 -0
  38. package/dist/collections/index.cjs.map +1 -0
  39. package/dist/collections/index.js +282 -276
  40. package/dist/collections/index.js.map +1 -1
  41. package/dist/errors/OptimisticConcurrencyError.d.ts +18 -0
  42. package/dist/errors/PluginDestroyedError.d.ts +10 -0
  43. package/dist/errors/index.cjs +132 -0
  44. package/dist/errors/index.cjs.map +1 -0
  45. package/dist/errors/index.d.ts +2 -0
  46. package/dist/errors/index.js +61 -19
  47. package/dist/errors/index.js.map +1 -1
  48. package/dist/expressions/evaluate.d.ts +53 -0
  49. package/dist/expressions/index.cjs +2087 -0
  50. package/dist/expressions/index.cjs.map +1 -0
  51. package/dist/expressions/index.d.ts +1 -1
  52. package/dist/expressions/index.js +1727 -1082
  53. package/dist/expressions/index.js.map +1 -1
  54. package/dist/expressions/parser.d.ts +19 -0
  55. package/dist/expressions/types.d.ts +87 -2
  56. package/dist/index.cjs +14377 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.js +12374 -7931
  59. package/dist/index.js.map +1 -1
  60. package/dist/performance/index.cjs +217 -0
  61. package/dist/performance/index.cjs.map +1 -0
  62. package/dist/performance/index.js +120 -55
  63. package/dist/performance/index.js.map +1 -1
  64. package/dist/pipeline/index.cjs +576 -0
  65. package/dist/pipeline/index.cjs.map +1 -0
  66. package/dist/pipeline/index.js +223 -161
  67. package/dist/pipeline/index.js.map +1 -1
  68. package/dist/plugins/BatchingDbPlugin.d.ts +139 -0
  69. package/dist/plugins/CacheDbPlugin.d.ts +70 -0
  70. package/dist/plugins/ConcurrencyDbPlugin.d.ts +78 -0
  71. package/dist/plugins/EphemeralDataPlugin.d.ts +57 -1
  72. package/dist/plugins/RetryDbPlugin.d.ts +77 -0
  73. package/dist/plugins/index.cjs +6551 -0
  74. package/dist/plugins/index.cjs.map +1 -0
  75. package/dist/plugins/index.d.ts +5 -0
  76. package/dist/plugins/index.js +6271 -1170
  77. package/dist/plugins/index.js.map +1 -1
  78. package/dist/plugins/query/QueryOptionsCollection.d.ts +34 -0
  79. package/dist/plugins/query/explain.d.ts +82 -0
  80. package/dist/plugins/query/formatExplanation.d.ts +9 -0
  81. package/dist/plugins/query/index.d.ts +4 -0
  82. package/dist/plugins/query/join.d.ts +210 -0
  83. package/dist/plugins/query/similarity.d.ts +38 -0
  84. package/dist/plugins/query/types.d.ts +75 -1
  85. package/dist/plugins/translators/DataTranslator.d.ts +28 -0
  86. package/dist/plugins/translators/JsonTranslator.d.ts +27 -0
  87. package/dist/plugins/translators/SqlTranslator.d.ts +45 -0
  88. package/dist/plugins/translators/TupleTranslator.d.ts +45 -0
  89. package/dist/plugins/translators/index.d.ts +1 -0
  90. package/dist/plugins/types.d.ts +125 -3
  91. package/dist/plugins/wire/handler.d.ts +122 -0
  92. package/dist/plugins/wire/index.d.ts +4 -0
  93. package/dist/plugins/wire/persist.d.ts +43 -0
  94. package/dist/plugins/wire/query.d.ts +49 -0
  95. package/dist/plugins/wire/types.d.ts +139 -0
  96. package/dist/results/index.cjs +174 -0
  97. package/dist/results/index.cjs.map +1 -0
  98. package/dist/results/index.js +29 -44
  99. package/dist/results/index.js.map +1 -1
  100. package/dist/schema/PropertyInfo.d.ts +31 -2
  101. package/dist/schema/SchemaDefinition.d.ts +23 -1
  102. package/dist/schema/builder.d.ts +35 -1
  103. package/dist/schema/communication/broadcast.d.ts +17 -1
  104. package/dist/schema/index.cjs +6911 -0
  105. package/dist/schema/index.cjs.map +1 -0
  106. package/dist/schema/index.d.ts +2 -0
  107. package/dist/schema/index.js +5330 -4541
  108. package/dist/schema/index.js.map +1 -1
  109. package/dist/schema/property/base/SchemaBase.d.ts +48 -2
  110. package/dist/schema/property/modifiers/SchemaNullable.d.ts +10 -0
  111. package/dist/schema/property/modifiers/SchemaOptional.d.ts +19 -0
  112. package/dist/schema/property/modifiers/SchemaSearchable.d.ts +34 -0
  113. package/dist/schema/property/modifiers/index.d.ts +1 -0
  114. package/dist/schema/property/types/SchemaFile.d.ts +60 -0
  115. package/dist/schema/property/types/SchemaString.d.ts +21 -1
  116. package/dist/schema/property/types/SchemaVector.d.ts +61 -0
  117. package/dist/schema/property/types/index.d.ts +2 -0
  118. package/dist/schema/table/SchemaTransform.d.ts +40 -0
  119. package/dist/schema/table/index.d.ts +1 -0
  120. package/dist/schema/types.d.ts +166 -8
  121. package/dist/schema/utils/propertyKind.d.ts +4 -0
  122. package/dist/types/index.cjs +23 -0
  123. package/dist/types/index.cjs.map +1 -0
  124. package/dist/types/index.js +0 -14
  125. package/dist/types/index.js.map +1 -1
  126. package/dist/utilities/index.cjs +1013 -0
  127. package/dist/utilities/index.cjs.map +1 -0
  128. package/dist/utilities/index.js +541 -379
  129. package/dist/utilities/index.js.map +1 -1
  130. package/dist/utilities/logger.d.ts +48 -0
  131. package/package.json +156 -98
  132. package/dist/codegen/SlotPath.test.d.ts +0 -1
  133. package/dist/codegen/blocks.test.d.ts +0 -1
  134. package/dist/codegen/utils.test.d.ts +0 -1
  135. package/dist/collections/Changes.test.d.ts +0 -1
  136. package/dist/collections/IdSet.test.d.ts +0 -1
  137. package/dist/collections/MemoryDataCollection.test.d.ts +0 -1
  138. package/dist/collections/TagCollection.contract.test.d.ts +0 -1
  139. package/dist/collections/TagCollection.test.d.ts +0 -1
  140. package/dist/expressions/parser.test.d.ts +0 -1
  141. package/dist/expressions/sql.d.ts +0 -28
  142. package/dist/expressions/sql.test.d.ts +0 -1
  143. package/dist/expressions/utils.test.d.ts +0 -1
  144. package/dist/pipeline/SyncronousQueue.test.d.ts +0 -1
  145. package/dist/plugins/EphemeralDataPlugin.test.d.ts +0 -1
  146. package/dist/plugins/query/Query.test.d.ts +0 -1
  147. package/dist/plugins/query/QueryOptionsCollection.test.d.ts +0 -1
  148. package/dist/plugins/translators/JsonTranslator.test.d.ts +0 -1
  149. package/dist/plugins/translators/SqlTranslator.test.d.ts +0 -1
  150. package/dist/plugins/translators/TranslatedValues.test.d.ts +0 -1
  151. package/dist/results/Result.test.d.ts +0 -1
  152. package/dist/results/utils.test.d.ts +0 -1
  153. package/dist/schema/PropertyInfo.test.d.ts +0 -1
  154. package/dist/schema/communication/broadcast.test.d.ts +0 -1
  155. package/dist/schema/schemaGeneration.test.d.ts +0 -1
  156. package/dist/schema/utils/standardJsonSchema.test.d.ts +0 -1
  157. package/dist/utilities/arrays.test.d.ts +0 -1
  158. package/dist/utilities/dates.test.d.ts +0 -1
  159. package/dist/utilities/runtime.test.d.ts +0 -1
  160. package/dist/utilities/strings.test.d.ts +0 -1
  161. package/dist/utilities/uuid.test.d.ts +0 -1
@@ -1,27 +1,16 @@
1
1
  var __webpack_modules__ = ({
2
- "./src/assertions/index.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
3
- __webpack_require__.r(__webpack_exports__);
2
+ 126(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
3
  __webpack_require__.d(__webpack_exports__, {
5
- assertDate: () => (assertDate),
6
- assertInstanceOf: () => (assertInstanceOf),
7
- assertIsArray: () => (assertIsArray),
8
- assertIsNotNull: () => (assertIsNotNull),
9
- assertIsNumber: () => (assertIsNumber),
10
- assertString: () => (assertString),
11
- isComparatorExpression: () => (isComparatorExpression),
12
- isEmptyExpression: () => (isEmptyExpression),
13
- isExpression: () => (isExpression),
14
- isNotParsableExpression: () => (isNotParsableExpression),
15
- isOperatorExpression: () => (isOperatorExpression),
16
- isPropertyExpression: () => (isPropertyExpression),
17
- isValueExpression: () => (isValueExpression)
4
+ Cv: () => (assertString),
5
+ S6: () => (isValueExpression),
6
+ e3: () => (isPropertyExpression),
7
+ vg: () => (isOperatorExpression),
8
+ xH: () => (isComparatorExpression)
18
9
  });
19
- /* import */ var _expressions_constants__rspack_import_1 = __webpack_require__("./src/expressions/constants.ts");
20
- /* import */ var _utilities__rspack_import_0 = __webpack_require__("./src/utilities/dates.ts");
21
10
 
22
11
 
23
12
  function assertDate(data) {
24
- if ((0,_utilities__rspack_import_0.isDate)(data) === false) {
13
+ if (isDate(data) === false) {
25
14
  throw new TypeError('Value is not a Date');
26
15
  }
27
16
  }
@@ -65,53 +54,45 @@ function isObjectWithType(value) {
65
54
  }
66
55
  /**
67
56
  * Type guard: narrows `value` to `Expression` when it is an object with a valid `type` property.
68
- */
69
- function isExpression(value) {
70
- return isObjectWithType(value) && _expressions_constants__rspack_import_1.EXPRESSION_TYPES.includes(value.type);
57
+ */ function isExpression(value) {
58
+ return isObjectWithType(value) && EXPRESSION_TYPES.includes(value.type);
71
59
  }
72
60
  /**
73
61
  * Type guard: narrows `value` to `OperatorExpression` when it is an object with `type === "operator"`.
74
- */
75
- function isOperatorExpression(value) {
62
+ */ function isOperatorExpression(value) {
76
63
  return isObjectWithType(value) && value.type === "operator";
77
64
  }
78
65
  /**
79
66
  * Type guard: narrows `value` to `ComparatorExpression` when it is an object with `type === "comparator"`.
80
- */
81
- function isComparatorExpression(value) {
67
+ */ function isComparatorExpression(value) {
82
68
  return isObjectWithType(value) && value.type === "comparator";
83
69
  }
84
70
  /**
85
71
  * Type guard: narrows `value` to `PropertyExpression` when it is an object with `type === "property"`.
86
- */
87
- function isPropertyExpression(value) {
72
+ */ function isPropertyExpression(value) {
88
73
  return isObjectWithType(value) && value.type === "property";
89
74
  }
90
75
  /**
91
76
  * Type guard: narrows `value` to `ValueExpression` when it is an object with `type === "value"`.
92
- */
93
- function isValueExpression(value) {
77
+ */ function isValueExpression(value) {
94
78
  return isObjectWithType(value) && value.type === "value";
95
79
  }
96
80
  /**
97
81
  * Type guard: narrows `value` to `EmptyExpression` when it is an object with `type === "empty"`.
98
- */
99
- function isEmptyExpression(value) {
82
+ */ function isEmptyExpression(value) {
100
83
  return isObjectWithType(value) && value.type === "empty";
101
84
  }
102
85
  /**
103
86
  * Type guard: narrows `value` to `NotParsableExpression` when it is an object with `type === "not-parsable"`.
104
- */
105
- function isNotParsableExpression(value) {
87
+ */ function isNotParsableExpression(value) {
106
88
  return isObjectWithType(value) && value.type === "not-parsable";
107
89
  }
108
90
 
109
91
 
110
92
  },
111
- "./src/expressions/constants.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
112
- __webpack_require__.r(__webpack_exports__);
93
+ 835(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
113
94
  __webpack_require__.d(__webpack_exports__, {
114
- EXPRESSION_TYPES: () => (EXPRESSION_TYPES)
95
+ t: () => (EXPRESSION_TYPES)
115
96
  });
116
97
  const EXPRESSION_TYPES = [
117
98
  "operator",
@@ -119,1020 +100,1487 @@ const EXPRESSION_TYPES = [
119
100
  "property",
120
101
  "value",
121
102
  "empty",
122
- "not-parsable",
103
+ "not-parsable"
123
104
  ];
124
105
 
125
106
 
126
107
  },
127
- "./src/expressions/parser.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
128
- __webpack_require__.r(__webpack_exports__);
108
+ 379(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
129
109
  __webpack_require__.d(__webpack_exports__, {
130
- combineExpressions: () => (combineExpressions),
131
- toExpression: () => (toExpression)
110
+ Vu: () => (toPredicate),
111
+ _3: () => (evaluate),
112
+ wS: () => (toStrictPredicate)
132
113
  });
133
- /* import */ var _utilities__rspack_import_2 = __webpack_require__("./src/utilities/logger.ts");
134
- /* import */ var _assertions__rspack_import_1 = __webpack_require__("./src/assertions/index.ts");
135
- /* import */ var _types__rspack_import_0 = __webpack_require__("./src/expressions/types.ts");
114
+ /* import */ var _assertions__rspack_import_0 = __webpack_require__(126);
136
115
 
116
+ /** Reads a property or literal operand, or `UNRESOLVED` when the node is not one. */ const UNRESOLVED = Symbol("unresolved");
117
+ const applyTransformer = (value, transformer)=>{
118
+ if (transformer == null) {
119
+ return value;
120
+ }
121
+ // A transformer applied to an absent value has no answer, and inventing one ("" for a missing
122
+ // string) is how a filter starts matching rows it should not.
123
+ if (value == null) {
124
+ return UNRESOLVED;
125
+ }
126
+ if (transformer === "to-lower-case") {
127
+ return typeof value === "string" ? value.toLowerCase() : UNRESOLVED;
128
+ }
129
+ if (transformer === "to-upper-case") {
130
+ return typeof value === "string" ? value.toUpperCase() : UNRESOLVED;
131
+ }
132
+ if (transformer === "length") {
133
+ return typeof value === "string" || Array.isArray(value) ? value.length : UNRESOLVED;
134
+ }
135
+ return UNRESOLVED;
136
+ };
137
+ const operand = (expression, row)=>{
138
+ if (expression == null) {
139
+ return UNRESOLVED;
140
+ }
141
+ if ((0,_assertions__rspack_import_0/* .isValueExpression */.S6)(expression)) {
142
+ return applyTransformer(expression.value, expression.transformer);
143
+ }
144
+ if ((0,_assertions__rspack_import_0/* .isPropertyExpression */.e3)(expression)) {
145
+ // Through the PropertyInfo, so a nested path and a `from`-renamed segment resolve the same
146
+ // way every other consumer of the tree resolves them.
147
+ return applyTransformer(expression.property.getValue(row), expression.transformer);
148
+ }
149
+ return UNRESOLVED;
150
+ };
151
+ /**
152
+ * `a === b` for the comparators, with Dates compared by VALUE.
153
+ *
154
+ * A Date compares by reference under `===`, so two Dates holding the same instant would be
155
+ * unequal — which is not what a filter on a date means, and not what any backend does.
156
+ */ const equals = (left, right, strict)=>{
157
+ if (left instanceof Date && right instanceof Date) {
158
+ return left.getTime() === right.getTime();
159
+ }
160
+ // oxlint-disable-next-line eqeqeq
161
+ return strict ? left === right : left == right;
162
+ };
163
+ /** Ordered comparison, only for shapes that have an order. */ const compare = (left, right, comparator)=>{
164
+ const asComparable = (value)=>value instanceof Date ? value.getTime() : value;
165
+ const a = asComparable(left);
166
+ const b = asComparable(right);
167
+ const comparable = typeof a === "number" && typeof b === "number" || typeof a === "string" && typeof b === "string";
168
+ if (comparable === false) {
169
+ return undefined;
170
+ }
171
+ if (comparator === "greater-than") {
172
+ return a > b;
173
+ }
174
+ if (comparator === "greater-than-equals") {
175
+ return a >= b;
176
+ }
177
+ if (comparator === "less-than") {
178
+ return a < b;
179
+ }
180
+ return a <= b;
181
+ };
182
+ const evaluateComparator = (comparator, left, right, strict)=>{
183
+ if (comparator === "equals") {
184
+ return equals(left, right, strict);
185
+ }
186
+ if (comparator === "includes") {
187
+ // Two shapes, and the tree does not distinguish them: `array.includes(value)` and
188
+ // `string.includes(substring)`. Whichever side is the container decides.
189
+ if (Array.isArray(left)) {
190
+ return left.some((item)=>equals(item, right, strict));
191
+ }
192
+ if (Array.isArray(right)) {
193
+ return right.some((item)=>equals(item, left, strict));
194
+ }
195
+ return typeof left === "string" && typeof right === "string" ? left.includes(right) : undefined;
196
+ }
197
+ if (comparator === "starts-with") {
198
+ return typeof left === "string" && typeof right === "string" ? left.startsWith(right) : undefined;
199
+ }
200
+ if (comparator === "ends-with") {
201
+ return typeof left === "string" && typeof right === "string" ? left.endsWith(right) : undefined;
202
+ }
203
+ return compare(left, right, comparator);
204
+ };
205
+ /**
206
+ * Evaluates `expression` against `row`, or returns `undefined` when it cannot.
207
+ *
208
+ * See the note at the top of this file: `undefined` means KEEP the row.
209
+ */ const evaluate = (expression, row)=>{
210
+ if ((0,_assertions__rspack_import_0/* .isOperatorExpression */.vg)(expression)) {
211
+ const left = expression.left == null ? undefined : evaluate(expression.left, row);
212
+ const right = expression.right == null ? undefined : evaluate(expression.right, row);
213
+ /**
214
+ * One unevaluable side does not have to sink the whole tree.
215
+ *
216
+ * `a && b` where `a` is definitely false is false whatever `b` is, and `a || b` where `a`
217
+ * is definitely true is true. That short-circuiting is what lets a mostly-understood
218
+ * predicate still narrow anything at all — without it, one unfamiliar sub-expression makes
219
+ * the entire filter a no-op.
220
+ */ if (expression.operator === "&&") {
221
+ if (left === false || right === false) {
222
+ return false;
223
+ }
224
+ return left === true && right === true ? true : undefined;
225
+ }
226
+ if (left === true || right === true) {
227
+ return true;
228
+ }
229
+ return left === false && right === false ? false : undefined;
230
+ }
231
+ if ((0,_assertions__rspack_import_0/* .isComparatorExpression */.xH)(expression)) {
232
+ const left = operand(expression.left, row);
233
+ const right = operand(expression.right, row);
234
+ if (left === UNRESOLVED || right === UNRESOLVED) {
235
+ return undefined;
236
+ }
237
+ const result = evaluateComparator(expression.comparator, left, right, expression.strict);
238
+ if (result === undefined) {
239
+ return undefined;
240
+ }
241
+ return expression.negated ? result === false : result;
242
+ }
243
+ // A tautology excludes nothing, which is exactly `true`. Anything else — a bare property, a
244
+ // literal, `not-parsable` — is not a predicate this can judge.
245
+ return expression.type === "empty" ? true : undefined;
246
+ };
247
+ /**
248
+ * `evaluate`, as a predicate that keeps whatever it cannot judge.
249
+ *
250
+ * The form every narrowing caller wants, with the fail-open rule applied once here rather than
251
+ * remembered at each call site.
252
+ */ const toPredicate = (expression)=>(row)=>evaluate(expression, row) !== false;
253
+ /**
254
+ * `evaluate`, as a predicate that THROWS on anything it cannot judge.
255
+ *
256
+ * The opposite default to `toPredicate`, and the right one when the predicate is the only thing
257
+ * standing between a caller and rows they asked to exclude — a filter that arrived over a wire and
258
+ * is being applied by the receiver. Failing open there does not cost a wasted comparison; it returns
259
+ * data the requester filtered out, and reports nothing.
260
+ *
261
+ * Use `toPredicate` when something authoritative re-checks the result, and this when nothing does.
262
+ */ const toStrictPredicate = (expression)=>(row)=>{
263
+ const result = evaluate(expression, row);
264
+ if (result === undefined) {
265
+ throw new Error("Cannot apply this filter: its expression cannot be evaluated in memory, and applying it partially would " + "return rows the filter excludes. This happens when a filter arrives without a runnable predicate — over a " + "wire, or rebuilt from a serialized query — and names something the evaluator does not understand.");
266
+ }
267
+ return result;
268
+ };
137
269
 
138
270
 
139
- // Pre-compiled regex patterns for better performance
140
- const METHOD_REGEX = /([a-zA-Z0-9_.]+)\.(startsWith|endsWith|includes)\(([^)]+)\)(\s*(===|==|!==|!=)\s*(true|false))?/;
141
- const TRANSFORM_METHOD_REGEX = /([a-zA-Z0-9_.]+)\.(toLowerCase|toUpperCase|toLocaleLowerCase|toLocaleUpperCase)\(\)\.(startsWith|endsWith|includes)\(((?:[^()]|\([^)]*\))*)\)(\s*(===|==|!==|!=)\s*(true|false))?/;
142
- const EQUALITY_REGEX = /([^=!<>]+?)\s*(===|==|!==|!=)\s*(.+)/;
143
- const COMPARISON_REGEX = /([^=!<>]+?)\s*(>=|<=|>|<)\s*(.+)/;
144
- const PARAM_PATH_REGEX = /^([a-zA-Z0-9_.]+)/;
145
- // Pre-compiled regex patterns for comment removal
146
- const SINGLE_LINE_COMMENT_REGEX = /\/\/.*$/gm;
147
- const MULTI_LINE_COMMENT_REGEX = /\/\*[\s\S]*?\*\//g;
148
- const WHITESPACE_REGEX = /\s+/g;
149
- // need to have negated + strict
150
- const comparators = {
151
- startsWith: new _types__rspack_import_0.ComparatorExpression({
152
- comparator: "starts-with",
153
- negated: false,
154
- strict: false
155
- }),
156
- endsWith: new _types__rspack_import_0.ComparatorExpression({
157
- comparator: "ends-with",
158
- negated: false,
159
- strict: false
160
- }),
161
- includes: new _types__rspack_import_0.ComparatorExpression({
162
- comparator: "includes",
163
- negated: false,
164
- strict: false
165
- }),
166
- "==": new _types__rspack_import_0.ComparatorExpression({
271
+ },
272
+ 91(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
273
+ __webpack_require__.d(__webpack_exports__, {
274
+ MY: () => (toExpression),
275
+ oH: () => (parseFragment),
276
+ pg: () => (combineExpressions)
277
+ });
278
+ /* import */ var _utilities__rspack_import_3 = __webpack_require__(581);
279
+ /* import */ var _assertions__rspack_import_0 = __webpack_require__(126);
280
+ /* import */ var _schema__rspack_import_2 = __webpack_require__(537);
281
+ /* import */ var _types__rspack_import_1 = __webpack_require__(27);
282
+
283
+
284
+
285
+
286
+ // Error message constants
287
+ const ERROR_MESSAGES = {
288
+ PROPERTY_NOT_FOUND: (path)=>`Error parsing query, could not find PropertyInfo for path: ${path}`,
289
+ PARAM_PATH_NOT_FOUND: (value, params)=>`Cannot find path in params for .where(). Make sure parameters are not used inline.\r\nPath: ${value}, Params: ${JSON.stringify(params)}`,
290
+ VARIABLE_VALUE: (value)=>`Cannot derive value from variable, please pass parameters into the expression.
291
+
292
+ Example: .where(([x, params]) => x.id === params.id, { id: someVar.id })
293
+ Issue At: ${value}`,
294
+ UNSUPPORTED: (value)=>`Unsupported expression format: ${value}`
295
+ };
296
+ const parseUnknown = (value)=>{
297
+ (0,_assertions__rspack_import_0/* .assertString */.Cv)(value);
298
+ return JSON.parse(value);
299
+ };
300
+ /**
301
+ * A parse failure caused by the params VALUES rather than the filter source.
302
+ * These must never poison the template cache — the same source can succeed
303
+ * with different params.
304
+ */ class ParamDependentParseError extends Error {
305
+ }
306
+ const converters = {
307
+ Array: (v)=>v,
308
+ Boolean: (v)=>v == null ? v : Boolean(v),
309
+ // Stryker disable next-line ArrowFunction: filters on computed properties route to
310
+ // in-memory execution, so this entry cannot be reached through a parsable filter.
311
+ Computed: (v)=>v,
312
+ Date: (v)=>v,
313
+ // A file is a reference, and a filter can legitimately compare its fields — content type
314
+ // and size are ordinary columns. The value passes through unconverted like an object.
315
+ File: (v)=>v,
316
+ // Stryker disable next-line ArrowFunction: SchemaTypes.Definition is handled as a
317
+ // generic primitive everywhere (specs/known-defects.md) and never pairs in a filter.
318
+ Definition: (v)=>v,
319
+ // Stryker disable next-line ArrowFunction: filters on function properties route to
320
+ // in-memory execution, so this entry cannot be reached through a parsable filter.
321
+ Function: (v)=>v,
322
+ Number: (v)=>v == null ? v : Number(v),
323
+ Object: (v)=>v,
324
+ String: (v)=>v == null ? v : String(v),
325
+ // A vector is a list of numbers and passes through like any other array. Nothing
326
+ // converts it because nothing compares it: similarity is `.nearest()`, not a filter.
327
+ Vector: (v)=>v
328
+ };
329
+ // Longest first so multi-character punctuation wins over its prefixes
330
+ const MULTI_CHARACTER_PUNCTUATION = [
331
+ "===",
332
+ "!==",
333
+ "?.",
334
+ "&&",
335
+ "||",
336
+ "==",
337
+ "!=",
338
+ ">=",
339
+ "<=",
340
+ "=>"
341
+ ];
342
+ // Stryker disable next-line all: documented equivalent cluster (see
343
+ // docs/mutation-backlog.md) — dropping an entry only affects source the parser rejects
344
+ // either way, and the rejection message names the character from the source rather than
345
+ // from this set, so no observable boundary distinguishes the mutant. Established
346
+ // experimentally: 30 message-asserting tests killed 1 of 12.
347
+ const SINGLE_CHARACTER_PUNCTUATION = new Set([
348
+ "(",
349
+ ")",
350
+ "[",
351
+ "]",
352
+ "{",
353
+ "}",
354
+ ".",
355
+ ",",
356
+ ";",
357
+ "!",
358
+ ">",
359
+ "<",
360
+ "-",
361
+ "+",
362
+ "*",
363
+ "/",
364
+ "%",
365
+ "=",
366
+ "?",
367
+ ":",
368
+ "&",
369
+ "|"
370
+ ]);
371
+ const STRING_ESCAPES = {
372
+ "n": "\n",
373
+ "r": "\r",
374
+ "t": "\t",
375
+ "b": "\b",
376
+ "f": "\f",
377
+ "v": "\v",
378
+ "0": "\0"
379
+ };
380
+ const isIdentifierStart = (char)=>/[a-zA-Z_$]/.test(char);
381
+ const isIdentifierPart = (char)=>/[a-zA-Z0-9_$]/.test(char);
382
+ const isDigit = (char)=>char >= "0" && char <= "9";
383
+ const isHexDigit = (char)=>isDigit(char) || char >= "a" && char <= "f" || char >= "A" && char <= "F";
384
+ /**
385
+ * Decodes a `\uXXXX`, `\u{...}` or `\xXX` escape starting at the backslash.
386
+ * Returns the decoded character and the index just past the escape. These
387
+ * escapes carry a computed character, so mapping them through STRING_ESCAPES
388
+ * (which would yield the literal "u"/"x") silently corrupts the value.
389
+ */ const decodeCodeEscape = (source, backslashIndex)=>{
390
+ const kind = source[backslashIndex + 1];
391
+ let start = backslashIndex + 2;
392
+ if (kind === "u" && source[start] === "{") {
393
+ const end = source.indexOf("}", start + 1);
394
+ if (end === -1) {
395
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("unterminated unicode escape"));
396
+ }
397
+ return {
398
+ value: String.fromCodePoint(parseInt(source.slice(start + 1, end), 16)),
399
+ nextIndex: end + 1
400
+ };
401
+ }
402
+ const length = kind === "u" ? 4 : 2;
403
+ const digits = source.slice(start, start + length);
404
+ if (digits.length < length || [
405
+ ...digits
406
+ ].some((d)=>!isHexDigit(d))) {
407
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`'\\${kind}' escape`));
408
+ }
409
+ return {
410
+ value: String.fromCharCode(parseInt(digits, 16)),
411
+ nextIndex: start + length
412
+ };
413
+ };
414
+ /**
415
+ * Converts filter source text into a flat token stream. Strings and comments are
416
+ * consumed here so operator characters inside literals can never be mistaken for
417
+ * real operators.
418
+ */ const tokenize = (source)=>{
419
+ const tokens = [];
420
+ let i = 0;
421
+ while(i < source.length){
422
+ const char = source[i];
423
+ // Whitespace
424
+ if (char === " " || char === "\t" || char === "\r" || char === "\n") {
425
+ i++;
426
+ continue;
427
+ }
428
+ // Comments
429
+ if (char === "/" && source[i + 1] === "/") {
430
+ while(i < source.length && source[i] !== "\n"){
431
+ i++;
432
+ }
433
+ continue;
434
+ }
435
+ if (char === "/" && source[i + 1] === "*") {
436
+ i += 2;
437
+ while(i < source.length && !(source[i] === "*" && source[i + 1] === "/")){
438
+ i++;
439
+ }
440
+ i += 2;
441
+ continue;
442
+ }
443
+ // String literals
444
+ if (char === "'" || char === "\"" || char === "`") {
445
+ const quote = char;
446
+ let value = "";
447
+ i++;
448
+ while(i < source.length && source[i] !== quote){
449
+ if (source[i] === "\\") {
450
+ const escaped = source[i + 1];
451
+ if (escaped === "u" || escaped === "x") {
452
+ const decoded = decodeCodeEscape(source, i);
453
+ value += decoded.value;
454
+ i = decoded.nextIndex;
455
+ continue;
456
+ }
457
+ value += STRING_ESCAPES[escaped] ?? escaped;
458
+ i += 2;
459
+ continue;
460
+ }
461
+ if (quote === "`" && source[i] === "$" && source[i + 1] === "{") {
462
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("template literal interpolation"));
463
+ }
464
+ value += source[i];
465
+ i++;
466
+ }
467
+ if (i >= source.length) {
468
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("unterminated string literal"));
469
+ }
470
+ i++; // consume closing quote
471
+ tokens.push({
472
+ kind: "string",
473
+ value
474
+ });
475
+ continue;
476
+ }
477
+ // Numbers — covers decimals, exponents (1e6), hex/octal/binary (0xFF),
478
+ // and numeric separators (1_000_000). Values are normalized here (the
479
+ // separator stripped) so the parser can hand them straight to Number()
480
+ if (isDigit(char)) {
481
+ let value = "";
482
+ const nextChar = source[i + 1];
483
+ const radixPrefix = char === "0" && nextChar != null && "xXoObB".includes(nextChar);
484
+ if (radixPrefix) {
485
+ value = source[i] + source[i + 1];
486
+ i += 2;
487
+ while(i < source.length && (isHexDigit(source[i]) || source[i] === "_")){
488
+ value += source[i];
489
+ i++;
490
+ }
491
+ } else {
492
+ while(i < source.length && (isDigit(source[i]) || source[i] === "." || source[i] === "_")){
493
+ value += source[i];
494
+ i++;
495
+ }
496
+ // Exponent part: e/E, optional sign, then digits. Only consumed when
497
+ // digits follow, so a stray identifier after a number still errors
498
+ if (source[i] === "e" || source[i] === "E") {
499
+ const signLength = source[i + 1] === "+" || source[i + 1] === "-" ? 1 : 0;
500
+ if (isDigit(source[i + 1 + signLength])) {
501
+ value += source[i];
502
+ i++;
503
+ if (signLength === 1) {
504
+ value += source[i];
505
+ i++;
506
+ }
507
+ while(i < source.length && isDigit(source[i])){
508
+ value += source[i];
509
+ i++;
510
+ }
511
+ }
512
+ }
513
+ }
514
+ tokens.push({
515
+ kind: "number",
516
+ value: value.replace(/_/g, "")
517
+ });
518
+ continue;
519
+ }
520
+ // Identifiers / keywords
521
+ if (isIdentifierStart(char)) {
522
+ let value = "";
523
+ while(i < source.length && isIdentifierPart(source[i])){
524
+ value += source[i];
525
+ i++;
526
+ }
527
+ tokens.push({
528
+ kind: "identifier",
529
+ value
530
+ });
531
+ continue;
532
+ }
533
+ // Multi-character punctuation (longest match first)
534
+ const multi = MULTI_CHARACTER_PUNCTUATION.find((w)=>source.startsWith(w, i));
535
+ if (multi != null) {
536
+ tokens.push({
537
+ kind: "punctuation",
538
+ value: multi
539
+ });
540
+ i += multi.length;
541
+ continue;
542
+ }
543
+ if (SINGLE_CHARACTER_PUNCTUATION.has(char)) {
544
+ tokens.push({
545
+ kind: "punctuation",
546
+ value: char
547
+ });
548
+ i++;
549
+ continue;
550
+ }
551
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`unexpected character '${char}'`));
552
+ }
553
+ return tokens;
554
+ };
555
+ /**
556
+ * Cursor over the token stream with the small set of lookahead operations the
557
+ * parser needs.
558
+ */ class TokenStream {
559
+ tokens;
560
+ index = 0;
561
+ constructor(tokens){
562
+ this.tokens = tokens;
563
+ }
564
+ get isAtEnd() {
565
+ return this.index >= this.tokens.length;
566
+ }
567
+ peek(offset = 0) {
568
+ return this.tokens[this.index + offset] ?? null;
569
+ }
570
+ next() {
571
+ const token = this.tokens[this.index];
572
+ if (token == null) {
573
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("unexpected end of expression"));
574
+ }
575
+ this.index++;
576
+ return token;
577
+ }
578
+ isPunctuation(value, offset = 0) {
579
+ const token = this.peek(offset);
580
+ return token != null && token.kind === "punctuation" && token.value === value;
581
+ }
582
+ matchPunctuation(value) {
583
+ if (this.isPunctuation(value)) {
584
+ this.index++;
585
+ return true;
586
+ }
587
+ return false;
588
+ }
589
+ expectPunctuation(value) {
590
+ if (!this.matchPunctuation(value)) {
591
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`expected '${value}'`));
592
+ }
593
+ }
594
+ }
595
+ const COMPARATOR_METHODS = {
596
+ startsWith: "starts-with",
597
+ endsWith: "ends-with",
598
+ includes: "includes"
599
+ };
600
+ const TRANSFORM_METHODS = {
601
+ toLowerCase: {
602
+ transformer: "to-lower-case",
603
+ locale: null
604
+ },
605
+ toUpperCase: {
606
+ transformer: "to-upper-case",
607
+ locale: null
608
+ },
609
+ toLocaleLowerCase: {
610
+ transformer: "to-lower-case",
611
+ locale: "en-US"
612
+ },
613
+ toLocaleUpperCase: {
614
+ transformer: "to-upper-case",
615
+ locale: "en-US"
616
+ }
617
+ };
618
+ const COMPARISON_OPERATORS = {
619
+ "==": {
167
620
  comparator: "equals",
168
621
  negated: false,
169
622
  strict: false
170
- }),
171
- "===": new _types__rspack_import_0.ComparatorExpression({
623
+ },
624
+ "===": {
172
625
  comparator: "equals",
173
626
  negated: false,
174
627
  strict: true
175
- }),
176
- "!=": new _types__rspack_import_0.ComparatorExpression({
628
+ },
629
+ "!=": {
177
630
  comparator: "equals",
178
631
  negated: true,
179
632
  strict: false
180
- }),
181
- "!==": new _types__rspack_import_0.ComparatorExpression({
633
+ },
634
+ "!==": {
182
635
  comparator: "equals",
183
636
  negated: true,
184
637
  strict: true
185
- }),
186
- ">=": new _types__rspack_import_0.ComparatorExpression({
187
- comparator: "greater-than-equals",
638
+ },
639
+ ">": {
640
+ comparator: "greater-than",
188
641
  negated: false,
189
642
  strict: false
190
- }),
191
- ">==": new _types__rspack_import_0.ComparatorExpression({
643
+ },
644
+ ">=": {
192
645
  comparator: "greater-than-equals",
193
646
  negated: false,
194
- strict: true
195
- }),
196
- "<=": new _types__rspack_import_0.ComparatorExpression({
197
- comparator: "less-than-equals",
198
- negated: false,
199
647
  strict: false
200
- }),
201
- "<==": new _types__rspack_import_0.ComparatorExpression({
202
- comparator: "less-than-equals",
203
- negated: false,
204
- strict: true
205
- }),
206
- ">": new _types__rspack_import_0.ComparatorExpression({
207
- comparator: "greater-than",
648
+ },
649
+ "<": {
650
+ comparator: "less-than",
208
651
  negated: false,
209
652
  strict: false
210
- }),
211
- "<": new _types__rspack_import_0.ComparatorExpression({
212
- comparator: "less-than",
653
+ },
654
+ "<=": {
655
+ comparator: "less-than-equals",
213
656
  negated: false,
214
657
  strict: false
215
- })
658
+ }
216
659
  };
217
- // Optimized comparator lookup using Map
218
- const COMPARATOR_MAP = new Map(Object.entries(comparators));
219
- // Error message constants
220
- const ERROR_MESSAGES = {
221
- COMPARATOR_NOT_FOUND: (value) => `Cannot find comparator: ${value}`,
222
- PROPERTY_NOT_FOUND: (path) => `Error parsing query, could not find PropertyInfo for path: ${path}`,
223
- PARAM_PATH_NOT_FOUND: (value, params) => `Cannot find path in params for .where(). Make sure parameters are not used inline.\r\nPath: ${value}, Params: ${JSON.stringify(params)}`
660
+ const SWAPPED_COMPARATORS = {
661
+ "equals": "equals",
662
+ "greater-than": "less-than",
663
+ "greater-than-equals": "less-than-equals",
664
+ "less-than": "greater-than",
665
+ "less-than-equals": "greater-than-equals",
666
+ "starts-with": "starts-with",
667
+ "ends-with": "ends-with",
668
+ "includes": "includes"
224
669
  };
225
- const STRINGIFIED_COMPARE_OPERATORS = ["true", "false"];
226
- const parseUnknown = (value) => {
227
- (0,_assertions__rspack_import_1.assertString)(value);
228
- return JSON.parse(value);
670
+ // #endregion
671
+ // #region Param references
672
+ /**
673
+ * Placeholder for a parameter value inside a cached expression template. Never
674
+ * escapes this module — binding replaces it with a plain ValueExpression that
675
+ * holds the resolved value.
676
+ */ class ParamReferenceExpression extends _types__rspack_import_1/* .ValueExpression */.Ko {
677
+ /** Path into the params object, excluding the params root name. */ paramPath;
678
+ /** The property this value is compared against; drives serialization/conversion at bind time. */ pairedProperty;
679
+ /** Whether the paired property's type converter applies (equality/relational comparisons only). */ applyConverter;
680
+ constructor(options){
681
+ super({
682
+ value: undefined
683
+ });
684
+ this.paramPath = options.paramPath;
685
+ this.pairedProperty = options.pairedProperty;
686
+ this.applyConverter = options.applyConverter;
687
+ }
688
+ }
689
+ const resolveParamPath = (paramsName, path, data)=>{
690
+ let result = data;
691
+ for(let i = 0; i < path.length; i++){
692
+ const name = path[i];
693
+ if (result != null && typeof result === "object" && name in result) {
694
+ result = result[name];
695
+ continue;
696
+ }
697
+ throw new ParamDependentParseError(ERROR_MESSAGES.PARAM_PATH_NOT_FOUND([
698
+ paramsName,
699
+ ...path
700
+ ].join("."), data));
701
+ }
702
+ return result;
229
703
  };
230
- const combineExpressions = (...expressions) => {
231
- if (expressions.length === 0) {
232
- throw new Error("combineExpressions requires at least 1 expression");
704
+ /**
705
+ * Applies the paired property's value serializer and (optionally) its schema
706
+ * type converter, matching how literal values are treated at parse time.
707
+ */ const resolvePairedValue = (value, pairedProperty, applyConverter)=>{
708
+ if (pairedProperty == null) {
709
+ return value;
233
710
  }
234
- if (expressions.length === 1) {
235
- return expressions[0];
711
+ let result = value;
712
+ if (pairedProperty.valueSerializer != null) {
713
+ result = String(pairedProperty.valueSerializer(parseUnknown(result)));
236
714
  }
237
- // Start with the first expression
238
- let result = expressions[0];
239
- // Loop through remaining expressions and combine them
240
- for (let i = 1; i < expressions.length; i++) {
241
- result = new _types__rspack_import_0.OperatorExpression({
242
- operator: "&&",
243
- left: result,
244
- right: expressions[i]
245
- });
715
+ if (applyConverter) {
716
+ result = converters[pairedProperty.type](result);
246
717
  }
247
718
  return result;
248
719
  };
249
- const toExpression = (schema, fn, params) => {
250
- const stringifiedFunction = fn.toString();
251
- try {
252
- // Optimized string parsing
253
- const arrowIndex = stringifiedFunction.indexOf('=>');
254
- if (arrowIndex === -1) {
255
- throw new Error("Invalid Function");
720
+ // #endregion
721
+ // #region Parser
722
+ /**
723
+ * Recursive descent parser over the token stream. Produces an expression
724
+ * template: literal values are fully resolved, parameter values are represented
725
+ * as ParamReferenceExpression placeholders so the template can be cached and
726
+ * re-bound with different params.
727
+ */ class ExpressionParser {
728
+ schema;
729
+ stream;
730
+ entityName;
731
+ paramsName;
732
+ params;
733
+ /** Set when a param value shaped the tree itself (e.g. x[p.name]) — such templates cannot be cached. */ structurallyDependsOnParams = false;
734
+ constructor(schema, stream, entityName, paramsName, params){
735
+ this.schema = schema;
736
+ this.stream = stream;
737
+ this.entityName = entityName;
738
+ this.paramsName = paramsName;
739
+ this.params = params;
740
+ }
741
+ parse() {
742
+ const expression = this.parseOr();
743
+ if (!this.stream.isAtEnd) {
744
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`unexpected token '${this.stream.peek()?.value}'`));
256
745
  }
257
- const parameterNames = stringifiedFunction.substring(0, arrowIndex).trim();
258
- let expression = stringifiedFunction.substring(arrowIndex + 2).trim();
259
- // Remove JavaScript comments from the expression
260
- expression = expression
261
- .replace(SINGLE_LINE_COMMENT_REGEX, '') // Remove single-line comments
262
- .replace(MULTI_LINE_COMMENT_REGEX, '') // Remove multi-line comments
263
- .replace(WHITESPACE_REGEX, ' ') // Normalize whitespace
264
- .trim();
265
- let parameterData = undefined;
266
- if (params != null) {
267
- let name;
268
- if (parameterNames.includes("[") && parameterNames.includes("]")) {
269
- // Optimized parameter name extraction
270
- const commaIndex = parameterNames.indexOf(",");
271
- if (commaIndex !== -1) {
272
- const bracketIndex = parameterNames.indexOf("]", commaIndex);
273
- if (bracketIndex !== -1) {
274
- name = parameterNames.substring(commaIndex + 1, bracketIndex).trim();
275
- }
276
- }
746
+ return expression;
747
+ }
748
+ // || binds loosest, so it sits at the root of the parse
749
+ parseOr() {
750
+ let left = this.parseAnd();
751
+ while(this.stream.matchPunctuation("||")){
752
+ const right = this.parseAnd();
753
+ // A tautology (`true`) absorbs the whole disjunction
754
+ if (_types__rspack_import_1/* .Expression.isEmpty */.r4.isEmpty(left) || _types__rspack_import_1/* .Expression.isEmpty */.r4.isEmpty(right)) {
755
+ left = _types__rspack_import_1/* .Expression.EMPTY */.r4.EMPTY;
756
+ continue;
277
757
  }
278
- parameterData = {
279
- name,
280
- data: params
281
- };
758
+ left = new _types__rspack_import_1/* .OperatorExpression */.fw({
759
+ operator: "||",
760
+ left,
761
+ right
762
+ });
282
763
  }
283
- return parseExpressionToTree(schema, expression, parameterData);
764
+ return left;
765
+ }
766
+ parseAnd() {
767
+ let left = this.parseUnary();
768
+ while(this.stream.matchPunctuation("&&")){
769
+ const right = this.parseUnary();
770
+ // A tautology (`true`) is the identity of a conjunction
771
+ if (_types__rspack_import_1/* .Expression.isEmpty */.r4.isEmpty(left)) {
772
+ left = right;
773
+ continue;
774
+ }
775
+ if (_types__rspack_import_1/* .Expression.isEmpty */.r4.isEmpty(right)) {
776
+ continue;
777
+ }
778
+ left = new _types__rspack_import_1/* .OperatorExpression */.fw({
779
+ operator: "&&",
780
+ left,
781
+ right
782
+ });
783
+ }
784
+ return left;
284
785
  }
285
- catch (error) {
286
- _utilities__rspack_import_2.logger.warn("Error parsing expression", {
287
- error,
288
- collectionName: schema.collectionName,
289
- params,
290
- selector: stringifiedFunction
291
- });
292
- return _types__rspack_import_0.Expression.NOT_PARSABLE;
786
+ parseUnary() {
787
+ if (this.stream.matchPunctuation("!")) {
788
+ return this.negateExpression(this.parseUnary());
789
+ }
790
+ return this.parseComparison();
791
+ }
792
+ /**
793
+ * Applies `!` to an already-parsed expression: comparators flip their
794
+ * negated flag, compound expressions distribute via De Morgan's laws.
795
+ */ negateExpression(expression) {
796
+ if (expression instanceof _types__rspack_import_1/* .ComparatorExpression */.bQ) {
797
+ expression.negated = !expression.negated;
798
+ return expression;
799
+ }
800
+ if (expression instanceof _types__rspack_import_1/* .OperatorExpression */.fw && expression.left != null && expression.right != null) {
801
+ return new _types__rspack_import_1/* .OperatorExpression */.fw({
802
+ operator: expression.operator === "&&" ? "||" : "&&",
803
+ left: this.negateExpression(expression.left),
804
+ right: this.negateExpression(expression.right)
805
+ });
806
+ }
807
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("'!' on this expression"));
808
+ }
809
+ parseComparison() {
810
+ // Parenthesized group
811
+ if (this.stream.matchPunctuation("(")) {
812
+ const expression = this.parseOr();
813
+ this.stream.expectPunctuation(")");
814
+ const trailing = this.stream.peek();
815
+ if (trailing != null && trailing.kind === "punctuation" && COMPARISON_OPERATORS[trailing.value] != null) {
816
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("comparison against a parenthesized expression"));
817
+ }
818
+ return expression;
819
+ }
820
+ const left = this.parseOperand();
821
+ const operatorToken = this.stream.peek();
822
+ if (operatorToken != null && operatorToken.kind === "punctuation" && COMPARISON_OPERATORS[operatorToken.value] != null) {
823
+ this.stream.next();
824
+ const right = this.parseOperand();
825
+ return this.buildComparison(left, COMPARISON_OPERATORS[operatorToken.value], right);
826
+ }
827
+ return this.buildStandalone(left);
293
828
  }
294
- };
295
- const parseExpressionToTree = (schema, expression, params) => {
296
- const parse = (exp) => {
297
- // Remove any wrapping parentheses
298
- exp = exp.trim();
299
- if (exp.startsWith('(') && exp.endsWith(')')) {
300
- let depth = 0;
301
- let isWrapper = true;
302
- for (let i = 0; i < exp.length; i++) {
303
- const char = exp[i];
304
- if (char === '(') {
305
- depth++;
306
- }
307
- else if (char === ')') {
308
- depth--;
309
- if (depth < 0)
310
- break; // Early exit for invalid parentheses
311
- }
312
- // Early exit if we find a closing parenthesis that's not the last character
313
- if (depth === 0 && i !== exp.length - 1) {
314
- isWrapper = false;
315
- break; // Early exit
316
- }
317
- // Early exit if we go negative (invalid parentheses)
318
- if (depth < 0) {
319
- isWrapper = false;
320
- break;
321
- }
829
+ parseOperand() {
830
+ const token = this.stream.peek();
831
+ if (token == null) {
832
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("unexpected end of expression"));
833
+ }
834
+ if (token.kind === "string") {
835
+ this.stream.next();
836
+ return this.withValueTransformer({
837
+ kind: "value",
838
+ value: token.value,
839
+ transformer: null,
840
+ locale: null
841
+ });
842
+ }
843
+ if (token.kind === "number") {
844
+ this.stream.next();
845
+ return {
846
+ kind: "value",
847
+ value: Number(token.value),
848
+ transformer: null,
849
+ locale: null
850
+ };
851
+ }
852
+ if (token.kind === "punctuation" && token.value === "-") {
853
+ this.stream.next();
854
+ const numberToken = this.stream.next();
855
+ if (numberToken.kind !== "number") {
856
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("unary '-' on a non-number"));
322
857
  }
323
- if (isWrapper) {
324
- exp = exp.slice(1, -1).trim();
858
+ return {
859
+ kind: "value",
860
+ value: -Number(numberToken.value),
861
+ transformer: null,
862
+ locale: null
863
+ };
864
+ }
865
+ if (token.kind === "punctuation" && token.value === "[") {
866
+ return this.parseArrayLiteralOperand();
867
+ }
868
+ if (token.kind === "identifier") {
869
+ return this.parseIdentifierOperand();
870
+ }
871
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(String(token.value)));
872
+ }
873
+ /**
874
+ * Parses an inline array of literals, e.g. `["active", "pending"]`, and the
875
+ * membership test that follows it: `[...].includes(entity.property)`.
876
+ */ parseArrayLiteralOperand() {
877
+ this.stream.expectPunctuation("[");
878
+ const elements = [];
879
+ while(!this.stream.isPunctuation("]")){
880
+ const element = this.parseOperand();
881
+ if (element.kind !== "value" || element.transformer != null) {
882
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a non-literal element in an array literal"));
883
+ }
884
+ elements.push(element.value);
885
+ if (!this.stream.matchPunctuation(",")) {
886
+ break;
325
887
  }
326
888
  }
327
- // Parse based on the operator precedence
328
- let operator = null, splitIndex = -1, depth = 0;
329
- for (let i = 0; i < exp.length - 1; i++) {
330
- const char = exp[i];
331
- if (char === '(')
332
- depth++;
333
- else if (char === ')')
334
- depth--;
335
- else if (depth === 0) {
336
- // Optimized operator detection using character comparison
337
- if (char === '&' && exp[i + 1] === '&') {
338
- operator = '&&';
339
- splitIndex = i;
340
- break; // AND takes precedence over OR
341
- }
342
- else if (operator === null && char === '|' && exp[i + 1] === '|') {
343
- operator = '||';
344
- splitIndex = i;
345
- }
889
+ this.stream.expectPunctuation("]");
890
+ const array = {
891
+ kind: "value",
892
+ value: elements,
893
+ transformer: null,
894
+ locale: null
895
+ };
896
+ // The only supported use is a membership test on a schema property
897
+ if (this.stream.isPunctuation(".") || this.stream.isPunctuation("?.")) {
898
+ this.stream.next();
899
+ const method = this.stream.next();
900
+ if (method.kind !== "identifier" || method.value !== "includes") {
901
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`'.${method.value}' on an array literal`));
902
+ }
903
+ this.stream.expectPunctuation("(");
904
+ const argument = this.parseOperand();
905
+ this.stream.expectPunctuation(")");
906
+ if (argument.kind === "method-call") {
907
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("nested method call inside .includes()"));
346
908
  }
909
+ return {
910
+ kind: "method-call",
911
+ target: array,
912
+ method: "includes",
913
+ argument
914
+ };
915
+ }
916
+ return array;
917
+ }
918
+ parseIdentifierOperand() {
919
+ const root = this.stream.next().value;
920
+ // Keyword literals
921
+ if (root === "true" || root === "false") {
922
+ return {
923
+ kind: "value",
924
+ value: root === "true",
925
+ transformer: null,
926
+ locale: null
927
+ };
928
+ }
929
+ if (root === "null") {
930
+ return {
931
+ kind: "value",
932
+ value: null,
933
+ transformer: null,
934
+ locale: null
935
+ };
936
+ }
937
+ if (root === "undefined") {
938
+ return {
939
+ kind: "value",
940
+ value: undefined,
941
+ transformer: null,
942
+ locale: null
943
+ };
347
944
  }
348
- if (operator) {
349
- const left = exp.slice(0, splitIndex).trim();
350
- const right = exp.slice(splitIndex + 2).trim();
351
- return new _types__rspack_import_0.OperatorExpression({
352
- operator,
353
- left: parse(left),
354
- right: parse(right)
945
+ if (root === "void") {
946
+ this.stream.next(); // the '0'
947
+ return {
948
+ kind: "value",
949
+ value: undefined,
950
+ transformer: null,
951
+ locale: null
952
+ };
953
+ }
954
+ if (root === this.entityName) {
955
+ return this.parseChain({
956
+ kind: "property",
957
+ root
355
958
  });
356
959
  }
357
- // If no operator, try to parse as a condition
358
- return parseCondition(schema, exp, params);
359
- };
360
- return parse(expression);
361
- };
362
- const convertAndAssignValue = (valueExpression, propertyPathExpression) => {
363
- assertIsPropertyPathExpression(propertyPathExpression);
364
- assertIsValueExpression(valueExpression);
365
- const propertyType = propertyPathExpression.property.type;
366
- valueExpression.value = converters[propertyType](valueExpression.value);
367
- };
368
- const converters = {
369
- Array: v => v,
370
- Boolean: v => v == null ? v : Boolean(v),
371
- Computed: v => v,
372
- Date: v => v,
373
- Definition: v => v,
374
- Function: v => v,
375
- Number: v => v == null ? v : Number(v),
376
- Object: v => v,
377
- String: v => v == null ? v : String(v)
378
- };
379
- const isExpression = (value) => {
380
- return typeof value === "object" && value !== null && "type" in value;
381
- };
382
- function assertIsExpression(value) {
383
- if (isExpression(value) === false) {
384
- throw new Error("Assertion Failed: Value is not a Expression");
385
- }
386
- }
387
- function assertIsPropertyPathExpression(value) {
388
- assertIsExpression(value);
389
- if (!("property" in value)) {
390
- throw new Error("Assertion Failed: Value is not a PropertyPathExpression");
391
- }
392
- }
393
- function assertIsValueExpression(value) {
394
- assertIsExpression(value);
395
- if (!("value" in value)) {
396
- throw new Error("Assertion Failed: Value is not a ValueExpression");
397
- }
398
- }
399
- // Helper function to detect if a string is a property path
400
- const isPropertyPath = (value, params) => {
401
- // Check for dot notation (e.g., entity.name)
402
- if (value.includes('.') && value.match(/^[a-zA-Z0-9_.]+$/) !== null) {
403
- return true;
404
- }
405
- // Check for bracket notation with literal strings (e.g., entity["name"], entity['name'], or entity[\"name\"] with escaped quotes)
406
- const literalBracketPattern = /^[a-zA-Z_$][a-zA-Z0-9_$]*(\[\\?["'][^"']+\\?["']\])+$/;
407
- if (literalBracketPattern.test(value)) {
408
- return true;
409
- }
410
- // Check for bracket notation with parameter paths (e.g., entity[p.name], entity[params.property])
411
- if (params && value.includes('[') && value.includes(']')) {
412
- const bracketMatch = value.match(/\[([^\]]+)\]/);
413
- if (bracketMatch) {
414
- const bracketContent = bracketMatch[1].trim();
415
- // Check if it's a parameter path - should start with params.name followed by dot, or be just params.name
416
- const isParamPath = bracketContent.startsWith(params.name + '.') || bracketContent === params.name;
417
- if (isParamPath || (bracketContent.includes('.') && bracketContent.match(PARAM_PATH_REGEX))) {
418
- return true;
960
+ if (this.paramsName != null && root === this.paramsName) {
961
+ return this.parseChain({
962
+ kind: "param",
963
+ root
964
+ });
965
+ }
966
+ // A bare variable from the outer scope — its value cannot be derived from source text
967
+ throw new Error(ERROR_MESSAGES.VARIABLE_VALUE(root));
968
+ }
969
+ /**
970
+ * Parses the segments after an entity/params root: dot access, bracket
971
+ * access, transform methods and comparator methods.
972
+ */ parseChain(options) {
973
+ const path = [];
974
+ let transformer = null;
975
+ let locale = null;
976
+ while(true){
977
+ if (this.stream.matchPunctuation(".") || this.stream.matchPunctuation("?.")) {
978
+ const segment = this.stream.next();
979
+ if (segment.kind !== "identifier") {
980
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`'.${segment.value}'`));
981
+ }
982
+ // Method call
983
+ if (this.stream.isPunctuation("(")) {
984
+ const method = segment.value;
985
+ if (TRANSFORM_METHODS[method] != null) {
986
+ this.stream.expectPunctuation("(");
987
+ this.stream.expectPunctuation(")");
988
+ transformer = TRANSFORM_METHODS[method].transformer;
989
+ locale = TRANSFORM_METHODS[method].locale;
990
+ continue;
991
+ }
992
+ if (COMPARATOR_METHODS[method] != null) {
993
+ this.stream.expectPunctuation("(");
994
+ const argument = this.parseOperand();
995
+ this.stream.expectPunctuation(")");
996
+ if (argument.kind === "method-call") {
997
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`nested method call inside .${method}()`));
998
+ }
999
+ return {
1000
+ kind: "method-call",
1001
+ target: this.resolveChain(options.kind, path, transformer, locale),
1002
+ method: method,
1003
+ argument
1004
+ };
1005
+ }
1006
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`method '.${method}()'`));
1007
+ }
1008
+ if (transformer != null) {
1009
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("property access after a transform method"));
1010
+ }
1011
+ path.push(segment.value);
1012
+ continue;
1013
+ }
1014
+ if (this.stream.matchPunctuation("[")) {
1015
+ path.push(this.parseBracketSegment(options.kind));
1016
+ this.stream.expectPunctuation("]");
1017
+ continue;
419
1018
  }
1019
+ break;
420
1020
  }
1021
+ return this.resolveChain(options.kind, path, transformer, locale);
421
1022
  }
422
- return false;
423
- };
424
- // Helper function to determine if we need to swap the operator for reversed comparisons
425
- const getSwappedOperator = (operator) => {
426
- const swapMap = {
427
- '>': '<',
428
- '<': '>',
429
- '>=': '<=',
430
- '<=': '>='
431
- };
432
- return swapMap[operator] || operator;
433
- };
434
- const parseCondition = (schema, expression, params) => {
435
- // Optimized string operations - single trim operation
436
- const trimmed = expression.trim();
437
- const isNegation = trimmed.startsWith('!');
438
- const finalExpression = isNegation ? trimmed.slice(1).trim() : trimmed;
439
- // Enhanced pattern matching for complex expressions
440
- const methodMatch = finalExpression.match(METHOD_REGEX);
441
- const transformMethodMatch = finalExpression.match(TRANSFORM_METHOD_REGEX);
442
- const equalityMatch = finalExpression.match(EQUALITY_REGEX);
443
- const comparisonMatch = finalExpression.match(COMPARISON_REGEX);
444
- if (methodMatch) {
445
- // Handle .startsWith or .endsWith
446
- const comparator = getComparator(methodMatch[2]);
447
- if (isNegation) {
448
- comparator.negated = isNegation;
449
- }
450
- // Check if the left side is a parameter path
451
- const leftSide = methodMatch[1];
452
- const rightSide = methodMatch[3];
453
- if (params && leftSide.startsWith(params.name)) {
454
- // This is a parameter path on the left side (e.g., params.distinctPlayers.includes(entity.playerId))
455
- // For includes method, we need to swap left and right sides
456
- if (methodMatch[2] === 'includes') {
457
- const property = getProperty(schema, rightSide, params);
458
- const value = getValue(leftSide, params); // retrieve the original value
459
- const serializer = property.property.valueSerializer;
460
- comparator.left = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
461
- comparator.right = property;
1023
+ parseBracketSegment(kind) {
1024
+ const token = this.stream.next();
1025
+ // Literal segment: entity["name"]
1026
+ if (token.kind === "string") {
1027
+ return token.value;
1028
+ }
1029
+ // Param-driven segment: entity[p.name] — the property depends on the
1030
+ // param VALUE, so the resulting template is tied to these params.
1031
+ // Stryker disable next-line all: documented equivalent cluster (see
1032
+ // docs/mutation-backlog.md) — every mutation of this four-conjunct guard reroutes
1033
+ // bracket access between two paths that both collapse to NOT_PARSABLE; the
1034
+ // experiment recorded there aimed 30 tests at this line and killed none.
1035
+ if (kind === "property" && token.kind === "identifier" && this.paramsName != null && token.value === this.paramsName) {
1036
+ const paramPath = [];
1037
+ while(this.stream.matchPunctuation(".") || this.stream.matchPunctuation("?.")){
1038
+ paramPath.push(this.stream.next().value);
462
1039
  }
463
- else {
464
- // For other methods, return NOT_PARSABLE for now
465
- return _types__rspack_import_0.Expression.NOT_PARSABLE;
1040
+ const resolved = resolveParamPath(this.paramsName, paramPath, this.params);
1041
+ if (typeof resolved !== "string") {
1042
+ throw new ParamDependentParseError(ERROR_MESSAGES.PROPERTY_NOT_FOUND(paramPath.join(".")));
466
1043
  }
1044
+ this.structurallyDependsOnParams = true;
1045
+ return resolved;
467
1046
  }
468
- else {
469
- // Normal case: property on left, value on right
470
- const property = getProperty(schema, leftSide, params);
471
- const serializer = property.property.valueSerializer;
472
- const value = getValue(rightSide, params); // retrieve the original value
473
- comparator.left = property;
474
- comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
475
- }
476
- // If the comparison is explicitly to false, mark it as negated
477
- if (methodMatch[6] === "false") {
478
- comparator.negated = true;
479
- }
480
- return comparator;
481
- }
482
- // Check for transformations on the value side (right side of comparison) - check this FIRST
483
- const valueTransformMatch = finalExpression.match(/([^=!<>]+?)\s*(===|==|!==|!=)\s*([^)]+)\.(toLowerCase|toUpperCase|toLocaleLowerCase|toLocaleUpperCase)\(\)/);
484
- if (valueTransformMatch) {
485
- const comparator = getComparator(valueTransformMatch[2]);
486
- if (isNegation) {
487
- comparator.negated = isNegation;
488
- }
489
- const property = getProperty(schema, valueTransformMatch[1].trim(), params);
490
- const serializer = property.property.valueSerializer;
491
- const value = getValue(valueTransformMatch[3], params); // retrieve the original value
492
- // Create the property expression for the left side (no transformer)
493
- const propertyExpression = property;
494
- // Create a ValueExpression for the right side with transformer
495
- const valueExpression = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
496
- // Set transformer and locale based on the method
497
- const method = valueTransformMatch[4];
498
- if (method === 'toLowerCase' || method === 'toLocaleLowerCase') {
499
- valueExpression.transformer = 'to-lower-case';
500
- if (method === 'toLocaleLowerCase') {
501
- valueExpression.locale = 'en-US';
1047
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`bracket access '[${token.value}]'`));
1048
+ }
1049
+ resolveChain(kind, path, transformer, locale) {
1050
+ if (kind === "param") {
1051
+ if (path.length === 0) {
1052
+ // `params` alone is a variable, not a value we can resolve
1053
+ throw new Error(ERROR_MESSAGES.PARAM_PATH_NOT_FOUND(this.paramsName ?? "params", this.params));
502
1054
  }
1055
+ return {
1056
+ kind: "param",
1057
+ path,
1058
+ transformer,
1059
+ locale
1060
+ };
503
1061
  }
504
- else {
505
- valueExpression.transformer = 'to-upper-case';
506
- if (method === 'toLocaleUpperCase') {
507
- valueExpression.locale = 'en-US';
1062
+ const pathString = path.join(".");
1063
+ const property = this.schema.properties.find((w)=>w.getAssignmentPath() == pathString);
1064
+ if (property == null) {
1065
+ // `.length` on a string/array property — a real schema property named
1066
+ // `length` wins (checked above); otherwise treat it as a transformer
1067
+ if (path.length > 1 && path[path.length - 1] === "length" && transformer == null) {
1068
+ const parentPath = path.slice(0, -1).join(".");
1069
+ const parent = this.schema.properties.find((w)=>w.getAssignmentPath() == parentPath);
1070
+ // Vector is deliberately absent. Its length is the dimension count declared
1071
+ // in the schema — a constant, not data — so a filter on it answers a question
1072
+ // nobody asks, and pushing it down would need `json_array_length` on a
1073
+ // backend storing JSON and something else entirely on one with a native
1074
+ // vector column. Not parsing it leaves a clear error instead of a dialect gap.
1075
+ if (parent != null && (parent.type === _schema__rspack_import_2/* .SchemaTypes.String */.L.String || parent.type === _schema__rspack_import_2/* .SchemaTypes.Array */.L.Array)) {
1076
+ return {
1077
+ kind: "property",
1078
+ property: parent,
1079
+ transformer: "length",
1080
+ locale: null
1081
+ };
1082
+ }
508
1083
  }
1084
+ throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(pathString));
509
1085
  }
510
- comparator.left = propertyExpression;
511
- comparator.right = valueExpression;
512
- return comparator;
513
- }
514
- if (transformMethodMatch) {
515
- // Handle .toLowerCase or .toUpperCase on the property side
516
- const comparator = getComparator(transformMethodMatch[3]); // e.g., startsWith, endsWith, includes
517
- if (isNegation) {
518
- comparator.negated = isNegation;
519
- }
520
- // Create the property expression for the left side with transformer
521
- const property = getProperty(schema, transformMethodMatch[1], params);
522
- // Set transformer and locale based on the method
523
- const method = transformMethodMatch[2];
524
- if (method === 'toLowerCase' || method === 'toLocaleLowerCase') {
525
- property.transformer = 'to-lower-case';
526
- if (method === 'toLocaleLowerCase') {
527
- property.locale = 'en-US'; // Default locale, could be extracted from method call
1086
+ return {
1087
+ kind: "property",
1088
+ property,
1089
+ transformer,
1090
+ locale
1091
+ };
1092
+ }
1093
+ withValueTransformer(operand) {
1094
+ if (this.stream.isPunctuation(".")) {
1095
+ const method = this.stream.peek(1);
1096
+ // Stryker disable next-line all: documented equivalent cluster (see
1097
+ // docs/mutation-backlog.md) the guard's conjuncts each route to a rejection that
1098
+ // collapses to NOT_PARSABLE with an indistinguishable message; 18 targeted tests
1099
+ // killed none of these.
1100
+ if (method != null && method.kind === "identifier" && TRANSFORM_METHODS[method.value] != null) {
1101
+ this.stream.next(); // .
1102
+ this.stream.next(); // method name
1103
+ this.stream.expectPunctuation("(");
1104
+ this.stream.expectPunctuation(")");
1105
+ operand.transformer = TRANSFORM_METHODS[method.value].transformer;
1106
+ operand.locale = TRANSFORM_METHODS[method.value].locale;
528
1107
  }
529
1108
  }
530
- else {
531
- property.transformer = 'to-upper-case';
532
- if (method === 'toLocaleUpperCase') {
533
- property.locale = 'en-US'; // Default locale, could be extracted from method call
1109
+ return operand;
1110
+ }
1111
+ // #region Condition building
1112
+ buildComparison(left, operator, right) {
1113
+ // methodCall == true/false — fold the boolean into negation
1114
+ if (left.kind === "method-call") {
1115
+ if (operator.comparator === "equals" && right.kind === "value" && typeof right.value === "boolean") {
1116
+ const comparator = this.buildMethodComparator(left);
1117
+ const comparedToFalse = right.value === false;
1118
+ comparator.negated = comparator.negated !== (operator.negated !== comparedToFalse);
1119
+ return comparator;
534
1120
  }
1121
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("comparing a method call to a non-boolean"));
535
1122
  }
536
- // Create a ValueExpression for the right side
537
- let value = getValue(transformMethodMatch[4], params);
538
- // Check if the value also has a transformation (but only if it's not already handled by value-side check)
539
- const valueTransformMatch = transformMethodMatch[4].match(/^([^)]+)\.(toLowerCase|toUpperCase|toLocaleLowerCase|toLocaleUpperCase)\(\)$/);
540
- if (valueTransformMatch) {
541
- // Create a new ValueExpression with the base value and transformer
542
- value = new _types__rspack_import_0.ValueExpression({
543
- value: valueTransformMatch[1].replace(/^["']|["']$/g, '') // Remove quotes
544
- });
545
- // Set transformer and locale based on the method
546
- const valueMethod = valueTransformMatch[2];
547
- if (valueMethod === 'toLowerCase' || valueMethod === 'toLocaleLowerCase') {
548
- value.transformer = 'to-lower-case';
549
- if (valueMethod === 'toLocaleLowerCase') {
550
- value.locale = 'en-US'; // Default locale
551
- }
552
- }
553
- else {
554
- value.transformer = 'to-upper-case';
555
- if (valueMethod === 'toLocaleUpperCase') {
556
- value.locale = 'en-US'; // Default locale
557
- }
1123
+ if (right.kind === "method-call") {
1124
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("method call on the right side of a comparison"));
1125
+ }
1126
+ if (left.kind === "property" && right.kind === "property") {
1127
+ // Casing transformers are only valid with string-matching comparators,
1128
+ // which cannot produce a property-to-property comparison
1129
+ if (left.transformer === "to-lower-case" || left.transformer === "to-upper-case" || right.transformer === "to-lower-case" || right.transformer === "to-upper-case") {
1130
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("transform method outside of startsWith/endsWith/includes"));
558
1131
  }
1132
+ return new _types__rspack_import_1/* .ComparatorExpression */.bQ({
1133
+ comparator: operator.comparator,
1134
+ negated: operator.negated,
1135
+ strict: operator.strict,
1136
+ left: this.createPropertyExpression(left),
1137
+ right: this.createPropertyExpression(right)
1138
+ });
559
1139
  }
560
- const serializer = property.property.valueSerializer;
561
- comparator.left = property;
562
- comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
563
- // If the comparison is explicitly to false, mark it as negated
564
- if (transformMethodMatch[7] === "false") {
565
- comparator.negated = true;
566
- }
567
- return comparator;
568
- }
569
- if (equalityMatch) {
570
- const left = equalityMatch[1].trim();
571
- const operator = equalityMatch[2];
572
- const right = equalityMatch[3].trim();
573
- const leftIsProperty = isPropertyPath(left, params);
574
- const rightIsProperty = isPropertyPath(right, params);
575
- // Determine which side is the property and which is the value
576
- let propertySide, valueSide, finalOperator;
577
- if (leftIsProperty && !rightIsProperty) {
578
- // Normal case: property === value
579
- propertySide = left;
580
- valueSide = right;
581
- finalOperator = operator;
582
- }
583
- else if (!leftIsProperty && rightIsProperty) {
584
- // Reversed case: value === property
585
- propertySide = right;
586
- valueSide = left;
587
- finalOperator = operator;
588
- }
589
- else {
590
- // Both sides look like properties or neither does - assume left is property
591
- propertySide = left;
592
- valueSide = right;
593
- finalOperator = operator;
594
- }
595
- const comparator = getComparator(finalOperator);
596
- if (isNegation) {
597
- comparator.negated = isNegation;
598
- }
599
- const property = getProperty(schema, propertySide, params);
600
- const value = getValue(valueSide, params);
601
- const serializer = property.property.valueSerializer;
602
- comparator.left = property;
603
- comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
604
- convertAndAssignValue(comparator.right, comparator.left);
605
- return comparator;
606
- }
607
- if (comparisonMatch) {
608
- const left = comparisonMatch[1].trim();
609
- const operator = comparisonMatch[2];
610
- const right = comparisonMatch[3].trim();
611
- const leftIsProperty = isPropertyPath(left, params);
612
- const rightIsProperty = isPropertyPath(right, params);
613
- // Determine which side is the property and which is the value
614
- let propertySide, valueSide, finalOperator;
615
- if (leftIsProperty && !rightIsProperty) {
616
- // Normal case: property > value
617
- propertySide = left;
618
- valueSide = right;
619
- finalOperator = operator;
620
- }
621
- else if (!leftIsProperty && rightIsProperty) {
622
- // Reversed case: value > property -> property < value
623
- propertySide = right;
624
- valueSide = left;
625
- finalOperator = getSwappedOperator(operator);
626
- }
627
- else {
628
- // Both sides look like properties or neither does - assume left is property
629
- propertySide = left;
630
- valueSide = right;
631
- finalOperator = operator;
632
- }
633
- const comparator = getComparator(finalOperator);
634
- if (isNegation) {
635
- comparator.negated = isNegation;
636
- }
637
- const property = getProperty(schema, propertySide, params);
638
- const value = getValue(valueSide, params);
639
- const serializer = property.property.valueSerializer;
640
- comparator.left = property;
641
- comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
642
- convertAndAssignValue(comparator.right, comparator.left);
643
- return comparator;
644
- }
645
- // Check for standalone property reference (truthy comparison)
646
- // Pattern: property name only (e.g., "w.inStock" -> w.inStock === true)
647
- const standalonePropertyMatch = finalExpression.match(/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/);
648
- if (standalonePropertyMatch && isPropertyPath(finalExpression, params)) {
649
- const comparator = getComparator('===');
650
- if (isNegation) {
651
- comparator.negated = isNegation;
652
- }
653
- const property = getProperty(schema, finalExpression, params);
654
- const value = getValue('true', params);
655
- const serializer = property.property.valueSerializer;
656
- comparator.left = property;
657
- // need to parse the value so it matches what the serializer expects
658
- comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
659
- return comparator;
660
- }
661
- // If we get here, the expression is too complex for the current parser
662
- // This is expected for complex real-world expressions
663
- throw new Error(`Unsupported expression format: ${finalExpression}`);
664
- };
665
- const getComparator = (value) => {
666
- const comparator = COMPARATOR_MAP.get(value);
667
- if (comparator == null) {
668
- throw new Error(ERROR_MESSAGES.COMPARATOR_NOT_FOUND(value));
669
- }
670
- // Return a new instance to avoid modifying the cached one
671
- return new _types__rspack_import_0.ComparatorExpression({
672
- comparator: comparator.comparator,
673
- negated: comparator.negated,
674
- strict: comparator.strict
675
- });
676
- };
677
- const getValue = (value, params) => {
678
- // Early return for string literals
679
- if (value.startsWith("'") || value.startsWith("\"")) {
680
- return new _types__rspack_import_0.ValueExpression({
681
- value: value.replace(/"|'/g, "")
682
- });
683
- }
684
- // Early return for null/undefined
685
- if (value === "null") {
686
- return new _types__rspack_import_0.ValueExpression({ value: null });
687
- }
688
- if (value === "undefined" || value === "void 0") {
689
- return new _types__rspack_import_0.ValueExpression({ value: undefined });
1140
+ if (left.kind === "property" && right.kind !== "property") {
1141
+ return this.buildPropertyComparator(left, operator, right, /* applyConverter */ true);
1142
+ }
1143
+ if (right.kind === "property" && left.kind !== "property") {
1144
+ const swapped = {
1145
+ ...operator,
1146
+ comparator: SWAPPED_COMPARATORS[operator.comparator]
1147
+ };
1148
+ return this.buildPropertyComparator(right, swapped, left, /* applyConverter */ true);
1149
+ }
1150
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("comparison requires a schema property on at least one side"));
690
1151
  }
691
- // Optimized number parsing with early return
692
- const numValue = +value;
693
- if (!isNaN(numValue) && isFinite(numValue)) {
694
- return new _types__rspack_import_0.ValueExpression({ value: numValue });
1152
+ buildStandalone(operand) {
1153
+ if (operand.kind === "method-call") {
1154
+ return this.buildMethodComparator(operand);
1155
+ }
1156
+ if (operand.kind === "property") {
1157
+ // Truthy shorthand on `.length`: a length is truthy exactly when > 0
1158
+ if (operand.transformer === "length") {
1159
+ return this.buildPropertyComparator(operand, COMPARISON_OPERATORS[">"], {
1160
+ kind: "value",
1161
+ value: 0,
1162
+ transformer: null,
1163
+ locale: null
1164
+ }, /* applyConverter */ true);
1165
+ }
1166
+ // Truthy shorthand: `w.isActive` → isActive === true
1167
+ return this.buildPropertyComparator(operand, COMPARISON_OPERATORS["==="], {
1168
+ kind: "value",
1169
+ value: true,
1170
+ transformer: null,
1171
+ locale: null
1172
+ }, /* applyConverter */ true);
1173
+ }
1174
+ // Constant `true` — a tautology, which parseAnd/parseOr simplify away
1175
+ if (operand.kind === "value" && operand.value === true && operand.transformer == null) {
1176
+ return _types__rspack_import_1/* .Expression.EMPTY */.r4.EMPTY;
1177
+ }
1178
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a filter condition must reference a schema property"));
695
1179
  }
696
- // Handle parameter paths if params are provided
697
- if (params != null) {
698
- // Check if this is a parameter path (starts with params.name)
699
- if (value.startsWith(params.name)) {
700
- return new _types__rspack_import_0.ValueExpression({
701
- value: getValueFromParams(value, params)
1180
+ buildMethodComparator(operand) {
1181
+ const { target, method, argument } = operand;
1182
+ if (target.kind === "property") {
1183
+ if (argument.kind === "property") {
1184
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`.${method}() comparing two schema properties`));
1185
+ }
1186
+ // Method arguments skip type conversion — only the value serializer applies
1187
+ return this.buildPropertyComparator(target, {
1188
+ comparator: COMPARATOR_METHODS[method],
1189
+ negated: false,
1190
+ strict: false
1191
+ }, argument, /* applyConverter */ false);
1192
+ }
1193
+ // ["a", "b"].includes(x.prop) / params.list.includes(x.prop) —
1194
+ // membership test with the collection on the left
1195
+ if (method === "includes" && argument.kind === "property") {
1196
+ if (target.transformer != null) {
1197
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("transform method on a collection used with .includes()"));
1198
+ }
1199
+ return new _types__rspack_import_1/* .ComparatorExpression */.bQ({
1200
+ comparator: "includes",
1201
+ negated: false,
1202
+ strict: false,
1203
+ left: this.createValueExpression(target, argument.property, /* applyConverter */ false),
1204
+ right: this.createPropertyExpression(argument)
702
1205
  });
703
1206
  }
704
- // Check if this is a parameter path without the params prefix
705
- if (value.includes('.')) {
706
- // Try to extract the parameter path
707
- const paramMatch = value.match(PARAM_PATH_REGEX);
708
- if (paramMatch) {
709
- const potentialParamPath = paramMatch[1];
710
- try {
711
- const paramValue = getValueFromParams(`${params.name}.${potentialParamPath}`, params);
712
- return new _types__rspack_import_0.ValueExpression({ value: paramValue });
713
- }
714
- catch {
715
- // Not a parameter path, continue with normal parsing
716
- }
1207
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`.${method}() on a non-property target`));
1208
+ }
1209
+ buildPropertyComparator(property, operator, value, applyConverter) {
1210
+ const isStringMatch = operator.comparator === "starts-with" || operator.comparator === "ends-with" || operator.comparator === "includes";
1211
+ // `.length` compares a NUMBER, so the paired property's serializer and
1212
+ // type converter must not touch the value; and a length has no meaning
1213
+ // inside a string-matching comparator
1214
+ if (property.transformer === "length") {
1215
+ if (isStringMatch) {
1216
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("'.length' with startsWith/endsWith/includes"));
717
1217
  }
1218
+ return new _types__rspack_import_1/* .ComparatorExpression */.bQ({
1219
+ comparator: operator.comparator,
1220
+ negated: operator.negated,
1221
+ strict: operator.strict,
1222
+ left: this.createPropertyExpression(property),
1223
+ right: this.createValueExpression(value, null, /* applyConverter */ false)
1224
+ });
718
1225
  }
1226
+ // Casing transformers on a property are only meaningful with string-matching
1227
+ // comparators; on relational comparators the plugins would silently
1228
+ // ignore them and return wrong data
1229
+ if (property.transformer != null && !isStringMatch) {
1230
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("transform method outside of startsWith/endsWith/includes"));
1231
+ }
1232
+ return new _types__rspack_import_1/* .ComparatorExpression */.bQ({
1233
+ comparator: operator.comparator,
1234
+ negated: operator.negated,
1235
+ strict: operator.strict,
1236
+ left: this.createPropertyExpression(property),
1237
+ right: this.createValueExpression(value, property.property, applyConverter)
1238
+ });
719
1239
  }
720
- if (STRINGIFIED_COMPARE_OPERATORS.includes(value)) {
721
- return new _types__rspack_import_0.ValueExpression({ value });
1240
+ createPropertyExpression(operand) {
1241
+ const expression = new _types__rspack_import_1/* .PropertyExpression */.ep({
1242
+ property: operand.property
1243
+ });
1244
+ expression.transformer = operand.transformer;
1245
+ expression.locale = operand.locale;
1246
+ return expression;
1247
+ }
1248
+ createValueExpression(operand, pairedProperty, applyConverter) {
1249
+ if (operand.kind === "param") {
1250
+ const expression = new ParamReferenceExpression({
1251
+ paramPath: operand.path,
1252
+ pairedProperty,
1253
+ applyConverter
1254
+ });
1255
+ expression.transformer = operand.transformer;
1256
+ expression.locale = operand.locale;
1257
+ return expression;
1258
+ }
1259
+ const expression = new _types__rspack_import_1/* .ValueExpression */.Ko({
1260
+ value: resolvePairedValue(operand.value, pairedProperty, applyConverter)
1261
+ });
1262
+ expression.transformer = operand.transformer;
1263
+ expression.locale = operand.locale;
1264
+ return expression;
722
1265
  }
723
- if (isNaN(numValue)) {
724
- // value is a variable passed in by the dev, we cannot evaluate it's value
725
- // need to fallback to select all by throwing an error
726
- throw new Error(`Cannot derive value from variable, please pass parameters into the expression.
727
-
728
- Example: .where(([x, params]) => x.id === params.id, { id: someVar.id })
729
- Issue At: ${value}`);
1266
+ }
1267
+ // #endregion
1268
+ // #region Template binding
1269
+ /**
1270
+ * Deep-clones a template into a consumer-facing tree, resolving parameter
1271
+ * placeholders against the supplied params. Always clones so cached templates
1272
+ * can never be mutated by consumers.
1273
+ */ const bindExpression = (expression, paramsName, params)=>{
1274
+ if (expression instanceof ParamReferenceExpression) {
1275
+ const raw = resolveParamPath(paramsName ?? "params", expression.paramPath, params);
1276
+ const bound = new _types__rspack_import_1/* .ValueExpression */.Ko({
1277
+ value: resolvePairedValue(raw, expression.pairedProperty, expression.applyConverter)
1278
+ });
1279
+ bound.transformer = expression.transformer;
1280
+ bound.locale = expression.locale;
1281
+ return bound;
730
1282
  }
731
- // Default case: return as-is
732
- return new _types__rspack_import_0.ValueExpression({ value });
733
- };
734
- const getValueFromParams = (value, params) => {
735
- const split = value.split('.');
736
- // Early exit for invalid paths
737
- if (split.length === 1) {
738
- throw new Error(ERROR_MESSAGES.PARAM_PATH_NOT_FOUND(value, params.data));
739
- }
740
- let result = params.data;
741
- // For nested params - start from index 1 to skip the params prefix
742
- for (let i = 1; i < split.length; i++) {
743
- const name = split[i];
744
- if (name in result) {
745
- result = result[name];
746
- continue;
747
- }
748
- throw new Error(ERROR_MESSAGES.PARAM_PATH_NOT_FOUND(value, params.data));
1283
+ if (expression instanceof _types__rspack_import_1/* .ValueExpression */.Ko) {
1284
+ const clone = new _types__rspack_import_1/* .ValueExpression */.Ko({
1285
+ value: expression.value
1286
+ });
1287
+ clone.transformer = expression.transformer;
1288
+ clone.locale = expression.locale;
1289
+ return clone;
749
1290
  }
750
- return result;
1291
+ if (expression instanceof _types__rspack_import_1/* .PropertyExpression */.ep) {
1292
+ const clone = new _types__rspack_import_1/* .PropertyExpression */.ep({
1293
+ property: expression.property
1294
+ });
1295
+ clone.transformer = expression.transformer;
1296
+ clone.locale = expression.locale;
1297
+ return clone;
1298
+ }
1299
+ if (expression instanceof _types__rspack_import_1/* .ComparatorExpression */.bQ) {
1300
+ return new _types__rspack_import_1/* .ComparatorExpression */.bQ({
1301
+ comparator: expression.comparator,
1302
+ negated: expression.negated,
1303
+ strict: expression.strict,
1304
+ left: expression.left ? bindExpression(expression.left, paramsName, params) : undefined,
1305
+ right: expression.right ? bindExpression(expression.right, paramsName, params) : undefined
1306
+ });
1307
+ }
1308
+ if (expression instanceof _types__rspack_import_1/* .OperatorExpression */.fw) {
1309
+ return new _types__rspack_import_1/* .OperatorExpression */.fw({
1310
+ operator: expression.operator,
1311
+ left: expression.left ? bindExpression(expression.left, paramsName, params) : undefined,
1312
+ right: expression.right ? bindExpression(expression.right, paramsName, params) : undefined
1313
+ });
1314
+ }
1315
+ return expression;
751
1316
  };
752
- const getProperty = (schema, value, params) => {
753
- let pathString;
754
- // Handle bracket notation (e.g., entity["name"], entity['name'], entity[p.name], or entity[\"name\"] with escaped quotes)
755
- if (value.includes('[') && value.includes(']')) {
756
- // First try to match literal string brackets: ["name"], ['name'], [\"name\"], [\'name\']
757
- const literalBracketMatches = value.matchAll(/\[\\?["']([^"']+)\\?["']\]/g);
758
- const pathParts = [];
759
- let foundLiteral = false;
760
- for (const match of literalBracketMatches) {
761
- // match[1] is the property name inside the brackets
762
- const propName = match[1];
763
- if (propName) {
764
- pathParts.push(propName);
765
- foundLiteral = true;
766
- }
1317
+ /**
1318
+ * Splits stringified filter source into parameter names and the expression
1319
+ * body, unwrapping single-return block bodies.
1320
+ */ const resolveFunctionShape = (stringifiedFunction, hasParams)=>{
1321
+ const source = stringifiedFunction.trim();
1322
+ let parameterNames;
1323
+ let body;
1324
+ // `function (x) { ... }` / `function name(x) { ... }` — what ES5-targeting
1325
+ // transpilers rewrite every arrow filter into
1326
+ const functionHead = /^function\b[^(]*\(/.exec(source);
1327
+ if (functionHead != null) {
1328
+ const parametersEnd = source.indexOf(")", functionHead[0].length);
1329
+ if (parametersEnd === -1) {
1330
+ throw new Error("Invalid Function");
767
1331
  }
768
- // If no literal matches found, try parameter path in brackets (e.g., [p.name])
769
- if (!foundLiteral && params) {
770
- // Match brackets containing parameter paths: [p.name], [params.property], etc.
771
- const bracketParamMatch = value.match(/\[([^\]]+)\]/);
772
- if (bracketParamMatch) {
773
- const bracketContent = bracketParamMatch[1].trim();
774
- // Check if this is a parameter path
775
- // It should start with params.name (e.g., "p") followed by a dot, or be just params.name
776
- const isParamPath = bracketContent.startsWith(params.name + '.') || bracketContent === params.name;
777
- if (isParamPath || (bracketContent.includes('.') && bracketContent.match(PARAM_PATH_REGEX))) {
778
- try {
779
- // Try to resolve as a parameter path
780
- let paramPath;
781
- if (bracketContent.startsWith(params.name + '.') || bracketContent === params.name) {
782
- // Already has params.name prefix
783
- paramPath = bracketContent;
784
- }
785
- else {
786
- // Add params.name prefix
787
- const paramMatch = bracketContent.match(PARAM_PATH_REGEX);
788
- paramPath = paramMatch
789
- ? `${params.name}.${paramMatch[1]}`
790
- : `${params.name}.${bracketContent}`;
791
- }
792
- const resolvedValue = getValueFromParams(paramPath, params);
793
- // The resolved value should be the property name
794
- if (typeof resolvedValue === 'string') {
795
- pathParts.push(resolvedValue);
796
- }
797
- else {
798
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
799
- }
800
- }
801
- catch {
802
- // Not a valid parameter path, continue to error
803
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
804
- }
805
- }
806
- else {
807
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
808
- }
809
- }
810
- else {
811
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
812
- }
1332
+ parameterNames = source.slice(functionHead[0].length, parametersEnd).trim();
1333
+ body = source.slice(parametersEnd + 1).trim();
1334
+ } else {
1335
+ const arrowIndex = source.indexOf("=>");
1336
+ if (arrowIndex === -1) {
1337
+ throw new Error("Invalid Function");
813
1338
  }
814
- if (pathParts.length === 0) {
815
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
1339
+ parameterNames = source.substring(0, arrowIndex).trim();
1340
+ body = source.substring(arrowIndex + 2).trim();
1341
+ // Strip wrapping parens: (entity) or ([x, p])
1342
+ if (parameterNames.startsWith("(") && parameterNames.endsWith(")")) {
1343
+ parameterNames = parameterNames.slice(1, -1).trim();
816
1344
  }
817
- pathString = pathParts.join(".");
818
1345
  }
819
- else if (value.includes('.')) {
820
- // Handle dot notation (e.g., entity.name)
821
- const pathSplit = value.split(/[?!.]/g).slice(1);
822
- pathString = pathSplit.join(".");
823
- }
824
- else {
825
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
1346
+ let entityName;
1347
+ let paramsName = null;
1348
+ if (parameterNames.startsWith("[") && parameterNames.endsWith("]")) {
1349
+ const destructured = parameterNames.slice(1, -1).split(",").map((w)=>w.trim());
1350
+ entityName = destructured[0];
1351
+ if (hasParams) {
1352
+ paramsName = destructured[1] ?? null;
1353
+ }
1354
+ } else {
1355
+ entityName = parameterNames;
826
1356
  }
827
- // Early exit if no path found
828
- if (!pathString) {
829
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
1357
+ if (entityName == null || entityName.length === 0) {
1358
+ throw new Error("Invalid Function");
830
1359
  }
831
- const found = schema.properties.find(w => w.getAssignmentPath() == pathString);
832
- if (found == null) {
833
- throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
1360
+ // Unwrap a single-return block body: { return <expression>; }
1361
+ if (body.startsWith("{")) {
1362
+ const inner = body.slice(1, body.lastIndexOf("}")).trim();
1363
+ if (!inner.startsWith("return")) {
1364
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("block body without a single return statement"));
1365
+ }
1366
+ body = inner.slice("return".length).trim();
1367
+ if (body.endsWith(";")) {
1368
+ body = body.slice(0, -1).trim();
1369
+ }
834
1370
  }
835
- return new _types__rspack_import_0.PropertyExpression({ property: found });
1371
+ return {
1372
+ entityName,
1373
+ paramsName,
1374
+ body
1375
+ };
836
1376
  };
837
-
838
-
839
- },
840
- "./src/expressions/sql.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
841
- __webpack_require__.r(__webpack_exports__);
842
- __webpack_require__.d(__webpack_exports__, {
843
- getDialect: () => (getDialect),
844
- toSql: () => (toSql)
845
- });
846
- /* import */ var _assertions__rspack_import_0 = __webpack_require__("./src/assertions/index.ts");
847
-
848
- const DIALECTS = {
849
- sqlite: {
850
- quoteIdentifier(name) {
851
- return `"${name.replace(/"/g, '""')}"`;
852
- },
853
- getPlaceholder(_i) {
854
- return "?";
855
- },
856
- stringMatchKind: "GLOB",
857
- likeEscapeClause() {
858
- return "";
859
- },
860
- },
861
- postgresql: {
862
- quoteIdentifier(name) {
863
- return `"${name.replace(/"/g, '""')}"`;
864
- },
865
- getPlaceholder(i) {
866
- return `$${i + 1}`;
867
- },
868
- stringMatchKind: "LIKE",
869
- likeEscapeClause() {
870
- return " ESCAPE E'\\\\'";
871
- },
872
- },
873
- mysql: {
874
- quoteIdentifier(name) {
875
- return "`" + name.replace(/`/g, "``") + "`";
876
- },
877
- getPlaceholder(_i) {
878
- return "?";
879
- },
880
- stringMatchKind: "LIKE",
881
- likeEscapeClause() {
882
- return " ESCAPE '\\\\'";
883
- },
884
- },
885
- mssql: {
886
- quoteIdentifier(name) {
887
- return "[" + name.replace(/]/g, "]]") + "]";
888
- },
889
- getPlaceholder(i) {
890
- return `@p${i + 1}`;
891
- },
892
- stringMatchKind: "LIKE",
893
- likeEscapeClause() {
894
- return " ESCAPE '\\\\'";
895
- },
896
- },
1377
+ // Keyed by schema instance so identical filter source on different schemas can
1378
+ // never collide; entries live only as long as the schema does
1379
+ const templateCache = new WeakMap();
1380
+ const MAX_CACHED_TEMPLATES_PER_SCHEMA = 1024;
1381
+ const getCachedTemplate = (schema, source)=>{
1382
+ return templateCache.get(schema)?.get(source) ?? null;
897
1383
  };
898
- function getDialect(name) {
899
- const d = DIALECTS[name];
900
- if (!d)
901
- throw new Error(`Unknown SQL dialect: ${name}`);
902
- return d;
903
- }
904
- function escapeLikeLiteral(value) {
905
- return value.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
906
- }
907
- function escapeGlobLiteral(value) {
908
- return value.replace(/\\/g, "\\\\").replace(/\*/g, "\\*").replace(/\?/g, "\\?");
909
- }
910
- function escapeForPattern(value, kind) {
911
- return kind === "LIKE" ? escapeLikeLiteral(value) : escapeGlobLiteral(value);
912
- }
913
- function buildPattern(escapedValue, match, kind) {
914
- if (kind === "LIKE") {
915
- switch (match) {
916
- case "contains":
917
- return `%${escapedValue}%`;
918
- case "starts-with":
919
- return `${escapedValue}%`;
920
- case "ends-with":
921
- return `%${escapedValue}`;
922
- }
923
- }
924
- switch (match) {
925
- case "contains":
926
- return `*${escapedValue}*`;
927
- case "starts-with":
928
- return `${escapedValue}*`;
929
- case "ends-with":
930
- return `*${escapedValue}`;
931
- }
932
- }
933
- function getPropertyValueSides(cmp) {
934
- const propLeft = cmp.left && (0,_assertions__rspack_import_0.isPropertyExpression)(cmp.left) ? cmp.left : null;
935
- const propRight = cmp.right && (0,_assertions__rspack_import_0.isPropertyExpression)(cmp.right) ? cmp.right : null;
936
- const valLeft = cmp.left && (0,_assertions__rspack_import_0.isValueExpression)(cmp.left) ? cmp.left.value : null;
937
- const valRight = cmp.right && (0,_assertions__rspack_import_0.isValueExpression)(cmp.right) ? cmp.right.value : null;
938
- return { propLeft, propRight, valLeft, valRight };
939
- }
940
- function getEqualsCase(value, columnOnLeft, columnOnRight) {
941
- if (value === null && columnOnLeft)
942
- return "null-column-left";
943
- if (value === null && columnOnRight)
944
- return "null-column-right";
945
- if (value !== null && columnOnLeft)
946
- return "value-column-left";
947
- if (value !== null && columnOnRight)
948
- return "value-column-right";
949
- return null;
950
- }
951
- function equalsNullColumnLeft(ctx) {
952
- return ctx.negated ? `${ctx.col} IS NOT NULL` : `${ctx.col} IS NULL`;
953
- }
954
- function equalsNullColumnRight(ctx) {
955
- ctx.params.push(null);
956
- const ph = ctx.placeholder();
957
- return ctx.negated ? `${ph} IS NOT NULL` : `${ph} IS NULL`;
958
- }
959
- function equalsValueColumnLeft(ctx) {
960
- ctx.params.push(ctx.value);
961
- const ph = ctx.placeholder();
962
- return ctx.negated ? `${ctx.col} != ${ph}` : `${ctx.col} = ${ph}`;
963
- }
964
- function equalsValueColumnRight(ctx) {
965
- ctx.params.push(ctx.value);
966
- const ph = ctx.placeholder();
967
- return ctx.negated ? `${ph} != ${ctx.col}` : `${ph} = ${ctx.col}`;
968
- }
969
- const EQUALS_STRATEGIES = {
970
- "null-column-left": equalsNullColumnLeft,
971
- "null-column-right": equalsNullColumnRight,
972
- "value-column-left": equalsValueColumnLeft,
973
- "value-column-right": equalsValueColumnRight,
1384
+ const setCachedTemplate = (schema, source, entry)=>{
1385
+ let bySource = templateCache.get(schema);
1386
+ if (bySource == null) {
1387
+ bySource = new Map();
1388
+ templateCache.set(schema, bySource);
1389
+ }
1390
+ // Filter source strings come from static code, so this cap should never be
1391
+ // hit in practice — it only guards against unbounded dynamic generation.
1392
+ // Stryker disable next-line all: the cap is a pure resource bound — every mutation of
1393
+ // it (never clear, always clear, off-by-one) parses identically and differs only in
1394
+ // memory growth, which no observable boundary can assert.
1395
+ if (bySource.size >= MAX_CACHED_TEMPLATES_PER_SCHEMA) {
1396
+ bySource.clear();
1397
+ }
1398
+ bySource.set(source, entry);
974
1399
  };
975
- // --- String-pattern comparison (includes / starts-with / ends-with) ---
976
- function renderStringPatternComparison(cmp, d, params, placeholder) {
977
- const { propLeft, propRight, valLeft, valRight } = getPropertyValueSides(cmp);
978
- const kind = d.stringMatchKind;
979
- if (cmp.comparator === "includes") {
980
- const col = propLeft && valRight !== null
981
- ? d.quoteIdentifier(propLeft.property.name)
982
- : propRight && valLeft !== null
983
- ? d.quoteIdentifier(propRight.property.name)
984
- : null;
985
- const value = valRight !== null ? valRight : valLeft;
986
- if (col === null) {
987
- throw new Error("Complex expressions not supported for includes operations");
988
- }
989
- if (Array.isArray(value)) {
990
- const placeholders = value.map(() => placeholder()).join(", ");
991
- params.push(...value);
992
- return cmp.negated ? `${col} NOT IN (${placeholders})` : `${col} IN (${placeholders})`;
993
- }
994
- const escaped = escapeForPattern(String(value), kind);
995
- const pattern = buildPattern(escaped, "contains", kind);
996
- params.push(pattern);
997
- const ph = placeholder();
998
- const op = kind === "GLOB" ? "GLOB" : "LIKE";
999
- const escape = kind === "LIKE" ? d.likeEscapeClause() : "";
1000
- if (propLeft && valRight !== null) {
1001
- return cmp.negated ? `${col} NOT ${op} ${ph}${escape}` : `${col} ${op} ${ph}${escape}`;
1002
- }
1003
- return cmp.negated ? `${ph} NOT ${op} ${col}${escape}` : `${ph} ${op} ${col}${escape}`;
1004
- }
1005
- const col = propLeft && valRight !== null
1006
- ? d.quoteIdentifier(propLeft.property.name)
1007
- : propRight && valLeft !== null
1008
- ? d.quoteIdentifier(propRight.property.name)
1009
- : null;
1010
- const value = valRight !== null ? String(valRight) : valLeft !== null ? String(valLeft) : null;
1011
- if (col === null || value === null) {
1012
- throw new Error(`Complex expressions not supported for ${cmp.comparator} operations`);
1013
- }
1014
- const escaped = escapeForPattern(value, kind);
1015
- const pattern = buildPattern(escaped, cmp.comparator === "starts-with" ? "starts-with" : "ends-with", kind);
1016
- params.push(pattern);
1017
- const ph = placeholder();
1018
- const op = kind === "GLOB" ? "GLOB" : "LIKE";
1019
- const escape = kind === "LIKE" ? d.likeEscapeClause() : "";
1020
- if (propLeft && valRight !== null) {
1021
- return cmp.negated ? `${col} NOT ${op} ${ph}${escape}` : `${col} ${op} ${ph}${escape}`;
1022
- }
1023
- return cmp.negated ? `${ph} NOT ${op} ${col}${escape}` : `${ph} ${op} ${col}${escape}`;
1024
- }
1025
- // --- Generic comparison ---
1026
- function renderGenericComparison(cmp, walk) {
1027
- const leftExpr = walk(cmp.left);
1028
- const rightExpr = walk(cmp.right);
1029
- switch (cmp.comparator) {
1030
- case "equals":
1031
- return cmp.negated ? `${leftExpr} != ${rightExpr}` : `${leftExpr} = ${rightExpr}`;
1032
- case "greater-than":
1033
- return cmp.negated ? `${leftExpr} <= ${rightExpr}` : `${leftExpr} > ${rightExpr}`;
1034
- case "greater-than-equals":
1035
- return cmp.negated ? `${leftExpr} < ${rightExpr}` : `${leftExpr} >= ${rightExpr}`;
1036
- case "less-than":
1037
- return cmp.negated ? `${leftExpr} >= ${rightExpr}` : `${leftExpr} < ${rightExpr}`;
1038
- case "less-than-equals":
1039
- return cmp.negated ? `${leftExpr} > ${rightExpr}` : `${leftExpr} <= ${rightExpr}`;
1040
- default:
1041
- throw new Error(`Unsupported comparator: ${cmp.comparator}`);
1400
+ // #endregion
1401
+ const combineExpressions = (...expressions)=>{
1402
+ if (expressions.length === 0) {
1403
+ throw new Error("combineExpressions requires at least 1 expression");
1042
1404
  }
1043
- }
1405
+ if (expressions.length === 1) {
1406
+ return expressions[0];
1407
+ }
1408
+ // Start with the first expression
1409
+ let result = expressions[0];
1410
+ // Loop through remaining expressions and combine them
1411
+ for(let i = 1; i < expressions.length; i++){
1412
+ result = new _types__rspack_import_1/* .OperatorExpression */.fw({
1413
+ operator: "&&",
1414
+ left: result,
1415
+ right: expressions[i]
1416
+ });
1417
+ }
1418
+ return result;
1419
+ };
1044
1420
  /**
1045
- * Converts an Expression to a SQL WHERE clause and bound parameters for the given dialect.
1046
- */
1047
- function toSql(expr, dialect) {
1048
- const d = typeof dialect === "string" ? getDialect(dialect) : dialect;
1049
- const params = [];
1050
- let paramIndex = 0;
1051
- function placeholder() {
1052
- const p = d.getPlaceholder(paramIndex);
1053
- paramIndex += 1;
1054
- return p;
1055
- }
1056
- /** Visitor: map each expression node type to a SQL fragment. */
1057
- function walk(e) {
1058
- if ((0,_assertions__rspack_import_0.isOperatorExpression)(e)) {
1059
- const left = e.left ? walk(e.left) : "";
1060
- const right = e.right ? walk(e.right) : "";
1061
- const sqlOp = e.operator === "&&" ? "AND" : e.operator === "||" ? "OR" : e.operator;
1062
- return `(${left} ${sqlOp} ${right})`;
1063
- }
1064
- if ((0,_assertions__rspack_import_0.isComparatorExpression)(e)) {
1065
- const cmp = e;
1066
- const isStringPattern = cmp.comparator === "starts-with" ||
1067
- cmp.comparator === "ends-with" ||
1068
- cmp.comparator === "includes";
1069
- if (isStringPattern) {
1070
- /* String pattern: includes / starts-with / ends-with → one renderer. */
1071
- return renderStringPatternComparison(cmp, d, params, placeholder);
1072
- }
1073
- if (cmp.comparator === "equals") {
1074
- /* Equals: Strategy per (column-side, null vs value) case. */
1075
- const { propLeft, propRight, valLeft, valRight } = getPropertyValueSides(cmp);
1076
- const col = propLeft && (valRight !== undefined || propRight)
1077
- ? d.quoteIdentifier(propLeft.property.name)
1078
- : propRight && (valLeft !== undefined || propLeft)
1079
- ? d.quoteIdentifier(propRight.property.name)
1080
- : null;
1081
- const value = valRight !== undefined ? valRight : valLeft;
1082
- const columnOnLeft = Boolean(propLeft && cmp.right && (0,_assertions__rspack_import_0.isValueExpression)(cmp.right));
1083
- const columnOnRight = Boolean(propRight && cmp.left && (0,_assertions__rspack_import_0.isValueExpression)(cmp.left));
1084
- if (col !== null && value !== undefined) {
1085
- const caseKey = getEqualsCase(value, columnOnLeft, columnOnRight);
1086
- if (caseKey !== null) {
1087
- const strategy = EQUALS_STRATEGIES[caseKey];
1088
- return strategy({
1089
- col,
1090
- value,
1091
- negated: cmp.negated,
1092
- params,
1093
- placeholder,
1094
- });
1095
- }
1096
- }
1097
- }
1098
- /* Generic: walk both sides and emit comparison operator. */
1099
- return renderGenericComparison(cmp, walk);
1421
+ * Parses an expression SOURCE FRAGMENT against one schema and one root name.
1422
+ *
1423
+ * `toExpression` starts from a function and works out its own roots. This starts from text, which
1424
+ * is what a caller has when it has split a larger predicate apart — `p.rank > 10` lifted out of
1425
+ * `([p, m]) => p.rank > 10 && m.won === true`.
1426
+ *
1427
+ * **A fragment naming anything other than `rootName` returns `NOT_PARSABLE`, and that is the
1428
+ * point.** It is how a caller discovers which side of a join a conjunct belongs to: parse it
1429
+ * against each side in turn, and exactly one succeeds for a single-side condition. A condition
1430
+ * spanning both fails against both, which is the correct answer — it cannot be pushed to either.
1431
+ *
1432
+ * No params: a fragment carrying a params reference has no bag to resolve it against here, so it
1433
+ * fails rather than binding to nothing.
1434
+ *
1435
+ * Deliberately NOT cached. The cache is keyed by function source, and a fragment is not a function
1436
+ * two different lambdas can contain the same fragment text against different schemas.
1437
+ */ const parseFragment = (schema, body, rootName)=>{
1438
+ try {
1439
+ const stream = new TokenStream(tokenize(body));
1440
+ const parser = new ExpressionParser(schema, stream, rootName, null, undefined);
1441
+ return parser.parse();
1442
+ } catch {
1443
+ // The failure is expected and informative — see above — so it is not logged. A caller that
1444
+ // parses one conjunct against two schemas would otherwise warn on every successful split.
1445
+ return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
1446
+ }
1447
+ };
1448
+ const toExpression = (schema, fn, params)=>{
1449
+ const stringifiedFunction = fn.toString();
1450
+ const warn = (error)=>_utilities__rspack_import_3/* .logger.warn */.vF.warn("Error parsing expression", {
1451
+ error,
1452
+ collectionName: schema.collectionName,
1453
+ params,
1454
+ selector: stringifiedFunction
1455
+ });
1456
+ const cached = getCachedTemplate(schema, stringifiedFunction);
1457
+ if (cached != null) {
1458
+ // A cached failure the warning was already logged when it was discovered
1459
+ if (_types__rspack_import_1/* .Expression.isNotParsable */.r4.isNotParsable(cached.template)) {
1460
+ return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
1100
1461
  }
1101
- if ((0,_assertions__rspack_import_0.isPropertyExpression)(e)) {
1102
- return d.quoteIdentifier(e.property.name);
1462
+ try {
1463
+ return bindExpression(cached.template, cached.paramsName, params);
1464
+ } catch (error) {
1465
+ // Binding failures are param-dependent by nature — never cached
1466
+ warn(error);
1467
+ return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
1103
1468
  }
1104
- if ((0,_assertions__rspack_import_0.isValueExpression)(e)) {
1105
- params.push(e.value);
1106
- return placeholder();
1469
+ }
1470
+ let paramsName = null;
1471
+ let template;
1472
+ let structurallyDependsOnParams;
1473
+ try {
1474
+ const shape = resolveFunctionShape(stringifiedFunction, params != null);
1475
+ const stream = new TokenStream(tokenize(shape.body));
1476
+ const parser = new ExpressionParser(schema, stream, shape.entityName, shape.paramsName, params);
1477
+ paramsName = shape.paramsName;
1478
+ template = parser.parse();
1479
+ structurallyDependsOnParams = parser.structurallyDependsOnParams;
1480
+ } catch (error) {
1481
+ // Cache the failure so a hot query on an unsupported filter doesn't
1482
+ // re-parse and re-warn on every execution. Param-dependent failures are
1483
+ // exempt: the same source can succeed with different params.
1484
+ if (!(error instanceof ParamDependentParseError)) {
1485
+ setCachedTemplate(schema, stringifiedFunction, {
1486
+ template: _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE,
1487
+ paramsName: null
1488
+ });
1107
1489
  }
1108
- throw new Error(`Unknown expression type: ${e.type}`);
1490
+ warn(error);
1491
+ return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
1492
+ }
1493
+ // Templates whose structure was resolved from param values are only
1494
+ // valid for this exact params object — parse those fresh every time
1495
+ if (!structurallyDependsOnParams) {
1496
+ setCachedTemplate(schema, stringifiedFunction, {
1497
+ template,
1498
+ paramsName
1499
+ });
1109
1500
  }
1110
- const where = walk(expr);
1111
- return { where, params };
1112
- }
1501
+ try {
1502
+ return bindExpression(template, paramsName, params);
1503
+ } catch (error) {
1504
+ warn(error);
1505
+ return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
1506
+ }
1507
+ };
1113
1508
 
1114
1509
 
1115
1510
  },
1116
- "./src/expressions/types.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1117
- __webpack_require__.r(__webpack_exports__);
1511
+ 27(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1118
1512
  __webpack_require__.d(__webpack_exports__, {
1119
- ComparatorExpression: () => (ComparatorExpression),
1120
- EmptyExpression: () => (EmptyExpression),
1121
- Expression: () => (Expression),
1122
- NotParsableExpression: () => (NotParsableExpression),
1123
- OperatorExpression: () => (OperatorExpression),
1124
- PropertyExpression: () => (PropertyExpression),
1125
- ValueExpression: () => (ValueExpression)
1513
+ Ko: () => (ValueExpression),
1514
+ SC: () => (NotParsableExpression),
1515
+ Sm: () => (EmptyExpression),
1516
+ bQ: () => (ComparatorExpression),
1517
+ ep: () => (PropertyExpression),
1518
+ fw: () => (OperatorExpression),
1519
+ r4: () => (Expression)
1126
1520
  });
1521
+ const valueToJson = (value)=>{
1522
+ if (value === undefined) {
1523
+ return {
1524
+ k: "undefined"
1525
+ };
1526
+ }
1527
+ if (value === null) {
1528
+ return {
1529
+ k: "raw",
1530
+ v: null
1531
+ };
1532
+ }
1533
+ if (value instanceof Date) {
1534
+ // ISO rather than epoch millis: it survives a human reading the payload, and an invalid
1535
+ // Date has no ISO form — so it is caught here rather than becoming a silent `null`.
1536
+ return {
1537
+ k: "date",
1538
+ v: value.toISOString()
1539
+ };
1540
+ }
1541
+ if (Array.isArray(value)) {
1542
+ return {
1543
+ k: "array",
1544
+ v: value.map(valueToJson)
1545
+ };
1546
+ }
1547
+ if (typeof value === "number" && Number.isFinite(value) === false) {
1548
+ // `JSON.stringify` turns all three of these into `null`, which would compare as a different
1549
+ // value entirely rather than failing.
1550
+ return {
1551
+ k: "number",
1552
+ v: Number.isNaN(value) ? "NaN" : value > 0 ? "Infinity" : "-Infinity"
1553
+ };
1554
+ }
1555
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1556
+ return {
1557
+ k: "raw",
1558
+ v: value
1559
+ };
1560
+ }
1561
+ throw new Error(`Cannot serialize this filter value: only strings, numbers, booleans, null, undefined, Dates and arrays of those can cross a wire. ` + `Received: ${Object.prototype.toString.call(value)}`);
1562
+ };
1563
+ const valueFromJson = (value)=>{
1564
+ if (value.k === "undefined") {
1565
+ return undefined;
1566
+ }
1567
+ if (value.k === "date") {
1568
+ return new Date(value.v);
1569
+ }
1570
+ if (value.k === "array") {
1571
+ return value.v.map(valueFromJson);
1572
+ }
1573
+ if (value.k === "number") {
1574
+ return value.v === "NaN" ? Number.NaN : value.v === "Infinity" ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
1575
+ }
1576
+ return value.v;
1577
+ };
1127
1578
  /**
1128
1579
  * The base class for all expression types.
1129
- */
1130
- class Expression {
1131
- /** The left-hand side of the expression (if applicable). */
1132
- left;
1133
- /** The right-hand side of the expression (if applicable). */
1134
- right;
1135
- constructor(left, right) {
1580
+ */ class Expression {
1581
+ /** The left-hand side of the expression (if applicable). */ left;
1582
+ /** The right-hand side of the expression (if applicable). */ right;
1583
+ constructor(left, right){
1136
1584
  this.left = left;
1137
1585
  this.right = right;
1138
1586
  }
@@ -1148,6 +1596,132 @@ class Expression {
1148
1596
  static isNotParsable(expression) {
1149
1597
  return expression.type === "not-parsable" || expression instanceof NotParsableExpression;
1150
1598
  }
1599
+ /**
1600
+ * Turns a tree into plain JSON, so a whole query can cross a wire.
1601
+ *
1602
+ * On the class rather than beside it, because this is the type's own REPRESENTATION — there is one
1603
+ * right answer and it belongs with the thing being represented, next to `EMPTY` and `isEmpty`.
1604
+ * Rendering a tree into some other language (`toSql`, `toMql`, `evaluate`) is a different kind of
1605
+ * thing: there are many, each belongs to its consumer, and none of them is canonical.
1606
+ *
1607
+ * ## Why it is this small
1608
+ *
1609
+ * Of the six node types a bound tree can contain, exactly one holds anything JSON cannot carry:
1610
+ * `PropertyExpression`, whose live `PropertyInfo` has functions, a parent chain and caches. It
1611
+ * reduces to a property PATH — `PropertyInfo.id` IS the dotted path, and `getProperty` is keyed by
1612
+ * exactly that — so rebinding is one lookup.
1613
+ *
1614
+ * `ParamReferenceExpression` never appears: it is a parse-time placeholder that binding replaces
1615
+ * with a plain `ValueExpression` holding the resolved value. A serialized tree is always already
1616
+ * bound, so there is no params object to send alongside it.
1617
+ *
1618
+ * Switches on `type` rather than using the `isXExpression` guards, which live in `../assertions`
1619
+ * and import this module — the guards test the same discriminant, so nothing is lost.
1620
+ */ static toJson(expression) {
1621
+ if (expression.type === "operator") {
1622
+ const operator = expression;
1623
+ return {
1624
+ t: "operator",
1625
+ operator: operator.operator,
1626
+ ...operator.left != null && {
1627
+ left: Expression.toJson(operator.left)
1628
+ },
1629
+ ...operator.right != null && {
1630
+ right: Expression.toJson(operator.right)
1631
+ }
1632
+ };
1633
+ }
1634
+ if (expression.type === "comparator") {
1635
+ const comparator = expression;
1636
+ return {
1637
+ t: "comparator",
1638
+ comparator: comparator.comparator,
1639
+ negated: comparator.negated,
1640
+ strict: comparator.strict,
1641
+ ...comparator.left != null && {
1642
+ left: Expression.toJson(comparator.left)
1643
+ },
1644
+ ...comparator.right != null && {
1645
+ right: Expression.toJson(comparator.right)
1646
+ }
1647
+ };
1648
+ }
1649
+ if (expression.type === "property") {
1650
+ const property = expression;
1651
+ return {
1652
+ t: "property",
1653
+ // The dotted path, which is exactly the key `getProperty` is looking up
1654
+ path: property.property.id,
1655
+ transformer: property.transformer,
1656
+ locale: property.locale
1657
+ };
1658
+ }
1659
+ if (expression.type === "value") {
1660
+ const value = expression;
1661
+ return {
1662
+ t: "value",
1663
+ value: valueToJson(value.value),
1664
+ transformer: value.transformer,
1665
+ locale: value.locale
1666
+ };
1667
+ }
1668
+ return expression.type === "empty" ? {
1669
+ t: "empty"
1670
+ } : {
1671
+ t: "not-parsable"
1672
+ };
1673
+ }
1674
+ /**
1675
+ * Rebuilds a tree from JSON, rebinding every property against `schema`.
1676
+ *
1677
+ * The schema is SUPPLIED rather than read out of the payload. A filter always belongs to a known
1678
+ * collection, and the RECEIVER's schema is the authority on what its properties are — taking an
1679
+ * id from the payload would mean rebinding against a schema the sender chose, which is backwards
1680
+ * for anything crossing a trust boundary.
1681
+ *
1682
+ * @throws when a property path is not declared by `schema`. Not `NOT_PARSABLE`: on a receiver, a
1683
+ * filter that silently stops filtering returns rows the requester excluded, which is the one
1684
+ * failure here worse than an error.
1685
+ */ static fromJson(json, schema) {
1686
+ const child = (node)=>node == null ? undefined : Expression.fromJson(node, schema);
1687
+ if (json.t === "operator") {
1688
+ return new OperatorExpression({
1689
+ operator: json.operator,
1690
+ left: child(json.left),
1691
+ right: child(json.right)
1692
+ });
1693
+ }
1694
+ if (json.t === "comparator") {
1695
+ return new ComparatorExpression({
1696
+ comparator: json.comparator,
1697
+ negated: json.negated,
1698
+ strict: json.strict,
1699
+ left: child(json.left),
1700
+ right: child(json.right)
1701
+ });
1702
+ }
1703
+ if (json.t === "property") {
1704
+ const property = schema.getProperty(json.path);
1705
+ if (property == null) {
1706
+ throw new Error(`Cannot deserialize a filter: this schema does not declare the property it names. ` + `Property: ${json.path}, Collection: ${schema.collectionName}. ` + `The two sides disagree about the shape of the data, so the filter cannot be applied.`);
1707
+ }
1708
+ const rebuilt = new PropertyExpression({
1709
+ property
1710
+ });
1711
+ rebuilt.transformer = json.transformer;
1712
+ rebuilt.locale = json.locale;
1713
+ return rebuilt;
1714
+ }
1715
+ if (json.t === "value") {
1716
+ const rebuilt = new ValueExpression({
1717
+ value: valueFromJson(json.value)
1718
+ });
1719
+ rebuilt.transformer = json.transformer;
1720
+ rebuilt.locale = json.locale;
1721
+ return rebuilt;
1722
+ }
1723
+ return json.t === "empty" ? Expression.EMPTY : Expression.NOT_PARSABLE;
1724
+ }
1151
1725
  }
1152
1726
  class EmptyExpression extends Expression {
1153
1727
  type = "empty";
@@ -1157,17 +1731,12 @@ class NotParsableExpression extends Expression {
1157
1731
  }
1158
1732
  /**
1159
1733
  * A class representing a comparison operation (e.g., equals, greater-than).
1160
- */
1161
- class ComparatorExpression extends Expression {
1162
- /** The type of the expression (always 'comparator'). */
1163
- type = "comparator";
1164
- /** The comparator operation (e.g., equals, greater-than). */
1165
- comparator;
1166
- /** Whether the comparison is negated (e.g., not equals). */
1167
- negated;
1168
- /** Whether the comparison is strict (type-sensitive). */
1169
- strict;
1170
- constructor(options) {
1734
+ */ class ComparatorExpression extends Expression {
1735
+ /** The type of the expression (always 'comparator'). */ type = "comparator";
1736
+ /** The comparator operation (e.g., equals, greater-than). */ comparator;
1737
+ /** Whether the comparison is negated (e.g., not equals). */ negated;
1738
+ /** Whether the comparison is strict (type-sensitive). */ strict;
1739
+ constructor(options){
1171
1740
  super(options.left, options.right);
1172
1741
  this.comparator = options.comparator;
1173
1742
  this.negated = options.negated;
@@ -1176,43 +1745,34 @@ class ComparatorExpression extends Expression {
1176
1745
  }
1177
1746
  /**
1178
1747
  * A class representing a logical operator (e.g., &&, ||).
1179
- */
1180
- class OperatorExpression extends Expression {
1181
- /** The type of the expression (always 'operator'). */
1182
- type = "operator";
1183
- /** The logical operator. */
1184
- operator;
1185
- constructor(options) {
1748
+ */ class OperatorExpression extends Expression {
1749
+ /** The type of the expression (always 'operator'). */ type = "operator";
1750
+ /** The logical operator. */ operator;
1751
+ constructor(options){
1186
1752
  super(options.left, options.right);
1187
1753
  this.operator = options.operator;
1188
1754
  }
1189
1755
  }
1190
1756
  /**
1191
1757
  * A class representing a property path.
1192
- */
1193
- class PropertyExpression extends Expression {
1194
- /** The type of the expression (always 'property'). */
1195
- type = "property";
1196
- /** The property info for the path. */
1197
- property;
1758
+ */ class PropertyExpression extends Expression {
1759
+ /** The type of the expression (always 'property'). */ type = "property";
1760
+ /** The property info for the path. */ property;
1198
1761
  transformer = null;
1199
1762
  locale = null;
1200
- constructor(options) {
1763
+ constructor(options){
1201
1764
  super();
1202
1765
  this.property = options.property;
1203
1766
  }
1204
1767
  }
1205
1768
  /**
1206
1769
  * A class representing a literal value.
1207
- */
1208
- class ValueExpression extends Expression {
1209
- /** The type of the expression (always 'value'). */
1210
- type = "value";
1211
- /** The literal value. */
1212
- value;
1770
+ */ class ValueExpression extends Expression {
1771
+ /** The type of the expression (always 'value'). */ type = "value";
1772
+ /** The literal value. */ value;
1213
1773
  transformer = null;
1214
1774
  locale = null;
1215
- constructor(options) {
1775
+ constructor(options){
1216
1776
  super();
1217
1777
  this.value = options.value;
1218
1778
  }
@@ -1220,18 +1780,16 @@ class ValueExpression extends Expression {
1220
1780
 
1221
1781
 
1222
1782
  },
1223
- "./src/expressions/utils.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1224
- __webpack_require__.r(__webpack_exports__);
1783
+ 63(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1225
1784
  __webpack_require__.d(__webpack_exports__, {
1226
- forEach: () => (forEach),
1227
- getProperties: () => (getProperties)
1785
+ j: () => (forEach),
1786
+ o: () => (getProperties)
1228
1787
  });
1229
1788
  /**
1230
1789
  * Extracts all properties referenced in an expression
1231
1790
  * @param expression The expression to analyze
1232
1791
  * @returns Array of PropertyInfo objects referenced in the expression
1233
- */
1234
- function getProperties(expression) {
1792
+ */ function getProperties(expression) {
1235
1793
  const properties = [];
1236
1794
  function traverse(expr) {
1237
1795
  // If this is a property expression, add it to our collection
@@ -1274,71 +1832,165 @@ function forEach(expression, callback) {
1274
1832
 
1275
1833
 
1276
1834
  },
1277
- "./src/utilities/dates.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1278
- __webpack_require__.r(__webpack_exports__);
1835
+ 537(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1279
1836
  __webpack_require__.d(__webpack_exports__, {
1280
- isDate: () => (isDate)
1837
+ L: () => (SchemaTypes)
1281
1838
  });
1282
- const isDate = (data) => {
1283
- if (data == null) {
1284
- return false;
1285
- }
1286
- if (typeof data !== "object") {
1287
- return false;
1288
- }
1289
- return data instanceof Date;
1290
- };
1839
+ var SchemaTypes = /*#__PURE__*/ function(SchemaTypes) {
1840
+ SchemaTypes["Array"] = "Array";
1841
+ SchemaTypes["Boolean"] = "Boolean";
1842
+ SchemaTypes["Date"] = "Date";
1843
+ SchemaTypes["Number"] = "Number";
1844
+ SchemaTypes["Object"] = "Object";
1845
+ SchemaTypes["String"] = "String";
1846
+ SchemaTypes["Definition"] = "Definition";
1847
+ SchemaTypes["Function"] = "Function";
1848
+ SchemaTypes["Computed"] = "Computed";
1849
+ /**
1850
+ * Content in, reference out. The only type whose write shape differs from its stored
1851
+ * shape, and a leaf on purpose — see `SchemaFile`.
1852
+ */ SchemaTypes["File"] = "File";
1853
+ /**
1854
+ * A fixed-length list of numbers, carrying its dimension count — see `SchemaVector`.
1855
+ *
1856
+ * Value-shaped exactly like `s.array(s.number())`, which is why every array codegen
1857
+ * handler accepts it. It is a distinct type only so a backend can recognise it and store
1858
+ * it natively; nothing else needs to tell the two apart.
1859
+ */ SchemaTypes["Vector"] = "Vector";
1860
+ return SchemaTypes;
1861
+ }({});
1862
+ var HashType = /*#__PURE__*/ (/* unused pure expression or super */ null && (function(HashType) {
1863
+ HashType["Ids"] = "Ids";
1864
+ HashType["Object"] = "Object";
1865
+ return HashType;
1866
+ }({})));
1291
1867
 
1292
1868
 
1293
1869
  },
1294
- "./src/utilities/logger.ts"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1295
- __webpack_require__.r(__webpack_exports__);
1870
+ 581(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1296
1871
  __webpack_require__.d(__webpack_exports__, {
1297
- logger: () => (logger)
1872
+ vF: () => (logger)
1298
1873
  });
1299
1874
  /**
1300
- * Enable logging by setting `globalThis.__ROUTIER_DEBUG__ = true` before any routier code runs.
1301
- */
1302
- const shouldLog = () => {
1875
+ * Levelled logging, resolved once.
1876
+ *
1877
+ * Three things about the previous implementation drove this shape:
1878
+ *
1879
+ * - **There was no way to turn logging off.** `globalThis.__ROUTIER_DEBUG__` was only ever
1880
+ * compared against `true`, so setting it to `false` did nothing — while
1881
+ * `docs/how-to/debug-logging.md` documented exactly that as the way to force logging off.
1882
+ * A documented switch that silently does nothing is worse than no switch.
1883
+ * - **`NODE_ENV === 'test'` enabled it.** Every Jest run therefore logged, because Jest always
1884
+ * sets `NODE_ENV=test`. Measured on the S7 stress scenario, which drives ~2,000 saves through
1885
+ * a plugin that logs three lines per query: 12.4s with logging, ~6s without. Test runners also
1886
+ * capture console output by snapshotting a stack trace per call, so the cost is far above what
1887
+ * writing to a terminal would suggest — and the output buries whatever the failure was.
1888
+ * - **It was all-or-nothing, and re-resolved per call.** An error could not be kept while debug
1889
+ * was dropped, and every one of the ~97 call sites re-read `globalThis` and `process.env`.
1890
+ *
1891
+ * Levels are compared numerically against a value cached at module load. Measured against a
1892
+ * no-op console at 200k calls: an enabled call costs ~70ns, a call rejected by the gate ~3ns.
1893
+ * Building the arguments the call site passes in accounts for ~0.2ns of that 3ns, which is why
1894
+ * this keeps the ordinary `logger.debug(msg, payload)` signature instead of taking a thunk —
1895
+ * a lazy API would recover 0.3% of an enabled call's cost and would have to change every call
1896
+ * site to do it.
1897
+ */ /** Ordered from most severe to most verbose. `silent` discards everything. */ const LOG_LEVELS = [
1898
+ 'silent',
1899
+ 'error',
1900
+ 'warn',
1901
+ 'info',
1902
+ 'debug'
1903
+ ];
1904
+ /** Numeric rank, so a gate is one integer comparison. */ const RANK = {
1905
+ silent: 0,
1906
+ error: 1,
1907
+ warn: 2,
1908
+ info: 3,
1909
+ debug: 4
1910
+ };
1911
+ const isLogLevel = (value)=>typeof value === 'string' && LOG_LEVELS.includes(value);
1912
+ /**
1913
+ * Resolves the configured level, in precedence order.
1914
+ *
1915
+ * Ordered most specific first: an explicit level beats a boolean flag, a boolean flag beats an
1916
+ * environment variable, and an environment variable beats an inference from `NODE_ENV`. Anything
1917
+ * unrecognised is ignored rather than treated as an error — a typo'd level should not take down
1918
+ * an application, and `silent` is the safe direction to fall back to.
1919
+ */ const resolveLevel = ()=>{
1303
1920
  if (typeof globalThis !== 'undefined') {
1304
1921
  const g = globalThis;
1305
- if (g.__ROUTIER_DEBUG__ === true)
1306
- return true;
1307
- }
1922
+ if (isLogLevel(g.__ROUTIER_LOG_LEVEL__)) {
1923
+ return g.__ROUTIER_LOG_LEVEL__;
1924
+ }
1925
+ // Both directions honoured. `=== false` used to fall through to the NODE_ENV checks
1926
+ // below and re-enable the logging it was asked to suppress.
1927
+ if (g.__ROUTIER_DEBUG__ === true) return 'debug';
1928
+ if (g.__ROUTIER_DEBUG__ === false) return 'silent';
1929
+ }
1930
+ // There is deliberately no `import.meta.env` branch, although the documentation used to
1931
+ // promise one. It could never work: this package is bundled with rspack, which replaces
1932
+ // `import.meta` with `undefined`, so the check would read the *library's* build-time
1933
+ // environment rather than the application's — and referencing `import.meta` at all is a parse
1934
+ // error under a CommonJS build target, which is how the test suite loads this file. Vite and
1935
+ // similar apps set `__ROUTIER_LOG_LEVEL__` or `__ROUTIER_DEBUG__` from their own
1936
+ // `import.meta.env`, which is what the docs now describe.
1308
1937
  if (typeof process !== 'undefined' && process.env != null) {
1938
+ if (isLogLevel(process.env.ROUTIER_LOG_LEVEL)) {
1939
+ return process.env.ROUTIER_LOG_LEVEL;
1940
+ }
1309
1941
  const debug = process.env.DEBUG;
1310
- if (debug === 'routier' || debug === '*')
1311
- return true;
1312
- const env = "development"?.toLowerCase();
1313
- if (env === 'dev' || env === 'development' || env === 'test')
1314
- return true;
1315
- }
1316
- return false;
1942
+ if (debug === 'routier' || debug === '*') return 'debug';
1943
+ const env = "production"?.toLowerCase();
1944
+ // `test` is deliberately absent. It used to be here, which meant no test suite anywhere
1945
+ // could run Routier quietly. Opt in with DEBUG=routier or ROUTIER_LOG_LEVEL when a test
1946
+ // needs the output.
1947
+ if (env === 'dev' || env === 'development') return 'debug';
1948
+ }
1949
+ return 'silent';
1317
1950
  };
1318
- const tryLog = (type, ...args) => {
1319
- if (shouldLog()) {
1320
- console[type](...args);
1951
+ let level = resolveLevel();
1952
+ let rank = RANK[level];
1953
+ /**
1954
+ * Overrides the level for the rest of the process.
1955
+ *
1956
+ * The configuration above is read once, at import, which is what makes the gate cheap — but it
1957
+ * also means an application that decides its verbosity after startup, or a test that wants to
1958
+ * assert on output, has no way in. This is that way in.
1959
+ */ const setLogLevel = (next)=>{
1960
+ if (isLogLevel(next) === false) {
1961
+ throw new Error(`Unknown log level "${next}". Expected one of: ${LOG_LEVELS.join(', ')}`);
1962
+ }
1963
+ level = next;
1964
+ rank = RANK[next];
1965
+ };
1966
+ const getLogLevel = ()=>level;
1967
+ /** Re-reads the environment. For tests that change it after this module was imported. */ const resetLogLevel = ()=>{
1968
+ level = resolveLevel();
1969
+ rank = RANK[level];
1970
+ };
1971
+ /**
1972
+ * Whether a message at this level would be emitted.
1973
+ *
1974
+ * For the rare call site whose *arguments* are expensive to build — a serialization, a deep
1975
+ * clone, a join over a large collection. An ordinary payload object is not worth guarding; see
1976
+ * the measurement in the header.
1977
+ */ const isLogLevelEnabled = (at)=>rank >= RANK[at];
1978
+ const emit = (at, method, args)=>{
1979
+ if (rank < RANK[at]) {
1980
+ return;
1321
1981
  }
1982
+ // Resolved at call time rather than captured once: test harnesses and browser devtools both
1983
+ // replace console methods after modules have loaded, and a captured reference would keep
1984
+ // writing past the replacement.
1985
+ console[method](...args);
1322
1986
  };
1323
1987
  const logger = {
1324
- log: (...args) => {
1325
- tryLog("log", ...args);
1326
- },
1327
- info: (...args) => {
1328
- tryLog("info", ...args);
1329
- },
1330
- warn: (...args) => {
1331
- tryLog("warn", ...args);
1332
- },
1333
- error: (...args) => {
1334
- tryLog("error", ...args);
1335
- },
1336
- debug: (...args) => {
1337
- tryLog("debug", ...args);
1338
- },
1339
- table: (...args) => {
1340
- tryLog("table", ...args);
1341
- },
1988
+ /** General-purpose output. Carried at `info`, since `log` names a console method, not a level. */ log: (...args)=>emit('info', 'log', args),
1989
+ info: (...args)=>emit('info', 'info', args),
1990
+ warn: (...args)=>emit('warn', 'warn', args),
1991
+ error: (...args)=>emit('error', 'error', args),
1992
+ debug: (...args)=>emit('debug', 'debug', args),
1993
+ /** Diagnostic tabular output; verbose by nature, so it sits at `debug`. */ table: (...args)=>emit('debug', 'table', args)
1342
1994
  };
1343
1995
 
1344
1996
 
@@ -1382,41 +2034,32 @@ __webpack_require__.d = (exports, definition) => {
1382
2034
  (() => {
1383
2035
  __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
1384
2036
  })();
1385
- // webpack/runtime/make_namespace_object
1386
- (() => {
1387
- // define __esModule on exports
1388
- __webpack_require__.r = (exports) => {
1389
- if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
1390
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1391
- }
1392
- Object.defineProperty(exports, '__esModule', { value: true });
1393
- };
1394
- })();
1395
2037
  var __webpack_exports__ = {};
1396
2038
  // This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
1397
2039
  (() => {
1398
- __webpack_require__.r(__webpack_exports__);
1399
2040
  __webpack_require__.d(__webpack_exports__, {
1400
- ComparatorExpression: () => (/* reexport safe */ _types__rspack_import_2.ComparatorExpression),
1401
- EXPRESSION_TYPES: () => (/* reexport safe */ _constants__rspack_import_4.EXPRESSION_TYPES),
1402
- EmptyExpression: () => (/* reexport safe */ _types__rspack_import_2.EmptyExpression),
1403
- Expression: () => (/* reexport safe */ _types__rspack_import_2.Expression),
1404
- NotParsableExpression: () => (/* reexport safe */ _types__rspack_import_2.NotParsableExpression),
1405
- OperatorExpression: () => (/* reexport safe */ _types__rspack_import_2.OperatorExpression),
1406
- PropertyExpression: () => (/* reexport safe */ _types__rspack_import_2.PropertyExpression),
1407
- ValueExpression: () => (/* reexport safe */ _types__rspack_import_2.ValueExpression),
1408
- combineExpressions: () => (/* reexport safe */ _parser__rspack_import_0.combineExpressions),
1409
- forEach: () => (/* reexport safe */ _utils__rspack_import_3.forEach),
1410
- getDialect: () => (/* reexport safe */ _sql__rspack_import_1.getDialect),
1411
- getProperties: () => (/* reexport safe */ _utils__rspack_import_3.getProperties),
1412
- toExpression: () => (/* reexport safe */ _parser__rspack_import_0.toExpression),
1413
- toSql: () => (/* reexport safe */ _sql__rspack_import_1.toSql)
2041
+ Ko: () => (/* reexport safe */ _types__rspack_import_2.Ko),
2042
+ MY: () => (/* reexport safe */ _parser__rspack_import_1.MY),
2043
+ SC: () => (/* reexport safe */ _types__rspack_import_2.SC),
2044
+ Sm: () => (/* reexport safe */ _types__rspack_import_2.Sm),
2045
+ Vu: () => (/* reexport safe */ _evaluate__rspack_import_0.Vu),
2046
+ _3: () => (/* reexport safe */ _evaluate__rspack_import_0._3),
2047
+ bQ: () => (/* reexport safe */ _types__rspack_import_2.bQ),
2048
+ ep: () => (/* reexport safe */ _types__rspack_import_2.ep),
2049
+ fw: () => (/* reexport safe */ _types__rspack_import_2.fw),
2050
+ jJ: () => (/* reexport safe */ _utils__rspack_import_3.j),
2051
+ oH: () => (/* reexport safe */ _parser__rspack_import_1.oH),
2052
+ oY: () => (/* reexport safe */ _utils__rspack_import_3.o),
2053
+ pg: () => (/* reexport safe */ _parser__rspack_import_1.pg),
2054
+ r4: () => (/* reexport safe */ _types__rspack_import_2.r4),
2055
+ tA: () => (/* reexport safe */ _constants__rspack_import_4.t),
2056
+ wS: () => (/* reexport safe */ _evaluate__rspack_import_0.wS)
1414
2057
  });
1415
- /* import */ var _parser__rspack_import_0 = __webpack_require__("./src/expressions/parser.ts");
1416
- /* import */ var _sql__rspack_import_1 = __webpack_require__("./src/expressions/sql.ts");
1417
- /* import */ var _types__rspack_import_2 = __webpack_require__("./src/expressions/types.ts");
1418
- /* import */ var _utils__rspack_import_3 = __webpack_require__("./src/expressions/utils.ts");
1419
- /* import */ var _constants__rspack_import_4 = __webpack_require__("./src/expressions/constants.ts");
2058
+ /* import */ var _evaluate__rspack_import_0 = __webpack_require__(379);
2059
+ /* import */ var _parser__rspack_import_1 = __webpack_require__(91);
2060
+ /* import */ var _types__rspack_import_2 = __webpack_require__(27);
2061
+ /* import */ var _utils__rspack_import_3 = __webpack_require__(63);
2062
+ /* import */ var _constants__rspack_import_4 = __webpack_require__(835);
1420
2063
 
1421
2064
 
1422
2065
 
@@ -1425,20 +2068,22 @@ __webpack_require__.d(__webpack_exports__, {
1425
2068
 
1426
2069
  })();
1427
2070
 
1428
- var __webpack_exports__ComparatorExpression = __webpack_exports__.ComparatorExpression;
1429
- var __webpack_exports__EXPRESSION_TYPES = __webpack_exports__.EXPRESSION_TYPES;
1430
- var __webpack_exports__EmptyExpression = __webpack_exports__.EmptyExpression;
1431
- var __webpack_exports__Expression = __webpack_exports__.Expression;
1432
- var __webpack_exports__NotParsableExpression = __webpack_exports__.NotParsableExpression;
1433
- var __webpack_exports__OperatorExpression = __webpack_exports__.OperatorExpression;
1434
- var __webpack_exports__PropertyExpression = __webpack_exports__.PropertyExpression;
1435
- var __webpack_exports__ValueExpression = __webpack_exports__.ValueExpression;
1436
- var __webpack_exports__combineExpressions = __webpack_exports__.combineExpressions;
1437
- var __webpack_exports__forEach = __webpack_exports__.forEach;
1438
- var __webpack_exports__getDialect = __webpack_exports__.getDialect;
1439
- var __webpack_exports__getProperties = __webpack_exports__.getProperties;
1440
- var __webpack_exports__toExpression = __webpack_exports__.toExpression;
1441
- var __webpack_exports__toSql = __webpack_exports__.toSql;
1442
- export { __webpack_exports__ComparatorExpression as ComparatorExpression, __webpack_exports__EXPRESSION_TYPES as EXPRESSION_TYPES, __webpack_exports__EmptyExpression as EmptyExpression, __webpack_exports__Expression as Expression, __webpack_exports__NotParsableExpression as NotParsableExpression, __webpack_exports__OperatorExpression as OperatorExpression, __webpack_exports__PropertyExpression as PropertyExpression, __webpack_exports__ValueExpression as ValueExpression, __webpack_exports__combineExpressions as combineExpressions, __webpack_exports__forEach as forEach, __webpack_exports__getDialect as getDialect, __webpack_exports__getProperties as getProperties, __webpack_exports__toExpression as toExpression, __webpack_exports__toSql as toSql };
2071
+ var __webpack_exports__ComparatorExpression = __webpack_exports__.bQ;
2072
+ var __webpack_exports__EXPRESSION_TYPES = __webpack_exports__.tA;
2073
+ var __webpack_exports__EmptyExpression = __webpack_exports__.Sm;
2074
+ var __webpack_exports__Expression = __webpack_exports__.r4;
2075
+ var __webpack_exports__NotParsableExpression = __webpack_exports__.SC;
2076
+ var __webpack_exports__OperatorExpression = __webpack_exports__.fw;
2077
+ var __webpack_exports__PropertyExpression = __webpack_exports__.ep;
2078
+ var __webpack_exports__ValueExpression = __webpack_exports__.Ko;
2079
+ var __webpack_exports__combineExpressions = __webpack_exports__.pg;
2080
+ var __webpack_exports__evaluate = __webpack_exports__._3;
2081
+ var __webpack_exports__forEach = __webpack_exports__.jJ;
2082
+ var __webpack_exports__getProperties = __webpack_exports__.oY;
2083
+ var __webpack_exports__parseFragment = __webpack_exports__.oH;
2084
+ var __webpack_exports__toExpression = __webpack_exports__.MY;
2085
+ var __webpack_exports__toPredicate = __webpack_exports__.Vu;
2086
+ var __webpack_exports__toStrictPredicate = __webpack_exports__.wS;
2087
+ export { __webpack_exports__ComparatorExpression as ComparatorExpression, __webpack_exports__EXPRESSION_TYPES as EXPRESSION_TYPES, __webpack_exports__EmptyExpression as EmptyExpression, __webpack_exports__Expression as Expression, __webpack_exports__NotParsableExpression as NotParsableExpression, __webpack_exports__OperatorExpression as OperatorExpression, __webpack_exports__PropertyExpression as PropertyExpression, __webpack_exports__ValueExpression as ValueExpression, __webpack_exports__combineExpressions as combineExpressions, __webpack_exports__evaluate as evaluate, __webpack_exports__forEach as forEach, __webpack_exports__getProperties as getProperties, __webpack_exports__parseFragment as parseFragment, __webpack_exports__toExpression as toExpression, __webpack_exports__toPredicate as toPredicate, __webpack_exports__toStrictPredicate as toStrictPredicate };
1443
2088
 
1444
2089
  //# sourceMappingURL=index.js.map