Repository: vercel/next.js
Pull request: Turbopack: better errors for strip_prefix_len

To help debugging

Closes PACK-5685

Changed files:
filename: turbopack/crates/turbopack-core/src/resolve/alias_map.rs
patch: @@ -610,7 +610,9 @@ where
 
                         if is_match {
                             let mut remaining = self.request.clone();
-                            remaining.strip_prefix_len(prefix.len());
+                            if let Err(e) = remaining.strip_prefix_len(prefix.len()) {
+                                return Some(Err(e.context(self.request.describe_as_string())));
+                            }
                             remaining.strip_suffix_len(suffix.len());
 
                             let output = template.replace(&remaining);

filename: turbopack/crates/turbopack-core/src/resolve/pattern.rs
patch: @@ -4,7 +4,7 @@ use std::{
     sync::LazyLock,
 };
 
-use anyhow::Result;
+use anyhow::{Result, bail};
 use regex::Regex;
 use rustc_hash::{FxHashMap, FxHashSet};
 use serde::{Deserialize, Serialize};
@@ -227,18 +227,18 @@ impl Pattern {
         longest_common_suffix(&strings)
     }
 
-    pub fn strip_prefix(&self, prefix: &str) -> Option<Self> {
+    pub fn strip_prefix(&self, prefix: &str) -> Result<Option<Self>> {
         if self.must_match(prefix) {
             let mut pat = self.clone();
-            pat.strip_prefix_len(prefix.len());
-            Some(pat)
+            pat.strip_prefix_len(prefix.len())?;
+            Ok(Some(pat))
         } else {
-            None
+            Ok(None)
         }
     }
 
-    pub fn strip_prefix_len(&mut self, len: usize) {
-        fn strip_prefix_internal(pattern: &mut Pattern, chars_to_strip: &mut usize) {
+    pub fn strip_prefix_len(&mut self, len: usize) -> Result<()> {
+        fn strip_prefix_internal(pattern: &mut Pattern, chars_to_strip: &mut usize) -> Result<()> {
             match pattern {
                 Pattern::Constant(c) => {
                     let c_len = c.len();
@@ -252,38 +252,45 @@ impl Pattern {
                 Pattern::Concatenation(list) => {
                     for c in list {
                         if *chars_to_strip > 0 {
-                            strip_prefix_internal(c, chars_to_strip);
+                            strip_prefix_internal(c, chars_to_strip)?;
                         }
                     }
                 }
                 Pattern::Alternatives(_) => {
-                    panic!("for strip_prefix a Pattern must be normalized");
+                    bail!("strip_prefix pattern must be normalized");
                 }
                 Pattern::Dynamic | Pattern::DynamicNoSlash => {
-                    panic!("strip_prefix prefix is too long");
+                    bail!("strip_prefix prefix is too long");
                 }
             }
+            Ok(())
         }
 
         match &mut *self {
             c @ Pattern::Constant(_) | c @ Pattern::Concatenation(_) => {
                 let mut len_local = len;
-                strip_prefix_internal(c, &mut len_local);
+                strip_prefix_internal(c, &mut len_local)?;
             }
             Pattern::Alternatives(list) => {
                 for c in list {
                     let mut len_local = len;
-                    strip_prefix_internal(c, &mut len_local);
+                    strip_prefix_internal(c, &mut len_local)?;
                 }
             }
             Pattern::Dynamic | Pattern::DynamicNoSlash => {
                 if len > 0 {
-                    panic!("strip_prefix prefix is too long");
+                    bail!(
+                        "strip_prefix prefix ({}) is too long: {}",
+                        len,
+                        self.describe_as_string()
+                    );
                 }
             }
         };
 
-        self.normalize()
+        self.normalize();
+
+        Ok(())
     }
 
     pub fn strip_suffix_len(&mut self, len: usize) {
@@ -2164,7 +2171,7 @@ mod tests {
     #[test]
     fn strip_prefix() {
         fn strip(mut pat: Pattern, n: usize) -> Pattern {
-            pat.strip_prefix_len(n);
+            pat.strip_prefix_len(n).unwrap();
             pat
         }
 

filename: turbopack/crates/turbopack-resolve/src/typescript.rs
patch: @@ -426,7 +426,7 @@ pub async fn type_resolve(
         fragment: _,
     } = &*request.await?
     {
-        let mut m = if let Some(mut stripped) = m.strip_prefix("@") {
+        let mut m = if let Some(mut stripped) = m.strip_prefix("@")? {
             stripped.replace_constants(&|c| Some(Pattern::Constant(c.replace("/", "__").into())));
             stripped
         } else {