package encoder_test import ( "encoding/binary" "fmt" "os" "path/filepath" "strings" "testing" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/api/encoder" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/ast" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/core" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/parser" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/repo" "efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/baseline" "gotest.tools/v3/assert" ) func TestEncodeSourceFile(t *testing.T) { t.Parallel() sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ FileName: "/test.ts", Path: "/test.ts", }, "import { bar } from \"bar\";\nexport function foo(a: string, b: string): any {}\nfoo();", core.ScriptKindTS) t.Run("baseline", func(t *testing.T) { t.Parallel() buf, err := encoder.EncodeSourceFile(sourceFile, "") assert.NilError(t, err) str := formatEncodedSourceFile(buf) baseline.Run(t, "encodeSourceFile.txt", str, baseline.Options{ Subfolder: "api", }) }) } func BenchmarkEncodeSourceFile(b *testing.B) { repo.SkipIfNoTypeScriptSubmodule(b) filePath := filepath.Join(repo.TypeScriptSubmodulePath, "src/compiler/checker.ts") fileContent, err := os.ReadFile(filePath) assert.NilError(b, err) sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ FileName: "/checker.ts", Path: "/checker.ts", }, string(fileContent), core.ScriptKindTS) for b.Loop() { _, err := encoder.EncodeSourceFile(sourceFile, "") assert.NilError(b, err) } } func readUint32(buf []byte, offset int) uint32 { return binary.LittleEndian.Uint32(buf[offset : offset+4]) } func formatEncodedSourceFile(encoded []byte) string { var result strings.Builder var getIndent func(parentIndex uint32) string offsetNodes := readUint32(encoded, encoder.HeaderOffsetNodes) offsetStringOffsets := readUint32(encoded, encoder.HeaderOffsetStringOffsets) offsetStrings := readUint32(encoded, encoder.HeaderOffsetStringData) getIndent = func(parentIndex uint32) string { if parentIndex == 0 { return "" } return " " + getIndent(readUint32(encoded, int(offsetNodes)+int(parentIndex)*encoder.NodeSize+encoder.NodeOffsetParent)) } j := 1 for i := int(offsetNodes) + encoder.NodeSize; i < len(encoded); i += encoder.NodeSize { kind := readUint32(encoded, i+encoder.NodeOffsetKind) pos := readUint32(encoded, i+encoder.NodeOffsetPos) end := readUint32(encoded, i+encoder.NodeOffsetEnd) parentIndex := readUint32(encoded, i+encoder.NodeOffsetParent) result.WriteString(getIndent(parentIndex)) if kind == encoder.SyntaxKindNodeList { result.WriteString("NodeList") } else { result.WriteString(ast.Kind(kind).String()) } if ast.Kind(kind) == ast.KindIdentifier || ast.Kind(kind) == ast.KindStringLiteral { stringIndex := readUint32(encoded, i+encoder.NodeOffsetData) & encoder.NodeDataStringIndexMask strStart := readUint32(encoded, int(offsetStringOffsets+stringIndex*4)) strEnd := readUint32(encoded, int(offsetStringOffsets+stringIndex*4)+4) str := string(encoded[offsetStrings+strStart : offsetStrings+strEnd]) result.WriteString(fmt.Sprintf(" \"%s\"", str)) } fmt.Fprintf(&result, " [%d, %d), i=%d, next=%d", pos, end, j, encoded[i+encoder.NodeOffsetNext]) result.WriteString("\n") j++ } return result.String() }