@silverbulletmd/silverbullet 2.5.3 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +4 -5
  2. package/client/asset_bundle/bundle.ts +3 -9
  3. package/client/data/datastore.ts +4 -5
  4. package/client/markdown_parser/constants.ts +3 -2
  5. package/client/plugos/hooks/code_widget.ts +3 -5
  6. package/client/plugos/hooks/command.ts +8 -8
  7. package/client/plugos/hooks/document_editor.ts +10 -12
  8. package/client/plugos/hooks/event.ts +33 -36
  9. package/client/plugos/hooks/mq.ts +17 -17
  10. package/client/plugos/hooks/plug_namespace.ts +3 -5
  11. package/client/plugos/hooks/slash_command.ts +12 -27
  12. package/client/plugos/hooks/syscall.ts +3 -3
  13. package/client/plugos/manifest_cache.ts +22 -15
  14. package/client/plugos/plug.ts +2 -5
  15. package/client/plugos/plug_compile.ts +67 -65
  16. package/client/plugos/protocol.ts +28 -28
  17. package/client/plugos/proxy_fetch.ts +7 -6
  18. package/client/plugos/sandboxes/worker_sandbox.ts +16 -15
  19. package/client/plugos/syscalls/asset.ts +1 -3
  20. package/client/plugos/syscalls/code_widget.ts +1 -3
  21. package/client/plugos/syscalls/config.ts +1 -5
  22. package/client/plugos/syscalls/datastore.ts +1 -1
  23. package/client/plugos/syscalls/editor.ts +63 -60
  24. package/client/plugos/syscalls/event.ts +9 -12
  25. package/client/plugos/syscalls/fetch.ts +30 -22
  26. package/client/plugos/syscalls/index.ts +10 -1
  27. package/client/plugos/syscalls/jsonschema.ts +72 -32
  28. package/client/plugos/syscalls/language.ts +9 -5
  29. package/client/plugos/syscalls/markdown.ts +29 -7
  30. package/client/plugos/syscalls/mq.ts +3 -11
  31. package/client/plugos/syscalls/service_registry.ts +1 -4
  32. package/client/plugos/syscalls/shell.ts +2 -5
  33. package/client/plugos/syscalls/sync.ts +69 -60
  34. package/client/plugos/syscalls/system.ts +2 -3
  35. package/client/plugos/system.ts +4 -10
  36. package/client/plugos/worker_runtime.ts +4 -3
  37. package/client/space_lua/aggregates.ts +632 -59
  38. package/client/space_lua/ast.ts +21 -9
  39. package/client/space_lua/ast_narrow.ts +4 -2
  40. package/client/space_lua/eval.ts +842 -536
  41. package/client/space_lua/labels.ts +6 -11
  42. package/client/space_lua/liq_null.ts +6 -0
  43. package/client/space_lua/numeric.ts +5 -8
  44. package/client/space_lua/parse.ts +290 -169
  45. package/client/space_lua/query_collection.ts +213 -149
  46. package/client/space_lua/render_lua_markdown.ts +369 -0
  47. package/client/space_lua/rp.ts +5 -4
  48. package/client/space_lua/runtime.ts +245 -142
  49. package/client/space_lua/stdlib/format.ts +34 -20
  50. package/client/space_lua/stdlib/js.ts +3 -7
  51. package/client/space_lua/stdlib/load.ts +1 -3
  52. package/client/space_lua/stdlib/math.ts +15 -14
  53. package/client/space_lua/stdlib/net.ts +25 -15
  54. package/client/space_lua/stdlib/os.ts +76 -85
  55. package/client/space_lua/stdlib/pattern.ts +28 -35
  56. package/client/space_lua/stdlib/prng.ts +15 -12
  57. package/client/space_lua/stdlib/space_lua.ts +16 -17
  58. package/client/space_lua/stdlib/string.ts +7 -17
  59. package/client/space_lua/stdlib/string_pack.ts +23 -19
  60. package/client/space_lua/stdlib/table.ts +5 -9
  61. package/client/space_lua/stdlib.ts +20 -30
  62. package/client/space_lua/tonumber.ts +79 -40
  63. package/client/space_lua/util.ts +14 -10
  64. package/dist/plug-compile.js +44 -41
  65. package/package.json +24 -22
  66. package/plug-api/lib/async.ts +19 -6
  67. package/plug-api/lib/crypto.ts +5 -6
  68. package/plug-api/lib/dates.ts +15 -7
  69. package/plug-api/lib/json.ts +10 -4
  70. package/plug-api/lib/ref.ts +18 -18
  71. package/plug-api/lib/resolve.ts +7 -11
  72. package/plug-api/lib/tags.ts +13 -4
  73. package/plug-api/lib/transclusion.ts +6 -17
  74. package/plug-api/lib/tree.ts +115 -43
  75. package/plug-api/lib/yaml.ts +25 -15
  76. package/plug-api/syscalls/asset.ts +1 -1
  77. package/plug-api/syscalls/config.ts +1 -4
  78. package/plug-api/syscalls/editor.ts +14 -14
  79. package/plug-api/syscalls/jsonschema.ts +1 -3
  80. package/plug-api/syscalls/lua.ts +3 -9
  81. package/plug-api/syscalls/mq.ts +1 -4
  82. package/plug-api/syscalls/shell.ts +4 -1
  83. package/plug-api/syscalls/space.ts +3 -10
  84. package/plug-api/syscalls/system.ts +1 -4
  85. package/plug-api/syscalls/yaml.ts +2 -6
  86. package/plug-api/types/client.ts +16 -1
  87. package/plug-api/types/event.ts +6 -4
  88. package/plug-api/types/manifest.ts +8 -9
  89. package/plugs/builtin_plugs.ts +2 -2
  90. package/dist/worker_runtime_bundle.js +0 -233
@@ -36,7 +36,7 @@ const luaStyleTags = styleTags({
36
36
  CompareOp: t.operator,
37
37
  "true false": t.bool,
38
38
  Comment: t.lineComment,
39
- "return break goto do end while repeat until function local if then else elseif in for nil or and not query from where limit select order by desc asc nulls first last group having filter using":
39
+ "return break goto do end while repeat until function local if then else elseif in for nil or and not query from where limit offset select order by desc asc nulls first last group having filter using":
40
40
  t.keyword,
41
41
  });
42
42
 
@@ -52,10 +52,7 @@ const customIndent = indentNodeProp.add({
52
52
  export const luaLanguage = LRLanguage.define({
53
53
  name: "space-lua",
54
54
  parser: parser.configure({
55
- props: [
56
- luaStyleTags,
57
- customIndent,
58
- ],
55
+ props: [luaStyleTags, customIndent],
59
56
  }),
60
57
  languageData: {
61
58
  commentTokens: { line: "--", block: { open: "--[[", close: "--]]" } },
@@ -97,8 +94,9 @@ function expressionHasFunctionDef(e: LuaExpression): boolean {
97
94
  }
98
95
  return false;
99
96
  case "Binary":
100
- return expressionHasFunctionDef(e.left) ||
101
- expressionHasFunctionDef(e.right);
97
+ return (
98
+ expressionHasFunctionDef(e.left) || expressionHasFunctionDef(e.right)
99
+ );
102
100
  case "Unary":
103
101
  return expressionHasFunctionDef(e.argument);
104
102
  case "Parenthesized":
@@ -119,8 +117,9 @@ function expressionHasFunctionDef(e: LuaExpression): boolean {
119
117
  }
120
118
  return false;
121
119
  case "TableAccess":
122
- return expressionHasFunctionDef(e.object) ||
123
- expressionHasFunctionDef(e.key);
120
+ return (
121
+ expressionHasFunctionDef(e.object) || expressionHasFunctionDef(e.key)
122
+ );
124
123
  case "PropertyAccess":
125
124
  return expressionHasFunctionDef(e.object);
126
125
  case "Query":
@@ -128,10 +127,22 @@ function expressionHasFunctionDef(e: LuaExpression): boolean {
128
127
  const c = e.clauses[i];
129
128
  switch (c.type) {
130
129
  case "From":
131
- if (expressionHasFunctionDef(c.expression)) return true;
130
+ case "Select":
131
+ case "GroupBy":
132
+ for (const f of c.fields) {
133
+ switch (f.type) {
134
+ case "DynamicField":
135
+ if (expressionHasFunctionDef(f.key)) return true;
136
+ if (expressionHasFunctionDef(f.value)) return true;
137
+ break;
138
+ case "PropField":
139
+ case "ExpressionField":
140
+ if (expressionHasFunctionDef(f.value)) return true;
141
+ break;
142
+ }
143
+ }
132
144
  break;
133
145
  case "Where":
134
- case "Select":
135
146
  case "Having":
136
147
  if (expressionHasFunctionDef(c.expression)) return true;
137
148
  break;
@@ -145,24 +156,28 @@ function expressionHasFunctionDef(e: LuaExpression): boolean {
145
156
  return true;
146
157
  }
147
158
  if (
148
- c.orderBy[j].using && typeof c.orderBy[j].using !== "string"
159
+ c.orderBy[j].using &&
160
+ typeof c.orderBy[j].using !== "string"
149
161
  ) {
150
162
  return true;
151
163
  }
152
164
  }
153
165
  break;
154
- case "GroupBy":
155
- for (let j = 0; j < c.expressions.length; j++) {
156
- if (expressionHasFunctionDef(c.expressions[j])) return true;
157
- }
158
- break;
159
166
  }
160
167
  }
161
168
  return false;
162
169
  case "FilteredCall":
163
170
  return (
164
- expressionHasFunctionDef(e.call) ||
165
- expressionHasFunctionDef(e.filter)
171
+ expressionHasFunctionDef(e.call) || expressionHasFunctionDef(e.filter)
172
+ );
173
+ case "AggregateCall":
174
+ return (
175
+ expressionHasFunctionDef((e as any).call) ||
176
+ ((e as any).orderBy as LuaOrderBy[]).some(
177
+ (ob) =>
178
+ expressionHasFunctionDef(ob.expression) ||
179
+ (ob.using && typeof ob.using !== "string"),
180
+ )
166
181
  );
167
182
  default:
168
183
  return false;
@@ -187,8 +202,10 @@ function exprReferencesNames(e: LuaExpression, names: Set<string>): boolean {
187
202
  case "Variable":
188
203
  return names.has(e.name);
189
204
  case "Binary":
190
- return exprReferencesNames(e.left, names) ||
191
- exprReferencesNames(e.right, names);
205
+ return (
206
+ exprReferencesNames(e.left, names) ||
207
+ exprReferencesNames(e.right, names)
208
+ );
192
209
  case "Unary":
193
210
  return exprReferencesNames(e.argument, names);
194
211
  case "Parenthesized":
@@ -200,8 +217,10 @@ function exprReferencesNames(e: LuaExpression, names: Set<string>): boolean {
200
217
  }
201
218
  return false;
202
219
  case "TableAccess":
203
- return exprReferencesNames(e.object, names) ||
204
- exprReferencesNames(e.key, names);
220
+ return (
221
+ exprReferencesNames(e.object, names) ||
222
+ exprReferencesNames(e.key, names)
223
+ );
205
224
  case "PropertyAccess":
206
225
  return exprReferencesNames(e.object, names);
207
226
  case "TableConstructor":
@@ -226,10 +245,22 @@ function exprReferencesNames(e: LuaExpression, names: Set<string>): boolean {
226
245
  const c = e.clauses[i];
227
246
  switch (c.type) {
228
247
  case "From":
229
- if (exprReferencesNames(c.expression, names)) return true;
248
+ case "Select":
249
+ case "GroupBy":
250
+ for (const f of c.fields) {
251
+ switch (f.type) {
252
+ case "DynamicField":
253
+ if (exprReferencesNames(f.key, names)) return true;
254
+ if (exprReferencesNames(f.value, names)) return true;
255
+ break;
256
+ case "PropField":
257
+ case "ExpressionField":
258
+ if (exprReferencesNames(f.value, names)) return true;
259
+ break;
260
+ }
261
+ }
230
262
  break;
231
263
  case "Where":
232
- case "Select":
233
264
  case "Having":
234
265
  if (exprReferencesNames(c.expression, names)) return true;
235
266
  break;
@@ -250,11 +281,6 @@ function exprReferencesNames(e: LuaExpression, names: Set<string>): boolean {
250
281
  }
251
282
  }
252
283
  break;
253
- case "GroupBy":
254
- for (let j = 0; j < c.expressions.length; j++) {
255
- if (exprReferencesNames(c.expressions[j], names)) return true;
256
- }
257
- break;
258
284
  }
259
285
  }
260
286
  return false;
@@ -263,6 +289,15 @@ function exprReferencesNames(e: LuaExpression, names: Set<string>): boolean {
263
289
  exprReferencesNames(e.call, names) ||
264
290
  exprReferencesNames(e.filter, names)
265
291
  );
292
+ case "AggregateCall": {
293
+ const ac = e as any;
294
+ if (exprReferencesNames(ac.call, names)) return true;
295
+ for (const ob of ac.orderBy as LuaOrderBy[]) {
296
+ if (exprReferencesNames(ob.expression, names)) return true;
297
+ if (typeof ob.using === "string" && names.has(ob.using)) return true;
298
+ }
299
+ return false;
300
+ }
266
301
  default:
267
302
  return false;
268
303
  }
@@ -275,8 +310,10 @@ function lvalueReferencesNames(lv: LuaLValue, names: Set<string>): boolean {
275
310
  case "PropertyAccess":
276
311
  return exprReferencesNames(lv.object as LuaExpression, names);
277
312
  case "TableAccess":
278
- return exprReferencesNames(lv.object as LuaExpression, names) ||
279
- exprReferencesNames(lv.key, names);
313
+ return (
314
+ exprReferencesNames(lv.object as LuaExpression, names) ||
315
+ exprReferencesNames(lv.key, names)
316
+ );
280
317
  }
281
318
  }
282
319
 
@@ -409,10 +446,7 @@ function blockCapturesNames(block: LuaBlock, names: Set<string>): boolean {
409
446
  return false;
410
447
  }
411
448
 
412
- function statementCapturesNames(
413
- s: LuaStatement,
414
- names: Set<string>,
415
- ): boolean {
449
+ function statementCapturesNames(s: LuaStatement, names: Set<string>): boolean {
416
450
  switch (s.type) {
417
451
  case "Local": {
418
452
  const exprs = (s as any).expressions as LuaExpression[] | undefined;
@@ -505,8 +539,9 @@ function exprCapturesNames(e: LuaExpression, names: Set<string>): boolean {
505
539
  case "FunctionDefinition":
506
540
  return functionBodyCapturesNames(e.body, names);
507
541
  case "Binary":
508
- return exprCapturesNames(e.left, names) ||
509
- exprCapturesNames(e.right, names);
542
+ return (
543
+ exprCapturesNames(e.left, names) || exprCapturesNames(e.right, names)
544
+ );
510
545
  case "Unary":
511
546
  return exprCapturesNames(e.argument, names);
512
547
  case "Parenthesized":
@@ -518,8 +553,9 @@ function exprCapturesNames(e: LuaExpression, names: Set<string>): boolean {
518
553
  }
519
554
  return false;
520
555
  case "TableAccess":
521
- return exprCapturesNames(e.object, names) ||
522
- exprCapturesNames(e.key, names);
556
+ return (
557
+ exprCapturesNames(e.object, names) || exprCapturesNames(e.key, names)
558
+ );
523
559
  case "PropertyAccess":
524
560
  return exprCapturesNames(e.object, names);
525
561
  case "TableConstructor":
@@ -542,10 +578,22 @@ function exprCapturesNames(e: LuaExpression, names: Set<string>): boolean {
542
578
  const c = e.clauses[i];
543
579
  switch (c.type) {
544
580
  case "From":
545
- if (exprCapturesNames(c.expression, names)) return true;
581
+ case "Select":
582
+ case "GroupBy":
583
+ for (const f of c.fields) {
584
+ switch (f.type) {
585
+ case "DynamicField":
586
+ if (exprCapturesNames(f.key, names)) return true;
587
+ if (exprCapturesNames(f.value, names)) return true;
588
+ break;
589
+ case "PropField":
590
+ case "ExpressionField":
591
+ if (exprCapturesNames(f.value, names)) return true;
592
+ break;
593
+ }
594
+ }
546
595
  break;
547
596
  case "Where":
548
- case "Select":
549
597
  case "Having":
550
598
  if (exprCapturesNames(c.expression, names)) return true;
551
599
  break;
@@ -564,19 +612,25 @@ function exprCapturesNames(e: LuaExpression, names: Set<string>): boolean {
564
612
  }
565
613
  }
566
614
  break;
567
- case "GroupBy":
568
- for (let j = 0; j < c.expressions.length; j++) {
569
- if (exprCapturesNames(c.expressions[j], names)) return true;
570
- }
571
- break;
572
615
  }
573
616
  }
574
617
  return false;
575
618
  case "FilteredCall":
576
619
  return (
577
- exprCapturesNames(e.call, names) ||
578
- exprCapturesNames(e.filter, names)
620
+ exprCapturesNames(e.call, names) || exprCapturesNames(e.filter, names)
579
621
  );
622
+ case "AggregateCall": {
623
+ const ac = e as any;
624
+ if (exprCapturesNames(ac.call, names)) return true;
625
+ for (const ob of ac.orderBy as LuaOrderBy[]) {
626
+ if (exprCapturesNames(ob.expression, names)) return true;
627
+ const u = ob.using;
628
+ if (u && typeof u !== "string") {
629
+ if (functionBodyCapturesNames(u, names)) return true;
630
+ }
631
+ }
632
+ return false;
633
+ }
580
634
  default:
581
635
  return false;
582
636
  }
@@ -644,7 +698,8 @@ function parseBlock(t: ParseTree, ctx: ASTCtx): LuaBlock {
644
698
  case "FunctionCallStatement": {
645
699
  if (!hasFunctionDef) {
646
700
  const call = (s as any).call as LuaFunctionCallExpression;
647
- hasFunctionDef = expressionHasFunctionDef(call.prefix) ||
701
+ hasFunctionDef =
702
+ expressionHasFunctionDef(call.prefix) ||
648
703
  expressionsHaveFunctionDef(call.args);
649
704
  }
650
705
  break;
@@ -711,7 +766,8 @@ function parseBlock(t: ParseTree, ctx: ASTCtx): LuaBlock {
711
766
  hasCloseHere = hasCloseHere || !!child.hasCloseHere;
712
767
  hasFunctionDef = hasFunctionDef || !!child.hasFunctionDef;
713
768
  if (!hasFunctionDef) {
714
- hasFunctionDef = expressionHasFunctionDef((s as any).start) ||
769
+ hasFunctionDef =
770
+ expressionHasFunctionDef((s as any).start) ||
715
771
  expressionHasFunctionDef((s as any).end) ||
716
772
  ((s as any).step
717
773
  ? expressionHasFunctionDef((s as any).step)
@@ -814,7 +870,7 @@ function parseStatement(t: ParseTree, ctx: ASTCtx): LuaStatement {
814
870
  from?: number;
815
871
  to?: number;
816
872
  }[] = [];
817
- let elseBlock: LuaBlock | undefined ;
873
+ let elseBlock: LuaBlock | undefined;
818
874
  for (let i = 0; i < t.children!.length; i += 4) {
819
875
  const child = t.children![i];
820
876
  if (!child || !child.children || !child.children[0]) {
@@ -904,8 +960,8 @@ function parseStatement(t: ParseTree, ctx: ASTCtx): LuaStatement {
904
960
  case "Assign":
905
961
  return {
906
962
  type: "Assignment",
907
- variables: t.children![0].children!
908
- .filter((c) => c.type && c.type !== ",")
963
+ variables: t
964
+ .children![0].children!.filter((c) => c.type && c.type !== ",")
909
965
  .map((lvalue) => parseLValue(lvalue, ctx)),
910
966
  expressions: parseExpList(t.children![2], ctx),
911
967
  ctx: context(t, ctx),
@@ -949,9 +1005,7 @@ function parseStatement(t: ParseTree, ctx: ASTCtx): LuaStatement {
949
1005
  console.error(t);
950
1006
  throw new Error(
951
1007
  `Unknown statement type: ${
952
- t.children![0]?.text
953
- ? t.children![0].text
954
- : String(t.type)
1008
+ t.children![0]?.text ? t.children![0].text : String(t.type)
955
1009
  }`,
956
1010
  );
957
1011
  }
@@ -962,28 +1016,44 @@ function parseFunctionCall(
962
1016
  ctx: ASTCtx,
963
1017
  ): LuaFunctionCallExpression {
964
1018
  if (t.children![1] && t.children![1].type === ":") {
965
- return {
1019
+ const { args, aggOrderBy } = parseFunctionArgsWithOrderBy(
1020
+ t.children!.slice(3),
1021
+ ctx,
1022
+ );
1023
+ const result: LuaFunctionCallExpression = {
966
1024
  type: "FunctionCall",
967
1025
  prefix: parsePrefixExpression(t.children![0], ctx),
968
1026
  name: t.children![2].children![0].text!,
969
- args: parseFunctionArgs(t.children!.slice(3), ctx),
1027
+ args,
970
1028
  ctx: context(t, ctx),
971
1029
  };
1030
+ if (aggOrderBy) {
1031
+ (result as any).orderBy = aggOrderBy;
1032
+ }
1033
+ return result;
972
1034
  }
973
- return {
1035
+ const { args, aggOrderBy } = parseFunctionArgsWithOrderBy(
1036
+ t.children!.slice(1),
1037
+ ctx,
1038
+ );
1039
+ const result: LuaFunctionCallExpression = {
974
1040
  type: "FunctionCall",
975
1041
  prefix: parsePrefixExpression(t.children![0], ctx),
976
- args: parseFunctionArgs(t.children!.slice(1), ctx),
1042
+ args,
977
1043
  ctx: context(t, ctx),
978
1044
  };
1045
+ if (aggOrderBy) {
1046
+ (result as any).orderBy = aggOrderBy;
1047
+ }
1048
+ return result;
979
1049
  }
980
1050
 
981
1051
  function parseAttNames(t: ParseTree, ctx: ASTCtx): LuaAttName[] {
982
1052
  if (t.type !== "AttNameList") {
983
1053
  throw new Error(`Expected AttNameList, got ${t.type}`);
984
1054
  }
985
- return t.children!
986
- .filter((c) => c.type && c.type !== ",")
1055
+ return t
1056
+ .children!.filter((c) => c.type && c.type !== ",")
987
1057
  .map((att) => parseAttName(att, ctx));
988
1058
  }
989
1059
 
@@ -1044,7 +1114,7 @@ function parseFunctionName(t: ParseTree, ctx: ASTCtx): LuaFunctionName {
1044
1114
  throw new Error(`Expected FunctionName, got ${t.type}`);
1045
1115
  }
1046
1116
  const propNames: string[] = [];
1047
- let colonName: string | undefined ;
1117
+ let colonName: string | undefined;
1048
1118
  for (let i = 0; i < t.children!.length; i += 2) {
1049
1119
  const prop = t.children![i];
1050
1120
  propNames.push(prop.children![0].text!);
@@ -1065,8 +1135,8 @@ function parseNameList(t: ParseTree): string[] {
1065
1135
  if (t.type !== "NameList") {
1066
1136
  throw new Error(`Expected NameList, got ${t.type}`);
1067
1137
  }
1068
- return t.children!
1069
- .filter((c) => c.type === "Name")
1138
+ return t
1139
+ .children!.filter((c) => c.type === "Name")
1070
1140
  .map((c) => c.children![0].text!);
1071
1141
  }
1072
1142
 
@@ -1074,8 +1144,8 @@ function parseExpList(t: ParseTree, ctx: ASTCtx): LuaExpression[] {
1074
1144
  if (t.type !== "ExpList") {
1075
1145
  throw new Error(`Expected ExpList, got ${t.type}`);
1076
1146
  }
1077
- return t.children!
1078
- .filter((c) => c.type && c.type !== ",")
1147
+ return t
1148
+ .children!.filter((c) => c.type && c.type !== ",")
1079
1149
  .map((e) => parseExpression(e, ctx));
1080
1150
  }
1081
1151
 
@@ -1094,44 +1164,46 @@ function parseString(s: string): string {
1094
1164
  }
1095
1165
  return text;
1096
1166
  }
1097
- return s.slice(1, -1).replace(
1098
- /\\(x[0-9a-fA-F]{2}|u\{[0-9a-fA-F]+\}|[abfnrtv\\'"n])/g,
1099
- (match, capture) => {
1100
- switch (capture) {
1101
- case "a":
1102
- return "\x07"; // Bell
1103
- case "b":
1104
- return "\b"; // Backspace
1105
- case "f":
1106
- return "\f"; // Form feed
1107
- case "n":
1108
- return "\n"; // Newline
1109
- case "r":
1110
- return "\r"; // Carriage return
1111
- case "t":
1112
- return "\t"; // Horizontal tab
1113
- case "v":
1114
- return "\v"; // Vertical tab
1115
- case "\\":
1116
- return "\\"; // Backslash
1117
- case '"':
1118
- return '"'; // Double quote
1119
- case "'":
1120
- return "'"; // Single quote
1121
- default:
1122
- // Handle hexadecimal \x00
1123
- if (capture.startsWith("x")) {
1124
- return String.fromCharCode(parseInt(capture.slice(1), 16));
1125
- }
1126
- // Handle unicode \u{XXXX}
1127
- if (capture.startsWith("u{")) {
1128
- const codePoint = parseInt(capture.slice(2, -1), 16);
1129
- return String.fromCodePoint(codePoint);
1130
- }
1131
- return match; // return the original match if nothing fits
1132
- }
1133
- },
1134
- );
1167
+ return s
1168
+ .slice(1, -1)
1169
+ .replace(
1170
+ /\\(x[0-9a-fA-F]{2}|u\{[0-9a-fA-F]+\}|[abfnrtv\\'"n])/g,
1171
+ (match, capture) => {
1172
+ switch (capture) {
1173
+ case "a":
1174
+ return "\x07"; // Bell
1175
+ case "b":
1176
+ return "\b"; // Backspace
1177
+ case "f":
1178
+ return "\f"; // Form feed
1179
+ case "n":
1180
+ return "\n"; // Newline
1181
+ case "r":
1182
+ return "\r"; // Carriage return
1183
+ case "t":
1184
+ return "\t"; // Horizontal tab
1185
+ case "v":
1186
+ return "\v"; // Vertical tab
1187
+ case "\\":
1188
+ return "\\"; // Backslash
1189
+ case '"':
1190
+ return '"'; // Double quote
1191
+ case "'":
1192
+ return "'"; // Single quote
1193
+ default:
1194
+ // Handle hexadecimal \x00
1195
+ if (capture.startsWith("x")) {
1196
+ return String.fromCharCode(parseInt(capture.slice(1), 16));
1197
+ }
1198
+ // Handle unicode \u{XXXX}
1199
+ if (capture.startsWith("u{")) {
1200
+ const codePoint = parseInt(capture.slice(2, -1), 16);
1201
+ return String.fromCodePoint(codePoint);
1202
+ }
1203
+ return match; // return the original match if nothing fits
1204
+ }
1205
+ },
1206
+ );
1135
1207
  }
1136
1208
 
1137
1209
  function parseExpression(t: ParseTree, ctx: ASTCtx): LuaExpression {
@@ -1224,10 +1296,10 @@ function parseExpression(t: ParseTree, ctx: ASTCtx): LuaExpression {
1224
1296
  case "TableConstructor":
1225
1297
  return {
1226
1298
  type: "TableConstructor",
1227
- fields: t.children!
1228
- .slice(1, -1)
1299
+ fields: t
1300
+ .children!.slice(1, -1)
1229
1301
  .filter((c) =>
1230
- ["FieldExp", "FieldProp", "FieldDynamic"].includes(c.type!)
1302
+ ["FieldExp", "FieldProp", "FieldDynamic"].includes(c.type!),
1231
1303
  )
1232
1304
  .map((tf) => parseTableField(tf, ctx)),
1233
1305
  ctx: context(t, ctx),
@@ -1256,6 +1328,20 @@ function parseExpression(t: ParseTree, ctx: ASTCtx): LuaExpression {
1256
1328
  }
1257
1329
  }
1258
1330
 
1331
+ function parseFieldList(t: ParseTree, ctx: ASTCtx): LuaTableField[] {
1332
+ if (t.type !== "FieldList") {
1333
+ throw new Error(`Expected FieldList, got ${t.type}`);
1334
+ }
1335
+ return t
1336
+ .children!.filter(
1337
+ (c) =>
1338
+ c.type === "FieldExp" ||
1339
+ c.type === "FieldProp" ||
1340
+ c.type === "FieldDynamic",
1341
+ )
1342
+ .map((c) => parseTableField(c, ctx));
1343
+ }
1344
+
1259
1345
  function parseQueryClause(t: ParseTree, ctx: ASTCtx): LuaQueryClause {
1260
1346
  if (t.type !== "QueryClause") {
1261
1347
  throw new Error(`Expected QueryClause, got ${t.type}`);
@@ -1263,18 +1349,14 @@ function parseQueryClause(t: ParseTree, ctx: ASTCtx): LuaQueryClause {
1263
1349
  t = t.children![0];
1264
1350
  switch (t.type) {
1265
1351
  case "FromClause": {
1266
- if (t.children!.length === 4) {
1267
- // From clause with a name
1268
- return {
1269
- type: "From",
1270
- name: t.children![1].children![0].text!,
1271
- expression: parseExpression(t.children![3], ctx),
1272
- ctx: context(t, ctx),
1273
- };
1352
+ // children: ckw<"from">, FieldList
1353
+ const fieldListNode = t.children!.find((c) => c.type === "FieldList");
1354
+ if (!fieldListNode) {
1355
+ throw new Error("FromClause missing FieldList");
1274
1356
  }
1275
1357
  return {
1276
1358
  type: "From",
1277
- expression: parseExpression(t.children![1], ctx),
1359
+ fields: parseFieldList(fieldListNode, ctx),
1278
1360
  ctx: context(t, ctx),
1279
1361
  };
1280
1362
  }
@@ -1296,40 +1378,18 @@ function parseQueryClause(t: ParseTree, ctx: ASTCtx): LuaQueryClause {
1296
1378
  ctx: context(t, ctx),
1297
1379
  };
1298
1380
  }
1381
+ case "OffsetClause": {
1382
+ return {
1383
+ type: "Offset",
1384
+ offset: parseExpression(t.children![1], ctx),
1385
+ ctx: context(t, ctx),
1386
+ };
1387
+ }
1299
1388
  case "OrderByClause": {
1300
1389
  const orderBy: LuaOrderBy[] = [];
1301
1390
  for (const child of t.children!) {
1302
1391
  if (child.type === "OrderBy") {
1303
- const kids = child.children!;
1304
- let direction: "asc" | "desc" = "asc";
1305
- let nulls: "first" | "last" | undefined;
1306
- let usingVal: string | LuaFunctionBody | undefined;
1307
- for (let i = 1; i < kids.length; i++) {
1308
- const typ = kids[i].type;
1309
- if (typ === "desc") direction = "desc";
1310
- else if (typ === "asc") direction = "asc";
1311
- else if (typ === "first") nulls = "first";
1312
- else if (typ === "last") nulls = "last";
1313
- else if (typ === "using") {
1314
- const next = kids[i + 1];
1315
- if (next.type === "function") {
1316
- usingVal = parseFunctionBody(kids[i + 2], ctx);
1317
- i += 2;
1318
- } else {
1319
- usingVal = next.children![0].text!;
1320
- i++;
1321
- }
1322
- }
1323
- }
1324
- const ob: LuaOrderBy = {
1325
- type: "Order",
1326
- expression: parseExpression(kids[0], ctx),
1327
- direction,
1328
- ctx: context(child, ctx),
1329
- };
1330
- if (nulls) ob.nulls = nulls;
1331
- if (usingVal !== undefined) ob.using = usingVal;
1332
- orderBy.push(ob);
1392
+ orderBy.push(parseOrderByNode(child, ctx));
1333
1393
  }
1334
1394
  }
1335
1395
  return {
@@ -1339,23 +1399,26 @@ function parseQueryClause(t: ParseTree, ctx: ASTCtx): LuaQueryClause {
1339
1399
  };
1340
1400
  }
1341
1401
  case "SelectClause": {
1402
+ // children: ckw<"select">, FieldList
1403
+ const fieldListNode = t.children!.find((c) => c.type === "FieldList");
1404
+ if (!fieldListNode) {
1405
+ throw new Error("SelectClause missing FieldList");
1406
+ }
1342
1407
  return {
1343
1408
  type: "Select",
1344
- expression: parseExpression(t.children![1], ctx),
1409
+ fields: parseFieldList(fieldListNode, ctx),
1345
1410
  ctx: context(t, ctx),
1346
1411
  };
1347
1412
  }
1348
1413
  case "GroupByClause": {
1349
- // children: ckw<"group">, ckw<"by">, exp, ",", exp, ...
1350
- const expressions: LuaExpression[] = t.children!
1351
- .filter((c) =>
1352
- c.type !== undefined && c.type !== "group" && c.type !== "by" &&
1353
- c.type !== ","
1354
- )
1355
- .map((c) => parseExpression(c, ctx));
1414
+ // children: ckw<"group">, ckw<"by">, FieldList
1415
+ const fieldListNode = t.children!.find((c) => c.type === "FieldList");
1416
+ if (!fieldListNode) {
1417
+ throw new Error("GroupByClause missing FieldList");
1418
+ }
1356
1419
  return {
1357
1420
  type: "GroupBy",
1358
- expressions,
1421
+ fields: parseFieldList(fieldListNode, ctx),
1359
1422
  ctx: context(t, ctx),
1360
1423
  };
1361
1424
  }
@@ -1372,10 +1435,70 @@ function parseQueryClause(t: ParseTree, ctx: ASTCtx): LuaQueryClause {
1372
1435
  }
1373
1436
  }
1374
1437
 
1375
- function parseFunctionArgs(ts: ParseTree[], ctx: ASTCtx): LuaExpression[] {
1376
- return ts
1377
- .filter((t) => t.type && ![",", "(", ")"].includes(t.type))
1378
- .map((e) => parseExpression(e, ctx));
1438
+ // Parse a single OrderBy node (shared by query OrderByClause and AggOrderBy)
1439
+ function parseOrderByNode(child: ParseTree, ctx: ASTCtx): LuaOrderBy {
1440
+ const kids = child.children!;
1441
+ let direction: "asc" | "desc" = "asc";
1442
+ let nulls: "first" | "last" | undefined;
1443
+ let usingVal: string | LuaFunctionBody | undefined;
1444
+ for (let i = 1; i < kids.length; i++) {
1445
+ const typ = kids[i].type;
1446
+ if (typ === "desc") direction = "desc";
1447
+ else if (typ === "asc") direction = "asc";
1448
+ else if (typ === "first") nulls = "first";
1449
+ else if (typ === "last") nulls = "last";
1450
+ else if (typ === "using") {
1451
+ const next = kids[i + 1];
1452
+ if (next.type === "function") {
1453
+ usingVal = parseFunctionBody(kids[i + 2], ctx);
1454
+ i += 2;
1455
+ } else {
1456
+ usingVal = next.children![0].text!;
1457
+ i++;
1458
+ }
1459
+ }
1460
+ }
1461
+ const ob: LuaOrderBy = {
1462
+ type: "Order",
1463
+ expression: parseExpression(kids[0], ctx),
1464
+ direction,
1465
+ ctx: context(child, ctx),
1466
+ };
1467
+ if (nulls) ob.nulls = nulls;
1468
+ if (usingVal !== undefined) ob.using = usingVal;
1469
+ return ob;
1470
+ }
1471
+
1472
+ // Parse an AggOrderBy node into LuaOrderBy[]
1473
+ function parseAggOrderBy(t: ParseTree, ctx: ASTCtx): LuaOrderBy[] {
1474
+ if (t.type !== "AggOrderBy") {
1475
+ throw new Error(`Expected AggOrderBy, got ${t.type}`);
1476
+ }
1477
+ const orderBy: LuaOrderBy[] = [];
1478
+ for (const child of t.children!) {
1479
+ if (child.type === "OrderBy") {
1480
+ orderBy.push(parseOrderByNode(child, ctx));
1481
+ }
1482
+ }
1483
+ return orderBy;
1484
+ }
1485
+
1486
+ // Parse function args, extracting AggOrderBy if present inside funcParams
1487
+ function parseFunctionArgsWithOrderBy(
1488
+ ts: ParseTree[],
1489
+ ctx: ASTCtx,
1490
+ ): { args: LuaExpression[]; aggOrderBy?: LuaOrderBy[] } {
1491
+ let aggOrderBy: LuaOrderBy[] | undefined;
1492
+ const args: LuaExpression[] = [];
1493
+ for (const t of ts) {
1494
+ if (!t.type || [",", "(", ")"].includes(t.type)) continue;
1495
+ if (t.type === "AggOrderBy") {
1496
+ aggOrderBy = parseAggOrderBy(t, ctx);
1497
+ } else {
1498
+ args.push(parseExpression(t, ctx));
1499
+ }
1500
+ }
1501
+ return { args, aggOrderBy };
1379
1502
  }
1380
1503
 
1381
1504
  function parseFunctionBody(t: ParseTree, ctx: ASTCtx): LuaFunctionBody {
@@ -1384,8 +1507,10 @@ function parseFunctionBody(t: ParseTree, ctx: ASTCtx): LuaFunctionBody {
1384
1507
  }
1385
1508
  return {
1386
1509
  type: "FunctionBody",
1387
- parameters: t.children![1].children!
1388
- .filter((c) => c.type && ["Name", "Ellipsis"].includes(c.type))
1510
+ parameters: t
1511
+ .children![1].children!.filter(
1512
+ (c) => c.type && ["Name", "Ellipsis"].includes(c.type),
1513
+ )
1389
1514
  .map((c) => c.children![0].text!),
1390
1515
  block: parseBlock(t.children![3], ctx),
1391
1516
  ctx: context(t, ctx),
@@ -1573,9 +1698,7 @@ export function parse(s: string, ctx: ASTCtx = {}): LuaBlock {
1573
1698
  if (e && typeof e === "object" && "astCtx" in e) {
1574
1699
  throw new LuaRuntimeError(
1575
1700
  e.message,
1576
- LuaStackFrame.lostFrame.withCtx(
1577
- (e as any).astCtx as ASTCtx,
1578
- ),
1701
+ LuaStackFrame.lostFrame.withCtx((e as any).astCtx as ASTCtx),
1579
1702
  );
1580
1703
  }
1581
1704
  throw e;
@@ -1619,9 +1742,7 @@ function luaUnexpectedSymbolMessage(src: string, from: number): string {
1619
1742
  /**
1620
1743
  * Helper function to parse a Lua expression string
1621
1744
  */
1622
- export function parseExpressionString(
1623
- expr: string,
1624
- ): LuaExpression {
1745
+ export function parseExpressionString(expr: string): LuaExpression {
1625
1746
  const parsedLua = parse(`_(${expr})`) as LuaBlock;
1626
1747
  return (parsedLua.statements[0] as LuaFunctionCallStatement).call.args[0];
1627
1748
  }