@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.
- package/README.md +42 -25
- package/client/plugos/hooks/syscall.ts +24 -10
- package/client/plugos/syscalls/asset.ts +61 -23
- package/client/plugos/syscalls/clientStore.ts +32 -6
- package/client/plugos/syscalls/client_code_widget.ts +9 -4
- package/client/plugos/syscalls/code_widget.ts +26 -11
- package/client/plugos/syscalls/config.ts +146 -30
- package/client/plugos/syscalls/datastore.ts +146 -40
- package/client/plugos/syscalls/editor.ts +1432 -700
- package/client/plugos/syscalls/event.ts +46 -13
- package/client/plugos/syscalls/fetch.ts +123 -82
- package/client/plugos/syscalls/index.ts +243 -114
- package/client/plugos/syscalls/jsonschema.ts +107 -8
- package/client/plugos/syscalls/language.ts +38 -12
- package/client/plugos/syscalls/markdown.ts +166 -50
- package/client/plugos/syscalls/mq.ts +93 -20
- package/client/plugos/syscalls/schema_introspection.ts +33 -0
- package/client/plugos/syscalls/service_registry.ts +74 -20
- package/client/plugos/syscalls/shell.ts +51 -20
- package/client/plugos/syscalls/space.ts +169 -113
- package/client/plugos/syscalls/sync.ts +50 -19
- package/client/plugos/syscalls/system.ts +236 -139
- package/client/plugos/system.ts +21 -5
- package/client/space_lua/api_documentation.ts +107 -0
- package/client/space_lua/ast.ts +13 -0
- package/client/space_lua/eval.ts +12 -4
- package/client/space_lua/parse.ts +254 -119
- package/client/space_lua/pretty_print.ts +465 -0
- package/client/space_lua/query_collection.ts +3 -3
- package/client/space_lua/render_widget.ts +156 -0
- package/client/space_lua/runtime.ts +83 -22
- package/client/space_lua/stdlib/crypto.ts +8 -3
- package/client/space_lua/stdlib/encoding.ts +27 -9
- package/client/space_lua/stdlib/js.ts +137 -22
- package/client/space_lua/stdlib/load.ts +26 -17
- package/client/space_lua/stdlib/math.ts +323 -118
- package/client/space_lua/stdlib/net.ts +57 -9
- package/client/space_lua/stdlib/os.ts +111 -44
- package/client/space_lua/stdlib/space_lua.ts +397 -13
- package/client/space_lua/stdlib/string.ts +282 -104
- package/client/space_lua/stdlib/string_pack.ts +58 -19
- package/client/space_lua/stdlib/table.ts +195 -40
- package/client/space_lua/stdlib.ts +336 -94
- package/client/space_lua/syscalls.ts +270 -0
- package/dist/plug-compile.js +1 -1
- package/package.json +12 -4
- package/plug-api/lib/ref.ts +96 -0
- package/plug-api/lib/shortcut.ts +2 -1
- package/plug-api/syscalls/config.ts +5 -3
- package/plug-api/syscalls/editor.ts +23 -2
- package/plug-api/syscalls/index.ts +24 -1
- package/plug-api/syscalls/jsonschema.ts +9 -0
- package/plug-api/syscalls/lua.ts +28 -1
- package/plug-api/syscalls/shell.ts +0 -1
- package/plug-api/syscalls/system.ts +7 -0
- package/plug-api/system_mock.ts +2 -2
- package/plug-api/types/config.ts +1 -1
- package/plug-api/types/index.ts +52 -1
- package/plug-api/types/manifest.ts +22 -4
- package/plug-api/ui/cx.ts +4 -0
- package/plug-api/ui/index.ts +22 -0
- package/plug-api/ui/panel_styles.ts +33 -0
- package/plug-api/ui/slugify.ts +44 -0
- package/plugs/builtin_plugs.ts +1 -0
- package/client/plugos/syscalls/lua.ts +0 -58
|
@@ -5,6 +5,10 @@ import { isPromise, rpAll } from "./rp.ts";
|
|
|
5
5
|
import { isNegativeZero, isTaggedFloat } from "./numeric.ts";
|
|
6
6
|
import { isSqlNull } from "./sliq_null.ts";
|
|
7
7
|
import { luaFormat } from "./stdlib/format.ts";
|
|
8
|
+
import type {
|
|
9
|
+
LuaFunctionDocumentation,
|
|
10
|
+
LuaFunctionInfo,
|
|
11
|
+
} from "../../plug-api/types/index.ts";
|
|
8
12
|
|
|
9
13
|
export type LuaType =
|
|
10
14
|
| "nil"
|
|
@@ -20,10 +24,19 @@ export type LuaType =
|
|
|
20
24
|
export type LuaValue = any;
|
|
21
25
|
export type JSValue = any;
|
|
22
26
|
|
|
27
|
+
type LuaFunctionDefinitionMetadata = LuaFunctionDocumentation &
|
|
28
|
+
Partial<Pick<LuaFunctionInfo, "kind" | "name" | "source">>;
|
|
29
|
+
|
|
30
|
+
export type LuaFunctionDefinition<Callback> = {
|
|
31
|
+
callback: Callback;
|
|
32
|
+
} & LuaFunctionDefinitionMetadata;
|
|
33
|
+
|
|
23
34
|
export interface ILuaFunction {
|
|
24
35
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue;
|
|
25
36
|
|
|
26
37
|
asString(): string;
|
|
38
|
+
|
|
39
|
+
info?: LuaFunctionInfo;
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
export interface ILuaSettable {
|
|
@@ -453,12 +466,25 @@ export function singleResult(value: any): any {
|
|
|
453
466
|
export class LuaFunction implements ILuaFunction {
|
|
454
467
|
private capturedEnv: LuaEnv;
|
|
455
468
|
funcHasGotos?: boolean;
|
|
469
|
+
info: LuaFunctionInfo;
|
|
456
470
|
|
|
457
471
|
constructor(
|
|
458
472
|
readonly body: LuaFunctionBody,
|
|
459
473
|
closure: LuaEnv,
|
|
474
|
+
info: Partial<LuaFunctionInfo> = {},
|
|
460
475
|
) {
|
|
461
476
|
this.capturedEnv = closure;
|
|
477
|
+
const documentation = body.documentation ?? {};
|
|
478
|
+
this.info = {
|
|
479
|
+
kind: "lua",
|
|
480
|
+
source: { ...body.ctx },
|
|
481
|
+
...documentation,
|
|
482
|
+
...info,
|
|
483
|
+
parameters:
|
|
484
|
+
info.parameters ??
|
|
485
|
+
documentation.parameters ??
|
|
486
|
+
body.parameters.map((name) => ({ name })),
|
|
487
|
+
};
|
|
462
488
|
}
|
|
463
489
|
|
|
464
490
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
@@ -482,10 +508,7 @@ export class LuaFunction implements ILuaFunction {
|
|
|
482
508
|
for (let i = 0; i < varargStart; i++) {
|
|
483
509
|
env.setLocal(params[i], resolvedArgs[i] ?? null);
|
|
484
510
|
}
|
|
485
|
-
env.setLocal(
|
|
486
|
-
"...",
|
|
487
|
-
new LuaMultiRes(resolvedArgs.slice(varargStart)),
|
|
488
|
-
);
|
|
511
|
+
env.setLocal("...", new LuaMultiRes(resolvedArgs.slice(varargStart)));
|
|
489
512
|
} else {
|
|
490
513
|
// Non-variadic: bind all named params directly
|
|
491
514
|
for (let i = 0; i < params.length; i++) {
|
|
@@ -565,7 +588,26 @@ function mapFunctionReturnValue(values: any[]): any {
|
|
|
565
588
|
}
|
|
566
589
|
|
|
567
590
|
export class LuaNativeJSFunction implements ILuaFunction {
|
|
568
|
-
|
|
591
|
+
readonly fn: (...args: JSValue[]) => JSValue;
|
|
592
|
+
public info: LuaFunctionInfo;
|
|
593
|
+
|
|
594
|
+
constructor(
|
|
595
|
+
definition:
|
|
596
|
+
| ((...args: JSValue[]) => JSValue)
|
|
597
|
+
| LuaFunctionDefinition<(...args: JSValue[]) => JSValue>,
|
|
598
|
+
) {
|
|
599
|
+
if (typeof definition === "function") {
|
|
600
|
+
this.fn = definition;
|
|
601
|
+
this.info = { kind: "builtin" };
|
|
602
|
+
} else {
|
|
603
|
+
const { callback, ...info } = definition;
|
|
604
|
+
this.fn = callback;
|
|
605
|
+
this.info = {
|
|
606
|
+
kind: "builtin",
|
|
607
|
+
...info,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
}
|
|
569
611
|
|
|
570
612
|
// Performs automatic conversion between Lua and JS values for arguments, but not for return values
|
|
571
613
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
@@ -595,9 +637,28 @@ export class LuaNativeJSFunction implements ILuaFunction {
|
|
|
595
637
|
}
|
|
596
638
|
|
|
597
639
|
export class LuaBuiltinFunction implements ILuaFunction {
|
|
640
|
+
readonly fn: (sf: LuaStackFrame, ...args: LuaValue[]) => LuaValue;
|
|
641
|
+
public info: LuaFunctionInfo;
|
|
642
|
+
|
|
598
643
|
constructor(
|
|
599
|
-
|
|
600
|
-
|
|
644
|
+
definition:
|
|
645
|
+
| ((sf: LuaStackFrame, ...args: LuaValue[]) => LuaValue)
|
|
646
|
+
| LuaFunctionDefinition<
|
|
647
|
+
(sf: LuaStackFrame, ...args: LuaValue[]) => LuaValue
|
|
648
|
+
>,
|
|
649
|
+
) {
|
|
650
|
+
if (typeof definition === "function") {
|
|
651
|
+
this.fn = definition;
|
|
652
|
+
this.info = { kind: "builtin" };
|
|
653
|
+
} else {
|
|
654
|
+
const { callback, ...info } = definition;
|
|
655
|
+
this.fn = callback;
|
|
656
|
+
this.info = {
|
|
657
|
+
kind: "builtin",
|
|
658
|
+
...info,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
}
|
|
601
662
|
|
|
602
663
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
603
664
|
// _CTX is already available via the stack frame
|
|
@@ -1313,11 +1374,9 @@ export function luaSet(
|
|
|
1313
1374
|
const k = toNumKey(normKey);
|
|
1314
1375
|
const jsVal = luaValueToJS(value, sf);
|
|
1315
1376
|
if (isPromise(jsVal)) {
|
|
1316
|
-
return (jsVal as Promise<any>).then(
|
|
1317
|
-
(
|
|
1318
|
-
|
|
1319
|
-
},
|
|
1320
|
-
);
|
|
1377
|
+
return (jsVal as Promise<any>).then((v) => {
|
|
1378
|
+
(obj as Record<string | number, any>)[k] = v;
|
|
1379
|
+
});
|
|
1321
1380
|
}
|
|
1322
1381
|
(obj as Record<string | number, any>)[k] = jsVal;
|
|
1323
1382
|
}
|
|
@@ -1492,16 +1551,18 @@ export function luaCall(
|
|
|
1492
1551
|
|
|
1493
1552
|
export function luaEquals(a: any, b: any): boolean {
|
|
1494
1553
|
// Normalize nil variants (null, undefined, SQL NULL) to null
|
|
1495
|
-
const an =
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1554
|
+
const an =
|
|
1555
|
+
a === null || a === undefined || isSqlNull(a)
|
|
1556
|
+
? null
|
|
1557
|
+
: isTaggedFloat(a)
|
|
1558
|
+
? a.value
|
|
1559
|
+
: a;
|
|
1560
|
+
const bn =
|
|
1561
|
+
b === null || b === undefined || isSqlNull(b)
|
|
1562
|
+
? null
|
|
1563
|
+
: isTaggedFloat(b)
|
|
1564
|
+
? b.value
|
|
1565
|
+
: b;
|
|
1505
1566
|
return an === bn;
|
|
1506
1567
|
}
|
|
1507
1568
|
|
|
@@ -2,9 +2,14 @@ import { LuaBuiltinFunction, LuaTable } from "../runtime.ts";
|
|
|
2
2
|
import { hashSHA256 } from "../../../plug-api/lib/crypto.ts";
|
|
3
3
|
|
|
4
4
|
export const cryptoApi = new LuaTable({
|
|
5
|
-
sha256: new LuaBuiltinFunction(
|
|
6
|
-
(_sf, s: string | Uint8Array): Promise<string> => {
|
|
5
|
+
sha256: new LuaBuiltinFunction({
|
|
6
|
+
callback: (_sf, s: string | Uint8Array): Promise<string> => {
|
|
7
7
|
return hashSHA256(s);
|
|
8
8
|
},
|
|
9
|
-
|
|
9
|
+
description: "Computes the SHA-256 digest of a string or byte buffer.",
|
|
10
|
+
parameters: [
|
|
11
|
+
{ name: "data", type: "string|bytes", description: "Data to hash." },
|
|
12
|
+
],
|
|
13
|
+
returns: [{ type: "string", description: "Hexadecimal SHA-256 digest." }],
|
|
14
|
+
}),
|
|
10
15
|
});
|
|
@@ -2,18 +2,36 @@ import { LuaBuiltinFunction, LuaTable } from "../runtime.ts";
|
|
|
2
2
|
import { base64Decode, base64Encode } from "../../../plug-api/lib/crypto.ts";
|
|
3
3
|
|
|
4
4
|
export const encodingApi = new LuaTable({
|
|
5
|
-
base64Encode: new LuaBuiltinFunction(
|
|
6
|
-
(_sf, s: string | Uint8Array): string => {
|
|
5
|
+
base64Encode: new LuaBuiltinFunction({
|
|
6
|
+
callback: (_sf, s: string | Uint8Array): string => {
|
|
7
7
|
return base64Encode(s);
|
|
8
8
|
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
description: "Encodes a string or byte buffer as Base64.",
|
|
10
|
+
parameters: [{ name: "data", type: "string|bytes" }],
|
|
11
|
+
returns: [{ type: "string", description: "Base64-encoded data." }],
|
|
12
12
|
}),
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
base64Decode: new LuaBuiltinFunction({
|
|
14
|
+
callback: (_sf, s: string): Uint8Array => {
|
|
15
|
+
return base64Decode(s);
|
|
16
|
+
},
|
|
17
|
+
description: "Decodes a Base64 string into a byte buffer.",
|
|
18
|
+
parameters: [{ name: "encoded", type: "string" }],
|
|
19
|
+
returns: [{ type: "bytes", description: "Decoded bytes." }],
|
|
20
|
+
}),
|
|
21
|
+
utf8Encode: new LuaBuiltinFunction({
|
|
22
|
+
callback: (_sf, s: string): Uint8Array => {
|
|
23
|
+
return new TextEncoder().encode(s);
|
|
24
|
+
},
|
|
25
|
+
description: "Encodes a UTF-8 string into a byte buffer.",
|
|
26
|
+
parameters: [{ name: "value", type: "string" }],
|
|
27
|
+
returns: [{ type: "bytes", description: "UTF-8 encoded bytes." }],
|
|
15
28
|
}),
|
|
16
|
-
utf8Decode: new LuaBuiltinFunction(
|
|
17
|
-
|
|
29
|
+
utf8Decode: new LuaBuiltinFunction({
|
|
30
|
+
callback: (_sf, data: Uint8Array): string => {
|
|
31
|
+
return new TextDecoder().decode(data);
|
|
32
|
+
},
|
|
33
|
+
description: "Decodes a UTF-8 byte buffer into a string.",
|
|
34
|
+
parameters: [{ name: "data", type: "bytes" }],
|
|
35
|
+
returns: [{ type: "string", description: "Decoded text." }],
|
|
18
36
|
}),
|
|
19
37
|
});
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
LuaTable,
|
|
5
5
|
luaValueToJS,
|
|
6
6
|
} from "../runtime.ts";
|
|
7
|
+
import { fsEndpoint } from "../../spaces/constants.ts";
|
|
7
8
|
|
|
8
9
|
export const jsApi = new LuaTable({
|
|
9
10
|
/**
|
|
@@ -12,57 +13,171 @@ export const jsApi = new LuaTable({
|
|
|
12
13
|
* @param args - The arguments to pass to the constructor.
|
|
13
14
|
* @returns The new instance.
|
|
14
15
|
*/
|
|
15
|
-
new: new LuaBuiltinFunction(
|
|
16
|
-
|
|
16
|
+
new: new LuaBuiltinFunction({
|
|
17
|
+
callback: (sf, constructorFn: any, ...args) => {
|
|
18
|
+
return new constructorFn(...args.map((v) => luaValueToJS(v, sf)));
|
|
19
|
+
},
|
|
20
|
+
description: "Creates an instance of a JavaScript class.",
|
|
21
|
+
signatures: ["js.new(constructor, ...): userdata"],
|
|
22
|
+
parameters: [
|
|
23
|
+
{
|
|
24
|
+
name: "constructor",
|
|
25
|
+
type: "userdata",
|
|
26
|
+
description: "JavaScript constructor function.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "...",
|
|
30
|
+
description: "Constructor arguments converted to JavaScript values.",
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
returns: [{ type: "userdata", description: "New JavaScript instance." }],
|
|
34
|
+
examples: [{ code: 'local value = js.new(js.window.Date, "2024-03-14")' }],
|
|
17
35
|
}),
|
|
18
36
|
/**
|
|
19
37
|
* Imports a JavaScript module.
|
|
20
38
|
* @param url - The URL of the module to import.
|
|
21
39
|
* @returns The imported module.
|
|
22
40
|
*/
|
|
23
|
-
import: new LuaBuiltinFunction(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
m
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
import: new LuaBuiltinFunction({
|
|
42
|
+
callback: async (_sf, url) => {
|
|
43
|
+
let m = await import(url);
|
|
44
|
+
// Unwrap default if it exists
|
|
45
|
+
if (Object.keys(m).length === 1 && m.default) {
|
|
46
|
+
m = m.default;
|
|
47
|
+
}
|
|
48
|
+
return m;
|
|
49
|
+
},
|
|
50
|
+
description: "Dynamically imports a JavaScript module from a URL.",
|
|
51
|
+
parameters: [{ name: "url", type: "string", description: "Module URL." }],
|
|
52
|
+
returns: [
|
|
53
|
+
{
|
|
54
|
+
type: "userdata",
|
|
55
|
+
description: "Imported module, with a sole default export unwrapped.",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
examples: [
|
|
59
|
+
{ code: 'local lib = js.import("https://esm.sh/lodash@4.17.21")' },
|
|
60
|
+
],
|
|
30
61
|
}),
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Like `js.import`, but takes a path to a file in the current space (e.g.
|
|
64
|
+
* "Library/foo/bar.js") and resolves it to its full same-origin `/.fs` URL
|
|
65
|
+
* before importing.
|
|
66
|
+
* @param path - Space-relative path to the JS module (leading "/" optional).
|
|
67
|
+
* @returns The imported module (with a sole `default` export unwrapped).
|
|
68
|
+
*/
|
|
69
|
+
importFromSpace: new LuaBuiltinFunction({
|
|
70
|
+
callback: async (_sf, path: string) => {
|
|
71
|
+
const base = document.baseURI.replace(/\/*$/, "/");
|
|
72
|
+
const rel = String(path).replace(/^\/+/, "");
|
|
73
|
+
let m = await import(`${base}${fsEndpoint.slice(1)}/${rel}`);
|
|
74
|
+
// Unwrap default if it exists (same contract as `js.import`).
|
|
75
|
+
if (Object.keys(m).length === 1 && m.default) {
|
|
76
|
+
m = m.default;
|
|
37
77
|
}
|
|
38
|
-
return
|
|
39
|
-
}
|
|
78
|
+
return m;
|
|
79
|
+
},
|
|
80
|
+
description:
|
|
81
|
+
"Imports a JavaScript module from a file in the current space.",
|
|
82
|
+
parameters: [
|
|
83
|
+
{
|
|
84
|
+
name: "path",
|
|
85
|
+
type: "string",
|
|
86
|
+
description:
|
|
87
|
+
"Space-relative module path, with an optional leading slash.",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
returns: [
|
|
91
|
+
{
|
|
92
|
+
type: "userdata",
|
|
93
|
+
description: "Imported module, with a sole default export unwrapped.",
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
examples: [
|
|
97
|
+
{ code: 'local acme = js.importFromSpace("Library/acme/acme.js")' },
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
eachIterable: new LuaBuiltinFunction({
|
|
101
|
+
callback: (_sf, val) => {
|
|
102
|
+
const iterator = val[Symbol.asyncIterator]();
|
|
103
|
+
return async () => {
|
|
104
|
+
const result = await iterator.next();
|
|
105
|
+
if (result.done) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
return result.value;
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
description: "Creates a Lua iterator over a JavaScript async iterable.",
|
|
112
|
+
parameters: [
|
|
113
|
+
{
|
|
114
|
+
name: "iterable",
|
|
115
|
+
type: "userdata",
|
|
116
|
+
description: "JavaScript async iterable.",
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
returns: [
|
|
120
|
+
{
|
|
121
|
+
type: "function",
|
|
122
|
+
description: "Iterator yielding successive JavaScript values.",
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
examples: [
|
|
126
|
+
{
|
|
127
|
+
code: "for value in js.eachIterable(someJsAsyncIterable) do\n print(value)\nend",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
40
130
|
}),
|
|
41
131
|
/**
|
|
42
132
|
* Converts a JavaScript value to a Lua value.
|
|
43
133
|
* @param val - The JavaScript value to convert.
|
|
44
134
|
* @returns The Lua value.
|
|
45
135
|
*/
|
|
46
|
-
tolua: new LuaBuiltinFunction(
|
|
136
|
+
tolua: new LuaBuiltinFunction({
|
|
137
|
+
callback: (_sf, val) => jsToLuaValue(val),
|
|
138
|
+
description: "Converts a JavaScript value to its Lua representation.",
|
|
139
|
+
parameters: [
|
|
140
|
+
{ name: "value", description: "JavaScript value to convert." },
|
|
141
|
+
],
|
|
142
|
+
returns: [{ description: "Converted Lua value." }],
|
|
143
|
+
examples: [{ code: "local luaTable = js.tolua(jsArray)" }],
|
|
144
|
+
}),
|
|
47
145
|
/**
|
|
48
146
|
* Converts a Lua value to a JavaScript value.
|
|
49
147
|
* @param val - The Lua value to convert.
|
|
50
148
|
* @returns The JavaScript value.
|
|
51
149
|
*/
|
|
52
|
-
tojs: new LuaBuiltinFunction(
|
|
150
|
+
tojs: new LuaBuiltinFunction({
|
|
151
|
+
callback: (sf, val) => luaValueToJS(val, sf),
|
|
152
|
+
description: "Converts a Lua value to its JavaScript representation.",
|
|
153
|
+
parameters: [{ name: "value", description: "Lua value to convert." }],
|
|
154
|
+
returns: [{ description: "Converted JavaScript value." }],
|
|
155
|
+
examples: [{ code: "local jsArray = js.tojs({1, 2, 3})" }],
|
|
156
|
+
}),
|
|
53
157
|
/**
|
|
54
158
|
* Logs a message to the console.
|
|
55
159
|
* @param args - The arguments to log.
|
|
56
160
|
*/
|
|
57
|
-
log: new LuaBuiltinFunction(
|
|
58
|
-
|
|
161
|
+
log: new LuaBuiltinFunction({
|
|
162
|
+
callback: (_sf, ...args) => {
|
|
163
|
+
console.log(...args);
|
|
164
|
+
},
|
|
165
|
+
description: "Logs values to the JavaScript console.",
|
|
166
|
+
parameters: [{ name: "...", description: "Values to log." }],
|
|
167
|
+
examples: [{ code: 'js.log("User data:", {name = "Ada"})' }],
|
|
59
168
|
}),
|
|
60
169
|
/**
|
|
61
170
|
* Converts a Lua value to a JSON string.
|
|
62
171
|
* @param val - The Lua value to convert.
|
|
63
172
|
* @returns The JSON string.
|
|
64
173
|
*/
|
|
65
|
-
stringify: new LuaBuiltinFunction(
|
|
174
|
+
stringify: new LuaBuiltinFunction({
|
|
175
|
+
callback: (_sf, val) => JSON.stringify(val),
|
|
176
|
+
description: "Serializes a value as JSON using JavaScript semantics.",
|
|
177
|
+
parameters: [{ name: "value", description: "Value to serialize." }],
|
|
178
|
+
returns: [{ type: "string", description: "JSON representation." }],
|
|
179
|
+
examples: [{ code: "print(js.stringify({1, 2, 3})) -- [1,2,3]" }],
|
|
180
|
+
}),
|
|
66
181
|
|
|
67
182
|
// Expose the global window object
|
|
68
183
|
window: globalThis,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type LuaStackFrame,
|
|
6
6
|
type LuaValue,
|
|
7
7
|
} from "../runtime.ts";
|
|
8
|
-
import {
|
|
8
|
+
import { parseBlock } from "../parse.ts";
|
|
9
9
|
import { evalStatement } from "../eval.ts";
|
|
10
10
|
|
|
11
11
|
// Returns a function (callable chunk) or (nil, "error message") pair.
|
|
@@ -13,7 +13,7 @@ export function luaLoad(code: LuaValue, sf: LuaStackFrame): LuaValue {
|
|
|
13
13
|
const s = typeof code === "string" ? code : String(code);
|
|
14
14
|
|
|
15
15
|
try {
|
|
16
|
-
const block =
|
|
16
|
+
const block = parseBlock(s, sf.astCtx || {});
|
|
17
17
|
const globalEnvMaybe = sf.threadLocal.get("_GLOBAL");
|
|
18
18
|
|
|
19
19
|
// Be vocal when no _GLOBAL is set
|
|
@@ -24,22 +24,31 @@ export function luaLoad(code: LuaValue, sf: LuaStackFrame): LuaValue {
|
|
|
24
24
|
|
|
25
25
|
const globalEnv: LuaEnv = globalEnvMaybe as LuaEnv;
|
|
26
26
|
|
|
27
|
-
const runner = new LuaBuiltinFunction(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const runner = new LuaBuiltinFunction({
|
|
28
|
+
callback: async (innerSf: LuaStackFrame) => {
|
|
29
|
+
const res = await evalStatement(block, globalEnv, innerSf, true);
|
|
30
|
+
if (res === undefined) {
|
|
31
|
+
return null;
|
|
32
|
+
} else {
|
|
33
|
+
if (
|
|
34
|
+
res &&
|
|
35
|
+
typeof res === "object" &&
|
|
36
|
+
(res as any).ctrl === "return"
|
|
37
|
+
) {
|
|
38
|
+
return new LuaMultiRes((res as any).values);
|
|
39
|
+
}
|
|
40
|
+
if (res && typeof res === "object" && (res as any).ctrl === "break") {
|
|
41
|
+
throw new Error("break outside loop");
|
|
42
|
+
}
|
|
43
|
+
if (res && typeof res === "object" && (res as any).ctrl === "goto") {
|
|
44
|
+
throw new Error("unexpected goto signal");
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
34
47
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
throw new Error("unexpected goto signal");
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
48
|
+
},
|
|
49
|
+
description: "Executes the Lua chunk compiled by `load`.",
|
|
50
|
+
signatures: ["function(...)"],
|
|
51
|
+
returns: [{ description: "Values returned by the compiled chunk." }],
|
|
43
52
|
});
|
|
44
53
|
|
|
45
54
|
return runner;
|