// Copyright (c) 2026 The WebRTC project authors. All Rights Reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file in the root of the source // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. //! Path manipulation utilities for the WebRTC Rust macro. //! //! This module contains the pure string transformation logic used by the import //! macro. It is deliberately separated from the `proc_macro` crate file so that //! it can be cross-compiled and validated via native target-platform unit //! tests. /// Re-routes a source-relative GN absolute path string based on the build root /// prefix. /// /// # Arguments /// * `prefix` - The current build context prefix (e.g., `"//"` or /// `"//third_party/webrtc"`). /// * `path_str` - The raw GN label string literal passed into the macro. /// /// # Behavior /// - If `path_str` is a first-party absolute label (starts with `"//"`): /// - If `prefix` is `"//"`, the project is standalone; the path is left /// untouched. /// - If `prefix` is a subfolder (e.g., `"//third_party/webrtc"`): /// - If the remainder starts with a colon (e.g., `"//:target"`), it maps /// directly to the parent directory, so it concatenates without adding a /// slash (`//prefix:target`). /// - Otherwise, it maps down a nested subdirectory folder /// (`//prefix/path/to/target`). /// - Third-party or relative paths are returned completely unmodified. pub fn adjust_path(prefix: &str, path_str: &str) -> String { if path_str.starts_with("//") { if prefix == "//" { path_str.to_string() } else { // Remove trailing slash from prefix if present. let prefix = prefix.strip_suffix("/").unwrap_or(prefix); let remainder = &path_str[2..]; if remainder.starts_with(':') { format!("{}{}", prefix, remainder) } else { format!("{}/{}", prefix, remainder) } } } else { path_str.to_string() } } #[cfg(test)] mod tests { use super::*; /// Checks Standalone mode behavior where `WEBRTC_GN_PREFIX = "//"`. /// Verifies that absolute paths remain completely untouched. #[test] fn test_adjust_path_standalone() { assert_eq!(adjust_path("//", "//api/units:time_delta_rs"), "//api/units:time_delta_rs"); } /// Checks Vendor Prefix mode behavior (e.g., nested under Chromium). /// Verifies that `//third_party/webrtc` is successfully prepended onto /// first-party paths. #[test] fn test_adjust_path_chromium() { assert_eq!( adjust_path("//third_party/webrtc", "//api/units:time_delta_rs"), "//third_party/webrtc/api/units:time_delta_rs" ); } /// Checks third-party crate or target-relative imports. /// Verifies that paths not beginning with `//` pass through without /// alterations. #[test] fn test_adjust_path_relative() { assert_eq!( adjust_path("//third_party/webrtc", "api/units:time_delta_rs"), "api/units:time_delta_rs" ); } /// Checks the open-source explicit root-colon syntax (e.g., `"//:target"`). /// Verifies that the trailing slash is omitted right before the colon, /// avoiding invalid GN path expansion errors in the underlying token /// parser. #[test] fn test_adjust_path_with_colon() { assert_eq!( adjust_path("//third_party/webrtc", "//:webrtc_import_prefix_lib"), "//third_party/webrtc:webrtc_import_prefix_lib" ); } /// Removes trailing slash from a path string. #[test] fn test_remove_trailing_slash() { assert_eq!( adjust_path("//third_party/webrtc/", "//:webrtc_import_prefix_lib"), "//third_party/webrtc:webrtc_import_prefix_lib" ); } }