kittenipc/kitcom/internal/tsgo/printer/namegenerator_test.go
2025-10-15 10:12:44 +03:00

641 lines
16 KiB
Go

package printer_test
import (
"testing"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/binder"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/printer"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/parsetestutil"
"gotest.tools/v3/assert"
)
func TestTempVariable1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewTempVariable()
name2 := ec.Factory.NewTempVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "_a", text1)
assert.Equal(t, "_b", text2)
}
func TestTempVariable2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewTempVariableEx(printer.AutoGenerateOptions{
Prefix: "A",
Suffix: "B",
})
name2 := ec.Factory.NewTempVariableEx(printer.AutoGenerateOptions{
Prefix: "A",
Suffix: "B",
})
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "A_aB", text1)
assert.Equal(t, "A_bB", text2)
}
func TestTempVariable3(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewTempVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name1)
assert.Equal(t, "_a", text1)
assert.Equal(t, "_a", text2)
}
func TestTempVariableScoped(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewTempVariable()
name2 := ec.Factory.NewTempVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
g.PushScope(false)
text2 := g.GenerateName(name2)
g.PopScope(false)
assert.Equal(t, "_a", text1)
assert.Equal(t, "_a", text2)
}
func TestTempVariableScopedReserved(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewTempVariableEx(printer.AutoGenerateOptions{Flags: printer.GeneratedIdentifierFlagsReservedInNestedScopes})
name2 := ec.Factory.NewTempVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
g.PushScope(false)
text2 := g.GenerateName(name2)
g.PopScope(false)
assert.Equal(t, "_a", text1)
assert.Equal(t, "_b", text2)
}
func TestLoopVariable1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewLoopVariable()
name2 := ec.Factory.NewLoopVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "_i", text1)
assert.Equal(t, "_a", text2)
}
func TestLoopVariable2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewLoopVariableEx(printer.AutoGenerateOptions{
Prefix: "A",
Suffix: "B",
})
name2 := ec.Factory.NewLoopVariableEx(printer.AutoGenerateOptions{
Prefix: "A",
Suffix: "B",
})
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "A_iB", text1)
assert.Equal(t, "A_aB", text2)
}
func TestLoopVariable3(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewLoopVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name1)
assert.Equal(t, "_i", text1)
assert.Equal(t, "_i", text2)
}
func TestLoopVariableScoped(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewLoopVariable()
name2 := ec.Factory.NewLoopVariable()
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
g.PushScope(false)
text2 := g.GenerateName(name2)
g.PopScope(false)
assert.Equal(t, "_i", text1)
assert.Equal(t, "_i", text2)
}
func TestUniqueName1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniqueName("foo")
name2 := ec.Factory.NewUniqueName("foo")
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "foo_1", text1)
assert.Equal(t, "foo_2", text2)
}
func TestUniqueName2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniqueName("foo")
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name1)
assert.Equal(t, "foo_1", text1)
// Expected to be same because GenerateName goes off object identity
assert.Equal(t, "foo_1", text2)
}
func TestUniqueNameScoped(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniqueName("foo")
name2 := ec.Factory.NewUniqueName("foo")
g := &printer.NameGenerator{Context: ec}
assert.Equal(t, "foo_1", g.GenerateName(name1))
g.PushScope(false)
assert.Equal(t, "foo_2", g.GenerateName(name2)) // Matches Strada, but is incorrect
// assert.Equal(t, "foo_1", g.GenerateName(name2)) // TODO: Fix after Strada port is complete.
g.PopScope(false)
}
func TestUniquePrivateName1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniquePrivateName("#foo")
name2 := ec.Factory.NewUniquePrivateName("#foo")
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "#foo_1", text1)
assert.Equal(t, "#foo_2", text2)
}
func TestUniquePrivateName2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniquePrivateName("#foo")
g := &printer.NameGenerator{Context: ec}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name1)
assert.Equal(t, "#foo_1", text1)
assert.Equal(t, "#foo_1", text2)
}
func TestUniquePrivateNameScoped(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
name1 := ec.Factory.NewUniquePrivateName("#foo")
name2 := ec.Factory.NewUniquePrivateName("#foo")
g := &printer.NameGenerator{Context: ec}
assert.Equal(t, "#foo_1", g.GenerateName(name1))
g.PushScope(false) // private names are always reserved in nested scopes
assert.Equal(t, "#foo_2", g.GenerateName(name2))
g.PopScope(false)
}
func TestGeneratedNameForIdentifier1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].Name()
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "f_1", text1)
}
func TestGeneratedNameForIdentifier2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].Name()
name1 := ec.Factory.NewGeneratedNameForNodeEx(n, printer.AutoGenerateOptions{
Prefix: "a",
Suffix: "b",
})
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "afb", text1)
}
func TestGeneratedNameForIdentifier3(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("function f() {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].Name()
name1 := ec.Factory.NewGeneratedNameForNodeEx(n, printer.AutoGenerateOptions{
Prefix: "a",
Suffix: "b",
})
name2 := ec.Factory.NewGeneratedNameForNode(name1)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name2)
assert.Equal(t, "afb_1", text1)
}
// namespace reuses name if it does not collide with locals
func TestGeneratedNameForNamespace1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("namespace foo { }", false /*jsx*/)
binder.BindSourceFile(file)
ns1 := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(ns1)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "foo", text1)
}
// namespace uses generated name if it collides with locals
func TestGeneratedNameForNamespace2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/)
binder.BindSourceFile(file)
ns1 := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(ns1)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "foo_1", text1)
}
// avoids collisions when unscoped
func TestGeneratedNameForNamespace3(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/)
binder.BindSourceFile(file)
ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(ns1)
name2 := ec.Factory.NewGeneratedNameForNode(ns2)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "foo_1", text1)
assert.Equal(t, "foo_2", text2)
}
// reuse name when scoped
func TestGeneratedNameForNamespace4(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("namespace ns1 { namespace foo { var foo; } } namespace ns2 { namespace foo { var foo; } }", false /*jsx*/)
binder.BindSourceFile(file)
ns1 := file.Statements.Nodes[0].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
ns2 := file.Statements.Nodes[1].AsModuleDeclaration().Body.AsModuleBlock().Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(ns1)
name2 := ec.Factory.NewGeneratedNameForNode(ns2)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
g.PushScope(false)
text1 := g.GenerateName(name1)
g.PopScope(false)
g.PushScope(false)
text2 := g.GenerateName(name2)
g.PopScope(false)
assert.Equal(t, "foo_1", text1)
assert.Equal(t, "foo_2", text2) // Matches Strada, but is incorrect
// assert.Equal(t, "foo_1", text2) // TODO: Fix after Strada port is complete.
}
func TestGeneratedNameForNodeCached(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("namespace foo { var foo; }", false /*jsx*/)
binder.BindSourceFile(file)
ns1 := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(ns1)
name2 := ec.Factory.NewGeneratedNameForNode(ns1)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
text2 := g.GenerateName(name2)
assert.Equal(t, "foo_1", text1)
assert.Equal(t, "foo_1", text2)
}
func TestGeneratedNameForImport(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("import * as foo from 'foo'", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "foo_1", text1)
}
func TestGeneratedNameForExport(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export * as foo from 'foo'", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "foo_1", text1)
}
func TestGeneratedNameForFunctionDeclaration1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export function f() {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "f_1", text1)
}
func TestGeneratedNameForFunctionDeclaration2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export default function () {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "default_1", text1)
}
func TestGeneratedNameForClassDeclaration1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export class C {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "C_1", text1)
}
func TestGeneratedNameForClassDeclaration2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export default class {}", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "default_1", text1)
}
func TestGeneratedNameForExportAssignment(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("export default 0", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "default_1", text1)
}
func TestGeneratedNameForClassExpression(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("(class {})", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].AsExpressionStatement().Expression.AsParenthesizedExpression().Expression
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "class_1", text1)
}
func TestGeneratedNameForMethod1(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "m_1", text1)
}
func TestGeneratedNameForMethod2(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("class C { 0() {} }", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "_a", text1)
}
func TestGeneratedPrivateNameForMethod(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("class C { m() {} }", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0]
name1 := ec.Factory.NewGeneratedPrivateNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "#m_1", text1)
}
func TestGeneratedNameForComputedPropertyName(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/)
binder.BindSourceFile(file)
n := file.Statements.Nodes[0].AsClassDeclaration().Members.Nodes[0].Name()
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "_a", text1)
}
func TestGeneratedNameForOther(t *testing.T) {
t.Parallel()
ec := printer.NewEmitContext()
file := parsetestutil.ParseTypeScript("class C { [x] }", false /*jsx*/)
binder.BindSourceFile(file)
n := ec.Factory.NewObjectLiteralExpression(
ec.Factory.NewNodeList([]*ast.Node{}),
false, /*multiLine*/
)
name1 := ec.Factory.NewGeneratedNameForNode(n)
g := &printer.NameGenerator{Context: ec, GetTextOfNode: (*ast.Node).Text}
text1 := g.GenerateName(name1)
assert.Equal(t, "_a", text1)
}