@silverbulletmd/silverbullet 2.4.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 (117) hide show
  1. package/LICENSE.md +18 -0
  2. package/README.md +98 -0
  3. package/client/asset_bundle/bundle.ts +95 -0
  4. package/client/data/datastore.ts +85 -0
  5. package/client/data/kv_primitives.ts +25 -0
  6. package/client/markdown_parser/constants.ts +13 -0
  7. package/client/plugos/event.ts +36 -0
  8. package/client/plugos/eventhook.ts +8 -0
  9. package/client/plugos/hooks/code_widget.ts +59 -0
  10. package/client/plugos/hooks/command.ts +104 -0
  11. package/client/plugos/hooks/document_editor.ts +77 -0
  12. package/client/plugos/hooks/event.ts +187 -0
  13. package/client/plugos/hooks/mq.ts +154 -0
  14. package/client/plugos/hooks/plug_namespace.ts +85 -0
  15. package/client/plugos/hooks/slash_command.ts +192 -0
  16. package/client/plugos/hooks/syscall.ts +66 -0
  17. package/client/plugos/manifest_cache.ts +67 -0
  18. package/client/plugos/plug.ts +99 -0
  19. package/client/plugos/plug_compile.ts +202 -0
  20. package/client/plugos/protocol.ts +40 -0
  21. package/client/plugos/proxy_fetch.ts +53 -0
  22. package/client/plugos/sandboxes/deno_worker_sandbox.ts +6 -0
  23. package/client/plugos/sandboxes/sandbox.ts +14 -0
  24. package/client/plugos/sandboxes/web_worker_sandbox.ts +17 -0
  25. package/client/plugos/sandboxes/worker_sandbox.ts +132 -0
  26. package/client/plugos/syscalls/asset.ts +35 -0
  27. package/client/plugos/syscalls/clientStore.ts +21 -0
  28. package/client/plugos/syscalls/client_code_widget.ts +12 -0
  29. package/client/plugos/syscalls/code_widget.ts +24 -0
  30. package/client/plugos/syscalls/config.ts +46 -0
  31. package/client/plugos/syscalls/datastore.ts +89 -0
  32. package/client/plugos/syscalls/editor.ts +673 -0
  33. package/client/plugos/syscalls/event.ts +36 -0
  34. package/client/plugos/syscalls/fetch.ts +128 -0
  35. package/client/plugos/syscalls/index.ts +102 -0
  36. package/client/plugos/syscalls/jsonschema.ts +69 -0
  37. package/client/plugos/syscalls/language.ts +23 -0
  38. package/client/plugos/syscalls/lua.ts +58 -0
  39. package/client/plugos/syscalls/markdown.ts +84 -0
  40. package/client/plugos/syscalls/mq.ts +52 -0
  41. package/client/plugos/syscalls/service_registry.ts +43 -0
  42. package/client/plugos/syscalls/shell.ts +39 -0
  43. package/client/plugos/syscalls/space.ts +139 -0
  44. package/client/plugos/syscalls/sync.ts +77 -0
  45. package/client/plugos/syscalls/system.ts +150 -0
  46. package/client/plugos/system.ts +201 -0
  47. package/client/plugos/types.ts +60 -0
  48. package/client/plugos/util.ts +14 -0
  49. package/client/plugos/worker_runtime.ts +195 -0
  50. package/client/space_lua/ast.ts +328 -0
  51. package/client/space_lua/ast_narrow.ts +81 -0
  52. package/client/space_lua/eval.ts +2478 -0
  53. package/client/space_lua/labels.ts +416 -0
  54. package/client/space_lua/numeric.ts +240 -0
  55. package/client/space_lua/parse.ts +1522 -0
  56. package/client/space_lua/query_collection.ts +232 -0
  57. package/client/space_lua/rp.ts +27 -0
  58. package/client/space_lua/runtime.ts +1702 -0
  59. package/client/space_lua/stdlib/crypto.ts +10 -0
  60. package/client/space_lua/stdlib/encoding.ts +19 -0
  61. package/client/space_lua/stdlib/format.ts +770 -0
  62. package/client/space_lua/stdlib/js.ts +73 -0
  63. package/client/space_lua/stdlib/load.ts +52 -0
  64. package/client/space_lua/stdlib/math.ts +193 -0
  65. package/client/space_lua/stdlib/net.ts +113 -0
  66. package/client/space_lua/stdlib/os.ts +368 -0
  67. package/client/space_lua/stdlib/space_lua.ts +153 -0
  68. package/client/space_lua/stdlib/string.ts +286 -0
  69. package/client/space_lua/stdlib/table.ts +401 -0
  70. package/client/space_lua/stdlib.ts +489 -0
  71. package/client/space_lua/tonumber.ts +501 -0
  72. package/client/space_lua/util.ts +96 -0
  73. package/dist/plug-compile.js +1513 -0
  74. package/package.json +120 -0
  75. package/plug-api/constants.ts +42 -0
  76. package/plug-api/lib/async.ts +162 -0
  77. package/plug-api/lib/crypto.ts +202 -0
  78. package/plug-api/lib/dates.ts +13 -0
  79. package/plug-api/lib/json.ts +136 -0
  80. package/plug-api/lib/limited_map.ts +72 -0
  81. package/plug-api/lib/memory_cache.ts +21 -0
  82. package/plug-api/lib/native_fetch.ts +6 -0
  83. package/plug-api/lib/ref.ts +275 -0
  84. package/plug-api/lib/resolve.ts +90 -0
  85. package/plug-api/lib/tags.ts +15 -0
  86. package/plug-api/lib/transclusion.ts +122 -0
  87. package/plug-api/lib/tree.ts +232 -0
  88. package/plug-api/lib/yaml.ts +284 -0
  89. package/plug-api/syscall.ts +15 -0
  90. package/plug-api/syscalls/asset.ts +36 -0
  91. package/plug-api/syscalls/client_store.ts +33 -0
  92. package/plug-api/syscalls/code_widget.ts +8 -0
  93. package/plug-api/syscalls/config.ts +58 -0
  94. package/plug-api/syscalls/datastore.ts +96 -0
  95. package/plug-api/syscalls/editor.ts +517 -0
  96. package/plug-api/syscalls/event.ts +47 -0
  97. package/plug-api/syscalls/index.ts +77 -0
  98. package/plug-api/syscalls/jsonschema.ts +25 -0
  99. package/plug-api/syscalls/language.ts +23 -0
  100. package/plug-api/syscalls/lua.ts +20 -0
  101. package/plug-api/syscalls/markdown.ts +38 -0
  102. package/plug-api/syscalls/mq.ts +79 -0
  103. package/plug-api/syscalls/shell.ts +14 -0
  104. package/plug-api/syscalls/space.ts +212 -0
  105. package/plug-api/syscalls/sync.ts +28 -0
  106. package/plug-api/syscalls/system.ts +102 -0
  107. package/plug-api/syscalls/yaml.ts +28 -0
  108. package/plug-api/syscalls.ts +21 -0
  109. package/plug-api/system_mock.ts +89 -0
  110. package/plug-api/types/client.ts +116 -0
  111. package/plug-api/types/config.ts +22 -0
  112. package/plug-api/types/datastore.ts +28 -0
  113. package/plug-api/types/event.ts +27 -0
  114. package/plug-api/types/index.ts +56 -0
  115. package/plug-api/types/manifest.ts +98 -0
  116. package/plug-api/types/namespace.ts +6 -0
  117. package/plugs/builtin_plugs.ts +14 -0
@@ -0,0 +1,368 @@
1
+ import { LuaBuiltinFunction, LuaTable } from "../runtime.ts";
2
+
3
+ const ONE_DAY = 1000 * 60 * 60 * 24;
4
+ const ONE_WEEK = ONE_DAY * 7;
5
+
6
+ function weekNumber(
7
+ d: Date,
8
+ utc: boolean,
9
+ weekStartDay: number,
10
+ iso: boolean,
11
+ ): number {
12
+ const year = utc ? d.getUTCFullYear() : d.getFullYear();
13
+ const month = utc ? d.getUTCMonth() : d.getMonth();
14
+ const day = utc ? d.getUTCDate() : d.getDate();
15
+ const date = new Date(Date.UTC(year, month, day));
16
+
17
+ if (iso) {
18
+ const target = new Date(date);
19
+ target.setUTCDate(
20
+ target.getUTCDate() + 3 - ((target.getUTCDay() + 6) % 7),
21
+ );
22
+
23
+ const yearStart = new Date(Date.UTC(target.getUTCFullYear(), 0, 4));
24
+ const weekStart = new Date(yearStart);
25
+ weekStart.setUTCDate(
26
+ yearStart.getUTCDate() - ((yearStart.getUTCDay() + 6) % 7),
27
+ );
28
+
29
+ return 1 + Math.floor((target.getTime() - weekStart.getTime()) / ONE_WEEK);
30
+ }
31
+
32
+ const yearStart = new Date(Date.UTC(year, 0, 1));
33
+ const startDay = yearStart.getUTCDay();
34
+ const offset = (7 + (startDay - weekStartDay)) % 7;
35
+ const firstWeekStart = new Date(yearStart);
36
+
37
+ firstWeekStart.setUTCDate(yearStart.getUTCDate() + (7 - offset) % 7);
38
+
39
+ if (date < firstWeekStart) return 0;
40
+ return 1 +
41
+ Math.floor((date.getTime() - firstWeekStart.getTime()) / ONE_WEEK);
42
+ }
43
+
44
+ function dayOfYear(d: Date, utc: boolean): number {
45
+ const year = utc ? d.getUTCFullYear() : d.getFullYear();
46
+ const start = new Date(Date.UTC(year, 0, 0));
47
+
48
+ const current = utc
49
+ ? new Date(
50
+ Date.UTC(
51
+ year,
52
+ d.getUTCMonth(),
53
+ d.getUTCDate(),
54
+ d.getUTCHours(),
55
+ d.getUTCMinutes(),
56
+ d.getUTCSeconds(),
57
+ ),
58
+ )
59
+ : new Date(
60
+ Date.UTC(
61
+ year,
62
+ d.getMonth(),
63
+ d.getDate(),
64
+ d.getHours(),
65
+ d.getMinutes(),
66
+ d.getSeconds(),
67
+ ),
68
+ );
69
+
70
+ return Math.floor((current.getTime() - start.getTime()) / ONE_DAY);
71
+ }
72
+
73
+ function isoWeekYear(d: Date, utc: boolean): number {
74
+ const year = utc ? d.getUTCFullYear() : d.getFullYear();
75
+ const month = utc ? d.getUTCMonth() : d.getMonth();
76
+ const day = utc ? d.getUTCDate() : d.getDate();
77
+ const target = new Date(Date.UTC(year, month, day));
78
+
79
+ target.setUTCDate(
80
+ target.getUTCDate() + 3 - ((target.getUTCDay() + 6) % 7),
81
+ );
82
+
83
+ return target.getUTCFullYear();
84
+ }
85
+
86
+ function isDST(d: Date): boolean {
87
+ const jan = new Date(d.getFullYear(), 0, 1);
88
+
89
+ return d.getTimezoneOffset() < jan.getTimezoneOffset();
90
+ }
91
+
92
+ function yr(d: Date, utc: boolean): number {
93
+ return utc ? d.getUTCFullYear() : d.getFullYear();
94
+ }
95
+
96
+ function mo(d: Date, utc: boolean): number {
97
+ return utc ? d.getUTCMonth() : d.getMonth();
98
+ }
99
+
100
+ function da(d: Date, utc: boolean): number {
101
+ return utc ? d.getUTCDate() : d.getDate();
102
+ }
103
+
104
+ function hr(d: Date, utc: boolean): number {
105
+ return utc ? d.getUTCHours() : d.getHours();
106
+ }
107
+
108
+ function mi(d: Date, utc: boolean): number {
109
+ return utc ? d.getUTCMinutes() : d.getMinutes();
110
+ }
111
+
112
+ function sc(d: Date, utc: boolean): number {
113
+ return utc ? d.getUTCSeconds() : d.getSeconds();
114
+ }
115
+
116
+ function wd(d: Date, utc: boolean): number {
117
+ return utc ? d.getUTCDay() : d.getDay();
118
+ }
119
+
120
+ function pad2(n: number): string {
121
+ return n.toString().padStart(2, "0");
122
+ }
123
+
124
+ function pad3(n: number): string {
125
+ return n.toString().padStart(3, "0");
126
+ }
127
+
128
+ function dateTable(d: Date, utc: boolean): LuaTable {
129
+ const tbl = new LuaTable({
130
+ year: yr(d, utc),
131
+ month: mo(d, utc) + 1,
132
+ day: da(d, utc),
133
+ hour: hr(d, utc),
134
+ min: mi(d, utc),
135
+ sec: sc(d, utc),
136
+ wday: wd(d, utc) + 1,
137
+ yday: dayOfYear(d, utc),
138
+ });
139
+
140
+ if (!utc) {
141
+ tbl.rawSet("isdst", isDST(d));
142
+ }
143
+
144
+ return tbl;
145
+ }
146
+
147
+ // Build the specifier map for a given `Date` and `utc` flag.
148
+ // Returns a record mapping single-char specifier to its output string.
149
+ function buildSpecMap(
150
+ d: Date,
151
+ utc: boolean,
152
+ ): Record<string, () => string> {
153
+ const h = () => hr(d, utc);
154
+ const h12 = () => h() % 12 || 12;
155
+ const dow = () => wd(d, utc);
156
+
157
+ return {
158
+ // Date
159
+ "Y": () => yr(d, utc).toString(),
160
+ "y": () => pad2(yr(d, utc) % 100),
161
+ "C": () => pad2(Math.floor(yr(d, utc) / 100)),
162
+ "m": () => pad2(mo(d, utc) + 1),
163
+ "d": () => pad2(da(d, utc)),
164
+ "e": () => da(d, utc).toString().padStart(2, " "),
165
+ "j": () => pad3(dayOfYear(d, utc)),
166
+
167
+ // Time
168
+ "H": () => pad2(h()),
169
+ "I": () => pad2(h12()),
170
+ "M": () => pad2(mi(d, utc)),
171
+ "S": () => pad2(sc(d, utc)),
172
+ "p": () => h() >= 12 ? "PM" : "AM",
173
+
174
+ // Weekday
175
+ "A": () =>
176
+ d.toLocaleString("en-US", {
177
+ weekday: "long",
178
+ ...(utc ? { timeZone: "UTC" } : {}),
179
+ }),
180
+ "a": () =>
181
+ d.toLocaleString("en-US", {
182
+ weekday: "short",
183
+ ...(utc ? { timeZone: "UTC" } : {}),
184
+ }),
185
+ "w": () => dow().toString(),
186
+ "u": () => (dow() === 0 ? 7 : dow()).toString(),
187
+
188
+ // Month name
189
+ "b": () =>
190
+ d.toLocaleString("en-US", {
191
+ month: "short",
192
+ ...(utc ? { timeZone: "UTC" } : {}),
193
+ }),
194
+ "h": () =>
195
+ d.toLocaleString("en-US", {
196
+ month: "short",
197
+ ...(utc ? { timeZone: "UTC" } : {}),
198
+ }),
199
+ "B": () =>
200
+ d.toLocaleString("en-US", {
201
+ month: "long",
202
+ ...(utc ? { timeZone: "UTC" } : {}),
203
+ }),
204
+
205
+ // Week number
206
+ "U": () => pad2(weekNumber(d, utc, 0, false)),
207
+ "W": () => pad2(weekNumber(d, utc, 1, false)),
208
+ "V": () => pad2(weekNumber(d, utc, 1, true)),
209
+ "G": () => isoWeekYear(d, utc).toString(),
210
+ "g": () => pad2(isoWeekYear(d, utc) % 100),
211
+
212
+ // Composite specifiers
213
+ "c": () =>
214
+ d.toLocaleString("en-US", {
215
+ ...(utc ? { timeZone: "UTC" } : {}),
216
+ }),
217
+ "x": () =>
218
+ d.toLocaleDateString("en-US", {
219
+ ...(utc ? { timeZone: "UTC" } : {}),
220
+ }),
221
+ "X": () =>
222
+ d.toLocaleTimeString("en-US", {
223
+ ...(utc ? { timeZone: "UTC" } : {}),
224
+ }),
225
+ "D": () =>
226
+ `${pad2(mo(d, utc) + 1)}/${pad2(da(d, utc))}/${pad2(yr(d, utc) % 100)}`,
227
+ "F": () =>
228
+ `${yr(d, utc).toString()}-${pad2(mo(d, utc) + 1)}-${pad2(da(d, utc))}`,
229
+ "R": () => `${pad2(h())}:${pad2(mi(d, utc))}`,
230
+ "T": () => `${pad2(h())}:${pad2(mi(d, utc))}:${pad2(sc(d, utc))}`,
231
+ "r": () =>
232
+ `${pad2(h12())}:${pad2(mi(d, utc))}:${pad2(sc(d, utc))} ${
233
+ h() >= 12 ? "PM" : "AM"
234
+ }`,
235
+
236
+ // Epoch
237
+ "s": () => Math.floor(d.getTime() / 1000).toString(),
238
+
239
+ // Whitespace
240
+ "n": () => "\n",
241
+ "t": () => "\t",
242
+
243
+ // Timezone
244
+ "Z": () => {
245
+ if (utc) return "UTC";
246
+ const match = d.toTimeString().match(/\((.*)\)/);
247
+ return match ? match[1] : "";
248
+ },
249
+ "z": () => {
250
+ if (utc) return "+0000";
251
+ const offset = -d.getTimezoneOffset();
252
+ const sign = offset >= 0 ? "+" : "-";
253
+ const abs = Math.abs(offset);
254
+ return `${sign}${pad2(Math.floor(abs / 60))}${pad2(abs % 60)}`;
255
+ },
256
+
257
+ // Literal
258
+ "%": () => "%",
259
+ };
260
+ }
261
+
262
+ function luaFormatTime(fmt: string, d: Date, utc: boolean): string {
263
+ const specs = buildSpecMap(d, utc);
264
+
265
+ let out = "";
266
+ let i = 0;
267
+
268
+ while (i < fmt.length) {
269
+ if (fmt[i] !== "%") {
270
+ out += fmt[i];
271
+ i++;
272
+ continue;
273
+ }
274
+ i++; // skip '%'
275
+ if (i >= fmt.length) {
276
+ throw new Error("invalid conversion specifier '%'");
277
+ }
278
+
279
+ const ch = fmt[i];
280
+ const fn = specs[ch];
281
+ if (!fn) {
282
+ throw new Error(`invalid conversion specifier '%${ch}'`);
283
+ }
284
+
285
+ out += fn();
286
+ i++;
287
+ }
288
+
289
+ return out;
290
+ }
291
+
292
+ export const osApi = new LuaTable({
293
+ time: new LuaBuiltinFunction((_sf, tbl?: LuaTable) => {
294
+ if (tbl) {
295
+ if (!tbl.has("year")) {
296
+ throw new Error("time(): year is required");
297
+ }
298
+
299
+ if (!tbl.has("month")) {
300
+ throw new Error("time(): month is required");
301
+ }
302
+
303
+ if (!tbl.has("day")) {
304
+ throw new Error("time(): day is required");
305
+ }
306
+
307
+ const year = tbl.get("year");
308
+ const month = tbl.get("month");
309
+ const day = tbl.get("day");
310
+ const hour = tbl.get("hour") ?? 12;
311
+ const min = tbl.get("min") ?? 0;
312
+ const sec = tbl.get("sec") ?? 0;
313
+ const date = new Date(year, month - 1, day, hour, min, sec);
314
+
315
+ return Math.floor(date.getTime() / 1000);
316
+ }
317
+
318
+ return Math.floor(Date.now() / 1000);
319
+ }),
320
+
321
+ // Returns the difference, from time `t1` to time `t2` in seconds
322
+ // In POSIX and some other systems, this value is exactly $t2-t1$.
323
+ difftime: new LuaBuiltinFunction((_sf, t2: number, t1: number): number => {
324
+ return t2 - t1;
325
+ }),
326
+
327
+ // Returns a string or a table containing date and time, formatted
328
+ // according to the given string format.
329
+ //
330
+ // If format starts with '!', the date is formatted in UTC.
331
+ //
332
+ // If format is "*t" (or "!*t"), returns a table with fields:
333
+ //
334
+ // - `year`,
335
+ // - `month` (1-12),
336
+ // - `day` (1-31),
337
+ // - `hour` (0-23),
338
+ // - `min` (0-59),
339
+ // - `sec` (0-61),
340
+ // - `wday` (1-7, Sunday is 1),
341
+ // - `yday` (1-366), and
342
+ // - `isdst` (boolean).
343
+ //
344
+ // Otherwise, format specifiers follow ISO C `strftime`.
345
+ //
346
+ // If format is absent, it defaults to `%c`.
347
+ date: new LuaBuiltinFunction(
348
+ (_sf, format?: string, timestamp?: number) => {
349
+ let fmt = format ?? "%c";
350
+ let utc = false;
351
+
352
+ if (fmt.startsWith("!")) {
353
+ utc = true;
354
+ fmt = fmt.slice(1);
355
+ }
356
+
357
+ const d = timestamp !== undefined && timestamp !== null
358
+ ? new Date(timestamp * 1000)
359
+ : new Date();
360
+
361
+ if (fmt === "*t") {
362
+ return dateTable(d, utc);
363
+ }
364
+
365
+ return luaFormatTime(fmt, d, utc);
366
+ },
367
+ ),
368
+ });
@@ -0,0 +1,153 @@
1
+ import { parseExpressionString } from "../parse.ts";
2
+ import type { LuaExpression } from "../ast.ts";
3
+ import { evalExpression } from "../eval.ts";
4
+ import {
5
+ LuaBuiltinFunction,
6
+ LuaEnv,
7
+ LuaRuntimeError,
8
+ type LuaStackFrame,
9
+ LuaTable,
10
+ luaToString,
11
+ luaValueToJS,
12
+ singleResult,
13
+ } from "../runtime.ts";
14
+
15
+ /**
16
+ * These are Space Lua specific functions that are available to all scripts, but are not part of the standard Lua language.
17
+ */
18
+
19
+ /**
20
+ * Helper function to create an augmented environment
21
+ */
22
+ function createAugmentedEnv(
23
+ sf: LuaStackFrame,
24
+ envAugmentation?: LuaTable,
25
+ ): LuaEnv {
26
+ const globalEnv = sf.threadLocal.get("_GLOBAL");
27
+ if (!globalEnv) {
28
+ throw new Error("_GLOBAL not defined");
29
+ }
30
+ const env = new LuaEnv(globalEnv);
31
+ if (envAugmentation) {
32
+ env.setLocal("_", envAugmentation);
33
+ for (const key of envAugmentation.keys()) {
34
+ env.setLocal(key, envAugmentation.rawGet(key));
35
+ }
36
+ }
37
+ return env;
38
+ }
39
+
40
+ /**
41
+ * Interpolates a string with lua expressions and returns the result.
42
+ *
43
+ * @param sf - The current space_lua state.
44
+ * @param template - The template string to interpolate.
45
+ * @param envAugmentation - An optional environment to augment the global environment with.
46
+ * @returns The interpolated string.
47
+ */
48
+ export async function interpolateLuaString(
49
+ sf: LuaStackFrame,
50
+ template: string,
51
+ envAugmentation?: LuaTable,
52
+ ): Promise<string> {
53
+ let result = "";
54
+ let currentIndex = 0;
55
+
56
+ while (true) {
57
+ const startIndex = template.indexOf("${", currentIndex);
58
+ if (startIndex === -1) {
59
+ result += template.slice(currentIndex);
60
+ break;
61
+ }
62
+
63
+ result += template.slice(currentIndex, startIndex);
64
+
65
+ // Find matching closing brace by counting nesting
66
+ let nestLevel = 1;
67
+ let endIndex = startIndex + 2;
68
+ while (nestLevel > 0 && endIndex < template.length) {
69
+ if (template[endIndex] === "{") {
70
+ nestLevel++;
71
+ } else if (template[endIndex] === "}") {
72
+ nestLevel--;
73
+ }
74
+ if (nestLevel > 0) {
75
+ endIndex++;
76
+ }
77
+ }
78
+
79
+ if (nestLevel > 0) {
80
+ throw new LuaRuntimeError("Unclosed interpolation expression", sf);
81
+ }
82
+
83
+ const expr = template.slice(startIndex + 2, endIndex);
84
+ try {
85
+ const parsedExpr = parseExpressionString(expr);
86
+ const env = createAugmentedEnv(sf, envAugmentation);
87
+ // Do `luaToString` before `luaValueToJS` to preserve tagged float
88
+ // formatting.
89
+ const luaResult = singleResult(await evalExpression(parsedExpr, env, sf));
90
+ result += await luaToString(luaResult);
91
+ } catch (e: any) {
92
+ throw new LuaRuntimeError(
93
+ `Error evaluating "${expr}": ${e.message}`,
94
+ sf,
95
+ );
96
+ }
97
+
98
+ currentIndex = endIndex + 1;
99
+ }
100
+
101
+ return result;
102
+ }
103
+
104
+ export const spaceluaApi = new LuaTable({
105
+ /**
106
+ * Parses a lua expression and returns the parsed expression.
107
+ *
108
+ * @param sf - The current space_lua state.
109
+ * @param luaExpression - The lua expression to parse.
110
+ * @returns The parsed expression.
111
+ */
112
+ parseExpression: new LuaBuiltinFunction(
113
+ (_sf, luaExpression: string) => {
114
+ return parseExpressionString(luaExpression);
115
+ },
116
+ ),
117
+ /**
118
+ * Evaluates a parsed lua expression and returns the result.
119
+ *
120
+ * @param sf - The current space_lua state.
121
+ * @param parsedExpr - The parsed lua expression to evaluate.
122
+ * @param envAugmentation - An optional environment to augment the global environment with.
123
+ * @returns The result of the evaluated expression.
124
+ */
125
+ evalExpression: new LuaBuiltinFunction(
126
+ async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
127
+ const env = createAugmentedEnv(sf, envAugmentation);
128
+ return luaValueToJS(await evalExpression(parsedExpr, env, sf), sf);
129
+ },
130
+ ),
131
+ /**
132
+ * Interpolates a string with lua expressions and returns the result.
133
+ */
134
+ interpolate: new LuaBuiltinFunction(
135
+ (sf, template: string, envAugmentation?: LuaTable) => {
136
+ return interpolateLuaString(sf, template, envAugmentation);
137
+ },
138
+ ),
139
+ /**
140
+ * Returns your SilverBullet instance's base URL, or `undefined` when run on the server
141
+ */
142
+ baseUrl: new LuaBuiltinFunction(
143
+ () => {
144
+ // Deal with Deno
145
+ if (typeof location === "undefined") {
146
+ return null;
147
+ } else {
148
+ //NOTE: Removing trailing slash to stay compatible with original code: `location.protocol + "//" + location.host;`
149
+ return document.baseURI.replace(/\/*$/, "");
150
+ }
151
+ },
152
+ ),
153
+ });