2
2
3
3
use std:: path:: Path ;
4
4
5
+ use url:: Url ;
5
6
use wdl_analysis:: types:: PrimitiveType ;
6
7
use wdl_ast:: Diagnostic ;
7
8
@@ -21,32 +22,45 @@ use crate::Value;
21
22
///
22
23
/// https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#basename
23
24
fn basename ( context : CallContext < ' _ > ) -> Result < Value , Diagnostic > {
25
+ fn remove_suffix < ' a > ( context : CallContext < ' _ > , base : & ' a str ) -> & ' a str {
26
+ if context. arguments . len ( ) == 2 {
27
+ base. strip_suffix (
28
+ context
29
+ . coerce_argument ( 1 , PrimitiveType :: String )
30
+ . unwrap_string ( )
31
+ . as_str ( ) ,
32
+ )
33
+ . unwrap_or ( base)
34
+ } else {
35
+ base
36
+ }
37
+ }
38
+
24
39
debug_assert ! ( !context. arguments. is_empty( ) && context. arguments. len( ) < 3 ) ;
25
40
debug_assert ! ( context. return_type_eq( PrimitiveType :: String ) ) ;
26
41
27
42
let path = context
28
43
. coerce_argument ( 0 , PrimitiveType :: String )
29
44
. unwrap_string ( ) ;
30
45
31
- match Path :: new ( path. as_str ( ) ) . file_name ( ) {
32
- Some ( base) => {
33
- let base = base. to_str ( ) . expect ( "should be UTF-8" ) ;
34
- let base = if context. arguments . len ( ) == 2 {
35
- base. strip_suffix (
36
- context
37
- . coerce_argument ( 1 , PrimitiveType :: String )
38
- . unwrap_string ( )
39
- . as_str ( ) ,
40
- )
41
- . unwrap_or ( base)
42
- } else {
43
- base
44
- } ;
45
-
46
- Ok ( PrimitiveValue :: new_string ( base) . into ( ) )
46
+ // Do not attempt to parse absolute Windows paths (and by extension, we do not
47
+ // support single-character schemed URLs)
48
+ if path. get ( 1 ..2 ) != Some ( ":" ) {
49
+ if let Ok ( url) = path. parse :: < Url > ( ) {
50
+ let base = url
51
+ . path_segments ( )
52
+ . and_then ( |mut segments| segments. next_back ( ) )
53
+ . unwrap_or ( "" ) ;
54
+
55
+ return Ok ( PrimitiveValue :: new_string ( remove_suffix ( context, base) ) . into ( ) ) ;
47
56
}
48
- None => Ok ( PrimitiveValue :: String ( path) . into ( ) ) ,
49
57
}
58
+
59
+ let base = Path :: new ( path. as_str ( ) )
60
+ . file_name ( )
61
+ . map ( |f| f. to_str ( ) . expect ( "should be UTF-8" ) )
62
+ . unwrap_or ( "" ) ;
63
+ Ok ( PrimitiveValue :: new_string ( remove_suffix ( context, base) ) . into ( ) )
50
64
}
51
65
52
66
/// Gets the function describing `basename`.
@@ -97,5 +111,47 @@ mod test {
97
111
. await
98
112
. unwrap ( ) ;
99
113
assert_eq ! ( value. unwrap_string( ) . as_str( ) , "file" ) ;
114
+
115
+ let value = eval_v1_expr ( & env, V1 :: Two , "basename('file.txt', '.jpg')" )
116
+ . await
117
+ . unwrap ( ) ;
118
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "file.txt" ) ;
119
+
120
+ let value = eval_v1_expr ( & env, V1 :: Two , "basename('https://example.com')" )
121
+ . await
122
+ . unwrap ( ) ;
123
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "" ) ;
124
+
125
+ let value = eval_v1_expr ( & env, V1 :: Two , "basename('https://example.com/foo')" )
126
+ . await
127
+ . unwrap ( ) ;
128
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "foo" ) ;
129
+
130
+ let value = eval_v1_expr (
131
+ & env,
132
+ V1 :: Two ,
133
+ "basename('https://example.com/foo/bar/baz.txt')" ,
134
+ )
135
+ . await
136
+ . unwrap ( ) ;
137
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "baz.txt" ) ;
138
+
139
+ let value = eval_v1_expr (
140
+ & env,
141
+ V1 :: Two ,
142
+ "basename('https://example.com/foo/bar/baz.txt?foo=baz', '.txt')" ,
143
+ )
144
+ . await
145
+ . unwrap ( ) ;
146
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "baz" ) ;
147
+
148
+ let value = eval_v1_expr (
149
+ & env,
150
+ V1 :: Two ,
151
+ "basename('https://example.com/foo/bar/baz.txt#hmm', '.jpg')" ,
152
+ )
153
+ . await
154
+ . unwrap ( ) ;
155
+ assert_eq ! ( value. unwrap_string( ) . as_str( ) , "baz.txt" ) ;
100
156
}
101
157
}
0 commit comments