1- use std:: { borrow:: Cow , path :: Path , sync:: Arc } ;
1+ use std:: { borrow:: Cow , sync:: Arc } ;
22
33use once_cell:: sync:: Lazy ;
44use regex:: Regex ;
@@ -73,6 +73,9 @@ static ELEMENT_SPLIT_REGEX: Lazy<Regex> =
7373
7474const HYPHEN : char = '-' ;
7575const EXCLAMATION : char = '!' ;
76+ const DOT : char = '.' ;
77+ const SLASH : char = '/' ;
78+ const QUESTION_MARK : char = '?' ;
7679
7780impl NormalModuleFactory {
7881 pub fn new (
@@ -126,93 +129,83 @@ impl NormalModuleFactory {
126129 . expect ( "should be module dependency" ) ;
127130 let importer = data. issuer_identifier . as_ref ( ) ;
128131 let raw_request = dependency. request ( ) . to_owned ( ) ;
129- let mut request_without_match_resource = dependency. request ( ) ;
130132
131133 let mut file_dependencies = Default :: default ( ) ;
132134 let mut missing_dependencies = Default :: default ( ) ;
133135
134136 let plugin_driver = & self . plugin_driver ;
135137 let loader_resolver = self . get_loader_resolver ( ) ;
136138
137- let mut match_resource_data: Option < ResourceData > = None ;
139+ let mut match_resource_data = None ;
138140 let mut match_module_type = None ;
139- let mut inline_loaders: Vec < ModuleRuleUseLoader > = vec ! [ ] ;
141+ let mut inline_loaders = vec ! [ ] ;
140142 let mut no_pre_auto_loaders = false ;
141143 let mut no_auto_loaders = false ;
142144 let mut no_pre_post_auto_loaders = false ;
143145
144- request_without_match_resource = {
145- let match_resource_match = MATCH_RESOURCE_REGEX . captures ( request_without_match_resource) ;
146- if let Some ( m) = match_resource_match {
147- let mut match_resource: String = m
148- . get ( 1 )
149- . expect ( "Should have match resource" )
150- . as_str ( )
151- . to_owned ( ) ;
152- let mut chars = match_resource. chars ( ) ;
153- let first_char = chars. next ( ) ;
154- let second_char = chars. next ( ) ;
155-
156- if matches ! ( first_char, Some ( '.' ) )
157- && ( matches ! ( second_char, Some ( '/' ) )
158- || ( matches ! ( second_char, Some ( '.' ) ) && matches ! ( chars. next( ) , Some ( '/' ) ) ) )
159- {
160- // if matchResources startsWith ../ or ./
161- match_resource = data
162- . context
163- . as_path ( )
164- . join ( match_resource)
165- . absolutize ( )
166- . to_string_lossy ( )
167- . to_string ( ) ;
168- }
146+ let mut scheme = get_scheme ( dependency. request ( ) ) ;
147+ let context_scheme = get_scheme ( data. context . as_ref ( ) ) ;
148+ let mut unresolved_resource = dependency. request ( ) ;
149+ if scheme. is_none ( ) {
150+ let mut request_without_match_resource = dependency. request ( ) ;
151+ request_without_match_resource = {
152+ if let Some ( m) = MATCH_RESOURCE_REGEX . captures ( request_without_match_resource) {
153+ let match_resource = {
154+ let resource = m. get ( 1 ) . expect ( "Should have match resource" ) . as_str ( ) ;
155+ let mut chars = resource. chars ( ) ;
156+ let first_char = chars. next ( ) ;
157+ let second_char = chars. next ( ) ;
158+
159+ if matches ! ( first_char, Some ( DOT ) )
160+ && ( matches ! ( second_char, Some ( SLASH ) )
161+ || ( matches ! ( second_char, Some ( DOT ) ) && matches ! ( chars. next( ) , Some ( SLASH ) ) ) )
162+ {
163+ // if matchResources startsWith ../ or ./
164+ data
165+ . context
166+ . as_path ( )
167+ . join ( resource)
168+ . absolutize ( )
169+ . to_string_lossy ( )
170+ . to_string ( )
171+ } else {
172+ resource. to_owned ( )
173+ }
174+ } ;
169175
170- let ResourceParsedData {
171- path,
172- query,
173- fragment,
174- } = parse_resource ( & match_resource) . expect ( "Should parse resource" ) ;
175- match_resource_data = Some (
176- ResourceData :: new ( match_resource, path)
177- . query_optional ( query)
178- . fragment_optional ( fragment) ,
179- ) ;
180-
181- // e.g. ./index.js!=!
182- let whole_matched = m. get ( 0 ) . expect ( "Whole matched" ) . as_str ( ) ;
183-
184- match request_without_match_resource
185- . char_indices ( )
186- . nth ( whole_matched. chars ( ) . count ( ) )
187- {
188- Some ( ( pos, _) ) => & request_without_match_resource[ pos..] ,
189- None => {
190- unreachable ! ( "Invalid dependency: {:?}" , & data. dependency)
176+ let ResourceParsedData {
177+ path,
178+ query,
179+ fragment,
180+ } = parse_resource ( & match_resource) . expect ( "Should parse resource" ) ;
181+ match_resource_data = Some (
182+ ResourceData :: new ( match_resource, path)
183+ . query_optional ( query)
184+ . fragment_optional ( fragment) ,
185+ ) ;
186+
187+ // e.g. ./index.js!=!
188+ let whole_matched = m
189+ . get ( 0 )
190+ . expect ( "should guaranteed to return a non-None value." )
191+ . as_str ( ) ;
192+
193+ match request_without_match_resource
194+ . char_indices ( )
195+ . nth ( whole_matched. chars ( ) . count ( ) )
196+ {
197+ Some ( ( pos, _) ) => & request_without_match_resource[ pos..] ,
198+ None => {
199+ unreachable ! ( "Invalid dependency: {:?}" , & data. dependency)
200+ }
191201 }
202+ } else {
203+ request_without_match_resource
192204 }
193- } else {
194- request_without_match_resource
195- }
196- } ;
197-
198- let scheme = get_scheme ( request_without_match_resource) ;
199- let context_scheme = get_scheme ( data. context . as_ref ( ) ) ;
205+ } ;
200206
201- // with scheme, windows absolute path is considered scheme by `url`
202- let resource_data =
203- if scheme != Scheme :: None && !Path :: is_absolute ( Path :: new ( request_without_match_resource) ) {
204- let mut resource_data =
205- ResourceData :: new ( request_without_match_resource. to_string ( ) , "" . into ( ) ) ;
206- // resource with scheme
207- plugin_driver
208- . normal_module_factory_hooks
209- . resolve_for_scheme
210- . call ( data, & mut resource_data)
211- . await ?;
212- resource_data
213- }
214- // TODO: resource within scheme, call resolveInScheme hook
215- else {
207+ scheme = get_scheme ( request_without_match_resource) ;
208+ if scheme. is_none ( ) && context_scheme. is_none ( ) {
216209 let mut request = request_without_match_resource. chars ( ) ;
217210 let first_char = request. next ( ) ;
218211 let second_char = request. next ( ) ;
@@ -245,7 +238,7 @@ impl NormalModuleFactory {
245238 ELEMENT_SPLIT_REGEX . split ( s) . collect :: < Vec < _ > > ( )
246239 } ;
247240
248- request_without_match_resource = raw_elements
241+ unresolved_resource = raw_elements
249242 . pop ( )
250243 . ok_or_else ( || error ! ( "Invalid request: {request_without_match_resource}" ) ) ?;
251244
@@ -267,75 +260,84 @@ impl NormalModuleFactory {
267260 } ) ,
268261 }
269262 } ) ) ;
263+ scheme = get_scheme ( unresolved_resource) ;
264+ } else {
265+ unresolved_resource = request_without_match_resource;
266+ }
267+ }
270268
271- if request_without_match_resource. is_empty ( )
272- || request_without_match_resource. starts_with ( '?' )
273- {
274- let ResourceParsedData {
275- path,
276- query,
277- fragment,
278- } = parse_resource ( request_without_match_resource) . expect ( "Should parse resource" ) ;
279- ResourceData :: new ( request_without_match_resource. to_string ( ) , path)
280- . query_optional ( query)
281- . fragment_optional ( fragment)
282- } else {
283- let optional = dependency. get_optional ( ) ;
269+ let resource_data = if scheme. is_some ( ) {
270+ // resource with scheme
271+ let mut resource_data = ResourceData :: new ( unresolved_resource. to_owned ( ) , "" . into ( ) ) ;
272+ // resource with scheme
273+ plugin_driver
274+ . normal_module_factory_hooks
275+ . resolve_for_scheme
276+ . call ( data, & mut resource_data)
277+ . await ?;
278+ resource_data
279+ } else {
280+ // TODO: resource within scheme
284281
285- let resolve_args = ResolveArgs {
286- importer,
287- issuer : data. issuer . as_deref ( ) ,
288- context : if context_scheme != Scheme :: None {
289- self . options . context . clone ( )
290- } else {
291- data. context . clone ( )
292- } ,
293- specifier : request_without_match_resource,
294- dependency_type : dependency. dependency_type ( ) ,
295- dependency_category : dependency. category ( ) ,
296- span : dependency. source_span ( ) ,
297- // take the options is safe here, because it
298- // is not used in after_resolve hooks
299- resolve_options : data. resolve_options . take ( ) ,
300- resolve_to_context : false ,
301- optional,
302- file_dependencies : & mut file_dependencies,
303- missing_dependencies : & mut missing_dependencies,
304- } ;
282+ // default resolve
283+ // resource without scheme and with path
284+ if unresolved_resource. is_empty ( ) || unresolved_resource. starts_with ( QUESTION_MARK ) {
285+ ResourceData :: new ( unresolved_resource. to_owned ( ) , "" . into ( ) )
286+ } else {
287+ let resolve_args = ResolveArgs {
288+ importer,
289+ issuer : data. issuer . as_deref ( ) ,
290+ context : if context_scheme != Scheme :: None {
291+ self . options . context . clone ( )
292+ } else {
293+ data. context . clone ( )
294+ } ,
295+ specifier : unresolved_resource,
296+ dependency_type : dependency. dependency_type ( ) ,
297+ dependency_category : dependency. category ( ) ,
298+ span : dependency. source_span ( ) ,
299+ // take the options is safe here, because it
300+ // is not used in after_resolve hooks
301+ resolve_options : data. resolve_options . take ( ) ,
302+ resolve_to_context : false ,
303+ optional : dependency. get_optional ( ) ,
304+ file_dependencies : & mut file_dependencies,
305+ missing_dependencies : & mut missing_dependencies,
306+ } ;
305307
306- // default resolve
307- let resource_data = resolve ( resolve_args, plugin_driver) . await ;
308+ // default resolve
309+ let resource_data = resolve ( resolve_args, plugin_driver) . await ;
308310
309- match resource_data {
310- Ok ( ResolveResult :: Resource ( resource) ) => {
311- let uri = resource. full_path ( ) . display ( ) . to_string ( ) ;
312- ResourceData :: new ( uri, resource. path )
313- . query ( resource. query )
314- . fragment ( resource. fragment )
315- . description_optional ( resource. description_data )
316- }
317- Ok ( ResolveResult :: Ignored ) => {
318- let ident = format ! ( "{}/{}" , & data. context, request_without_match_resource) ;
319- let module_identifier = ModuleIdentifier :: from ( format ! ( "ignored|{ident}" ) ) ;
320-
321- let raw_module = RawModule :: new (
322- "/* (ignored) */" . to_owned ( ) ,
323- module_identifier,
324- format ! ( "{ident} (ignored)" ) ,
325- Default :: default ( ) ,
326- )
327- . boxed ( ) ;
328-
329- return Ok ( Some ( ModuleFactoryResult :: new_with_module ( raw_module) ) ) ;
330- }
331- Err ( err) => {
332- data. add_file_dependencies ( file_dependencies) ;
333- data. add_missing_dependencies ( missing_dependencies) ;
334- return Err ( err) ;
335- }
311+ match resource_data {
312+ Ok ( ResolveResult :: Resource ( resource) ) => {
313+ let uri = resource. full_path ( ) . display ( ) . to_string ( ) ;
314+ ResourceData :: new ( uri, resource. path )
315+ . query ( resource. query )
316+ . fragment ( resource. fragment )
317+ . description_optional ( resource. description_data )
318+ }
319+ Ok ( ResolveResult :: Ignored ) => {
320+ let ident = format ! ( "{}/{}" , & data. context, unresolved_resource) ;
321+ let module_identifier = ModuleIdentifier :: from ( format ! ( "ignored|{ident}" ) ) ;
322+
323+ let raw_module = RawModule :: new (
324+ "/* (ignored) */" . to_owned ( ) ,
325+ module_identifier,
326+ format ! ( "{ident} (ignored)" ) ,
327+ Default :: default ( ) ,
328+ )
329+ . boxed ( ) ;
330+
331+ return Ok ( Some ( ModuleFactoryResult :: new_with_module ( raw_module) ) ) ;
332+ }
333+ Err ( err) => {
334+ data. add_file_dependencies ( file_dependencies) ;
335+ data. add_missing_dependencies ( missing_dependencies) ;
336+ return Err ( err) ;
336337 }
337338 }
338- } ;
339+ }
340+ } ;
339341
340342 let resolved_module_rules = if let Some ( match_resource_data) = & mut match_resource_data
341343 && let Some ( captures) = MATCH_WEBPACK_EXT_REGEX . captures ( & match_resource_data. resource )
0 commit comments