@routier/core 0.2.0 → 0.3.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.
- package/LICENSE +21 -0
- package/{readme.md → README.md} +2 -2
- package/dist/assertions/index.cjs +191 -0
- package/dist/assertions/index.cjs.map +1 -0
- package/dist/assertions/index.d.ts +30 -0
- package/dist/assertions/index.js +94 -30
- package/dist/assertions/index.js.map +1 -1
- package/dist/capabilities/index.cjs +820 -0
- package/dist/capabilities/index.cjs.map +1 -0
- package/dist/capabilities/index.js +580 -545
- package/dist/capabilities/index.js.map +1 -1
- package/dist/codegen/handlers/CloneHandlerBuilder.d.ts +10 -1
- package/dist/codegen/handlers/SetHandlerBuilder.d.ts +4 -0
- package/dist/codegen/handlers/clone/CloneArrayHandler.d.ts +3 -0
- package/dist/codegen/handlers/clone/CloneDateHandler.d.ts +13 -0
- package/dist/codegen/handlers/clone/CloneValueHandler.d.ts +16 -0
- package/dist/codegen/handlers/compare/CompareComputedHandler.d.ts +10 -0
- package/dist/codegen/handlers/compare/CompareFunctionHandler.d.ts +10 -0
- package/dist/codegen/handlers/deserialize/DeserializeArrayHandler.d.ts +14 -0
- package/dist/codegen/handlers/enableChangeTracking/EnableChangeTrackingArrayHandler.d.ts +11 -0
- package/dist/codegen/handlers/enrichment/EnrichmentArrayHandler.d.ts +11 -0
- package/dist/codegen/handlers/freeze/FreezeArrayHandler.d.ts +6 -0
- package/dist/codegen/handlers/hash/HashArrayHandler.d.ts +10 -0
- package/dist/codegen/handlers/hash/HashFileHandler.d.ts +24 -0
- package/dist/codegen/handlers/hash/HashObjectHandler.d.ts +10 -0
- package/dist/codegen/handlers/hash/HashTransformHandler.d.ts +23 -0
- package/dist/codegen/handlers/index.d.ts +1 -0
- package/dist/codegen/handlers/merge/MergeArrayHandler.d.ts +20 -0
- package/dist/codegen/handlers/merge/MergeObjectHandler.d.ts +10 -0
- package/dist/codegen/handlers/serialize/SerializeArrayHandler.d.ts +19 -0
- package/dist/codegen/handlers/serialize/SerializeComputedHandler.d.ts +6 -0
- package/dist/codegen/handlers/set/SetComplexHandler.d.ts +6 -0
- package/dist/codegen/handlers/strip/StripComputedHandler.d.ts +10 -0
- package/dist/codegen/handlers/strip/StripFunctionHandler.d.ts +9 -0
- package/dist/codegen/handlers/types.d.ts +55 -1
- package/dist/codegen/index.cjs +618 -0
- package/dist/codegen/index.cjs.map +1 -0
- package/dist/codegen/index.js +100 -127
- package/dist/codegen/index.js.map +1 -1
- package/dist/collections/Changes.d.ts +2 -2
- package/dist/collections/MemoryDataCollection.d.ts +15 -1
- package/dist/collections/TagCollection.d.ts +7 -8
- package/dist/collections/index.cjs +702 -0
- package/dist/collections/index.cjs.map +1 -0
- package/dist/collections/index.js +282 -276
- package/dist/collections/index.js.map +1 -1
- package/dist/errors/OptimisticConcurrencyError.d.ts +18 -0
- package/dist/errors/PluginDestroyedError.d.ts +10 -0
- package/dist/errors/index.cjs +132 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +61 -19
- package/dist/errors/index.js.map +1 -1
- package/dist/expressions/constants.d.ts +2 -0
- package/dist/expressions/evaluate.d.ts +53 -0
- package/dist/expressions/index.cjs +2087 -0
- package/dist/expressions/index.cjs.map +1 -0
- package/dist/expressions/index.d.ts +2 -0
- package/dist/expressions/index.js +1784 -772
- package/dist/expressions/index.js.map +1 -1
- package/dist/expressions/parser.d.ts +19 -0
- package/dist/expressions/types.d.ts +87 -2
- package/dist/expressions/utils.d.ts +1 -2
- package/dist/index.cjs +13925 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +12094 -7049
- package/dist/index.js.map +1 -1
- package/dist/performance/index.cjs +217 -0
- package/dist/performance/index.cjs.map +1 -0
- package/dist/performance/index.js +126 -50
- package/dist/performance/index.js.map +1 -1
- package/dist/pipeline/index.cjs +576 -0
- package/dist/pipeline/index.cjs.map +1 -0
- package/dist/pipeline/index.js +229 -156
- package/dist/pipeline/index.js.map +1 -1
- package/dist/plugins/BatchingDbPlugin.d.ts +139 -0
- package/dist/plugins/CacheDbPlugin.d.ts +70 -0
- package/dist/plugins/ConcurrencyDbPlugin.d.ts +78 -0
- package/dist/plugins/EphemeralDataPlugin.d.ts +57 -1
- package/dist/plugins/RetryDbPlugin.d.ts +77 -0
- package/dist/plugins/index.cjs +6104 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.ts +5 -1
- package/dist/plugins/index.js +5572 -1491
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/query/QueryOptionsCollection.d.ts +22 -0
- package/dist/plugins/query/index.d.ts +2 -0
- package/dist/plugins/query/join.d.ts +210 -0
- package/dist/plugins/query/similarity.d.ts +38 -0
- package/dist/plugins/query/types.d.ts +64 -1
- package/dist/plugins/translators/DataTranslator.d.ts +28 -0
- package/dist/plugins/translators/JsonTranslator.d.ts +27 -0
- package/dist/plugins/translators/SqlTranslator.d.ts +45 -0
- package/dist/plugins/translators/TranslatedArrayValue.d.ts +3 -1
- package/dist/plugins/translators/TranslatedGroupValue.d.ts +3 -1
- package/dist/plugins/translators/TranslatedSingleValue.d.ts +3 -1
- package/dist/plugins/translators/TupleTranslator.d.ts +45 -0
- package/dist/plugins/translators/index.d.ts +1 -0
- package/dist/plugins/translators/types.d.ts +8 -1
- package/dist/plugins/types.d.ts +87 -11
- package/dist/plugins/wire/handler.d.ts +122 -0
- package/dist/plugins/wire/index.d.ts +4 -0
- package/dist/plugins/wire/persist.d.ts +43 -0
- package/dist/plugins/wire/query.d.ts +49 -0
- package/dist/plugins/wire/types.d.ts +123 -0
- package/dist/results/Result.d.ts +2 -2
- package/dist/results/index.cjs +174 -0
- package/dist/results/index.cjs.map +1 -0
- package/dist/results/index.js +29 -44
- package/dist/results/index.js.map +1 -1
- package/dist/schema/PropertyInfo.d.ts +35 -2
- package/dist/schema/SchemaDefinition.d.ts +51 -1
- package/dist/schema/builder.d.ts +35 -1
- package/dist/schema/communication/broadcast.d.ts +17 -1
- package/dist/schema/index.cjs +6911 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.js +5781 -3973
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/property/base/SchemaBase.d.ts +50 -2
- package/dist/schema/property/modifiers/SchemaDeserialize.d.ts +5 -1
- package/dist/schema/property/modifiers/SchemaForeignKey.d.ts +15 -0
- package/dist/schema/property/modifiers/SchemaKey.d.ts +2 -0
- package/dist/schema/property/modifiers/SchemaNullable.d.ts +15 -1
- package/dist/schema/property/modifiers/SchemaOptional.d.ts +22 -1
- package/dist/schema/property/modifiers/SchemaSearchable.d.ts +34 -0
- package/dist/schema/property/modifiers/SchemaTag.d.ts +27 -0
- package/dist/schema/property/modifiers/SchemaTracked.d.ts +5 -1
- package/dist/schema/property/modifiers/index.d.ts +3 -0
- package/dist/schema/property/types/SchemaArray.d.ts +2 -0
- package/dist/schema/property/types/SchemaBoolean.d.ts +2 -0
- package/dist/schema/property/types/SchemaDate.d.ts +2 -0
- package/dist/schema/property/types/SchemaFile.d.ts +60 -0
- package/dist/schema/property/types/SchemaNumber.d.ts +5 -1
- package/dist/schema/property/types/SchemaObject.d.ts +2 -0
- package/dist/schema/property/types/SchemaString.d.ts +25 -1
- package/dist/schema/property/types/SchemaVector.d.ts +61 -0
- package/dist/schema/property/types/index.d.ts +2 -0
- package/dist/schema/table/SchemaTransform.d.ts +40 -0
- package/dist/schema/table/index.d.ts +1 -0
- package/dist/schema/types.d.ts +200 -32
- package/dist/schema/utils/propertyKind.d.ts +4 -0
- package/dist/schema/utils/standardJsonSchema.d.ts +90 -0
- package/dist/types/index.cjs +23 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.js +0 -14
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/functions.d.ts +1 -1
- package/dist/utilities/index.cjs +982 -0
- package/dist/utilities/index.cjs.map +1 -0
- package/dist/utilities/index.js +590 -321
- package/dist/utilities/index.js.map +1 -1
- package/dist/utilities/logger.d.ts +48 -0
- package/package.json +152 -98
- package/dist/collections/Changes.test.d.ts +0 -1
- package/dist/collections/MemoryDataCollection.test.d.ts +0 -1
- package/dist/collections/TagCollection.test.d.ts +0 -1
- package/dist/expressions/parser.test.d.ts +0 -1
- package/dist/expressions/utils.test.d.ts +0 -1
- package/dist/pipeline/SyncronousQueue.test.d.ts +0 -1
- package/dist/pipeline/WorkPipeline.test.d.ts +0 -1
- package/dist/plugins/EphemeralDataPlugin.test.d.ts +0 -1
- package/dist/plugins/query/QueryOptionsCollection.test.d.ts +0 -1
- package/dist/plugins/replication/OptimisticReplicationDbPlugin.d.ts +0 -23
- package/dist/plugins/replication/ReplicationDbPlugin.d.ts +0 -22
- package/dist/plugins/replication/index.d.ts +0 -3
- package/dist/plugins/replication/types.d.ts +0 -5
- package/dist/plugins/translators/JsonTranslator.test.d.ts +0 -1
- package/dist/schema/PropertyInfo.test.d.ts +0 -1
- package/dist/schema/schemaGeneration.test.d.ts +0 -1
- package/dist/schema/testSchemas.test.d.ts +0 -314
- package/dist/utilities/arrays.test.d.ts +0 -1
- package/dist/utilities/dates.test.d.ts +0 -1
- package/dist/utilities/strings.test.d.ts +0 -1
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
var __webpack_modules__ = ({
|
|
2
|
-
|
|
3
|
-
__webpack_require__.r(__webpack_exports__);
|
|
2
|
+
126(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4
3
|
__webpack_require__.d(__webpack_exports__, {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
Cv: () => (assertString),
|
|
5
|
+
S6: () => (isValueExpression),
|
|
6
|
+
e3: () => (isPropertyExpression),
|
|
7
|
+
vg: () => (isOperatorExpression),
|
|
8
|
+
xH: () => (isComparatorExpression)
|
|
10
9
|
});
|
|
11
|
-
|
|
10
|
+
|
|
12
11
|
|
|
13
12
|
function assertDate(data) {
|
|
14
|
-
if (
|
|
13
|
+
if (isDate(data) === false) {
|
|
15
14
|
throw new TypeError('Value is not a Date');
|
|
16
15
|
}
|
|
17
16
|
}
|
|
@@ -41,746 +40,1547 @@ function assertInstanceOf(value, Instance) {
|
|
|
41
40
|
return;
|
|
42
41
|
}
|
|
43
42
|
if (value != null && typeof value === "object" && "constructor" in value) {
|
|
44
|
-
throw new TypeError(`
|
|
43
|
+
throw new TypeError(`value is not instance of type. Type: ${value.constructor.name}`);
|
|
44
|
+
}
|
|
45
|
+
throw new TypeError(`value is not instance of type`);
|
|
46
|
+
}
|
|
47
|
+
function assertIsNumber(value) {
|
|
48
|
+
if (typeof value !== "number") {
|
|
49
|
+
throw new TypeError("value is not of type `number`");
|
|
45
50
|
}
|
|
46
|
-
|
|
51
|
+
}
|
|
52
|
+
function isObjectWithType(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && "type" in value;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Type guard: narrows `value` to `Expression` when it is an object with a valid `type` property.
|
|
57
|
+
*/ function isExpression(value) {
|
|
58
|
+
return isObjectWithType(value) && EXPRESSION_TYPES.includes(value.type);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Type guard: narrows `value` to `OperatorExpression` when it is an object with `type === "operator"`.
|
|
62
|
+
*/ function isOperatorExpression(value) {
|
|
63
|
+
return isObjectWithType(value) && value.type === "operator";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Type guard: narrows `value` to `ComparatorExpression` when it is an object with `type === "comparator"`.
|
|
67
|
+
*/ function isComparatorExpression(value) {
|
|
68
|
+
return isObjectWithType(value) && value.type === "comparator";
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Type guard: narrows `value` to `PropertyExpression` when it is an object with `type === "property"`.
|
|
72
|
+
*/ function isPropertyExpression(value) {
|
|
73
|
+
return isObjectWithType(value) && value.type === "property";
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Type guard: narrows `value` to `ValueExpression` when it is an object with `type === "value"`.
|
|
77
|
+
*/ function isValueExpression(value) {
|
|
78
|
+
return isObjectWithType(value) && value.type === "value";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Type guard: narrows `value` to `EmptyExpression` when it is an object with `type === "empty"`.
|
|
82
|
+
*/ function isEmptyExpression(value) {
|
|
83
|
+
return isObjectWithType(value) && value.type === "empty";
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Type guard: narrows `value` to `NotParsableExpression` when it is an object with `type === "not-parsable"`.
|
|
87
|
+
*/ function isNotParsableExpression(value) {
|
|
88
|
+
return isObjectWithType(value) && value.type === "not-parsable";
|
|
47
89
|
}
|
|
48
90
|
|
|
49
91
|
|
|
50
92
|
},
|
|
51
|
-
|
|
52
|
-
__webpack_require__.r(__webpack_exports__);
|
|
93
|
+
835(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
53
94
|
__webpack_require__.d(__webpack_exports__, {
|
|
54
|
-
|
|
55
|
-
toExpression: () => (toExpression)
|
|
95
|
+
t: () => (EXPRESSION_TYPES)
|
|
56
96
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
97
|
+
const EXPRESSION_TYPES = [
|
|
98
|
+
"operator",
|
|
99
|
+
"comparator",
|
|
100
|
+
"property",
|
|
101
|
+
"value",
|
|
102
|
+
"empty",
|
|
103
|
+
"not-parsable"
|
|
104
|
+
];
|
|
60
105
|
|
|
61
106
|
|
|
107
|
+
},
|
|
108
|
+
379(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
109
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
110
|
+
Vu: () => (toPredicate),
|
|
111
|
+
_3: () => (evaluate),
|
|
112
|
+
wS: () => (toStrictPredicate)
|
|
113
|
+
});
|
|
114
|
+
/* import */ var _assertions__rspack_import_0 = __webpack_require__(126);
|
|
62
115
|
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
};
|
|
269
|
+
|
|
270
|
+
|
|
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
|
+
"==": {
|
|
91
620
|
comparator: "equals",
|
|
92
621
|
negated: false,
|
|
93
622
|
strict: false
|
|
94
|
-
}
|
|
95
|
-
"===":
|
|
623
|
+
},
|
|
624
|
+
"===": {
|
|
96
625
|
comparator: "equals",
|
|
97
626
|
negated: false,
|
|
98
627
|
strict: true
|
|
99
|
-
}
|
|
100
|
-
"!=":
|
|
628
|
+
},
|
|
629
|
+
"!=": {
|
|
101
630
|
comparator: "equals",
|
|
102
631
|
negated: true,
|
|
103
632
|
strict: false
|
|
104
|
-
}
|
|
105
|
-
"!==":
|
|
633
|
+
},
|
|
634
|
+
"!==": {
|
|
106
635
|
comparator: "equals",
|
|
107
636
|
negated: true,
|
|
108
637
|
strict: true
|
|
109
|
-
}
|
|
110
|
-
"
|
|
111
|
-
comparator: "greater-than
|
|
638
|
+
},
|
|
639
|
+
">": {
|
|
640
|
+
comparator: "greater-than",
|
|
112
641
|
negated: false,
|
|
113
642
|
strict: false
|
|
114
|
-
}
|
|
115
|
-
"
|
|
643
|
+
},
|
|
644
|
+
">=": {
|
|
116
645
|
comparator: "greater-than-equals",
|
|
117
646
|
negated: false,
|
|
118
|
-
strict: true
|
|
119
|
-
}),
|
|
120
|
-
"<=": new _types__rspack_import_0.ComparatorExpression({
|
|
121
|
-
comparator: "less-than-equals",
|
|
122
|
-
negated: false,
|
|
123
647
|
strict: false
|
|
124
|
-
}
|
|
125
|
-
"
|
|
126
|
-
comparator: "less-than
|
|
127
|
-
negated: false,
|
|
128
|
-
strict: true
|
|
129
|
-
}),
|
|
130
|
-
">": new _types__rspack_import_0.ComparatorExpression({
|
|
131
|
-
comparator: "greater-than",
|
|
648
|
+
},
|
|
649
|
+
"<": {
|
|
650
|
+
comparator: "less-than",
|
|
132
651
|
negated: false,
|
|
133
652
|
strict: false
|
|
134
|
-
}
|
|
135
|
-
"
|
|
136
|
-
comparator: "less-than",
|
|
653
|
+
},
|
|
654
|
+
"<=": {
|
|
655
|
+
comparator: "less-than-equals",
|
|
137
656
|
negated: false,
|
|
138
657
|
strict: false
|
|
139
|
-
}
|
|
658
|
+
}
|
|
140
659
|
};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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"
|
|
148
669
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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;
|
|
153
703
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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;
|
|
157
710
|
}
|
|
158
|
-
|
|
159
|
-
|
|
711
|
+
let result = value;
|
|
712
|
+
if (pairedProperty.valueSerializer != null) {
|
|
713
|
+
result = String(pairedProperty.valueSerializer(parseUnknown(result)));
|
|
160
714
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// Loop through remaining expressions and combine them
|
|
164
|
-
for (let i = 1; i < expressions.length; i++) {
|
|
165
|
-
result = new _types__rspack_import_0.OperatorExpression({
|
|
166
|
-
operator: "&&",
|
|
167
|
-
left: result,
|
|
168
|
-
right: expressions[i]
|
|
169
|
-
});
|
|
715
|
+
if (applyConverter) {
|
|
716
|
+
result = converters[pairedProperty.type](result);
|
|
170
717
|
}
|
|
171
718
|
return result;
|
|
172
719
|
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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}'`));
|
|
180
745
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (parameterNames.includes("[") && parameterNames.includes("]")) {
|
|
193
|
-
// Optimized parameter name extraction
|
|
194
|
-
const commaIndex = parameterNames.indexOf(",");
|
|
195
|
-
if (commaIndex !== -1) {
|
|
196
|
-
const bracketIndex = parameterNames.indexOf("]", commaIndex);
|
|
197
|
-
if (bracketIndex !== -1) {
|
|
198
|
-
name = parameterNames.substring(commaIndex + 1, bracketIndex).trim();
|
|
199
|
-
}
|
|
200
|
-
}
|
|
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;
|
|
201
757
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
758
|
+
left = new _types__rspack_import_1/* .OperatorExpression */.fw({
|
|
759
|
+
operator: "||",
|
|
760
|
+
left,
|
|
761
|
+
right
|
|
762
|
+
});
|
|
206
763
|
}
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
catch (error) {
|
|
210
|
-
_utilities__rspack_import_2.logger.warn("Error parsing expression", {
|
|
211
|
-
error,
|
|
212
|
-
collectionName: schema.collectionName,
|
|
213
|
-
params,
|
|
214
|
-
selector: stringifiedFunction
|
|
215
|
-
});
|
|
216
|
-
return _types__rspack_import_0.Expression.NOT_PARSABLE;
|
|
764
|
+
return left;
|
|
217
765
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
for (let i = 0; i < exp.length; i++) {
|
|
227
|
-
const char = exp[i];
|
|
228
|
-
if (char === '(') {
|
|
229
|
-
depth++;
|
|
230
|
-
}
|
|
231
|
-
else if (char === ')') {
|
|
232
|
-
depth--;
|
|
233
|
-
if (depth < 0)
|
|
234
|
-
break; // Early exit for invalid parentheses
|
|
235
|
-
}
|
|
236
|
-
// Early exit if we find a closing parenthesis that's not the last character
|
|
237
|
-
if (depth === 0 && i !== exp.length - 1) {
|
|
238
|
-
isWrapper = false;
|
|
239
|
-
break; // Early exit
|
|
240
|
-
}
|
|
241
|
-
// Early exit if we go negative (invalid parentheses)
|
|
242
|
-
if (depth < 0) {
|
|
243
|
-
isWrapper = false;
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
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;
|
|
246
774
|
}
|
|
247
|
-
if (
|
|
248
|
-
|
|
775
|
+
if (_types__rspack_import_1/* .Expression.isEmpty */.r4.isEmpty(right)) {
|
|
776
|
+
continue;
|
|
249
777
|
}
|
|
778
|
+
left = new _types__rspack_import_1/* .OperatorExpression */.fw({
|
|
779
|
+
operator: "&&",
|
|
780
|
+
left,
|
|
781
|
+
right
|
|
782
|
+
});
|
|
250
783
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
depth++;
|
|
257
|
-
else if (char === ')')
|
|
258
|
-
depth--;
|
|
259
|
-
else if (depth === 0) {
|
|
260
|
-
// Optimized operator detection using character comparison
|
|
261
|
-
if (char === '&' && exp[i + 1] === '&') {
|
|
262
|
-
operator = '&&';
|
|
263
|
-
splitIndex = i;
|
|
264
|
-
break; // AND takes precedence over OR
|
|
265
|
-
}
|
|
266
|
-
else if (operator === null && char === '|' && exp[i + 1] === '|') {
|
|
267
|
-
operator = '||';
|
|
268
|
-
splitIndex = i;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
784
|
+
return left;
|
|
785
|
+
}
|
|
786
|
+
parseUnary() {
|
|
787
|
+
if (this.stream.matchPunctuation("!")) {
|
|
788
|
+
return this.negateExpression(this.parseUnary());
|
|
271
789
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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)
|
|
279
805
|
});
|
|
280
806
|
}
|
|
281
|
-
|
|
282
|
-
return parseCondition(schema, exp, params);
|
|
283
|
-
};
|
|
284
|
-
return parse(expression);
|
|
285
|
-
};
|
|
286
|
-
const convertAndAssignValue = (valueExpression, propertyPathExpression) => {
|
|
287
|
-
assertIsPropertyPathExpression(propertyPathExpression);
|
|
288
|
-
assertIsValueExpression(valueExpression);
|
|
289
|
-
const propertyType = propertyPathExpression.property.type;
|
|
290
|
-
valueExpression.value = converters[propertyType](valueExpression.value);
|
|
291
|
-
};
|
|
292
|
-
const converters = {
|
|
293
|
-
Array: v => v,
|
|
294
|
-
Boolean: v => v == null ? v : Boolean(v),
|
|
295
|
-
Computed: v => v,
|
|
296
|
-
Date: v => v,
|
|
297
|
-
Definition: v => v,
|
|
298
|
-
Function: v => v,
|
|
299
|
-
Number: v => v == null ? v : Number(v),
|
|
300
|
-
Object: v => v,
|
|
301
|
-
String: v => v == null ? v : String(v)
|
|
302
|
-
};
|
|
303
|
-
const isExpression = (value) => {
|
|
304
|
-
return typeof value === "object" && value !== null && "type" in value;
|
|
305
|
-
};
|
|
306
|
-
function assertIsExpression(value) {
|
|
307
|
-
if (isExpression(value) === false) {
|
|
308
|
-
throw new Error("Assertion Failed: Value is not a Expression");
|
|
807
|
+
throw new Error(ERROR_MESSAGES.UNSUPPORTED("'!' on this expression"));
|
|
309
808
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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);
|
|
315
828
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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"));
|
|
857
|
+
}
|
|
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)));
|
|
321
872
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
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()"));
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
kind: "method-call",
|
|
911
|
+
target: array,
|
|
912
|
+
method: "includes",
|
|
913
|
+
argument
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
return array;
|
|
328
917
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
+
};
|
|
944
|
+
}
|
|
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
|
|
958
|
+
});
|
|
959
|
+
}
|
|
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));
|
|
333
968
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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;
|
|
343
1018
|
}
|
|
1019
|
+
break;
|
|
344
1020
|
}
|
|
1021
|
+
return this.resolveChain(options.kind, path, transformer, locale);
|
|
345
1022
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const finalExpression = isNegation ? trimmed.slice(1).trim() : trimmed;
|
|
363
|
-
// Enhanced pattern matching for complex expressions
|
|
364
|
-
const methodMatch = finalExpression.match(METHOD_REGEX);
|
|
365
|
-
const transformMethodMatch = finalExpression.match(TRANSFORM_METHOD_REGEX);
|
|
366
|
-
const equalityMatch = finalExpression.match(EQUALITY_REGEX);
|
|
367
|
-
const comparisonMatch = finalExpression.match(COMPARISON_REGEX);
|
|
368
|
-
if (methodMatch) {
|
|
369
|
-
// Handle .startsWith or .endsWith
|
|
370
|
-
const comparator = getComparator(methodMatch[2]);
|
|
371
|
-
if (isNegation) {
|
|
372
|
-
comparator.negated = isNegation;
|
|
373
|
-
}
|
|
374
|
-
// Check if the left side is a parameter path
|
|
375
|
-
const leftSide = methodMatch[1];
|
|
376
|
-
const rightSide = methodMatch[3];
|
|
377
|
-
if (params && leftSide.startsWith(params.name)) {
|
|
378
|
-
// This is a parameter path on the left side (e.g., params.distinctPlayers.includes(entity.playerId))
|
|
379
|
-
// For includes method, we need to swap left and right sides
|
|
380
|
-
if (methodMatch[2] === 'includes') {
|
|
381
|
-
const property = getProperty(schema, rightSide, params);
|
|
382
|
-
const value = getValue(leftSide, params); // retrieve the original value
|
|
383
|
-
const serializer = property.property.valueSerializer;
|
|
384
|
-
comparator.left = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
|
|
385
|
-
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);
|
|
386
1039
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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(".")));
|
|
390
1043
|
}
|
|
1044
|
+
this.structurallyDependsOnParams = true;
|
|
1045
|
+
return resolved;
|
|
391
1046
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
// If the comparison is explicitly to false, mark it as negated
|
|
401
|
-
if (methodMatch[6] === "false") {
|
|
402
|
-
comparator.negated = true;
|
|
403
|
-
}
|
|
404
|
-
return comparator;
|
|
405
|
-
}
|
|
406
|
-
// Check for transformations on the value side (right side of comparison) - check this FIRST
|
|
407
|
-
const valueTransformMatch = finalExpression.match(/([^=!<>]+?)\s*(===|==|!==|!=)\s*([^)]+)\.(toLowerCase|toUpperCase|toLocaleLowerCase|toLocaleUpperCase)\(\)/);
|
|
408
|
-
if (valueTransformMatch) {
|
|
409
|
-
const comparator = getComparator(valueTransformMatch[2]);
|
|
410
|
-
if (isNegation) {
|
|
411
|
-
comparator.negated = isNegation;
|
|
412
|
-
}
|
|
413
|
-
const property = getProperty(schema, valueTransformMatch[1].trim(), params);
|
|
414
|
-
const serializer = property.property.valueSerializer;
|
|
415
|
-
const value = getValue(valueTransformMatch[3], params); // retrieve the original value
|
|
416
|
-
// Create the property expression for the left side (no transformer)
|
|
417
|
-
const propertyExpression = property;
|
|
418
|
-
// Create a ValueExpression for the right side with transformer
|
|
419
|
-
const valueExpression = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
|
|
420
|
-
// Set transformer and locale based on the method
|
|
421
|
-
const method = valueTransformMatch[4];
|
|
422
|
-
if (method === 'toLowerCase' || method === 'toLocaleLowerCase') {
|
|
423
|
-
valueExpression.transformer = 'to-lower-case';
|
|
424
|
-
if (method === 'toLocaleLowerCase') {
|
|
425
|
-
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));
|
|
426
1054
|
}
|
|
1055
|
+
return {
|
|
1056
|
+
kind: "param",
|
|
1057
|
+
path,
|
|
1058
|
+
transformer,
|
|
1059
|
+
locale
|
|
1060
|
+
};
|
|
427
1061
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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
|
+
}
|
|
432
1083
|
}
|
|
1084
|
+
throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(pathString));
|
|
433
1085
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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;
|
|
452
1107
|
}
|
|
453
1108
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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;
|
|
458
1120
|
}
|
|
1121
|
+
throw new Error(ERROR_MESSAGES.UNSUPPORTED("comparing a method call to a non-boolean"));
|
|
459
1122
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
//
|
|
466
|
-
|
|
467
|
-
|
|
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"));
|
|
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)
|
|
468
1138
|
});
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
1139
|
+
}
|
|
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"));
|
|
1151
|
+
}
|
|
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);
|
|
476
1165
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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"));
|
|
1179
|
+
}
|
|
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`));
|
|
482
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);
|
|
483
1192
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
// Check for standalone property reference (truthy comparison)
|
|
570
|
-
// Pattern: property name only (e.g., "w.inStock" -> w.inStock === true)
|
|
571
|
-
const standalonePropertyMatch = finalExpression.match(/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/);
|
|
572
|
-
if (standalonePropertyMatch && isPropertyPath(finalExpression, params)) {
|
|
573
|
-
const comparator = getComparator('===');
|
|
574
|
-
if (isNegation) {
|
|
575
|
-
comparator.negated = isNegation;
|
|
576
|
-
}
|
|
577
|
-
const property = getProperty(schema, finalExpression, params);
|
|
578
|
-
const value = getValue('true', params);
|
|
579
|
-
const serializer = property.property.valueSerializer;
|
|
580
|
-
comparator.left = property;
|
|
581
|
-
// need to parse the value so it matches what the serializer expects
|
|
582
|
-
comparator.right = serializer ? getValue(String(property.property.valueSerializer(parseUnknown(value.value)))) : value;
|
|
583
|
-
return comparator;
|
|
584
|
-
}
|
|
585
|
-
// If we get here, the expression is too complex for the current parser
|
|
586
|
-
// This is expected for complex real-world expressions
|
|
587
|
-
throw new Error(`Unsupported expression format: ${finalExpression}`);
|
|
588
|
-
};
|
|
589
|
-
const getComparator = (value) => {
|
|
590
|
-
const comparator = COMPARATOR_MAP.get(value);
|
|
591
|
-
if (comparator == null) {
|
|
592
|
-
throw new Error(ERROR_MESSAGES.COMPARATOR_NOT_FOUND(value));
|
|
593
|
-
}
|
|
594
|
-
// Return a new instance to avoid modifying the cached one
|
|
595
|
-
return new _types__rspack_import_0.ComparatorExpression({
|
|
596
|
-
comparator: comparator.comparator,
|
|
597
|
-
negated: comparator.negated,
|
|
598
|
-
strict: comparator.strict
|
|
599
|
-
});
|
|
600
|
-
};
|
|
601
|
-
const getValue = (value, params) => {
|
|
602
|
-
// Early return for string literals
|
|
603
|
-
if (value.startsWith("\'") || value.startsWith("\"")) {
|
|
604
|
-
return new _types__rspack_import_0.ValueExpression({
|
|
605
|
-
value: value.replace(/\"|\'/g, "")
|
|
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)
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
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"));
|
|
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
|
+
});
|
|
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
|
+
});
|
|
1239
|
+
}
|
|
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;
|
|
1265
|
+
}
|
|
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)
|
|
606
1278
|
});
|
|
1279
|
+
bound.transformer = expression.transformer;
|
|
1280
|
+
bound.locale = expression.locale;
|
|
1281
|
+
return bound;
|
|
607
1282
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
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;
|
|
611
1290
|
}
|
|
612
|
-
if (
|
|
613
|
-
|
|
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;
|
|
614
1298
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
+
});
|
|
619
1307
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
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;
|
|
1316
|
+
};
|
|
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");
|
|
627
1331
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
641
|
-
}
|
|
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");
|
|
1338
|
+
}
|
|
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();
|
|
642
1344
|
}
|
|
643
1345
|
}
|
|
644
|
-
|
|
645
|
-
|
|
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;
|
|
646
1356
|
}
|
|
647
|
-
if (
|
|
648
|
-
|
|
649
|
-
// need to fallback to select all by throwing an error
|
|
650
|
-
throw new Error(`Cannot derive value from variable, please pass parameters into the expression.
|
|
651
|
-
|
|
652
|
-
Example: .where(([x, params]) => x.id === params.id, { id: someVar.id })
|
|
653
|
-
Issue At: ${value}`);
|
|
1357
|
+
if (entityName == null || entityName.length === 0) {
|
|
1358
|
+
throw new Error("Invalid Function");
|
|
654
1359
|
}
|
|
655
|
-
//
|
|
656
|
-
|
|
657
|
-
};
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
// Early exit for invalid paths
|
|
661
|
-
if (split.length === 1) {
|
|
662
|
-
throw new Error(ERROR_MESSAGES.PARAM_PATH_NOT_FOUND(value, params.data));
|
|
663
|
-
}
|
|
664
|
-
let result = params.data;
|
|
665
|
-
// For nested params - start from index 1 to skip the params prefix
|
|
666
|
-
for (let i = 1; i < split.length; i++) {
|
|
667
|
-
const name = split[i];
|
|
668
|
-
if (name in result) {
|
|
669
|
-
result = result[name];
|
|
670
|
-
continue;
|
|
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"));
|
|
671
1365
|
}
|
|
672
|
-
|
|
1366
|
+
body = inner.slice("return".length).trim();
|
|
1367
|
+
if (body.endsWith(";")) {
|
|
1368
|
+
body = body.slice(0, -1).trim();
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
return {
|
|
1372
|
+
entityName,
|
|
1373
|
+
paramsName,
|
|
1374
|
+
body
|
|
1375
|
+
};
|
|
1376
|
+
};
|
|
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;
|
|
1383
|
+
};
|
|
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);
|
|
1399
|
+
};
|
|
1400
|
+
// #endregion
|
|
1401
|
+
const combineExpressions = (...expressions)=>{
|
|
1402
|
+
if (expressions.length === 0) {
|
|
1403
|
+
throw new Error("combineExpressions requires at least 1 expression");
|
|
1404
|
+
}
|
|
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
|
+
});
|
|
673
1417
|
}
|
|
674
1418
|
return result;
|
|
675
1419
|
};
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
// The resolved value should be the property name
|
|
718
|
-
if (typeof resolvedValue === 'string') {
|
|
719
|
-
pathParts.push(resolvedValue);
|
|
720
|
-
}
|
|
721
|
-
else {
|
|
722
|
-
throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
catch (e) {
|
|
726
|
-
// Not a valid parameter path, continue to error
|
|
727
|
-
throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
else {
|
|
731
|
-
throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
else {
|
|
735
|
-
throw new Error(ERROR_MESSAGES.PROPERTY_NOT_FOUND(value));
|
|
736
|
-
}
|
|
1420
|
+
/**
|
|
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;
|
|
737
1461
|
}
|
|
738
|
-
|
|
739
|
-
|
|
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;
|
|
740
1468
|
}
|
|
741
|
-
pathString = pathParts.join(".");
|
|
742
1469
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
warn(error);
|
|
1491
|
+
return _types__rspack_import_1/* .Expression.NOT_PARSABLE */.r4.NOT_PARSABLE;
|
|
750
1492
|
}
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
|
|
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
|
+
});
|
|
754
1500
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
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;
|
|
758
1506
|
}
|
|
759
|
-
return new _types__rspack_import_0.PropertyExpression({ property: found });
|
|
760
1507
|
};
|
|
761
1508
|
|
|
762
1509
|
|
|
763
1510
|
},
|
|
764
|
-
|
|
765
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1511
|
+
27(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
766
1512
|
__webpack_require__.d(__webpack_exports__, {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1513
|
+
Ko: () => (ValueExpression),
|
|
1514
|
+
SC: () => (NotParsableExpression),
|
|
1515
|
+
Sm: () => (EmptyExpression),
|
|
1516
|
+
bQ: () => (ComparatorExpression),
|
|
1517
|
+
ep: () => (PropertyExpression),
|
|
1518
|
+
fw: () => (OperatorExpression),
|
|
1519
|
+
r4: () => (Expression)
|
|
774
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
|
+
};
|
|
775
1578
|
/**
|
|
776
1579
|
* The base class for all expression types.
|
|
777
|
-
*/
|
|
778
|
-
|
|
779
|
-
/** The
|
|
780
|
-
left
|
|
781
|
-
/** The right-hand side of the expression (if applicable). */
|
|
782
|
-
right;
|
|
783
|
-
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){
|
|
784
1584
|
this.left = left;
|
|
785
1585
|
this.right = right;
|
|
786
1586
|
}
|
|
@@ -796,6 +1596,132 @@ class Expression {
|
|
|
796
1596
|
static isNotParsable(expression) {
|
|
797
1597
|
return expression.type === "not-parsable" || expression instanceof NotParsableExpression;
|
|
798
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
|
+
}
|
|
799
1725
|
}
|
|
800
1726
|
class EmptyExpression extends Expression {
|
|
801
1727
|
type = "empty";
|
|
@@ -805,17 +1731,12 @@ class NotParsableExpression extends Expression {
|
|
|
805
1731
|
}
|
|
806
1732
|
/**
|
|
807
1733
|
* A class representing a comparison operation (e.g., equals, greater-than).
|
|
808
|
-
*/
|
|
809
|
-
|
|
810
|
-
/** The
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
|
|
814
|
-
/** Whether the comparison is negated (e.g., not equals). */
|
|
815
|
-
negated;
|
|
816
|
-
/** Whether the comparison is strict (type-sensitive). */
|
|
817
|
-
strict;
|
|
818
|
-
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){
|
|
819
1740
|
super(options.left, options.right);
|
|
820
1741
|
this.comparator = options.comparator;
|
|
821
1742
|
this.negated = options.negated;
|
|
@@ -824,43 +1745,34 @@ class ComparatorExpression extends Expression {
|
|
|
824
1745
|
}
|
|
825
1746
|
/**
|
|
826
1747
|
* A class representing a logical operator (e.g., &&, ||).
|
|
827
|
-
*/
|
|
828
|
-
|
|
829
|
-
/** The
|
|
830
|
-
|
|
831
|
-
/** The logical operator. */
|
|
832
|
-
operator;
|
|
833
|
-
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){
|
|
834
1752
|
super(options.left, options.right);
|
|
835
1753
|
this.operator = options.operator;
|
|
836
1754
|
}
|
|
837
1755
|
}
|
|
838
1756
|
/**
|
|
839
1757
|
* A class representing a property path.
|
|
840
|
-
*/
|
|
841
|
-
|
|
842
|
-
/** The
|
|
843
|
-
type = "property";
|
|
844
|
-
/** The property info for the path. */
|
|
845
|
-
property;
|
|
1758
|
+
*/ class PropertyExpression extends Expression {
|
|
1759
|
+
/** The type of the expression (always 'property'). */ type = "property";
|
|
1760
|
+
/** The property info for the path. */ property;
|
|
846
1761
|
transformer = null;
|
|
847
1762
|
locale = null;
|
|
848
|
-
constructor(options)
|
|
1763
|
+
constructor(options){
|
|
849
1764
|
super();
|
|
850
1765
|
this.property = options.property;
|
|
851
1766
|
}
|
|
852
1767
|
}
|
|
853
1768
|
/**
|
|
854
1769
|
* A class representing a literal value.
|
|
855
|
-
*/
|
|
856
|
-
|
|
857
|
-
/** The
|
|
858
|
-
type = "value";
|
|
859
|
-
/** The literal value. */
|
|
860
|
-
value;
|
|
1770
|
+
*/ class ValueExpression extends Expression {
|
|
1771
|
+
/** The type of the expression (always 'value'). */ type = "value";
|
|
1772
|
+
/** The literal value. */ value;
|
|
861
1773
|
transformer = null;
|
|
862
1774
|
locale = null;
|
|
863
|
-
constructor(options)
|
|
1775
|
+
constructor(options){
|
|
864
1776
|
super();
|
|
865
1777
|
this.value = options.value;
|
|
866
1778
|
}
|
|
@@ -868,19 +1780,16 @@ class ValueExpression extends Expression {
|
|
|
868
1780
|
|
|
869
1781
|
|
|
870
1782
|
},
|
|
871
|
-
|
|
872
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1783
|
+
63(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
873
1784
|
__webpack_require__.d(__webpack_exports__, {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
isPropertyExpression: () => (isPropertyExpression)
|
|
1785
|
+
j: () => (forEach),
|
|
1786
|
+
o: () => (getProperties)
|
|
877
1787
|
});
|
|
878
1788
|
/**
|
|
879
1789
|
* Extracts all properties referenced in an expression
|
|
880
1790
|
* @param expression The expression to analyze
|
|
881
1791
|
* @returns Array of PropertyInfo objects referenced in the expression
|
|
882
|
-
*/
|
|
883
|
-
function getProperties(expression) {
|
|
1792
|
+
*/ function getProperties(expression) {
|
|
884
1793
|
const properties = [];
|
|
885
1794
|
function traverse(expr) {
|
|
886
1795
|
// If this is a property expression, add it to our collection
|
|
@@ -898,9 +1807,6 @@ function getProperties(expression) {
|
|
|
898
1807
|
traverse(expression);
|
|
899
1808
|
return properties;
|
|
900
1809
|
}
|
|
901
|
-
function isPropertyExpression(expression) {
|
|
902
|
-
return expression.type === "property";
|
|
903
|
-
}
|
|
904
1810
|
function forEach(expression, callback) {
|
|
905
1811
|
function traverse(expr) {
|
|
906
1812
|
// Call the callback for this expression
|
|
@@ -926,60 +1832,165 @@ function forEach(expression, callback) {
|
|
|
926
1832
|
|
|
927
1833
|
|
|
928
1834
|
},
|
|
929
|
-
|
|
930
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1835
|
+
537(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
931
1836
|
__webpack_require__.d(__webpack_exports__, {
|
|
932
|
-
|
|
1837
|
+
L: () => (SchemaTypes)
|
|
933
1838
|
});
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
+
}({})));
|
|
943
1867
|
|
|
944
1868
|
|
|
945
1869
|
},
|
|
946
|
-
|
|
947
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1870
|
+
581(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
948
1871
|
__webpack_require__.d(__webpack_exports__, {
|
|
949
|
-
|
|
1872
|
+
vF: () => (logger)
|
|
950
1873
|
});
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1874
|
+
/**
|
|
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 = ()=>{
|
|
1920
|
+
if (typeof globalThis !== 'undefined') {
|
|
1921
|
+
const g = globalThis;
|
|
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.
|
|
1937
|
+
if (typeof process !== 'undefined' && process.env != null) {
|
|
1938
|
+
if (isLogLevel(process.env.ROUTIER_LOG_LEVEL)) {
|
|
1939
|
+
return process.env.ROUTIER_LOG_LEVEL;
|
|
1940
|
+
}
|
|
1941
|
+
const debug = process.env.DEBUG;
|
|
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';
|
|
1950
|
+
};
|
|
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(', ')}`);
|
|
954
1962
|
}
|
|
955
|
-
|
|
956
|
-
|
|
1963
|
+
level = next;
|
|
1964
|
+
rank = RANK[next];
|
|
957
1965
|
};
|
|
958
|
-
const
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
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;
|
|
962
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);
|
|
963
1986
|
};
|
|
964
1987
|
const logger = {
|
|
965
|
-
log: (...args)
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
warn: (...args) => {
|
|
972
|
-
tryLog("warn", ...args);
|
|
973
|
-
},
|
|
974
|
-
error: (...args) => {
|
|
975
|
-
tryLog("error", ...args);
|
|
976
|
-
},
|
|
977
|
-
debug: (...args) => {
|
|
978
|
-
tryLog("debug", ...args);
|
|
979
|
-
},
|
|
980
|
-
table: (...args) => {
|
|
981
|
-
tryLog("table", ...args);
|
|
982
|
-
},
|
|
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)
|
|
983
1994
|
};
|
|
984
1995
|
|
|
985
1996
|
|
|
@@ -1023,55 +2034,56 @@ __webpack_require__.d = (exports, definition) => {
|
|
|
1023
2034
|
(() => {
|
|
1024
2035
|
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
1025
2036
|
})();
|
|
1026
|
-
// webpack/runtime/make_namespace_object
|
|
1027
|
-
(() => {
|
|
1028
|
-
// define __esModule on exports
|
|
1029
|
-
__webpack_require__.r = (exports) => {
|
|
1030
|
-
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
1031
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
1032
|
-
}
|
|
1033
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1034
|
-
};
|
|
1035
|
-
})();
|
|
1036
2037
|
var __webpack_exports__ = {};
|
|
1037
2038
|
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
|
|
1038
2039
|
(() => {
|
|
1039
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1040
2040
|
__webpack_require__.d(__webpack_exports__, {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
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)
|
|
1053
2057
|
});
|
|
1054
|
-
/* import */ var
|
|
1055
|
-
/* import */ var
|
|
1056
|
-
/* import */ var
|
|
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);
|
|
2063
|
+
|
|
2064
|
+
|
|
1057
2065
|
|
|
1058
2066
|
|
|
1059
2067
|
|
|
1060
2068
|
|
|
1061
2069
|
})();
|
|
1062
2070
|
|
|
1063
|
-
var __webpack_exports__ComparatorExpression = __webpack_exports__.
|
|
1064
|
-
var
|
|
1065
|
-
var
|
|
1066
|
-
var
|
|
1067
|
-
var
|
|
1068
|
-
var
|
|
1069
|
-
var
|
|
1070
|
-
var
|
|
1071
|
-
var
|
|
1072
|
-
var
|
|
1073
|
-
var
|
|
1074
|
-
var
|
|
1075
|
-
|
|
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 };
|
|
1076
2088
|
|
|
1077
2089
|
//# sourceMappingURL=index.js.map
|