Created
February 10, 2026 18:30
-
-
Save jakubtomsu/730a4343ba0137388d789f507857b9d7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package import_scan | |
| import "core:strings" | |
| import "core:strconv" | |
| import "core:path/filepath" | |
| import "core:fmt" | |
| import "core:os/os2" | |
| import "core:odin/ast" | |
| import "core:odin/parser" | |
| import "core:odin/tokenizer" | |
| _collection_paths: map[string]string | |
| main :: proc() { | |
| if len(os2.args) <= 1 { | |
| fmt.println("Error: please specify root package path") | |
| } | |
| _collection_paths["base"] = filepath.join({ODIN_ROOT,"base"}) | |
| _collection_paths["core"] = filepath.join({ODIN_ROOT,"core"}) | |
| _collection_paths["vendor"] = filepath.join({ODIN_ROOT, "vendor"}) | |
| root_pkg := os2.args[1] | |
| pkgs: map[string]^ast.Package | |
| parse_package_tree(&pkgs, root_pkg, depth = 0) | |
| fmt.eprintln("\nRESULT:") | |
| for name, pkg in pkgs { | |
| fmt.eprintfln("PKG %s", name) | |
| for name, file in pkg.files { | |
| fmt.eprintfln(" FILE %s", name) | |
| for imp in file.imports { | |
| path, _ := resolve_import(imp) | |
| fmt.eprintfln(" import %s", path) | |
| } | |
| } | |
| } | |
| fmt.println("digraph deps {") | |
| fmt.println("\tnode [shape=box];") | |
| for name, pkg in pkgs { | |
| str, _ := strings.replace_all(name, "\\", "/") | |
| id := path_id(str) | |
| fmt.printfln("\t%s [label=\"%s\"];", id, str) | |
| imports: map[string]struct{} | |
| for name, file in pkg.files { | |
| for imp in file.imports { | |
| path, _ := resolve_import(imp) | |
| imports[path] = {} | |
| } | |
| } | |
| for imp in imports { | |
| fmt.printfln("\t%s -> %s;", id, path_id(imp)) | |
| } | |
| } | |
| fmt.println("}") | |
| } | |
| path_id :: proc(path: string) -> string { | |
| p := path | |
| p, _ = strings.replace_all(p, "/", "_") | |
| p, _ = strings.replace_all(p, "\\", "_") | |
| p, _ = strings.replace_all(p, ".", "_") | |
| p, _ = strings.replace_all(p, ":", "_") | |
| p, _ = strings.replace_all(p, "-", "_") | |
| return p | |
| } | |
| parse_package_tree :: proc(pkgs: ^map[string]^ast.Package, path: string, depth: int) { | |
| assert(depth < 30) | |
| if path in pkgs { | |
| return | |
| } | |
| pkg, pkg_ok := parser.parse_package_from_path(path) | |
| if !pkg_ok { | |
| fmt.eprintfln("Failed to parse package at '%s'", path) | |
| os2.exit(1) | |
| } | |
| // fmt.println(path, pkg.name, pkg.fullpath) | |
| pkgs[pkg.fullpath] = pkg | |
| for name, file in pkg.files { | |
| for imp in file.imports { | |
| path := resolve_import(imp) or_continue | |
| parse_package_tree(pkgs, path, depth + 1) | |
| } | |
| } | |
| } | |
| resolve_import :: proc(imp: ^ast.Import_Decl) -> (result: string, keep_resolving: bool) { | |
| relative := unquote(imp.relpath.text) | |
| if colon_index := strings.index_byte(relative, ':'); colon_index >= 0 { | |
| coll := relative[:colon_index] | |
| name := relative[colon_index + 1:] | |
| coll_path := _collection_paths[coll] | |
| result = filepath.join({coll_path, name}) | |
| switch coll { | |
| case "base": | |
| return result, false | |
| } | |
| } else { | |
| result = unquote(imp.fullpath) | |
| } | |
| return result, true | |
| } | |
| unquote :: proc(str: string) -> string { | |
| res, _, _ := strconv.unquote_string(str, context.temp_allocator) | |
| return res | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment