@silverbulletmd/silverbullet 2.8.1 → 2.10.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 (65) hide show
  1. package/README.md +42 -25
  2. package/client/plugos/hooks/syscall.ts +24 -10
  3. package/client/plugos/syscalls/asset.ts +61 -23
  4. package/client/plugos/syscalls/clientStore.ts +32 -6
  5. package/client/plugos/syscalls/client_code_widget.ts +9 -4
  6. package/client/plugos/syscalls/code_widget.ts +26 -11
  7. package/client/plugos/syscalls/config.ts +146 -30
  8. package/client/plugos/syscalls/datastore.ts +146 -40
  9. package/client/plugos/syscalls/editor.ts +1432 -700
  10. package/client/plugos/syscalls/event.ts +46 -13
  11. package/client/plugos/syscalls/fetch.ts +123 -82
  12. package/client/plugos/syscalls/index.ts +243 -114
  13. package/client/plugos/syscalls/jsonschema.ts +107 -8
  14. package/client/plugos/syscalls/language.ts +38 -12
  15. package/client/plugos/syscalls/markdown.ts +166 -50
  16. package/client/plugos/syscalls/mq.ts +93 -20
  17. package/client/plugos/syscalls/schema_introspection.ts +33 -0
  18. package/client/plugos/syscalls/service_registry.ts +74 -20
  19. package/client/plugos/syscalls/shell.ts +51 -20
  20. package/client/plugos/syscalls/space.ts +169 -113
  21. package/client/plugos/syscalls/sync.ts +50 -19
  22. package/client/plugos/syscalls/system.ts +236 -139
  23. package/client/plugos/system.ts +21 -5
  24. package/client/space_lua/api_documentation.ts +107 -0
  25. package/client/space_lua/ast.ts +13 -0
  26. package/client/space_lua/eval.ts +12 -4
  27. package/client/space_lua/parse.ts +254 -119
  28. package/client/space_lua/pretty_print.ts +465 -0
  29. package/client/space_lua/query_collection.ts +3 -3
  30. package/client/space_lua/render_widget.ts +156 -0
  31. package/client/space_lua/runtime.ts +83 -22
  32. package/client/space_lua/stdlib/crypto.ts +8 -3
  33. package/client/space_lua/stdlib/encoding.ts +27 -9
  34. package/client/space_lua/stdlib/js.ts +137 -22
  35. package/client/space_lua/stdlib/load.ts +26 -17
  36. package/client/space_lua/stdlib/math.ts +323 -118
  37. package/client/space_lua/stdlib/net.ts +57 -9
  38. package/client/space_lua/stdlib/os.ts +111 -44
  39. package/client/space_lua/stdlib/space_lua.ts +397 -13
  40. package/client/space_lua/stdlib/string.ts +282 -104
  41. package/client/space_lua/stdlib/string_pack.ts +58 -19
  42. package/client/space_lua/stdlib/table.ts +195 -40
  43. package/client/space_lua/stdlib.ts +336 -94
  44. package/client/space_lua/syscalls.ts +270 -0
  45. package/dist/plug-compile.js +1 -1
  46. package/package.json +12 -4
  47. package/plug-api/lib/ref.ts +96 -0
  48. package/plug-api/lib/shortcut.ts +2 -1
  49. package/plug-api/syscalls/config.ts +5 -3
  50. package/plug-api/syscalls/editor.ts +23 -2
  51. package/plug-api/syscalls/index.ts +24 -1
  52. package/plug-api/syscalls/jsonschema.ts +9 -0
  53. package/plug-api/syscalls/lua.ts +28 -1
  54. package/plug-api/syscalls/shell.ts +0 -1
  55. package/plug-api/syscalls/system.ts +7 -0
  56. package/plug-api/system_mock.ts +2 -2
  57. package/plug-api/types/config.ts +1 -1
  58. package/plug-api/types/index.ts +52 -1
  59. package/plug-api/types/manifest.ts +22 -4
  60. package/plug-api/ui/cx.ts +4 -0
  61. package/plug-api/ui/index.ts +22 -0
  62. package/plug-api/ui/panel_styles.ts +33 -0
  63. package/plug-api/ui/slugify.ts +44 -0
  64. package/plugs/builtin_plugs.ts +1 -0
  65. package/client/plugos/syscalls/lua.ts +0 -58
@@ -282,38 +282,71 @@ function luaFormatTime(fmt: string, d: Date, utc: boolean): string {
282
282
  }
283
283
 
284
284
  export const osApi = new LuaTable({
285
- time: new LuaBuiltinFunction((_sf, tbl?: LuaTable) => {
286
- if (tbl) {
287
- if (!tbl.has("year")) {
288
- throw new Error("time(): year is required");
285
+ time: new LuaBuiltinFunction({
286
+ callback: (_sf, tbl?: LuaTable) => {
287
+ if (tbl) {
288
+ if (!tbl.has("year")) {
289
+ throw new Error("time(): year is required");
290
+ }
291
+
292
+ if (!tbl.has("month")) {
293
+ throw new Error("time(): month is required");
294
+ }
295
+
296
+ if (!tbl.has("day")) {
297
+ throw new Error("time(): day is required");
298
+ }
299
+
300
+ const year = tbl.get("year");
301
+ const month = tbl.get("month");
302
+ const day = tbl.get("day");
303
+ const hour = tbl.get("hour") ?? 12;
304
+ const min = tbl.get("min") ?? 0;
305
+ const sec = tbl.get("sec") ?? 0;
306
+ const date = new Date(year, month - 1, day, hour, min, sec);
307
+
308
+ return Math.floor(date.getTime() / 1000);
289
309
  }
290
310
 
291
- if (!tbl.has("month")) {
292
- throw new Error("time(): month is required");
293
- }
294
-
295
- if (!tbl.has("day")) {
296
- throw new Error("time(): day is required");
297
- }
298
-
299
- const year = tbl.get("year");
300
- const month = tbl.get("month");
301
- const day = tbl.get("day");
302
- const hour = tbl.get("hour") ?? 12;
303
- const min = tbl.get("min") ?? 0;
304
- const sec = tbl.get("sec") ?? 0;
305
- const date = new Date(year, month - 1, day, hour, min, sec);
306
-
307
- return Math.floor(date.getTime() / 1000);
308
- }
309
-
310
- return Math.floor(Date.now() / 1000);
311
+ return Math.floor(Date.now() / 1000);
312
+ },
313
+ description:
314
+ "Returns the current Unix timestamp or one built from a local date table.",
315
+ signatures: ["os.time(): integer", "os.time(dateTable): integer"],
316
+ parameters: [
317
+ {
318
+ name: "dateTable",
319
+ type: "table",
320
+ description:
321
+ "Local date fields `year`, `month`, `day`, and optional `hour`, `min`, and `sec`.",
322
+ optional: true,
323
+ },
324
+ ],
325
+ returns: [
326
+ { type: "integer", description: "Seconds since the Unix epoch." },
327
+ ],
328
+ examples: [
329
+ {
330
+ code: "local timestamp = os.time({year = 2020, month = 1, day = 1})",
331
+ },
332
+ ],
311
333
  }),
312
334
 
313
335
  // Returns the difference, from time `t1` to time `t2` in seconds
314
336
  // In POSIX and some other systems, this value is exactly $t2-t1$.
315
- difftime: new LuaBuiltinFunction((_sf, t2: number, t1: number): number => {
316
- return t2 - t1;
337
+ difftime: new LuaBuiltinFunction({
338
+ callback: (_sf, t2: number, t1: number): number => {
339
+ return t2 - t1;
340
+ },
341
+ description:
342
+ "Returns the difference in seconds from timestamp `t1` to `t2`.",
343
+ parameters: [
344
+ { name: "t2", type: "number" },
345
+ { name: "t1", type: "number" },
346
+ ],
347
+ returns: [
348
+ { type: "number", description: "The value `t2 - t1` in seconds." },
349
+ ],
317
350
  }),
318
351
 
319
352
  // Returns a string or a table containing date and time, formatted
@@ -336,29 +369,63 @@ export const osApi = new LuaTable({
336
369
  // Otherwise, format specifiers follow ISO C `strftime`.
337
370
  //
338
371
  // If format is absent, it defaults to `%c`.
339
- date: new LuaBuiltinFunction((_sf, format?: string, timestamp?: number) => {
340
- let fmt = format ?? "%c";
341
- let utc = false;
342
-
343
- if (fmt.startsWith("!")) {
344
- utc = true;
345
- fmt = fmt.slice(1);
346
- }
372
+ date: new LuaBuiltinFunction({
373
+ callback: (_sf, format?: string, timestamp?: number) => {
374
+ let fmt = format ?? "%c";
375
+ let utc = false;
376
+
377
+ if (fmt.startsWith("!")) {
378
+ utc = true;
379
+ fmt = fmt.slice(1);
380
+ }
347
381
 
348
- const d =
349
- timestamp !== undefined && timestamp !== null
350
- ? new Date(timestamp * 1000)
351
- : new Date();
382
+ const d =
383
+ timestamp !== undefined && timestamp !== null
384
+ ? new Date(timestamp * 1000)
385
+ : new Date();
352
386
 
353
- if (fmt === "*t") {
354
- return dateTable(d, utc);
355
- }
387
+ if (fmt === "*t") {
388
+ return dateTable(d, utc);
389
+ }
356
390
 
357
- return luaFormatTime(fmt, d, utc);
391
+ return luaFormatTime(fmt, d, utc);
392
+ },
393
+ description:
394
+ "Formats a timestamp as a date string or date table, optionally in UTC.",
395
+ parameters: [
396
+ {
397
+ name: "format",
398
+ type: "string",
399
+ description:
400
+ "`strftime`-style format, `*t` for a table, and optional leading `!` for UTC.",
401
+ optional: true,
402
+ },
403
+ {
404
+ name: "timestamp",
405
+ type: "number",
406
+ description: "Unix timestamp; defaults to the current time.",
407
+ optional: true,
408
+ },
409
+ ],
410
+ returns: [
411
+ { type: "string|table", description: "Formatted date or date fields." },
412
+ ],
413
+ examples: [
414
+ { code: 'print(os.date("%Y-%m-%d"))\nlocal utc = os.date("!*t")' },
415
+ ],
358
416
  }),
359
417
 
360
418
  // Returns an approximation of CPU time used by the program in seconds.
361
- clock: new LuaBuiltinFunction((_sf): number => {
362
- return performance.now() / 1000.0;
419
+ clock: new LuaBuiltinFunction({
420
+ callback: (_sf): number => {
421
+ return performance.now() / 1000.0;
422
+ },
423
+ description: "Returns a high-resolution elapsed time value in seconds.",
424
+ returns: [
425
+ {
426
+ type: "number",
427
+ description: "Browser performance timer in seconds.",
428
+ },
429
+ ],
363
430
  }),
364
431
  });
@@ -1,7 +1,16 @@
1
- import { parseExpressionString } from "../parse.ts";
2
- import type { LuaExpression } from "../ast.ts";
1
+ import type { LuaFunctionInfo } from "../../../plug-api/types/index.ts";
2
+ import { renderApiDocumentationMarkdown } from "../api_documentation.ts";
3
+ import type { LuaBlock, LuaExpression } from "../ast.ts";
3
4
  import { evalExpression } from "../eval.ts";
5
+ import { parseBlock, parseExpressionString } from "../parse.ts";
4
6
  import {
7
+ type PrintOptions,
8
+ prettyPrintBlock,
9
+ prettyPrintExpression,
10
+ } from "../pretty_print.ts";
11
+ import {
12
+ type ILuaFunction,
13
+ isILuaFunction,
5
14
  jsToLuaValue,
6
15
  LuaBuiltinFunction,
7
16
  LuaEnv,
@@ -40,6 +49,112 @@ function createAugmentedEnv(
40
49
  return env;
41
50
  }
42
51
 
52
+ function globalEnv(sf: LuaStackFrame): LuaEnv {
53
+ const env = sf.threadLocal.get("_GLOBAL");
54
+ if (!(env instanceof LuaEnv)) {
55
+ throw new Error("_GLOBAL not defined");
56
+ }
57
+ return env;
58
+ }
59
+
60
+ function resolveApiValue(
61
+ sf: LuaStackFrame,
62
+ path: string,
63
+ ): ILuaFunction | LuaTable | LuaEnv | null {
64
+ let value: any = globalEnv(sf);
65
+ for (const part of path.split(".")) {
66
+ if (value instanceof LuaEnv || value instanceof LuaTable) {
67
+ value = value.get(part, sf);
68
+ } else {
69
+ return null;
70
+ }
71
+ if (value && typeof value.then === "function") {
72
+ throw new Error("Cannot describe asynchronously resolved API values");
73
+ }
74
+ if (value === null || value === undefined) return null;
75
+ }
76
+ return value;
77
+ }
78
+
79
+ function functionInfo(
80
+ value: unknown,
81
+ resolvedName?: string,
82
+ ): LuaFunctionInfo | null {
83
+ if (!isILuaFunction(value)) return null;
84
+ return {
85
+ ...(value.info ?? { kind: "builtin" }),
86
+ name: value.info?.name ?? resolvedName,
87
+ };
88
+ }
89
+
90
+ function describeFunction(
91
+ value: unknown,
92
+ resolvedName?: string,
93
+ ): LuaTable | null {
94
+ const info = functionInfo(value, resolvedName);
95
+ return info ? (jsToLuaValue(info) as LuaTable) : null;
96
+ }
97
+
98
+ function listFunctionInfo(
99
+ sf: LuaStackFrame,
100
+ target?: LuaTable | string,
101
+ ): LuaFunctionInfo[] {
102
+ let namespace: LuaTable | LuaEnv;
103
+ let prefix = "";
104
+ if (typeof target === "string") {
105
+ const resolved = resolveApiValue(sf, target);
106
+ if (!(resolved instanceof LuaTable) && !(resolved instanceof LuaEnv)) {
107
+ return [];
108
+ }
109
+ namespace = resolved;
110
+ prefix = `${target}.`;
111
+ } else if (target instanceof LuaTable) {
112
+ namespace = target;
113
+ } else {
114
+ namespace = globalEnv(sf);
115
+ }
116
+
117
+ const functions: LuaFunctionInfo[] = [];
118
+ for (const key of [...new Set(namespace.keys())].sort()) {
119
+ const value = namespace.get(key, sf);
120
+ if (value && typeof (value as any).then === "function") continue;
121
+ const info = functionInfo(value, `${prefix}${key}`);
122
+ if (info) functions.push(info);
123
+ }
124
+ return functions;
125
+ }
126
+
127
+ function functionNamespace(info: LuaFunctionInfo): string | undefined {
128
+ const separator = info.name?.lastIndexOf(".") ?? -1;
129
+ return separator > 0 ? info.name!.slice(0, separator) : undefined;
130
+ }
131
+
132
+ function apiDocumentationTarget(
133
+ sf: LuaStackFrame,
134
+ target?: ILuaFunction | LuaTable | string,
135
+ ): { functions: LuaFunctionInfo[]; context?: string } {
136
+ if (typeof target === "string") {
137
+ const resolved = resolveApiValue(sf, target);
138
+ const info = functionInfo(resolved, target);
139
+ if (info) {
140
+ return { functions: [info], context: functionNamespace(info) };
141
+ }
142
+ if (resolved instanceof LuaTable || resolved instanceof LuaEnv) {
143
+ return { functions: listFunctionInfo(sf, target), context: target };
144
+ }
145
+ return { functions: [], context: target };
146
+ }
147
+
148
+ const info = functionInfo(target);
149
+ if (info) {
150
+ return { functions: [info], context: functionNamespace(info) };
151
+ }
152
+ if (target instanceof LuaTable) {
153
+ return { functions: listFunctionInfo(sf, target) };
154
+ }
155
+ return { functions: listFunctionInfo(sf) };
156
+ }
157
+
43
158
  /**
44
159
  * Interpolates a string with lua expressions and returns the result.
45
160
  *
@@ -101,7 +216,113 @@ export async function interpolateLuaString(
101
216
  return result;
102
217
  }
103
218
 
219
+ /**
220
+ * Converts an optional Lua options table into a `PrintOptions` object,
221
+ * keeping only the recognised keys with the expected types.
222
+ */
223
+ function toPrintOptions(
224
+ sf: LuaStackFrame,
225
+ opts?: LuaTable,
226
+ ): PrintOptions | undefined {
227
+ if (!opts) return undefined;
228
+ const js = luaValueToJS(opts, sf) as Record<string, unknown>;
229
+ const result: PrintOptions = {};
230
+ if (typeof js.indentWidth === "number") result.indentWidth = js.indentWidth;
231
+ if (js.quote === "double" || js.quote === "single") result.quote = js.quote;
232
+ if (typeof js.trailingComma === "boolean") {
233
+ result.trailingComma = js.trailingComma;
234
+ }
235
+ return result;
236
+ }
237
+
104
238
  export const spaceluaApi = new LuaTable({
239
+ describe: new LuaBuiltinFunction({
240
+ callback: (sf, target: ILuaFunction | string) => {
241
+ const value =
242
+ typeof target === "string" ? resolveApiValue(sf, target) : target;
243
+ return describeFunction(
244
+ value,
245
+ typeof target === "string" ? target : undefined,
246
+ );
247
+ },
248
+ description:
249
+ "Returns structured documentation for a Lua function value or dotted API name.",
250
+ parameters: [
251
+ {
252
+ name: "functionOrName",
253
+ type: "function|string",
254
+ description: "Function value or dotted API name to inspect.",
255
+ },
256
+ ],
257
+ returns: [
258
+ {
259
+ type: "table|nil",
260
+ description:
261
+ "Structured function metadata, or `nil` when the target is not a function.",
262
+ },
263
+ ],
264
+ examples: [
265
+ {
266
+ code: 'local info = spacelua.describe(editor.getText)\nprint(info.name, info.kind, info.see)\n\nlocal sameInfo = spacelua.describe("editor.getText")',
267
+ },
268
+ ],
269
+ see: "API/spacelua",
270
+ }),
271
+ listFunctions: new LuaBuiltinFunction({
272
+ callback: (sf, target?: LuaTable | string) =>
273
+ jsToLuaValue(listFunctionInfo(sf, target)),
274
+ description:
275
+ "Lists documented functions in the global environment or an API namespace.",
276
+ parameters: [
277
+ {
278
+ name: "namespace",
279
+ type: "table|string",
280
+ description: "Namespace table or dotted name; omit for globals.",
281
+ optional: true,
282
+ },
283
+ ],
284
+ returns: [{ type: "table", description: "Function metadata records." }],
285
+ examples: [
286
+ {
287
+ code: 'for info in each(spacelua.listFunctions("editor")) do\n print(info.name, info.description or info.see)\nend',
288
+ },
289
+ ],
290
+ see: "API/spacelua",
291
+ }),
292
+ renderApiDocumentation: new LuaBuiltinFunction({
293
+ callback: (sf, target?: ILuaFunction | LuaTable | string): string => {
294
+ const selection = apiDocumentationTarget(sf, target);
295
+ return renderApiDocumentationMarkdown(
296
+ selection.functions,
297
+ selection.context,
298
+ );
299
+ },
300
+ description:
301
+ "Renders API documentation for a function, namespace, or the global environment as Markdown.",
302
+ parameters: [
303
+ {
304
+ name: "target",
305
+ type: "function|table|string",
306
+ description:
307
+ "Function value, namespace table, or dotted API name to document; omit for globals.",
308
+ optional: true,
309
+ },
310
+ ],
311
+ returns: [{ type: "string", description: "Rendered Markdown." }],
312
+ examples: [
313
+ {
314
+ code: '${spacelua.renderApiDocumentation("lua")}',
315
+ description: "Render a namespace as a live API-page directive.",
316
+ language: "markdown",
317
+ },
318
+ {
319
+ code: '${spacelua.renderApiDocumentation("editor.getText")}',
320
+ description: "Render one function by its dotted API name.",
321
+ language: "markdown",
322
+ },
323
+ ],
324
+ see: "API/spacelua",
325
+ }),
105
326
  /**
106
327
  * Parses a lua expression and returns the parsed expression.
107
328
  *
@@ -109,8 +330,116 @@ export const spaceluaApi = new LuaTable({
109
330
  * @param luaExpression - The lua expression to parse.
110
331
  * @returns The parsed expression.
111
332
  */
112
- parseExpression: new LuaBuiltinFunction((_sf, luaExpression: string) => {
113
- return parseExpressionString(luaExpression);
333
+ parseExpression: new LuaBuiltinFunction({
334
+ callback: (_sf, luaExpression: string) => {
335
+ return parseExpressionString(luaExpression);
336
+ },
337
+ description: "Parses a Lua expression and returns its AST.",
338
+ parameters: [
339
+ {
340
+ name: "luaExpression",
341
+ type: "string",
342
+ description: "Lua expression to parse.",
343
+ },
344
+ ],
345
+ returns: [{ type: "table", description: "Parsed expression AST." }],
346
+ examples: [
347
+ {
348
+ code: 'local parsed = spacelua.parseExpression("1 + 1")',
349
+ },
350
+ ],
351
+ see: "API/spacelua",
352
+ }),
353
+ /**
354
+ * Parses a lua chunk (block) and returns the parsed AST block.
355
+ *
356
+ * @param sf - The current space_lua state.
357
+ * @param code - The lua code to parse.
358
+ * @returns The parsed block.
359
+ */
360
+ parseBlock: new LuaBuiltinFunction({
361
+ callback: (_sf, code: string): LuaBlock => {
362
+ return parseBlock(code);
363
+ },
364
+ description:
365
+ "Parses a Lua chunk and returns its AST. Blocks retain comments in source order with their exact text, kind, and source range.",
366
+ parameters: [
367
+ { name: "code", type: "string", description: "Lua code to parse." },
368
+ ],
369
+ returns: [{ type: "table", description: "Parsed block AST." }],
370
+ examples: [
371
+ {
372
+ code: 'local parsed = spacelua.parseBlock("local x = 1\\nreturn x + 2")',
373
+ },
374
+ ],
375
+ see: "API/spacelua",
376
+ }),
377
+ /**
378
+ * Pretty-prints a parsed lua block AST back to formatted source.
379
+ *
380
+ * @param sf - The current space_lua state.
381
+ * @param block - The parsed lua block.
382
+ * @param opts - Optional formatting options.
383
+ * @returns The formatted lua source.
384
+ */
385
+ prettyPrintBlock: new LuaBuiltinFunction({
386
+ callback: (sf, block: LuaBlock, opts?: LuaTable): string => {
387
+ return prettyPrintBlock(block, toPrintOptions(sf, opts));
388
+ },
389
+ description:
390
+ "Pretty-prints a parsed Lua block AST. Comments are preserved while their placement and indentation are normalized.",
391
+ parameters: [
392
+ { name: "block", type: "table", description: "Parsed block AST." },
393
+ {
394
+ name: "options",
395
+ type: "table",
396
+ description:
397
+ "Formatting options: `indentWidth`, `quote`, and `trailingComma`.",
398
+ optional: true,
399
+ },
400
+ ],
401
+ returns: [{ type: "string", description: "Formatted Lua source." }],
402
+ examples: [
403
+ {
404
+ code: 'local formatted = spacelua.prettyPrintBlock(spacelua.parseBlock("if a then return 1 end"))\nprint(formatted)',
405
+ },
406
+ ],
407
+ see: "API/spacelua",
408
+ }),
409
+ /**
410
+ * Pretty-prints a parsed lua expression AST back to formatted source.
411
+ *
412
+ * @param sf - The current space_lua state.
413
+ * @param expr - The parsed lua expression.
414
+ * @param opts - Optional formatting options.
415
+ * @returns The formatted lua source.
416
+ */
417
+ prettyPrintExpression: new LuaBuiltinFunction({
418
+ callback: (sf, expr: LuaExpression, opts?: LuaTable): string => {
419
+ return prettyPrintExpression(expr, toPrintOptions(sf, opts));
420
+ },
421
+ description: "Pretty-prints a parsed Lua expression AST.",
422
+ parameters: [
423
+ {
424
+ name: "parsedExpr",
425
+ type: "table",
426
+ description: "Parsed expression AST.",
427
+ },
428
+ {
429
+ name: "options",
430
+ type: "table",
431
+ description:
432
+ "Formatting options: `indentWidth`, `quote`, and `trailingComma`.",
433
+ optional: true,
434
+ },
435
+ ],
436
+ returns: [{ type: "string", description: "Formatted Lua source." }],
437
+ examples: [
438
+ {
439
+ code: 'local parsed = spacelua.parseExpression("{a=1,b=2}")\nprint(spacelua.prettyPrintExpression(parsed))',
440
+ },
441
+ ],
442
+ see: "API/spacelua",
114
443
  }),
115
444
  /**
116
445
  * Evaluates a parsed lua expression and returns the result.
@@ -120,28 +449,83 @@ export const spaceluaApi = new LuaTable({
120
449
  * @param envAugmentation - An optional environment to augment the global environment with.
121
450
  * @returns The result of the evaluated expression.
122
451
  */
123
- evalExpression: new LuaBuiltinFunction(
124
- async (sf, parsedExpr: LuaExpression, envAugmentation?: LuaTable) => {
452
+ evalExpression: new LuaBuiltinFunction({
453
+ callback: async (
454
+ sf,
455
+ parsedExpr: LuaExpression,
456
+ envAugmentation?: LuaTable,
457
+ ) => {
125
458
  const env = createAugmentedEnv(sf, envAugmentation);
126
459
  return luaValueToJS(await evalExpression(parsedExpr, env, sf), sf);
127
460
  },
128
- ),
461
+ description:
462
+ "Evaluates a parsed Lua expression, optionally with additional environment values.",
463
+ parameters: [
464
+ {
465
+ name: "parsedExpr",
466
+ type: "table",
467
+ description: "Parsed expression AST.",
468
+ },
469
+ {
470
+ name: "envAugmentation",
471
+ type: "table",
472
+ description: "Values added to the expression environment.",
473
+ optional: true,
474
+ },
475
+ ],
476
+ returns: [{ description: "Evaluated result." }],
477
+ examples: [
478
+ {
479
+ code: 'local parsed = spacelua.parseExpression("x + y")\nlocal result = spacelua.evalExpression(parsed, {x = 1, y = 2})\nprint(result)',
480
+ },
481
+ ],
482
+ see: "API/spacelua",
483
+ }),
129
484
  /**
130
485
  * Interpolates a string with lua expressions and returns the result.
131
486
  */
132
- interpolate: new LuaBuiltinFunction(
133
- (sf, template: string, envAugmentation?: LuaTable | any) => {
487
+ interpolate: new LuaBuiltinFunction({
488
+ callback: (sf, template: string, envAugmentation?: LuaTable | any) => {
134
489
  if (envAugmentation && !(envAugmentation instanceof LuaTable)) {
135
490
  envAugmentation = jsToLuaValue(envAugmentation);
136
491
  }
137
492
  return interpolateLuaString(sf, template, envAugmentation);
138
493
  },
139
- ),
494
+ description:
495
+ "Interpolates `${...}` Lua expressions in a string, optionally with additional environment values.",
496
+ parameters: [
497
+ {
498
+ name: "template",
499
+ type: "string",
500
+ description: "Template containing `${...}` expressions.",
501
+ },
502
+ {
503
+ name: "envAugmentation",
504
+ type: "table",
505
+ description: "Values added to the interpolation environment.",
506
+ optional: true,
507
+ },
508
+ ],
509
+ returns: [{ type: "string", description: "Interpolated string." }],
510
+ examples: [
511
+ {
512
+ code: 'local greeting = spacelua.interpolate("Hello ${name}!", {name = "Pete"})\nprint(greeting)',
513
+ },
514
+ ],
515
+ see: "API/spacelua",
516
+ }),
140
517
  /**
141
518
  * Returns your SilverBullet instance's base URL
142
519
  */
143
- baseUrl: new LuaBuiltinFunction(() => {
144
- //NOTE: Removing trailing slash to stay compatible with original code: `location.protocol + "//" + location.host;`
145
- return document.baseURI.replace(/\/*$/, "");
520
+ baseUrl: new LuaBuiltinFunction({
521
+ callback: () => {
522
+ //NOTE: Removing trailing slash to stay compatible with original code: `location.protocol + "//" + location.host;`
523
+ return document.baseURI.replace(/\/*$/, "");
524
+ },
525
+ description:
526
+ "Returns the SilverBullet instance's base URL, or `nil` when run on the server.",
527
+ returns: [{ type: "string|nil" }],
528
+ examples: [{ code: "local url = spacelua.baseUrl()\nprint(url)" }],
529
+ see: "API/spacelua",
146
530
  }),
147
531
  });