diff --git a/context.go b/context.go index bb13adb..3acb6d0 100644 --- a/context.go +++ b/context.go @@ -388,6 +388,13 @@ func (ctx *Context) NewDate(epochMS float64) *Value { return &Value{ctx: ctx, ref: C.JS_NewDate(ctx.ref, C.double(epochMS))} } +func (ctx *Context) newSymbol(description *C.char, isGlobal bool) *Value { + if !ctx.hasValidRef() { + return nil + } + return &Value{ctx: ctx, ref: C.JS_NewSymbol(ctx.ref, description, C.bool(isGlobal))} +} + // NewSymbol returns a JavaScript local symbol. func (ctx *Context) NewSymbol(description string) *Value { if !ctx.hasValidRef() { @@ -395,7 +402,12 @@ func (ctx *Context) NewSymbol(description string) *Value { } desc := C.CString(description) defer C.free(unsafe.Pointer(desc)) - return &Value{ctx: ctx, ref: C.JS_NewSymbol(ctx.ref, desc, C.bool(false))} + return ctx.newSymbol(desc, false) +} + +// NewSymbolWithoutDescription returns a JavaScript local symbol created with Symbol(). +func (ctx *Context) NewSymbolWithoutDescription() *Value { + return ctx.newSymbol(nil, false) } // NewGlobalSymbol returns a JavaScript global symbol. @@ -405,7 +417,12 @@ func (ctx *Context) NewGlobalSymbol(description string) *Value { } desc := C.CString(description) defer C.free(unsafe.Pointer(desc)) - return &Value{ctx: ctx, ref: C.JS_NewSymbol(ctx.ref, desc, C.bool(true))} + return ctx.newSymbol(desc, true) +} + +// NewGlobalSymbolWithoutDescription returns a JavaScript global symbol created with Symbol.for("undefined"). +func (ctx *Context) NewGlobalSymbolWithoutDescription() *Value { + return ctx.newSymbol(nil, true) } // String returns a string value with given string. diff --git a/context_test.go b/context_test.go index 7e529d2..b46028c 100644 --- a/context_test.go +++ b/context_test.go @@ -357,14 +357,24 @@ func TestContextLibcStage4Helpers(t *testing.T) { require.NotNil(t, localSym) require.True(t, localSym.IsSymbol()) + localSymNoDesc := ctx.NewSymbolWithoutDescription() + require.NotNil(t, localSymNoDesc) + require.True(t, localSymNoDesc.IsSymbol()) + globalSym := ctx.NewGlobalSymbol("global-key") require.NotNil(t, globalSym) require.True(t, globalSym.IsSymbol()) + globalSymNoDesc := ctx.NewGlobalSymbolWithoutDescription() + require.NotNil(t, globalSymNoDesc) + require.True(t, globalSymNoDesc.IsSymbol()) + globals := ctx.Globals() require.NotNil(t, globals) globals.Set("_localSym", localSym) + globals.Set("_localSymNoDesc", localSymNoDesc) globals.Set("_globalSym", globalSym) + globals.Set("_globalSymNoDesc", globalSymNoDesc) localKey := ctx.Eval(`Symbol.keyFor(globalThis._localSym)`) require.NotNil(t, localKey) @@ -377,6 +387,18 @@ func TestContextLibcStage4Helpers(t *testing.T) { require.False(t, globalKey.IsException()) require.Equal(t, "global-key", globalKey.ToString()) + localNoDescSemantics := ctx.Eval(`globalThis._localSymNoDesc.description === undefined && Symbol.keyFor(globalThis._localSymNoDesc) === undefined`) + require.NotNil(t, localNoDescSemantics) + defer localNoDescSemantics.Free() + require.False(t, localNoDescSemantics.IsException()) + require.True(t, localNoDescSemantics.ToBool()) + + globalNoDescSemantics := ctx.Eval(`globalThis._globalSymNoDesc.description === "undefined" && Symbol.keyFor(globalThis._globalSymNoDesc) === "undefined"`) + require.NotNil(t, globalNoDescSemantics) + defer globalNoDescSemantics.Free() + require.False(t, globalNoDescSemantics.IsException()) + require.True(t, globalNoDescSemantics.ToBool()) + moduleFunc := ctx.Eval(`export const v = 1`, EvalFlagModule(true), EvalFlagCompileOnly(true)) require.NotNil(t, moduleFunc) defer moduleFunc.Free() @@ -411,7 +433,9 @@ func TestContextLibcStage4HelpersNilAndClosedGuards(t *testing.T) { var nilCtx *Context require.Nil(t, nilCtx.NewDate(0)) require.Nil(t, nilCtx.NewSymbol("x")) + require.Nil(t, nilCtx.NewSymbolWithoutDescription()) require.Nil(t, nilCtx.NewGlobalSymbol("x")) + require.Nil(t, nilCtx.NewGlobalSymbolWithoutDescription()) require.False(t, nilCtx.SetImportMeta(nil, false, false)) require.False(t, nilCtx.BootstrapBJSON()) require.Equal(t, -1, nilCtx.LoopOnce()) @@ -430,7 +454,9 @@ func TestContextLibcStage4HelpersNilAndClosedGuards(t *testing.T) { ctx.Close() require.Nil(t, ctx.NewDate(0)) require.Nil(t, ctx.NewSymbol("x")) + require.Nil(t, ctx.NewSymbolWithoutDescription()) require.Nil(t, ctx.NewGlobalSymbol("x")) + require.Nil(t, ctx.NewGlobalSymbolWithoutDescription()) require.False(t, ctx.SetImportMeta(moduleFunc, false, false)) require.False(t, ctx.BootstrapBJSON()) require.Equal(t, -1, ctx.LoopOnce())