@@ -97,9 +97,63 @@ impl ContentEq for SourceType {
9797 }
9898}
9999
100- /// Valid file extensions
100+ /// Valid file extensions.
101101pub const VALID_EXTENSIONS : & [ & str ] = & [ "js" , "mjs" , "cjs" , "jsx" , "ts" , "mts" , "cts" , "tsx" ] ;
102102
103+ /// Valid file extension.
104+ #[ derive( Clone , Copy , PartialEq , Eq ) ]
105+ enum FileExtension {
106+ Js ,
107+ Mjs ,
108+ Cjs ,
109+ Jsx ,
110+ Ts ,
111+ Mts ,
112+ Cts ,
113+ Tsx ,
114+ }
115+
116+ impl FileExtension {
117+ fn from_str ( extension : & str ) -> Option < Self > {
118+ let file_ext = match extension {
119+ "js" => Self :: Js ,
120+ "mjs" => Self :: Mjs ,
121+ "cjs" => Self :: Cjs ,
122+ "jsx" => Self :: Jsx ,
123+ "ts" => Self :: Ts ,
124+ "mts" => Self :: Mts ,
125+ "cts" => Self :: Cts ,
126+ "tsx" => Self :: Tsx ,
127+ _ => return None ,
128+ } ;
129+ Some ( file_ext)
130+ }
131+ }
132+
133+ impl From < FileExtension > for SourceType {
134+ fn from ( file_ext : FileExtension ) -> SourceType {
135+ #[ allow( clippy:: enum_glob_use, clippy:: allow_attributes) ]
136+ use FileExtension :: * ;
137+
138+ let language = match file_ext {
139+ Js | Cjs | Mjs | Jsx => Language :: JavaScript ,
140+ Ts | Tsx | Mts | Cts => Language :: TypeScript ,
141+ } ;
142+
143+ let module_kind = match file_ext {
144+ Js | Tsx | Ts | Jsx | Mts | Mjs => ModuleKind :: Module ,
145+ Cjs | Cts => ModuleKind :: Script ,
146+ } ;
147+
148+ let variant = match file_ext {
149+ Js | Mjs | Cjs | Jsx | Tsx => LanguageVariant :: Jsx ,
150+ Ts | Mts | Cts => LanguageVariant :: Standard ,
151+ } ;
152+
153+ SourceType { language, module_kind, variant }
154+ }
155+ }
156+
103157impl SourceType {
104158 /// Creates a [`SourceType`] representing a regular [`JavaScript`] file.
105159 ///
@@ -450,28 +504,31 @@ impl SourceType {
450504 . and_then ( std:: ffi:: OsStr :: to_str)
451505 . ok_or_else ( || UnknownExtension :: new ( "Please provide a valid file name." ) ) ?;
452506
453- let extension = path
454- . as_ref ( )
455- . extension ( )
456- . and_then ( std:: ffi:: OsStr :: to_str)
457- . filter ( |s| VALID_EXTENSIONS . contains ( s) )
458- . ok_or_else ( || {
507+ let file_ext =
508+ path. as_ref ( ) . extension ( ) . and_then ( std:: ffi:: OsStr :: to_str) . and_then ( FileExtension :: from_str) . ok_or_else ( || {
459509 let path = path. as_ref ( ) . to_string_lossy ( ) ;
460510 UnknownExtension :: new (
461511 format ! ( "Please provide a valid file extension for {path}: .js, .mjs, .jsx or .cjs for JavaScript, or .ts, .d.ts, .mts, .cts or .tsx for TypeScript" ) ,
462512 )
463513 } ) ?;
464514
465- let mut source_type = Self :: from_extension ( extension ) ? ;
515+ let mut source_type = SourceType :: from ( file_ext ) ;
466516
467- #[ expect( clippy:: case_sensitive_file_extension_comparisons) ]
468- if match extension {
469- "ts" if file_name[ ..file_name. len ( ) - 3 ] . split ( '.' ) . rev ( ) . take ( 2 ) . any ( |c| c == "d" ) => {
470- true
517+ let is_dts = match file_ext {
518+ // https://www.typescriptlang.org/tsconfig/#allowArbitraryExtensions
519+ // `{file basename}.d.{extension}.ts`
520+ // https://github.com/microsoft/TypeScript/issues/50133
521+ FileExtension :: Ts => {
522+ file_name[ ..file_name. len ( ) - 3 ] . split ( '.' ) . rev ( ) . take ( 2 ) . any ( |c| c == "d" )
523+ }
524+ FileExtension :: Mts | FileExtension :: Cts =>
525+ {
526+ #[ expect( clippy:: case_sensitive_file_extension_comparisons) ]
527+ file_name[ ..file_name. len ( ) - 4 ] . ends_with ( ".d" )
471528 }
472- "mts" | "cts" if file_name[ ..file_name. len ( ) - 4 ] . ends_with ( ".d" ) => true ,
473529 _ => false ,
474- } {
530+ } ;
531+ if is_dts {
475532 source_type. language = Language :: TypeScriptDefinition ;
476533 }
477534
@@ -487,27 +544,10 @@ impl SourceType {
487544 /// "mts", "cts", "tsx". See [`VALID_EXTENSIONS`] for the list of valid
488545 /// extensions.
489546 pub fn from_extension ( extension : & str ) -> Result < Self , UnknownExtension > {
490- let module_kind = match extension {
491- "js" | "tsx" | "ts" | "jsx" | "mts" | "mjs" => ModuleKind :: Module ,
492- "cjs" | "cts" => ModuleKind :: Script ,
493- _ => return Err ( UnknownExtension :: new ( "Unknown extension." ) ) ,
494- } ;
495-
496- let language = match extension {
497- // https://www.typescriptlang.org/tsconfig/#allowArbitraryExtensions
498- // `{file basename}.d.{extension}.ts`
499- // https://github.com/microsoft/TypeScript/issues/50133
500- "js" | "cjs" | "mjs" | "jsx" => Language :: JavaScript ,
501- "ts" | "tsx" | "mts" | "cts" => Language :: TypeScript ,
502- _ => return Err ( UnknownExtension :: new ( "Unknown extension." ) ) ,
503- } ;
504-
505- let variant = match extension {
506- "js" | "mjs" | "cjs" | "jsx" | "tsx" => LanguageVariant :: Jsx ,
507- _ => LanguageVariant :: Standard ,
508- } ;
509-
510- Ok ( Self { language, module_kind, variant } )
547+ match FileExtension :: from_str ( extension) {
548+ Some ( file_ext) => Ok ( SourceType :: from ( file_ext) ) ,
549+ None => Err ( UnknownExtension :: new ( "Unknown extension." ) ) ,
550+ }
511551 }
512552}
513553
0 commit comments