@routier/core 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/codegen/blocks.d.ts +17 -1
  2. package/dist/codegen/handlers/types.d.ts +13 -5
  3. package/dist/codegen/index.cjs +28 -0
  4. package/dist/codegen/index.cjs.map +1 -1
  5. package/dist/codegen/index.js +28 -0
  6. package/dist/codegen/index.js.map +1 -1
  7. package/dist/collections/MemoryDataCollection.d.ts +2 -4
  8. package/dist/collections/index.cjs +127 -15
  9. package/dist/collections/index.cjs.map +1 -1
  10. package/dist/collections/index.js +127 -15
  11. package/dist/collections/index.js.map +1 -1
  12. package/dist/expressions/index.cjs +226 -4
  13. package/dist/expressions/index.cjs.map +1 -1
  14. package/dist/expressions/index.js +228 -5
  15. package/dist/expressions/index.js.map +1 -1
  16. package/dist/expressions/parser.d.ts +42 -1
  17. package/dist/index.cjs +753 -345
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +756 -345
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugins/EphemeralDataPlugin.d.ts +8 -0
  22. package/dist/plugins/index.cjs +566 -49
  23. package/dist/plugins/index.cjs.map +1 -1
  24. package/dist/plugins/index.js +566 -48
  25. package/dist/plugins/index.js.map +1 -1
  26. package/dist/plugins/query/QueryOptionsCollection.d.ts +15 -5
  27. package/dist/plugins/query/index.d.ts +1 -0
  28. package/dist/plugins/query/renames.d.ts +27 -0
  29. package/dist/plugins/query/types.d.ts +15 -1
  30. package/dist/plugins/translators/SqlTranslator.d.ts +15 -0
  31. package/dist/schema/SchemaDefinition.d.ts +8 -0
  32. package/dist/schema/changeTracker.d.ts +10 -0
  33. package/dist/schema/index.cjs +291 -274
  34. package/dist/schema/index.cjs.map +1 -1
  35. package/dist/schema/index.d.ts +1 -0
  36. package/dist/schema/index.js +294 -276
  37. package/dist/schema/index.js.map +1 -1
  38. package/dist/schema/types.d.ts +8 -7
  39. package/dist/schema/utils/storageDates.d.ts +25 -0
  40. package/dist/transfer/index.cjs.map +1 -1
  41. package/dist/transfer/index.js.map +1 -1
  42. package/dist/utilities/index.cjs +74 -29
  43. package/dist/utilities/index.cjs.map +1 -1
  44. package/dist/utilities/index.js +74 -29
  45. package/dist/utilities/index.js.map +1 -1
  46. package/package.json +2 -2
  47. package/dist/codegen/utils.d.ts +0 -22
@@ -720,6 +720,7 @@ const readsAProperty = (expression)=>{
720
720
  91(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
721
721
  __webpack_require__.d(__webpack_exports__, {
722
722
  MY: () => (toExpression),
723
+ Pl: () => (parseSelector),
723
724
  oH: () => (parseFragment),
724
725
  pg: () => (combineExpressions)
725
726
  });
@@ -728,6 +729,7 @@ __webpack_require__.d(__webpack_exports__, {
728
729
  /* import */ var _schema__rspack_import_2 = __webpack_require__(537);
729
730
  /* import */ var _evaluate__rspack_import_3 = __webpack_require__(379);
730
731
  /* import */ var _fold__rspack_import_4 = __webpack_require__(43);
732
+ /* import */ var _utils__rspack_import_6 = __webpack_require__(63);
731
733
  /* import */ var _types__rspack_import_1 = __webpack_require__(27);
732
734
 
733
735
 
@@ -735,6 +737,7 @@ __webpack_require__.d(__webpack_exports__, {
735
737
 
736
738
 
737
739
 
740
+
738
741
  // Error message constants
739
742
  const ERROR_MESSAGES = {
740
743
  PROPERTY_NOT_FOUND: (path)=>`Error parsing query, could not find PropertyInfo for path: ${path}`,
@@ -1342,6 +1345,9 @@ const COALESCE_OPERATORS = sourceKeyed({
1342
1345
  // A comparison always names a schema property, so the condition alone settles it
1343
1346
  return true;
1344
1347
  }
1348
+ if (operand.kind === "opaque") {
1349
+ return operand.reads.some(containsProperty);
1350
+ }
1345
1351
  return operand.kind === "arithmetic" && (containsProperty(operand.left) || containsProperty(operand.right) || operand.extra != null && containsProperty(operand.extra));
1346
1352
  };
1347
1353
  const DECLARATION_KEYWORDS = new Set([
@@ -1519,13 +1525,18 @@ const resolveParamPath = (paramsName, path, data)=>{
1519
1525
  scope;
1520
1526
  paramsName;
1521
1527
  params;
1528
+ /**
1529
+ * Whether this parses a value selector rather than a filter, and so reads a call it has no node for
1530
+ * as an `OpaqueOperand` instead of refusing it.
1531
+ */ readsValues;
1522
1532
  /** Set when a param value shaped the tree itself (e.g. x[p.name]) — such templates cannot be cached. */ structurallyDependsOnParams = false;
1523
- constructor(schema, stream, scope, paramsName, params){
1533
+ constructor(schema, stream, scope, paramsName, params, readsValues = false){
1524
1534
  this.schema = schema;
1525
1535
  this.stream = stream;
1526
1536
  this.scope = scope;
1527
1537
  this.paramsName = paramsName;
1528
1538
  this.params = params;
1539
+ this.readsValues = readsValues;
1529
1540
  }
1530
1541
  parse() {
1531
1542
  const expression = this.parseOr();
@@ -1547,6 +1558,71 @@ const resolveParamPath = (paramsName, path, data)=>{
1547
1558
  }
1548
1559
  return answer;
1549
1560
  }
1561
+ /**
1562
+ * What a value selector returns: one value, or the fields of an object literal.
1563
+ *
1564
+ * A block body is read only when it does nothing but return, which is what a transpiler makes of an
1565
+ * arrow function. Anything more is refused, and the caller falls back to running the function.
1566
+ */ parseSelector() {
1567
+ const block = this.stream.matchPunctuation("{");
1568
+ if (block) {
1569
+ const keyword = this.stream.next();
1570
+ if (keyword.kind !== "identifier" || keyword.value !== "return") {
1571
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a selector block that does more than return"));
1572
+ }
1573
+ }
1574
+ const selected = this.stream.isPunctuation("{") ? this.parseObjectLiteral() : this.stream.isPunctuation("(") && this.stream.isPunctuation("{", 1) ? this.parseBracketedObjectLiteral() : this.parseInterpolation();
1575
+ if (block) {
1576
+ this.stream.matchPunctuation(";");
1577
+ this.stream.expectPunctuation("}");
1578
+ }
1579
+ if (!this.stream.isAtEnd) {
1580
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`unexpected token '${this.stream.peek()?.value}'`));
1581
+ }
1582
+ return selected;
1583
+ }
1584
+ /** `({ … })`, the arrow body that returns an object. */ parseBracketedObjectLiteral() {
1585
+ this.stream.expectPunctuation("(");
1586
+ const fields = this.parseObjectLiteral();
1587
+ this.stream.expectPunctuation(")");
1588
+ return fields;
1589
+ }
1590
+ /**
1591
+ * The fields of an object literal, each one value.
1592
+ *
1593
+ * A field's value is read without a top-level conditional, which needs brackets here: the look-ahead
1594
+ * for a `?` does not stop at the comma that ends the field.
1595
+ */ parseObjectLiteral() {
1596
+ this.stream.expectPunctuation("{");
1597
+ const fields = [];
1598
+ while(!this.stream.matchPunctuation("}")){
1599
+ const key = this.stream.next();
1600
+ if (key.kind !== "identifier" && key.kind !== "string") {
1601
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`the object key '${key.value}'`));
1602
+ }
1603
+ fields.push({
1604
+ name: key.value,
1605
+ operand: this.stream.matchPunctuation(":") ? this.parseValue() : this.parseShorthand(key)
1606
+ });
1607
+ if (!this.stream.matchPunctuation(",")) {
1608
+ this.stream.expectPunctuation("}");
1609
+ break;
1610
+ }
1611
+ }
1612
+ return fields;
1613
+ }
1614
+ /** `{ name }`, which reads what the parameter list bound `name` to. */ parseShorthand(key) {
1615
+ const binding = key.kind === "identifier" ? this.scope.get(key.value) : undefined;
1616
+ if (binding == null || binding.kind === "inlined") {
1617
+ throw new Error(ERROR_MESSAGES.VARIABLE_VALUE(key.value));
1618
+ }
1619
+ return this.parseChain({
1620
+ kind: binding.kind,
1621
+ path: [
1622
+ ...binding.path
1623
+ ]
1624
+ });
1625
+ }
1550
1626
  /** The expression a `{ … }` block answers with. */ parseBlock() {
1551
1627
  this.stream.expectPunctuation("{");
1552
1628
  const answer = this.parseStatements();
@@ -1810,7 +1886,7 @@ const resolveParamPath = (paramsName, path, data)=>{
1810
1886
  * A structural dependence found inside propagates outward: the template it belongs to cannot be
1811
1887
  * cached either.
1812
1888
  */ parseNested(source) {
1813
- const nested = new ExpressionParser(this.schema, new TokenStream(tokenize(source)), this.scope, this.paramsName, this.params);
1889
+ const nested = new ExpressionParser(this.schema, new TokenStream(tokenize(source)), this.scope, this.paramsName, this.params, this.readsValues);
1814
1890
  const operand = nested.parseInterpolation();
1815
1891
  // Leftover tokens mean the interpolation held something this reads only part of. Silently
1816
1892
  // keeping the part it understood is the worst outcome available: `${x.age > 5 ? "a" : "b"}`
@@ -2102,7 +2178,7 @@ const resolveParamPath = (paramsName, path, data)=>{
2102
2178
  if (argument.kind === "method-call") {
2103
2179
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("nested method call inside .includes()"));
2104
2180
  }
2105
- if (argument.kind === "arithmetic" || argument.kind === "conditional") {
2181
+ if (argument.kind === "arithmetic" || argument.kind === "conditional" || argument.kind === "opaque") {
2106
2182
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("arithmetic inside .includes()"));
2107
2183
  }
2108
2184
  return {
@@ -2196,7 +2272,7 @@ const resolveParamPath = (paramsName, path, data)=>{
2196
2272
  if (argument.kind === "method-call") {
2197
2273
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`nested method call inside .${method}()`));
2198
2274
  }
2199
- if (argument.kind === "arithmetic" || argument.kind === "conditional") {
2275
+ if (argument.kind === "arithmetic" || argument.kind === "conditional" || argument.kind === "opaque") {
2200
2276
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`arithmetic inside .${method}()`));
2201
2277
  }
2202
2278
  return {
@@ -2206,9 +2282,20 @@ const resolveParamPath = (paramsName, path, data)=>{
2206
2282
  argument
2207
2283
  };
2208
2284
  }
2285
+ if (this.readsValues) {
2286
+ return this.withGroupCall(this.opaqueCall(this.resolveChain(options.kind, path, transformer, locale)));
2287
+ }
2209
2288
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`method '.${method}()'`));
2210
2289
  }
2211
2290
  if (transformer != null) {
2291
+ if (this.readsValues) {
2292
+ return this.withGroupCall({
2293
+ kind: "opaque",
2294
+ reads: [
2295
+ this.resolveChain(options.kind, path, transformer, locale)
2296
+ ]
2297
+ });
2298
+ }
2212
2299
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("property access after a transform method"));
2213
2300
  }
2214
2301
  path.push(segment.value);
@@ -2353,10 +2440,39 @@ const resolveParamPath = (paramsName, path, data)=>{
2353
2440
  argument
2354
2441
  };
2355
2442
  }
2443
+ // Any other member or call of a value, which a selector reads through
2444
+ if (this.readsValues) {
2445
+ this.stream.next();
2446
+ this.stream.next();
2447
+ receiver = this.stream.isPunctuation("(") ? this.opaqueCall(receiver) : {
2448
+ kind: "opaque",
2449
+ reads: [
2450
+ receiver
2451
+ ]
2452
+ };
2453
+ continue;
2454
+ }
2356
2455
  break;
2357
2456
  }
2358
2457
  return receiver;
2359
2458
  }
2459
+ /** A call with no node of its own, from its `(`, kept for what its receiver and arguments read. */ opaqueCall(receiver) {
2460
+ const reads = [
2461
+ receiver
2462
+ ];
2463
+ this.stream.expectPunctuation("(");
2464
+ while(!this.stream.matchPunctuation(")")){
2465
+ reads.push(this.parseValue());
2466
+ if (!this.stream.matchPunctuation(",")) {
2467
+ this.stream.expectPunctuation(")");
2468
+ break;
2469
+ }
2470
+ }
2471
+ return {
2472
+ kind: "opaque",
2473
+ reads
2474
+ };
2475
+ }
2360
2476
  withValueTransformer(operand) {
2361
2477
  if (this.stream.isPunctuation(".")) {
2362
2478
  const method = this.stream.peek(1);
@@ -2390,6 +2506,10 @@ const resolveParamPath = (paramsName, path, data)=>{
2390
2506
  if (right.kind === "method-call") {
2391
2507
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("method call on the right side of a comparison"));
2392
2508
  }
2509
+ // A comparison is a tree a backend renders, and this operand has no node in one
2510
+ if (left.kind === "opaque" || right.kind === "opaque") {
2511
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a call with no expression form inside a comparison"));
2512
+ }
2393
2513
  if (needsBrackets(left) || needsBrackets(right)) {
2394
2514
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("a bitwise or nullish operator compared without brackets, which JavaScript reads the other way round"));
2395
2515
  }
@@ -2603,6 +2723,9 @@ const resolveParamPath = (paramsName, path, data)=>{
2603
2723
  if (operand.kind === "method-call") {
2604
2724
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("a method call inside arithmetic"));
2605
2725
  }
2726
+ if (operand.kind === "opaque") {
2727
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a call with no expression form inside arithmetic"));
2728
+ }
2606
2729
  return this.createValueExpression(operand, null, /* applyConverter */ false);
2607
2730
  }
2608
2731
  createPropertyExpression(operand) {
@@ -2938,6 +3061,104 @@ const toExpression = (schema, fn, params)=>{
2938
3061
  return _types__rspack_import_1/* .Expression.notParsable */.r4.notParsable(refusalOf(error));
2939
3062
  }
2940
3063
  };
3064
+ const collectReads = (operand, into)=>{
3065
+ switch(operand.kind){
3066
+ case "property":
3067
+ into.add(operand.property);
3068
+ return;
3069
+ case "method-call":
3070
+ collectReads(operand.target, into);
3071
+ collectReads(operand.argument, into);
3072
+ return;
3073
+ case "arithmetic":
3074
+ collectReads(operand.left, into);
3075
+ collectReads(operand.right, into);
3076
+ if (operand.extra != null) {
3077
+ collectReads(operand.extra, into);
3078
+ }
3079
+ return;
3080
+ case "conditional":
3081
+ for (const property of (0,_utils__rspack_import_6/* .getProperties */.oY)(operand.condition)){
3082
+ into.add(property);
3083
+ }
3084
+ collectReads(operand.whenTrue, into);
3085
+ collectReads(operand.whenFalse, into);
3086
+ return;
3087
+ case "opaque":
3088
+ for (const read of operand.reads){
3089
+ collectReads(read, into);
3090
+ }
3091
+ return;
3092
+ }
3093
+ };
3094
+ const selectedValue = (operand)=>{
3095
+ const found = new Set();
3096
+ collectReads(operand, found);
3097
+ const reads = [
3098
+ ...found
3099
+ ];
3100
+ return {
3101
+ property: reads.length === 1 ? reads[0] : null,
3102
+ reads,
3103
+ isDirectProperty: operand.kind === "property" && operand.transformer == null
3104
+ };
3105
+ };
3106
+ // Keyed like the template cache. A selector takes no params, so every result is cacheable
3107
+ const selectorCache = new WeakMap();
3108
+ /**
3109
+ * Reads a sort, map, group or `nearest` selector with the grammar filters use, for what its value is
3110
+ * read from.
3111
+ *
3112
+ * Not for evaluating it: the caller's function stays the value, and nothing here renders one. A plugin
3113
+ * decides from the result whether it can run the option. One that orders or projects by column cannot
3114
+ * run a value that is not the property itself, and one that runs the function over stored rows cannot
3115
+ * run it over a renamed property.
3116
+ *
3117
+ * So the grammar is wider here than for a filter. A call it has no node for, such as `getFullYear()`,
3118
+ * is kept for the operands it reads rather than refused, since the function it came from still runs.
3119
+ *
3120
+ * `not-parsable` is not logged. The option runs as it did before the selector was parsed.
3121
+ *
3122
+ * Cached by function source per schema, like `toExpression`. The result is shared, so it is read-only.
3123
+ */ const parseSelector = (schema, selector)=>{
3124
+ const source = selector.toString();
3125
+ let bySource = selectorCache.get(schema);
3126
+ const cached = bySource?.get(source);
3127
+ if (cached != null) {
3128
+ return cached;
3129
+ }
3130
+ let parsed;
3131
+ try {
3132
+ const shape = resolveFunctionShape(source, false);
3133
+ const parser = new ExpressionParser(schema, new TokenStream(tokenize(shape.body)), shape.scope, null, undefined, true);
3134
+ const selected = parser.parseSelector();
3135
+ parsed = Array.isArray(selected) ? {
3136
+ kind: "object",
3137
+ fields: selected.map((field)=>({
3138
+ name: field.name,
3139
+ ...selectedValue(field.operand)
3140
+ }))
3141
+ } : {
3142
+ kind: "value",
3143
+ value: selectedValue(selected)
3144
+ };
3145
+ } catch (error) {
3146
+ parsed = {
3147
+ kind: "not-parsable",
3148
+ reason: refusalOf(error)
3149
+ };
3150
+ }
3151
+ if (bySource == null) {
3152
+ bySource = new Map();
3153
+ selectorCache.set(schema, bySource);
3154
+ }
3155
+ // Stryker disable next-line all: the same resource bound as the template cache's
3156
+ if (bySource.size >= MAX_CACHED_TEMPLATES_PER_SCHEMA) {
3157
+ bySource.clear();
3158
+ }
3159
+ bySource.set(source, parsed);
3160
+ return parsed;
3161
+ }; // #endregion
2941
3162
 
2942
3163
 
2943
3164
  },
@@ -3552,6 +3773,7 @@ __webpack_require__.d(__webpack_exports__, {
3552
3773
  LU: () => (/* reexport safe */ _utils__rspack_import_5.LU),
3553
3774
  MY: () => (/* reexport safe */ _parser__rspack_import_3.MY),
3554
3775
  Nb: () => (/* reexport safe */ _callSource__rspack_import_0.N),
3776
+ Pl: () => (/* reexport safe */ _parser__rspack_import_3.Pl),
3555
3777
  SC: () => (/* reexport safe */ _types__rspack_import_4.SC),
3556
3778
  Sm: () => (/* reexport safe */ _types__rspack_import_4.Sm),
3557
3779
  Sv: () => (/* reexport safe */ _fold__rspack_import_2.Sv),
@@ -3610,11 +3832,12 @@ var __webpack_exports__forEach = __webpack_exports__.jJ;
3610
3832
  var __webpack_exports__getProperties = __webpack_exports__.oY;
3611
3833
  var __webpack_exports__operandValue = __webpack_exports__.Vv;
3612
3834
  var __webpack_exports__parseFragment = __webpack_exports__.oH;
3835
+ var __webpack_exports__parseSelector = __webpack_exports__.Pl;
3613
3836
  var __webpack_exports__peelCalls = __webpack_exports__.CC;
3614
3837
  var __webpack_exports__renderCallAsJs = __webpack_exports__.ax;
3615
3838
  var __webpack_exports__toExpression = __webpack_exports__.MY;
3616
3839
  var __webpack_exports__toPredicate = __webpack_exports__.Vu;
3617
3840
  var __webpack_exports__toStrictPredicate = __webpack_exports__.wS;
3618
- export { __webpack_exports__CALL_SOURCE as CALL_SOURCE, __webpack_exports__CallExpression as CallExpression, __webpack_exports__ComparatorExpression as ComparatorExpression, __webpack_exports__EXPRESSION_TYPES as EXPRESSION_TYPES, __webpack_exports__EmptyExpression as EmptyExpression, __webpack_exports__Expression as Expression, __webpack_exports__FOLDABLE as FOLDABLE, __webpack_exports__NotParsableExpression as NotParsableExpression, __webpack_exports__OperatorExpression as OperatorExpression, __webpack_exports__PropertyExpression as PropertyExpression, __webpack_exports__UNRESOLVED as UNRESOLVED, __webpack_exports__ValueExpression as ValueExpression, __webpack_exports__childrenOf as childrenOf, __webpack_exports__combineExpressions as combineExpressions, __webpack_exports__evaluate as evaluate, __webpack_exports__foldConstantCalls as foldConstantCalls, __webpack_exports__foldedOperandValue as foldedOperandValue, __webpack_exports__forEach as forEach, __webpack_exports__getProperties as getProperties, __webpack_exports__operandValue as operandValue, __webpack_exports__parseFragment as parseFragment, __webpack_exports__peelCalls as peelCalls, __webpack_exports__renderCallAsJs as renderCallAsJs, __webpack_exports__toExpression as toExpression, __webpack_exports__toPredicate as toPredicate, __webpack_exports__toStrictPredicate as toStrictPredicate };
3841
+ export { __webpack_exports__CALL_SOURCE as CALL_SOURCE, __webpack_exports__CallExpression as CallExpression, __webpack_exports__ComparatorExpression as ComparatorExpression, __webpack_exports__EXPRESSION_TYPES as EXPRESSION_TYPES, __webpack_exports__EmptyExpression as EmptyExpression, __webpack_exports__Expression as Expression, __webpack_exports__FOLDABLE as FOLDABLE, __webpack_exports__NotParsableExpression as NotParsableExpression, __webpack_exports__OperatorExpression as OperatorExpression, __webpack_exports__PropertyExpression as PropertyExpression, __webpack_exports__UNRESOLVED as UNRESOLVED, __webpack_exports__ValueExpression as ValueExpression, __webpack_exports__childrenOf as childrenOf, __webpack_exports__combineExpressions as combineExpressions, __webpack_exports__evaluate as evaluate, __webpack_exports__foldConstantCalls as foldConstantCalls, __webpack_exports__foldedOperandValue as foldedOperandValue, __webpack_exports__forEach as forEach, __webpack_exports__getProperties as getProperties, __webpack_exports__operandValue as operandValue, __webpack_exports__parseFragment as parseFragment, __webpack_exports__parseSelector as parseSelector, __webpack_exports__peelCalls as peelCalls, __webpack_exports__renderCallAsJs as renderCallAsJs, __webpack_exports__toExpression as toExpression, __webpack_exports__toPredicate as toPredicate, __webpack_exports__toStrictPredicate as toStrictPredicate };
3619
3842
 
3620
3843
  //# sourceMappingURL=index.js.map