@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.
- package/README.md +4 -5
- package/client/asset_bundle/bundle.ts +3 -9
- package/client/data/datastore.ts +4 -5
- package/client/markdown_parser/constants.ts +3 -2
- package/client/plugos/hooks/code_widget.ts +3 -5
- package/client/plugos/hooks/command.ts +8 -8
- package/client/plugos/hooks/document_editor.ts +10 -12
- package/client/plugos/hooks/event.ts +33 -36
- package/client/plugos/hooks/mq.ts +17 -17
- package/client/plugos/hooks/plug_namespace.ts +3 -5
- package/client/plugos/hooks/slash_command.ts +12 -27
- package/client/plugos/hooks/syscall.ts +3 -3
- package/client/plugos/manifest_cache.ts +22 -15
- package/client/plugos/plug.ts +2 -5
- package/client/plugos/plug_compile.ts +67 -65
- package/client/plugos/protocol.ts +28 -28
- package/client/plugos/proxy_fetch.ts +7 -6
- package/client/plugos/sandboxes/worker_sandbox.ts +16 -15
- package/client/plugos/syscalls/asset.ts +1 -3
- package/client/plugos/syscalls/code_widget.ts +1 -3
- package/client/plugos/syscalls/config.ts +1 -5
- package/client/plugos/syscalls/datastore.ts +1 -1
- package/client/plugos/syscalls/editor.ts +63 -60
- package/client/plugos/syscalls/event.ts +9 -12
- package/client/plugos/syscalls/fetch.ts +30 -22
- package/client/plugos/syscalls/index.ts +10 -1
- package/client/plugos/syscalls/jsonschema.ts +72 -32
- package/client/plugos/syscalls/language.ts +9 -5
- package/client/plugos/syscalls/markdown.ts +29 -7
- package/client/plugos/syscalls/mq.ts +3 -11
- package/client/plugos/syscalls/service_registry.ts +1 -4
- package/client/plugos/syscalls/shell.ts +2 -5
- package/client/plugos/syscalls/sync.ts +69 -60
- package/client/plugos/syscalls/system.ts +2 -3
- package/client/plugos/system.ts +4 -10
- package/client/plugos/worker_runtime.ts +4 -3
- package/client/space_lua/aggregates.ts +632 -59
- package/client/space_lua/ast.ts +21 -9
- package/client/space_lua/ast_narrow.ts +4 -2
- package/client/space_lua/eval.ts +842 -536
- package/client/space_lua/labels.ts +6 -11
- package/client/space_lua/liq_null.ts +6 -0
- package/client/space_lua/numeric.ts +5 -8
- package/client/space_lua/parse.ts +290 -169
- package/client/space_lua/query_collection.ts +213 -149
- package/client/space_lua/render_lua_markdown.ts +369 -0
- package/client/space_lua/rp.ts +5 -4
- package/client/space_lua/runtime.ts +245 -142
- package/client/space_lua/stdlib/format.ts +34 -20
- package/client/space_lua/stdlib/js.ts +3 -7
- package/client/space_lua/stdlib/load.ts +1 -3
- package/client/space_lua/stdlib/math.ts +15 -14
- package/client/space_lua/stdlib/net.ts +25 -15
- package/client/space_lua/stdlib/os.ts +76 -85
- package/client/space_lua/stdlib/pattern.ts +28 -35
- package/client/space_lua/stdlib/prng.ts +15 -12
- package/client/space_lua/stdlib/space_lua.ts +16 -17
- package/client/space_lua/stdlib/string.ts +7 -17
- package/client/space_lua/stdlib/string_pack.ts +23 -19
- package/client/space_lua/stdlib/table.ts +5 -9
- package/client/space_lua/stdlib.ts +20 -30
- package/client/space_lua/tonumber.ts +79 -40
- package/client/space_lua/util.ts +14 -10
- package/dist/plug-compile.js +44 -41
- package/package.json +24 -22
- package/plug-api/lib/async.ts +19 -6
- package/plug-api/lib/crypto.ts +5 -6
- package/plug-api/lib/dates.ts +15 -7
- package/plug-api/lib/json.ts +10 -4
- package/plug-api/lib/ref.ts +18 -18
- package/plug-api/lib/resolve.ts +7 -11
- package/plug-api/lib/tags.ts +13 -4
- package/plug-api/lib/transclusion.ts +6 -17
- package/plug-api/lib/tree.ts +115 -43
- package/plug-api/lib/yaml.ts +25 -15
- package/plug-api/syscalls/asset.ts +1 -1
- package/plug-api/syscalls/config.ts +1 -4
- package/plug-api/syscalls/editor.ts +14 -14
- package/plug-api/syscalls/jsonschema.ts +1 -3
- package/plug-api/syscalls/lua.ts +3 -9
- package/plug-api/syscalls/mq.ts +1 -4
- package/plug-api/syscalls/shell.ts +4 -1
- package/plug-api/syscalls/space.ts +3 -10
- package/plug-api/syscalls/system.ts +1 -4
- package/plug-api/syscalls/yaml.ts +2 -6
- package/plug-api/types/client.ts +16 -1
- package/plug-api/types/event.ts +6 -4
- package/plug-api/types/manifest.ts +8 -9
- package/plugs/builtin_plugs.ts +2 -2
- package/dist/worker_runtime_bundle.js +0 -233
|
@@ -3,6 +3,7 @@ import { evalStatement } from "./eval.ts";
|
|
|
3
3
|
import { asyncQuickSort } from "./util.ts";
|
|
4
4
|
import { isPromise, rpAll } from "./rp.ts";
|
|
5
5
|
import { isNegativeZero, isTaggedFloat } from "./numeric.ts";
|
|
6
|
+
import { isSqlNull } from "./liq_null.ts";
|
|
6
7
|
import { luaFormat } from "./stdlib/format.ts";
|
|
7
8
|
|
|
8
9
|
export type LuaType =
|
|
@@ -79,7 +80,7 @@ function isLuaNumber(v: any): boolean {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
export function luaTypeName(val: any): LuaType {
|
|
82
|
-
if (val === null || val === undefined) {
|
|
83
|
+
if (val === null || val === undefined || isSqlNull(val)) {
|
|
83
84
|
return "nil";
|
|
84
85
|
}
|
|
85
86
|
|
|
@@ -113,10 +114,7 @@ export function luaTypeName(val: any): LuaType {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// Check whether a value is callable without invoking it.
|
|
116
|
-
export function luaIsCallable(
|
|
117
|
-
v: LuaValue,
|
|
118
|
-
sf: LuaStackFrame,
|
|
119
|
-
): boolean {
|
|
117
|
+
export function luaIsCallable(v: LuaValue, sf: LuaStackFrame): boolean {
|
|
120
118
|
if (v === null || v === undefined) {
|
|
121
119
|
return false;
|
|
122
120
|
}
|
|
@@ -137,9 +135,7 @@ export function luaIsCallable(
|
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
// In Lua, `__close` must be a function (no `__call` fallback).
|
|
140
|
-
function luaIsCloseMethod(
|
|
141
|
-
v: LuaValue,
|
|
142
|
-
): boolean {
|
|
138
|
+
function luaIsCloseMethod(v: LuaValue): boolean {
|
|
143
139
|
return typeof v === "function" || isILuaFunction(v);
|
|
144
140
|
}
|
|
145
141
|
|
|
@@ -261,14 +257,13 @@ export class LuaEnv implements ILuaSettable, ILuaGettable {
|
|
|
261
257
|
private readonly consts = new Set<string>();
|
|
262
258
|
private readonly numericTypes = new Map<string, NumericType>();
|
|
263
259
|
|
|
264
|
-
constructor(readonly parent?: LuaEnv) {
|
|
265
|
-
}
|
|
260
|
+
constructor(readonly parent?: LuaEnv) {}
|
|
266
261
|
|
|
267
262
|
setLocal(name: string, value: LuaValue, numType?: NumericType) {
|
|
268
263
|
this.variables.set(name, value);
|
|
269
|
-
if (
|
|
264
|
+
if (numType) {
|
|
270
265
|
this.numericTypes.set(name, numType);
|
|
271
|
-
} else {
|
|
266
|
+
} else if (this.numericTypes.size > 0) {
|
|
272
267
|
this.numericTypes.delete(name);
|
|
273
268
|
}
|
|
274
269
|
}
|
|
@@ -276,9 +271,9 @@ export class LuaEnv implements ILuaSettable, ILuaGettable {
|
|
|
276
271
|
setLocalConst(name: string, value: LuaValue, numType?: NumericType) {
|
|
277
272
|
this.variables.set(name, value);
|
|
278
273
|
this.consts.add(name);
|
|
279
|
-
if (
|
|
274
|
+
if (numType) {
|
|
280
275
|
this.numericTypes.set(name, numType);
|
|
281
|
-
} else {
|
|
276
|
+
} else if (this.numericTypes.size > 0) {
|
|
282
277
|
this.numericTypes.delete(name);
|
|
283
278
|
}
|
|
284
279
|
}
|
|
@@ -297,9 +292,9 @@ export class LuaEnv implements ILuaSettable, ILuaGettable {
|
|
|
297
292
|
);
|
|
298
293
|
}
|
|
299
294
|
this.variables.set(key, value);
|
|
300
|
-
if (
|
|
295
|
+
if (numType) {
|
|
301
296
|
this.numericTypes.set(key, numType);
|
|
302
|
-
} else {
|
|
297
|
+
} else if (this.numericTypes.size > 0) {
|
|
303
298
|
this.numericTypes.delete(key);
|
|
304
299
|
}
|
|
305
300
|
} else {
|
|
@@ -327,13 +322,15 @@ export class LuaEnv implements ILuaSettable, ILuaGettable {
|
|
|
327
322
|
return false;
|
|
328
323
|
}
|
|
329
324
|
|
|
330
|
-
get(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (
|
|
335
|
-
return
|
|
325
|
+
get(name: string, _sf?: LuaStackFrame): Promise<LuaValue> | LuaValue | null {
|
|
326
|
+
// Fast path: single Map.get() instead of has() + get() for the common case
|
|
327
|
+
// where the variable exists and has a non-undefined value (null = Lua nil is fine).
|
|
328
|
+
const v = this.variables.get(name);
|
|
329
|
+
if (v !== undefined) {
|
|
330
|
+
return v;
|
|
336
331
|
}
|
|
332
|
+
// Variable set to null (Lua nil) returns null from Map.get() which is !== undefined,
|
|
333
|
+
// so it's handled above. Only fall through when the key is truly absent.
|
|
337
334
|
if (this.parent) {
|
|
338
335
|
return this.parent.get(name, _sf);
|
|
339
336
|
}
|
|
@@ -378,8 +375,7 @@ export class LuaStackFrame {
|
|
|
378
375
|
readonly parent?: LuaStackFrame,
|
|
379
376
|
readonly currentFunction?: LuaFunction,
|
|
380
377
|
readonly threadState: LuaThreadState = { closeStack: undefined },
|
|
381
|
-
) {
|
|
382
|
-
}
|
|
378
|
+
) {}
|
|
383
379
|
|
|
384
380
|
static createWithGlobalEnv(
|
|
385
381
|
globalEnv: LuaEnv,
|
|
@@ -458,46 +454,71 @@ export class LuaFunction implements ILuaFunction {
|
|
|
458
454
|
private capturedEnv: LuaEnv;
|
|
459
455
|
funcHasGotos?: boolean;
|
|
460
456
|
|
|
461
|
-
constructor(
|
|
457
|
+
constructor(
|
|
458
|
+
readonly body: LuaFunctionBody,
|
|
459
|
+
closure: LuaEnv,
|
|
460
|
+
) {
|
|
462
461
|
this.capturedEnv = closure;
|
|
463
462
|
}
|
|
464
463
|
|
|
465
464
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
466
465
|
// Create a new environment that chains to the captured environment
|
|
467
466
|
const env = new LuaEnv(this.capturedEnv);
|
|
468
|
-
if (!sf) {
|
|
469
|
-
console.trace(sf);
|
|
470
|
-
}
|
|
471
467
|
// Set _CTX to the thread local environment from the stack frame
|
|
472
468
|
env.setLocal("_CTX", sf.threadLocal);
|
|
473
469
|
|
|
474
470
|
// Eval using a stack frame that knows the current function
|
|
475
471
|
const sfWithFn = sf.currentFunction === this ? sf : sf.withFunction(this);
|
|
476
472
|
|
|
473
|
+
const params = this.body.parameters;
|
|
474
|
+
const hasVarargs = params.length > 0 && params[params.length - 1] === "...";
|
|
475
|
+
|
|
477
476
|
// Resolve args (sync-first)
|
|
478
477
|
const argsRP = rpAll(args as any[]);
|
|
479
478
|
const resolveArgs = (resolvedArgs: any[]) => {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
479
|
+
if (hasVarargs) {
|
|
480
|
+
// Variadic function: bind named params, collect rest into varargs
|
|
481
|
+
const varargStart = params.length - 1;
|
|
482
|
+
for (let i = 0; i < varargStart; i++) {
|
|
483
|
+
env.setLocal(params[i], resolvedArgs[i] ?? null);
|
|
484
|
+
}
|
|
485
|
+
env.setLocal(
|
|
486
|
+
"...",
|
|
487
|
+
new LuaMultiRes(resolvedArgs.slice(varargStart)),
|
|
488
|
+
);
|
|
489
|
+
} else {
|
|
490
|
+
// Non-variadic: bind all named params directly
|
|
491
|
+
for (let i = 0; i < params.length; i++) {
|
|
492
|
+
env.setLocal(params[i], resolvedArgs[i] ?? null);
|
|
489
493
|
}
|
|
490
|
-
env.setLocal(paramName, resolvedArgs[i] ?? null);
|
|
491
494
|
}
|
|
492
|
-
env.setLocal("...", new LuaMultiRes(varargs));
|
|
493
495
|
|
|
494
496
|
// Evaluate the function body with returnOnReturn set to true
|
|
495
497
|
const r = evalStatement(this.body.block, env, sfWithFn, true);
|
|
496
498
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
499
|
+
if (!isPromise(r)) {
|
|
500
|
+
// Fast path: synchronous result
|
|
501
|
+
if (r === undefined) return;
|
|
502
|
+
if (r && typeof r === "object" && r.ctrl === "return") {
|
|
503
|
+
return mapFunctionReturnValue(r.values);
|
|
504
|
+
}
|
|
505
|
+
if (r && typeof r === "object" && r.ctrl === "break") {
|
|
506
|
+
throw new LuaRuntimeError(
|
|
507
|
+
"break outside loop",
|
|
508
|
+
sfWithFn.withCtx(this.body.block.ctx),
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
if (r && typeof r === "object" && r.ctrl === "goto") {
|
|
512
|
+
throw new LuaRuntimeError(
|
|
513
|
+
"unexpected goto signal",
|
|
514
|
+
sfWithFn.withCtx(this.body.block.ctx),
|
|
515
|
+
);
|
|
500
516
|
}
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return r.then((val: any) => {
|
|
521
|
+
if (val === undefined) return;
|
|
501
522
|
if (val && typeof val === "object" && val.ctrl === "return") {
|
|
502
523
|
return mapFunctionReturnValue(val.values);
|
|
503
524
|
}
|
|
@@ -513,12 +534,7 @@ export class LuaFunction implements ILuaFunction {
|
|
|
513
534
|
sfWithFn.withCtx(this.body.block.ctx),
|
|
514
535
|
);
|
|
515
536
|
}
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
if (isPromise(r)) {
|
|
519
|
-
return r.then(map);
|
|
520
|
-
}
|
|
521
|
-
return map(r);
|
|
537
|
+
});
|
|
522
538
|
};
|
|
523
539
|
|
|
524
540
|
if (isPromise(argsRP)) {
|
|
@@ -549,17 +565,24 @@ function mapFunctionReturnValue(values: any[]): any {
|
|
|
549
565
|
}
|
|
550
566
|
|
|
551
567
|
export class LuaNativeJSFunction implements ILuaFunction {
|
|
552
|
-
constructor(readonly fn: (...args: JSValue[]) => JSValue) {
|
|
553
|
-
}
|
|
568
|
+
constructor(readonly fn: (...args: JSValue[]) => JSValue) {}
|
|
554
569
|
|
|
555
570
|
// Performs automatic conversion between Lua and JS values for arguments, but not for return values
|
|
556
571
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
557
|
-
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
572
|
+
// Avoid .map() allocation: convert in-place and check for promises
|
|
573
|
+
const len = args.length;
|
|
574
|
+
let hasAsync = false;
|
|
575
|
+
for (let i = 0; i < len; i++) {
|
|
576
|
+
const converted = luaValueToJS(args[i], sf);
|
|
577
|
+
args[i] = converted;
|
|
578
|
+
if (!hasAsync && isPromise(converted)) {
|
|
579
|
+
hasAsync = true;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (hasAsync) {
|
|
583
|
+
return Promise.all(args).then((jsArgs) => this.fn(...jsArgs));
|
|
561
584
|
}
|
|
562
|
-
return this.fn(...
|
|
585
|
+
return this.fn(...args);
|
|
563
586
|
}
|
|
564
587
|
|
|
565
588
|
asString(): string {
|
|
@@ -574,8 +597,7 @@ export class LuaNativeJSFunction implements ILuaFunction {
|
|
|
574
597
|
export class LuaBuiltinFunction implements ILuaFunction {
|
|
575
598
|
constructor(
|
|
576
599
|
readonly fn: (sf: LuaStackFrame, ...args: LuaValue[]) => LuaValue,
|
|
577
|
-
) {
|
|
578
|
-
}
|
|
600
|
+
) {}
|
|
579
601
|
|
|
580
602
|
call(sf: LuaStackFrame, ...args: LuaValue[]): Promise<LuaValue> | LuaValue {
|
|
581
603
|
// _CTX is already available via the stack frame
|
|
@@ -602,24 +624,16 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
602
624
|
// When tables are used as arrays, we use a native JavaScript array for that
|
|
603
625
|
private arrayPart: any[];
|
|
604
626
|
|
|
605
|
-
// Numeric type metadata at storage boundaries
|
|
606
|
-
private
|
|
627
|
+
// Numeric type metadata at storage boundaries (lazily allocated)
|
|
628
|
+
private stringKeyTypes: Map<string, NumericType> | null = null;
|
|
607
629
|
private otherKeyTypes: Map<any, NumericType> | null = null;
|
|
608
|
-
private
|
|
630
|
+
private arrayTypes: (NumericType | undefined)[] | null = null;
|
|
609
631
|
|
|
610
632
|
constructor(init?: any[] | Record<string, any>) {
|
|
611
633
|
// For efficiency and performance reasons we pre-allocate these (modern JS engines are very good at optimizing this)
|
|
612
634
|
this.arrayPart = Array.isArray(init) ? init : [];
|
|
613
635
|
this.stringKeys = init && !Array.isArray(init) ? init : {};
|
|
614
|
-
|
|
615
|
-
if (init && !Array.isArray(init)) {
|
|
616
|
-
for (const k in init) {
|
|
617
|
-
if (Object.hasOwn(init, k)) {
|
|
618
|
-
this.stringKeys[k] = (init as any)[k];
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
this.otherKeys = null; // Only create this when needed
|
|
636
|
+
this.otherKeys = null;
|
|
623
637
|
this.metatable = null;
|
|
624
638
|
}
|
|
625
639
|
|
|
@@ -724,10 +738,20 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
724
738
|
return this.stringKeys[key] !== undefined;
|
|
725
739
|
}
|
|
726
740
|
|
|
741
|
+
// Fast path for plain integer keys (common in for loops)
|
|
742
|
+
if (typeof key === "number") {
|
|
743
|
+
if (key >= 1 && (key | 0) === key) {
|
|
744
|
+
if (this.arrayPart[key - 1] !== undefined) return true;
|
|
745
|
+
return this.otherKeys ? this.otherKeys.has(key) : false;
|
|
746
|
+
}
|
|
747
|
+
return this.otherKeys ? this.otherKeys.has(key) : false;
|
|
748
|
+
}
|
|
749
|
+
|
|
727
750
|
const normalizedKey = LuaTable.normalizeNumericKey(key);
|
|
728
751
|
|
|
729
752
|
if (
|
|
730
|
-
typeof normalizedKey === "number" &&
|
|
753
|
+
typeof normalizedKey === "number" &&
|
|
754
|
+
Number.isInteger(normalizedKey) &&
|
|
731
755
|
normalizedKey >= 1
|
|
732
756
|
) {
|
|
733
757
|
const idx = normalizedKey - 1;
|
|
@@ -759,8 +783,9 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
759
783
|
|
|
760
784
|
this.arrayPart[idx] = value;
|
|
761
785
|
if (isLuaNumber(value) && numType) {
|
|
786
|
+
if (!this.arrayTypes) this.arrayTypes = [];
|
|
762
787
|
this.arrayTypes[idx] = numType;
|
|
763
|
-
} else {
|
|
788
|
+
} else if (this.arrayTypes) {
|
|
764
789
|
this.arrayTypes[idx] = undefined;
|
|
765
790
|
}
|
|
766
791
|
}
|
|
@@ -785,7 +810,12 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
785
810
|
}
|
|
786
811
|
|
|
787
812
|
this.arrayPart.push(v);
|
|
788
|
-
|
|
813
|
+
if (nt) {
|
|
814
|
+
if (!this.arrayTypes) this.arrayTypes = [];
|
|
815
|
+
this.arrayTypes.push(nt);
|
|
816
|
+
} else if (this.arrayTypes) {
|
|
817
|
+
this.arrayTypes.push(undefined);
|
|
818
|
+
}
|
|
789
819
|
}
|
|
790
820
|
}
|
|
791
821
|
|
|
@@ -805,12 +835,13 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
805
835
|
if (typeof key === "string") {
|
|
806
836
|
if (value === null || value === undefined) {
|
|
807
837
|
delete this.stringKeys[key];
|
|
808
|
-
this.stringKeyTypes.delete(key);
|
|
838
|
+
if (this.stringKeyTypes) this.stringKeyTypes.delete(key);
|
|
809
839
|
} else {
|
|
810
840
|
this.stringKeys[key] = value;
|
|
811
|
-
if (
|
|
841
|
+
if (numType) {
|
|
842
|
+
if (!this.stringKeyTypes) this.stringKeyTypes = new Map();
|
|
812
843
|
this.stringKeyTypes.set(key, numType);
|
|
813
|
-
} else {
|
|
844
|
+
} else if (this.stringKeyTypes) {
|
|
814
845
|
this.stringKeyTypes.delete(key);
|
|
815
846
|
}
|
|
816
847
|
}
|
|
@@ -822,12 +853,13 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
822
853
|
if (typeof normalizedKey === "string") {
|
|
823
854
|
if (value === null || value === undefined) {
|
|
824
855
|
delete this.stringKeys[normalizedKey];
|
|
825
|
-
this.stringKeyTypes.delete(normalizedKey);
|
|
856
|
+
if (this.stringKeyTypes) this.stringKeyTypes.delete(normalizedKey);
|
|
826
857
|
} else {
|
|
827
858
|
this.stringKeys[normalizedKey] = value;
|
|
828
859
|
if (isLuaNumber(value) && numType) {
|
|
860
|
+
if (!this.stringKeyTypes) this.stringKeyTypes = new Map();
|
|
829
861
|
this.stringKeyTypes.set(normalizedKey, numType);
|
|
830
|
-
} else {
|
|
862
|
+
} else if (this.stringKeyTypes) {
|
|
831
863
|
this.stringKeyTypes.delete(normalizedKey);
|
|
832
864
|
}
|
|
833
865
|
}
|
|
@@ -835,7 +867,8 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
835
867
|
}
|
|
836
868
|
|
|
837
869
|
if (
|
|
838
|
-
typeof normalizedKey === "number" &&
|
|
870
|
+
typeof normalizedKey === "number" &&
|
|
871
|
+
Number.isInteger(normalizedKey) &&
|
|
839
872
|
normalizedKey >= 1
|
|
840
873
|
) {
|
|
841
874
|
const idx = normalizedKey - 1;
|
|
@@ -845,8 +878,9 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
845
878
|
if (idx <= this.arrayPart.length) {
|
|
846
879
|
this.arrayPart[idx] = value;
|
|
847
880
|
if (isLuaNumber(value) && numType) {
|
|
881
|
+
if (!this.arrayTypes) this.arrayTypes = [];
|
|
848
882
|
this.arrayTypes[idx] = numType;
|
|
849
|
-
} else {
|
|
883
|
+
} else if (this.arrayTypes) {
|
|
850
884
|
this.arrayTypes[idx] = undefined;
|
|
851
885
|
}
|
|
852
886
|
|
|
@@ -869,7 +903,7 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
869
903
|
}
|
|
870
904
|
if (n !== this.arrayPart.length) {
|
|
871
905
|
this.arrayPart.length = n;
|
|
872
|
-
this.arrayTypes.length = n;
|
|
906
|
+
if (this.arrayTypes) this.arrayTypes.length = n;
|
|
873
907
|
}
|
|
874
908
|
}
|
|
875
909
|
|
|
@@ -924,28 +958,27 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
924
958
|
sf?: LuaStackFrame,
|
|
925
959
|
numType?: NumericType,
|
|
926
960
|
): Promise<void> | void {
|
|
927
|
-
const errSf = sf || LuaStackFrame.lostFrame;
|
|
928
|
-
const ctx = sf?.astCtx ?? EMPTY_CTX;
|
|
929
|
-
|
|
930
961
|
if (key === null || key === undefined) {
|
|
931
962
|
throw new LuaRuntimeError(
|
|
932
963
|
"table index is nil",
|
|
933
|
-
|
|
964
|
+
sf || LuaStackFrame.lostFrame,
|
|
934
965
|
);
|
|
935
966
|
}
|
|
936
967
|
|
|
937
968
|
if (typeof key === "number" && Number.isNaN(key)) {
|
|
938
969
|
throw new LuaRuntimeError(
|
|
939
970
|
"table index is NaN",
|
|
940
|
-
|
|
971
|
+
sf || LuaStackFrame.lostFrame,
|
|
941
972
|
);
|
|
942
973
|
}
|
|
943
974
|
|
|
944
|
-
|
|
975
|
+
// Fast path: no metatable — skip has() check and metamethod machinery
|
|
976
|
+
if (this.metatable === null) {
|
|
945
977
|
return this.rawSet(key, value, numType);
|
|
946
978
|
}
|
|
947
979
|
|
|
948
|
-
|
|
980
|
+
// Key exists — rawSet directly, no metamethod needed
|
|
981
|
+
if (this.has(key)) {
|
|
949
982
|
return this.rawSet(key, value, numType);
|
|
950
983
|
}
|
|
951
984
|
|
|
@@ -955,6 +988,9 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
955
988
|
return this.rawSet(key, value, numType);
|
|
956
989
|
}
|
|
957
990
|
|
|
991
|
+
// Slow path: __newindex metamethod chain (rare)
|
|
992
|
+
const errSf = sf || LuaStackFrame.lostFrame;
|
|
993
|
+
const ctx = sf?.astCtx ?? EMPTY_CTX;
|
|
958
994
|
const k: LuaValue = key;
|
|
959
995
|
const v: LuaValue = value;
|
|
960
996
|
const nt: NumericType | undefined = numType;
|
|
@@ -1014,10 +1050,19 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1014
1050
|
|
|
1015
1051
|
getNumericType(key: LuaValue): NumericType | undefined {
|
|
1016
1052
|
if (typeof key === "string") {
|
|
1017
|
-
return this.stringKeyTypes.get(key);
|
|
1053
|
+
return this.stringKeyTypes ? this.stringKeyTypes.get(key) : undefined;
|
|
1054
|
+
}
|
|
1055
|
+
// Fast path for plain integer keys
|
|
1056
|
+
if (typeof key === "number") {
|
|
1057
|
+
if (key >= 1 && (key | 0) === key) {
|
|
1058
|
+
return this.arrayTypes ? this.arrayTypes[key - 1] : undefined;
|
|
1059
|
+
}
|
|
1060
|
+
return this.otherKeyTypes ? this.otherKeyTypes.get(key) : undefined;
|
|
1018
1061
|
}
|
|
1019
1062
|
if (LuaTable.isIntegerKey(key)) {
|
|
1020
|
-
return this.arrayTypes
|
|
1063
|
+
return this.arrayTypes
|
|
1064
|
+
? this.arrayTypes[LuaTable.toIndex(key)]
|
|
1065
|
+
: undefined;
|
|
1021
1066
|
}
|
|
1022
1067
|
if (this.otherKeyTypes) {
|
|
1023
1068
|
return this.otherKeyTypes.get(key);
|
|
@@ -1030,6 +1075,19 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1030
1075
|
return this.stringKeys[key];
|
|
1031
1076
|
}
|
|
1032
1077
|
|
|
1078
|
+
// Fast path for plain integer keys (common in for loops)
|
|
1079
|
+
if (typeof key === "number") {
|
|
1080
|
+
if (key >= 1 && (key | 0) === key) {
|
|
1081
|
+
const v = this.arrayPart[key - 1];
|
|
1082
|
+
if (v !== undefined) return v;
|
|
1083
|
+
if (this.otherKeys) return this.otherKeys.get(key);
|
|
1084
|
+
return undefined;
|
|
1085
|
+
}
|
|
1086
|
+
// Non-integer or zero/negative number keys
|
|
1087
|
+
if (this.otherKeys) return this.otherKeys.get(key);
|
|
1088
|
+
return undefined;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1033
1091
|
const normalizedKey = LuaTable.normalizeNumericKey(key);
|
|
1034
1092
|
|
|
1035
1093
|
if (typeof normalizedKey === "string") {
|
|
@@ -1037,7 +1095,8 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1037
1095
|
}
|
|
1038
1096
|
|
|
1039
1097
|
if (
|
|
1040
|
-
typeof normalizedKey === "number" &&
|
|
1098
|
+
typeof normalizedKey === "number" &&
|
|
1099
|
+
Number.isInteger(normalizedKey) &&
|
|
1041
1100
|
normalizedKey >= 1
|
|
1042
1101
|
) {
|
|
1043
1102
|
const idx = normalizedKey - 1;
|
|
@@ -1058,6 +1117,11 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1058
1117
|
}
|
|
1059
1118
|
|
|
1060
1119
|
get(key: LuaValue, sf?: LuaStackFrame): LuaValue | Promise<LuaValue> | null {
|
|
1120
|
+
// Fast path: no metatable means rawGet is the final answer (most tables in SilverBullet)
|
|
1121
|
+
if (this.metatable === null) {
|
|
1122
|
+
const raw = this.rawGet(key);
|
|
1123
|
+
return raw !== undefined ? raw : null;
|
|
1124
|
+
}
|
|
1061
1125
|
return luaIndexValue(this, key, sf);
|
|
1062
1126
|
}
|
|
1063
1127
|
|
|
@@ -1081,8 +1145,21 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1081
1145
|
|
|
1082
1146
|
toJSObject(sf = LuaStackFrame.lostFrame): Record<string, any> {
|
|
1083
1147
|
const result: Record<string, any> = {};
|
|
1084
|
-
|
|
1085
|
-
|
|
1148
|
+
// Direct access to stringKeys avoids keys() allocation and get() metatable checks
|
|
1149
|
+
for (const k in this.stringKeys) {
|
|
1150
|
+
if (Object.hasOwn(this.stringKeys, k)) {
|
|
1151
|
+
result[k] = luaValueToJS(this.stringKeys[k], sf);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
// Include array part with 1-based keys
|
|
1155
|
+
for (let i = 0; i < this.arrayPart.length; i++) {
|
|
1156
|
+
result[i + 1] = luaValueToJS(this.arrayPart[i], sf);
|
|
1157
|
+
}
|
|
1158
|
+
// Include other keys
|
|
1159
|
+
if (this.otherKeys) {
|
|
1160
|
+
for (const [key, val] of this.otherKeys) {
|
|
1161
|
+
result[key] = luaValueToJS(val, sf);
|
|
1162
|
+
}
|
|
1086
1163
|
}
|
|
1087
1164
|
return result;
|
|
1088
1165
|
}
|
|
@@ -1111,10 +1188,7 @@ export class LuaTable implements ILuaSettable, ILuaGettable {
|
|
|
1111
1188
|
|
|
1112
1189
|
const s = singleResult(v);
|
|
1113
1190
|
if (typeof s !== "string") {
|
|
1114
|
-
throw new LuaRuntimeError(
|
|
1115
|
-
"'__tostring' must return a string",
|
|
1116
|
-
sf,
|
|
1117
|
-
);
|
|
1191
|
+
throw new LuaRuntimeError("'__tostring' must return a string", sf);
|
|
1118
1192
|
}
|
|
1119
1193
|
return s;
|
|
1120
1194
|
}
|
|
@@ -1168,6 +1242,7 @@ export function luaIndexValue(
|
|
|
1168
1242
|
if (t instanceof LuaTable) {
|
|
1169
1243
|
const raw = t.rawGet(key);
|
|
1170
1244
|
if (raw !== undefined) {
|
|
1245
|
+
if (isSqlNull(raw)) return null;
|
|
1171
1246
|
return raw;
|
|
1172
1247
|
}
|
|
1173
1248
|
// If no metatable, raw miss => nil
|
|
@@ -1219,27 +1294,32 @@ export function luaIndexValue(
|
|
|
1219
1294
|
|
|
1220
1295
|
export type LuaLValueContainer = { env: ILuaSettable; key: LuaValue };
|
|
1221
1296
|
|
|
1222
|
-
export
|
|
1297
|
+
export function luaSet(
|
|
1223
1298
|
obj: any,
|
|
1224
1299
|
key: any,
|
|
1225
1300
|
value: any,
|
|
1226
1301
|
sf: LuaStackFrame,
|
|
1227
1302
|
numType?: NumericType,
|
|
1228
|
-
): Promise<void> {
|
|
1303
|
+
): void | Promise<void> {
|
|
1229
1304
|
if (!obj) {
|
|
1230
|
-
throw new LuaRuntimeError(
|
|
1231
|
-
`Not a settable object: nil`,
|
|
1232
|
-
sf,
|
|
1233
|
-
);
|
|
1305
|
+
throw new LuaRuntimeError(`Not a settable object: nil`, sf);
|
|
1234
1306
|
}
|
|
1235
1307
|
|
|
1236
1308
|
const normKey = isTaggedFloat(key) ? key.value : key;
|
|
1237
1309
|
|
|
1238
1310
|
if (obj instanceof LuaTable || obj instanceof LuaEnv) {
|
|
1239
|
-
|
|
1311
|
+
return obj.set(normKey, value, sf, numType);
|
|
1240
1312
|
} else {
|
|
1241
1313
|
const k = toNumKey(normKey);
|
|
1242
|
-
|
|
1314
|
+
const jsVal = luaValueToJS(value, sf);
|
|
1315
|
+
if (isPromise(jsVal)) {
|
|
1316
|
+
return (jsVal as Promise<any>).then(
|
|
1317
|
+
(v) => {
|
|
1318
|
+
(obj as Record<string | number, any>)[k] = v;
|
|
1319
|
+
},
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
(obj as Record<string | number, any>)[k] = jsVal;
|
|
1243
1323
|
}
|
|
1244
1324
|
}
|
|
1245
1325
|
|
|
@@ -1249,12 +1329,10 @@ export function luaGet(
|
|
|
1249
1329
|
ctx: ASTCtx | null,
|
|
1250
1330
|
sf: LuaStackFrame,
|
|
1251
1331
|
): Promise<any> | any {
|
|
1252
|
-
const errSf = ctx ? sf.withCtx(ctx) : sf;
|
|
1253
|
-
|
|
1254
1332
|
if (obj === null || obj === undefined) {
|
|
1255
1333
|
throw new LuaRuntimeError(
|
|
1256
1334
|
`attempt to index a nil value`,
|
|
1257
|
-
|
|
1335
|
+
ctx ? sf.withCtx(ctx) : sf,
|
|
1258
1336
|
);
|
|
1259
1337
|
}
|
|
1260
1338
|
|
|
@@ -1338,16 +1416,23 @@ export function luaCall(
|
|
|
1338
1416
|
|
|
1339
1417
|
// Fast path: native JS function
|
|
1340
1418
|
if (typeof callee === "function") {
|
|
1341
|
-
const
|
|
1342
|
-
|
|
1343
|
-
|
|
1419
|
+
const baseSf = sf || LuaStackFrame.lostFrame;
|
|
1420
|
+
const len = args.length;
|
|
1421
|
+
let hasAsync = false;
|
|
1422
|
+
for (let i = 0; i < len; i++) {
|
|
1423
|
+
const converted = luaValueToJS(args[i], baseSf);
|
|
1424
|
+
args[i] = converted;
|
|
1425
|
+
if (!hasAsync && isPromise(converted)) {
|
|
1426
|
+
hasAsync = true;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1344
1429
|
|
|
1345
|
-
if (
|
|
1346
|
-
return
|
|
1347
|
-
(callee as (...a: any[]) => any)(...resolved)
|
|
1430
|
+
if (hasAsync) {
|
|
1431
|
+
return Promise.all(args).then((resolved) =>
|
|
1432
|
+
(callee as (...a: any[]) => any)(...resolved),
|
|
1348
1433
|
);
|
|
1349
1434
|
}
|
|
1350
|
-
return (callee as (...a: any[]) => any)(...
|
|
1435
|
+
return (callee as (...a: any[]) => any)(...args);
|
|
1351
1436
|
}
|
|
1352
1437
|
|
|
1353
1438
|
// Lua table: may be callable via __call metamethod
|
|
@@ -1383,14 +1468,20 @@ export function luaCall(
|
|
|
1383
1468
|
|
|
1384
1469
|
// ILuaFunction (LuaFunction/LuaBuiltinFunction/LuaNativeJSFunction/etc.)
|
|
1385
1470
|
if (isILuaFunction(callee)) {
|
|
1471
|
+
// Fast path for builtins: skip withFunction, defer withCtx
|
|
1472
|
+
if (callee instanceof LuaBuiltinFunction) {
|
|
1473
|
+
const base = sf || LuaStackFrame.lostFrame;
|
|
1474
|
+
return callee.call(base, ...args);
|
|
1475
|
+
}
|
|
1476
|
+
// Fast path for native JS functions: skip withCtx/withFunction
|
|
1477
|
+
if (callee instanceof LuaNativeJSFunction) {
|
|
1478
|
+
const base = sf || LuaStackFrame.lostFrame;
|
|
1479
|
+
return callee.call(base, ...args);
|
|
1480
|
+
}
|
|
1386
1481
|
const base = (sf || LuaStackFrame.lostFrame).withCtx(ctx);
|
|
1387
|
-
const frameForCall =
|
|
1388
|
-
? base.withFunction(callee)
|
|
1389
|
-
|
|
1390
|
-
return callee.call(
|
|
1391
|
-
frameForCall,
|
|
1392
|
-
...args,
|
|
1393
|
-
);
|
|
1482
|
+
const frameForCall =
|
|
1483
|
+
callee instanceof LuaFunction ? base.withFunction(callee) : base;
|
|
1484
|
+
return callee.call(frameForCall, ...args);
|
|
1394
1485
|
}
|
|
1395
1486
|
|
|
1396
1487
|
throw new LuaRuntimeError(
|
|
@@ -1400,8 +1491,17 @@ export function luaCall(
|
|
|
1400
1491
|
}
|
|
1401
1492
|
|
|
1402
1493
|
export function luaEquals(a: any, b: any): boolean {
|
|
1403
|
-
|
|
1404
|
-
const
|
|
1494
|
+
// Normalize nil variants (null, undefined, SQL NULL) to null
|
|
1495
|
+
const an = (a === null || a === undefined || isSqlNull(a))
|
|
1496
|
+
? null
|
|
1497
|
+
: isTaggedFloat(a)
|
|
1498
|
+
? a.value
|
|
1499
|
+
: a;
|
|
1500
|
+
const bn = (b === null || b === undefined || isSqlNull(b))
|
|
1501
|
+
? null
|
|
1502
|
+
: isTaggedFloat(b)
|
|
1503
|
+
? b.value
|
|
1504
|
+
: b;
|
|
1405
1505
|
return an === bn;
|
|
1406
1506
|
}
|
|
1407
1507
|
|
|
@@ -1416,7 +1516,7 @@ export function luaKeys(val: any): any[] {
|
|
|
1416
1516
|
}
|
|
1417
1517
|
|
|
1418
1518
|
export function luaTypeOf(val: any): LuaType | Promise<LuaType> {
|
|
1419
|
-
if (val === null || val === undefined) {
|
|
1519
|
+
if (val === null || val === undefined || isSqlNull(val)) {
|
|
1420
1520
|
return "nil";
|
|
1421
1521
|
}
|
|
1422
1522
|
if (isPromise(val)) {
|
|
@@ -1494,7 +1594,8 @@ export class LuaRuntimeError extends Error {
|
|
|
1494
1594
|
// Add position indicator
|
|
1495
1595
|
const pointer = `${" ".repeat(column)}^`;
|
|
1496
1596
|
|
|
1497
|
-
traceStr +=
|
|
1597
|
+
traceStr +=
|
|
1598
|
+
`* ${ctx.ref || "(unknown source)"} @ ${line}:${column}:\n` +
|
|
1498
1599
|
` ${codeLine}\n` +
|
|
1499
1600
|
` ${pointer}\n`;
|
|
1500
1601
|
current = current.parent;
|
|
@@ -1527,7 +1628,7 @@ export function luaToString(
|
|
|
1527
1628
|
value: any,
|
|
1528
1629
|
visited: Set<any> = new Set(),
|
|
1529
1630
|
): string | Promise<string> {
|
|
1530
|
-
if (value === null || value === undefined) {
|
|
1631
|
+
if (value === null || value === undefined || isSqlNull(value)) {
|
|
1531
1632
|
return "nil";
|
|
1532
1633
|
}
|
|
1533
1634
|
if (isPromise(value)) {
|
|
@@ -1613,7 +1714,7 @@ export function luaFormatNumber(n: number, kind?: "int" | "float"): string {
|
|
|
1613
1714
|
if (n === Infinity) return "inf";
|
|
1614
1715
|
if (n === -Infinity) return "-inf";
|
|
1615
1716
|
if (n === 0) {
|
|
1616
|
-
return
|
|
1717
|
+
return 1 / n === -Infinity ? "-0.0" : "0.0";
|
|
1617
1718
|
}
|
|
1618
1719
|
// Delegate to luaFormat for `%.14g`
|
|
1619
1720
|
const s = luaFormat("%.14g", n);
|
|
@@ -1643,7 +1744,7 @@ export function getMetatable(
|
|
|
1643
1744
|
}
|
|
1644
1745
|
|
|
1645
1746
|
const stringMetatable = new LuaTable();
|
|
1646
|
-
stringMetatable.set("__index", (globalEnv as any).get("string"));
|
|
1747
|
+
void stringMetatable.set("__index", (globalEnv as any).get("string"));
|
|
1647
1748
|
thread.setLocal("_STRING_MT", stringMetatable);
|
|
1648
1749
|
|
|
1649
1750
|
return stringMetatable;
|
|
@@ -1659,6 +1760,9 @@ export function getMetatable(
|
|
|
1659
1760
|
}
|
|
1660
1761
|
|
|
1661
1762
|
export function jsToLuaValue(value: any): any {
|
|
1763
|
+
if (value === null || value === undefined) {
|
|
1764
|
+
return value;
|
|
1765
|
+
}
|
|
1662
1766
|
if (isPromise(value)) {
|
|
1663
1767
|
return (value as Promise<any>).then(jsToLuaValue);
|
|
1664
1768
|
}
|
|
@@ -1673,26 +1777,26 @@ export function jsToLuaValue(value: any): any {
|
|
|
1673
1777
|
const regexMatch = value as RegExpMatchArray;
|
|
1674
1778
|
const regexMatchTable = new LuaTable();
|
|
1675
1779
|
for (let i = 0; i < regexMatch.length; i++) {
|
|
1676
|
-
regexMatchTable.set(i + 1, regexMatch[i]);
|
|
1780
|
+
void regexMatchTable.set(i + 1, regexMatch[i]);
|
|
1677
1781
|
}
|
|
1678
|
-
regexMatchTable.set("index", regexMatch.index);
|
|
1679
|
-
regexMatchTable.set("input", regexMatch.input);
|
|
1680
|
-
regexMatchTable.set("groups", regexMatch.groups);
|
|
1782
|
+
void regexMatchTable.set("index", regexMatch.index);
|
|
1783
|
+
void regexMatchTable.set("input", regexMatch.input);
|
|
1784
|
+
void regexMatchTable.set("groups", regexMatch.groups);
|
|
1681
1785
|
return regexMatchTable;
|
|
1682
1786
|
}
|
|
1683
1787
|
if (Array.isArray(value)) {
|
|
1684
|
-
const
|
|
1788
|
+
const converted = new Array(value.length);
|
|
1685
1789
|
for (let i = 0; i < value.length; i++) {
|
|
1686
|
-
|
|
1790
|
+
converted[i] = jsToLuaValue(value[i]);
|
|
1687
1791
|
}
|
|
1688
|
-
return
|
|
1792
|
+
return new LuaTable(converted);
|
|
1689
1793
|
}
|
|
1690
1794
|
if (typeof value === "object") {
|
|
1691
|
-
const
|
|
1795
|
+
const converted: Record<string, any> = {};
|
|
1692
1796
|
for (const key in value) {
|
|
1693
|
-
|
|
1797
|
+
converted[key] = jsToLuaValue((value as any)[key]);
|
|
1694
1798
|
}
|
|
1695
|
-
return
|
|
1799
|
+
return new LuaTable(converted);
|
|
1696
1800
|
}
|
|
1697
1801
|
if (typeof value === "function") {
|
|
1698
1802
|
return new LuaNativeJSFunction(value);
|
|
@@ -1709,13 +1813,12 @@ export function luaValueToJS(value: any, sf: LuaStackFrame): any {
|
|
|
1709
1813
|
return value.toJS(sf);
|
|
1710
1814
|
}
|
|
1711
1815
|
if (
|
|
1712
|
-
value instanceof LuaNativeJSFunction ||
|
|
1816
|
+
value instanceof LuaNativeJSFunction ||
|
|
1817
|
+
value instanceof LuaFunction ||
|
|
1713
1818
|
value instanceof LuaBuiltinFunction
|
|
1714
1819
|
) {
|
|
1715
1820
|
return (...args: any[]) => {
|
|
1716
|
-
const jsArgs = rpAll(
|
|
1717
|
-
args.map((v) => luaValueToJS(v, sf)),
|
|
1718
|
-
);
|
|
1821
|
+
const jsArgs = rpAll(args.map((v) => luaValueToJS(v, sf)));
|
|
1719
1822
|
if (isPromise(jsArgs)) {
|
|
1720
1823
|
return luaValueToJS(
|
|
1721
1824
|
jsArgs.then((jsArgs) => (value as ILuaFunction).call(sf, ...jsArgs)),
|