From b8a96484b9ee9174541d82a7b71cdc69cdde3c35 Mon Sep 17 00:00:00 2001 From: LUCCA DUKIC <109136188+LuccaBitfly@users.noreply.github.com> Date: Mon, 23 Sep 2024 09:05:47 +0200 Subject: [PATCH] (BEDS-506) change node address type --- backend/cmd/typescript_converter/main.go | 124 ++++++++++++---------- backend/pkg/api/types/notifications.go | 8 +- frontend/types/api/notifications.ts | 4 +- frontend/types/api/user.ts | 2 +- frontend/types/api/validator_dashboard.ts | 2 +- 5 files changed, 78 insertions(+), 62 deletions(-) diff --git a/backend/cmd/typescript_converter/main.go b/backend/cmd/typescript_converter/main.go index da6fa5be9..99f0ce243 100644 --- a/backend/cmd/typescript_converter/main.go +++ b/backend/cmd/typescript_converter/main.go @@ -3,6 +3,8 @@ package typescript_converter import ( "flag" "go/ast" + "iter" + "maps" "os" "path/filepath" "slices" @@ -18,6 +20,8 @@ const ( fallbackType = "any" commonFileName = "common" lintDisable = "/* eslint-disable */\n" + goFileSuffix = ".go" + tsFileSuffix = ".ts" ) // Files that should not be converted to TypeScript @@ -65,24 +69,23 @@ func Run() { log.Fatal(nil, "Failed to load package", 0) } - // Find all common types + // Find all common types, i.e. types that are used in multiple files and must be imported in ts commonTypes := getCommonTypes(pkgs) - // Find all usages of common types - usage := getCommonUsages(pkgs, commonTypes) - - // Generate Tygo for common.go - tygos := []*tygo.Tygo{tygo.New(getTygoConfig(out, commonFileName, ""))} - // Generate Tygo for each file - for file, typesUsed := range usage { - importStr := "" + // Find imports (usages of common types) for each file + imports := getImports(pkgs, commonTypes) + + var configs []*tygo.Tygo + // Generate Tygo config for each file + for fileName, typesUsed := range imports { + var importStr string if len(typesUsed) > 0 { - importStr = "import type { " + strings.Join(typesUsed, ", ") + " } from './" + commonFileName + "'\n" + importStr = "import type { " + strings.Join(slices.Collect(maps.Keys(typesUsed)), ", ") + " } from './" + commonFileName + "'\n" } - tygos = append(tygos, tygo.New(getTygoConfig(out, file, importStr))) + configs = append(configs, tygo.New(getTygoConfig(out, fileName, importStr))) } // Generate TypeScript - for _, tygo := range tygos { + for _, tygo := range configs { err := tygo.Generate() if err != nil { log.Fatal(err, "Failed to generate TypeScript", 0) @@ -93,7 +96,7 @@ func Run() { } func deleteFiles(out string) error { - files, err := filepath.Glob(out + "*.ts") + files, err := filepath.Glob(out + "*" + tsFileSuffix) if err != nil { return err } @@ -106,68 +109,81 @@ func deleteFiles(out string) error { return nil } -func getTygoConfig(out, file, frontmatter string) *tygo.Config { +func getTygoConfig(outDir, fileName, frontmatter string) *tygo.Config { return &tygo.Config{ Packages: []*tygo.PackageConfig{ { Path: packagePath, TypeMappings: typeMappings, FallbackType: fallbackType, - IncludeFiles: []string{file + ".go"}, - OutputPath: out + file + ".ts", + IncludeFiles: []string{fileName + goFileSuffix}, + OutputPath: outDir + fileName + tsFileSuffix, Frontmatter: lintDisable + frontmatter, }, }, } } -// Parse common.go to find all common types -func getCommonTypes(pkgs []*packages.Package) map[string]bool { - commonTypes := make(map[string]bool) - for _, pkg := range pkgs { - for _, file := range pkg.Syntax { - filename := strings.TrimSuffix(filepath.Base(pkg.Fset.File(file.Pos()).Name()), ".go") - if filepath.Base(filename) != commonFileName { - continue - } - ast.Inspect(file, func(n ast.Node) bool { - if typeSpec, ok := n.(*ast.TypeSpec); ok { - commonTypes[typeSpec.Name.Name] = true +// Iterate over all file names and files in the packages +func allFiles(pkgs []*packages.Package) iter.Seq2[string, *ast.File] { + return func(yield func(string, *ast.File) bool) { + for _, pkg := range pkgs { + for _, file := range pkg.Syntax { + fileName := filepath.Base(pkg.Fset.File(file.Pos()).Name()) + if !yield(fileName, file) { + return } - return true - }) - return commonTypes + } } } - return nil +} + +// Parse common.go to find all common types +func getCommonTypes(pkgs []*packages.Package) map[string]struct{} { + var commonFile *ast.File + // find common file + for fileName, file := range allFiles(pkgs) { + fileName = strings.TrimSuffix(fileName, goFileSuffix) + if filepath.Base(fileName) == commonFileName { + commonFile = file + break + } + } + if commonFile == nil { + log.Fatal(nil, "common.go not found", 0) + } + commonTypes := make(map[string]struct{}) + // iterate over all types in common file and add them to the map + for node := range ast.Preorder(commonFile) { + if typeSpec, ok := node.(*ast.TypeSpec); ok { + commonTypes[typeSpec.Name.Name] = struct{}{} + } + } + return commonTypes } // Parse all files to find used common types for each file -func getCommonUsages(pkgs []*packages.Package, commonTypes map[string]bool) map[string][]string { - usage := make(map[string][]string) // Map from file to list of commonTypes used - for _, pkg := range pkgs { - for _, file := range pkg.Syntax { - filename := strings.TrimSuffix(filepath.Base(pkg.Fset.File(file.Pos()).Name()), ".go") - if filepath.Base(filename) == commonFileName || slices.Contains(ignoredFiles, filename) { +// Returns a map with file name as key and a set of common types used in the file as value +func getImports(pkgs []*packages.Package, commonTypes map[string]struct{}) map[string]map[string]struct{} { + imports := make(map[string]map[string]struct{}) // Map from file to set of commonTypes used + imports[commonFileName] = make(map[string]struct{}) // Add common file to map with empty set + for fileName, file := range allFiles(pkgs) { + fileName = strings.TrimSuffix(fileName, goFileSuffix) + if filepath.Base(fileName) == commonFileName || slices.Contains(ignoredFiles, fileName) { + continue + } + imports[fileName] = make(map[string]struct{}) + // iterate over all struct fields in the file + for node := range ast.Preorder(file) { + ident, ok := node.(*ast.Ident) + if !ok { continue } - if _, exists := usage[filename]; !exists { - usage[filename] = make([]string, 0) + if _, ok := commonTypes[ident.Name]; ok { + // field is a common type, add it to the map + imports[fileName][ident.Name] = struct{}{} } - ast.Inspect(file, func(n ast.Node) bool { - ident, ok := n.(*ast.Ident) - if !ok { - return true - } - if !commonTypes[ident.Name] { - return true - } - if !slices.Contains(usage[filename], ident.Name) { - usage[filename] = append(usage[filename], ident.Name) - } - return true - }) } } - return usage + return imports } diff --git a/backend/pkg/api/types/notifications.go b/backend/pkg/api/types/notifications.go index af31fd56a..cd75f21fe 100644 --- a/backend/pkg/api/types/notifications.go +++ b/backend/pkg/api/types/notifications.go @@ -120,10 +120,10 @@ type InternalGetUserNotificationClientsResponse ApiPagingResponse[NotificationCl // ------------------------------------------------------------ // Rocket Pool Table type NotificationRocketPoolTableRow struct { - Timestamp int64 `json:"timestamp"` - EventType string `json:"event_type" tstype:"'reward_round' | 'collateral_max' | 'collateral_min'" faker:"oneof: reward_round, collateral_max, collateral_min"` - AlertValue float64 `json:"alert_value,omitempty"` // only for some notification types, e.g. max collateral - NodeAddress Hash `json:"node_address"` + Timestamp int64 `json:"timestamp"` + EventType string `json:"event_type" tstype:"'reward_round' | 'collateral_max' | 'collateral_min'" faker:"oneof: reward_round, collateral_max, collateral_min"` + AlertValue float64 `json:"alert_value,omitempty"` // only for some notification types, e.g. max collateral + Node Address `json:"node"` } type InternalGetUserNotificationRocketPoolResponse ApiPagingResponse[NotificationRocketPoolTableRow] diff --git a/frontend/types/api/notifications.ts b/frontend/types/api/notifications.ts index 1ff93b79b..6e864a8b9 100644 --- a/frontend/types/api/notifications.ts +++ b/frontend/types/api/notifications.ts @@ -1,6 +1,6 @@ // Code generated by tygo. DO NOT EDIT. /* eslint-disable */ -import type { ApiDataResponse, ApiPagingResponse, IndexBlocks, Address, Hash } from './common' +import type { Hash, ApiDataResponse, ApiPagingResponse, IndexBlocks, Address } from './common' ////////// // source: notifications.go @@ -119,7 +119,7 @@ export interface NotificationRocketPoolTableRow { timestamp: number /* int64 */; event_type: 'reward_round' | 'collateral_max' | 'collateral_min'; alert_value?: number /* float64 */; // only for some notification types, e.g. max collateral - node_address: Hash; + node: Address; } export type InternalGetUserNotificationRocketPoolResponse = ApiPagingResponse; /** diff --git a/frontend/types/api/user.ts b/frontend/types/api/user.ts index c31a2ac76..3726e962e 100644 --- a/frontend/types/api/user.ts +++ b/frontend/types/api/user.ts @@ -1,6 +1,6 @@ // Code generated by tygo. DO NOT EDIT. /* eslint-disable */ -import type { ApiDataResponse, ChartHistorySeconds } from './common' +import type { ChartHistorySeconds, ApiDataResponse } from './common' ////////// // source: user.go diff --git a/frontend/types/api/validator_dashboard.ts b/frontend/types/api/validator_dashboard.ts index 58bc40cce..f721ab09a 100644 --- a/frontend/types/api/validator_dashboard.ts +++ b/frontend/types/api/validator_dashboard.ts @@ -1,6 +1,6 @@ // Code generated by tygo. DO NOT EDIT. /* eslint-disable */ -import type { ValidatorStateCounts, PeriodicValues, ClElValue, ChartHistorySeconds, ApiDataResponse, StatusCount, ApiPagingResponse, Luck, ChartData, ValidatorHistoryDuties, Address, PubKey, Hash, PercentageDetails } from './common' +import type { ApiDataResponse, Luck, PubKey, ValidatorStateCounts, PeriodicValues, ValidatorHistoryDuties, Address, ChartData, Hash, PercentageDetails, ClElValue, ChartHistorySeconds, StatusCount, ApiPagingResponse } from './common' ////////// // source: validator_dashboard.go