From 90ab37e715b6c399f7aebe2f65325a4b0db4577d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sun, 14 Jun 2026 18:56:52 +0200 Subject: [PATCH] fix(resolve): treat bare '.' / '..' as relative directory imports (#5141) @tanstack/table-core failed to link (Undefined symbols: __getVisibleLeafColumns). Its source uses 'import { _getVisibleLeafColumns } from ".."' (package barrel), where '..' resolves to the package index.ts (export * from features/...). The import resolver detected relative imports via starts_with("./")||"../"; bare '.' and '..' (directory imports resolving to index) matched neither, so 'from ".."' fell through to bare-package resolution, import.resolved_path never matched the index module, and every name imported through it lowered to an unresolved raw extern symbol -> link failure. 'from "../index"' worked. Fix: shared is_relative_specifier() that also matches exact '.' / '..', used by resolve_relative_import_path, resolve_import, and the declaration-sidecar resolver. tanstack table-core now links and runs (getRowModel().rows.length=3, matches Node). No regression on ./ or ../foo imports. --- crates/perry/src/commands/compile/resolve.rs | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/crates/perry/src/commands/compile/resolve.rs b/crates/perry/src/commands/compile/resolve.rs index 6cb9c04f0e..04fad398bb 100644 --- a/crates/perry/src/commands/compile/resolve.rs +++ b/crates/perry/src/commands/compile/resolve.rs @@ -847,10 +847,7 @@ pub(super) fn declaration_sidecar_for_resolved_import( return canonical_existing_declaration(resolved_path.to_path_buf()); } - if !(import_source.starts_with("./") - || import_source.starts_with("../") - || import_source.starts_with('/')) - { + if !(is_relative_specifier(import_source) || import_source.starts_with('/')) { let (package_name, subpath) = parse_package_specifier(import_source); if let Some(package_dir) = package_dir_for_resolved_path(resolved_path, &package_name) { if let Some(sidecar) = resolve_package_declaration_entry( @@ -897,7 +894,7 @@ pub(super) fn resolve_relative_import_path( import_source: &str, importer_path: &Path, ) -> Option { - if !import_source.starts_with("./") && !import_source.starts_with("../") { + if !is_relative_specifier(import_source) { return None; } let parent = importer_path.parent()?; @@ -906,6 +903,21 @@ pub(super) fn resolve_relative_import_path( path.canonicalize().ok() } +/// True for ECMAScript relative-import specifiers. Besides the obvious `./x` +/// and `../x`, the bare `"."` and `".."` are also relative — they resolve to +/// the current / parent **directory**'s `index` file. `@tanstack/table-core`'s +/// source uses `import { _getVisibleLeafColumns } from '..'` (the package +/// barrel); without matching `".."` here it fell through to bare-package +/// resolution, `import.resolved_path` never matched the index module, and every +/// name imported through it lowered to an unresolved raw extern symbol → link +/// failure (`__getVisibleLeafColumns`). Refs #5141. +pub(super) fn is_relative_specifier(import_source: &str) -> bool { + import_source.starts_with("./") + || import_source.starts_with("../") + || import_source == "." + || import_source == ".." +} + /// Resolve an import specifier to a file path pub(super) fn resolve_import( import_source: &str, @@ -938,11 +950,8 @@ pub(super) fn resolve_import( None }; - // Handle relative imports (./ or ../) - if import_source.starts_with("./") - || import_source.starts_with("../") - || subpath_import_target.is_some() - { + // Handle relative imports (./ or ../, plus bare "." / ".." directory imports) + if is_relative_specifier(import_source) || subpath_import_target.is_some() { if let Some(canonical) = subpath_import_target .or_else(|| resolve_relative_import_path(import_source, importer_path)) {