1
- use std:: {
2
- collections:: { HashMap , HashSet } ,
3
- env, fs,
4
- path:: { Path , PathBuf } ,
5
- process,
6
- } ;
1
+ use std:: { env, process} ;
7
2
8
3
use anyhow:: Result ;
9
- use config :: get_compiler_options ;
10
- use css_parser :: { extract_classes , ClassName } ;
11
- use tsx_parser :: { extract_default_css_imports , extract_used_classes , UsedClassName } ;
12
- use utils :: { process_relative_import , replace_aliases } ;
4
+ use modules :: {
5
+ css_class :: get_class_body , defined_classes :: get_defined_classes , linter ,
6
+ styles_imports :: get_styles_imports ,
7
+ } ;
13
8
14
9
mod config;
15
- mod css_parser ;
16
- mod tsx_parser ;
10
+ mod modules ;
11
+ mod parsers ;
17
12
mod utils;
18
13
19
- fn list_files_in_directory ( path : PathBuf , exclude : Vec < String > ) -> Vec < String > {
20
- let mut files = Vec :: new ( ) ;
21
-
22
- if let Ok ( entries) = fs:: read_dir ( & path) {
23
- for entry in entries. flatten ( ) {
24
- let path = entry. path ( ) ;
25
-
26
- if path. is_dir ( ) {
27
- if let Some ( p) = path. file_name ( ) {
28
- let p_str = p. to_string_lossy ( ) ;
29
- if p_str. starts_with ( '.' ) || exclude. iter ( ) . any ( |i| p_str == * i) {
30
- continue ;
31
- }
32
- }
33
- files. extend ( list_files_in_directory ( path, exclude. clone ( ) ) ) ;
34
- } else if path. is_file ( ) {
35
- if let Some ( path_str) = path. to_str ( ) {
36
- files. push ( path_str. to_string ( ) ) ;
37
- }
38
- }
39
- }
40
- } else {
41
- eprintln ! ( "Cannot open target dir: {:?}" , path) ;
42
- }
43
-
44
- files
45
- }
46
-
47
14
fn main ( ) -> Result < ( ) > {
48
- const COLOR_BLUE : & str = "\x1b [34m" ;
49
- const COLOR_YELLOW : & str = "\x1b [33m" ;
50
- const COLOR_GREEN : & str = "\x1b [32m" ;
51
15
const COLOR_RED : & str = "\x1b [31m" ;
52
16
const COLOR_RESET : & str = "\u{001B} [0m" ;
53
17
54
18
let args: Vec < String > = env:: args ( ) . collect ( ) ;
19
+ if let Ok ( cwd) = std:: env:: var ( "cwd" ) {
20
+ env:: set_current_dir ( cwd) ?;
21
+ }
55
22
56
- let path = match args. get ( 1 ) {
23
+ match args. get ( 1 ) {
57
24
Some ( arg) if arg == "-v" => {
58
- println ! ( "v{}" , env!( "CARGO_PKG_VERSION" ) ) ;
25
+ print ! ( "v{}" , env!( "CARGO_PKG_VERSION" ) ) ;
59
26
process:: exit ( 0 ) ;
60
27
}
61
- Some ( arg) if arg == "--lint" => args. get ( 2 ) . unwrap_or_else ( || {
62
- eprintln ! (
63
- "\n {}Error{}: Linting path must be specified" ,
64
- COLOR_RED , COLOR_RESET
65
- ) ;
66
- process:: exit ( 1 ) ;
67
- } ) ,
28
+ Some ( arg) if arg == "--lint" => linter:: lint ( ) ?,
29
+ Some ( arg) if arg == "--imports" => get_styles_imports ( ) ?,
30
+ Some ( arg) if arg == "--classes" => get_defined_classes ( ) ?,
31
+ Some ( arg) if arg == "--class" => get_class_body ( ) ?,
68
32
Some ( arg) => {
69
33
eprintln ! (
70
34
"{}Error{}: Invalid argument: {}" ,
@@ -75,178 +39,5 @@ fn main() -> Result<()> {
75
39
None => todo ! ( ) ,
76
40
} ;
77
41
78
- let minify = args. get ( 3 ) . map_or ( "" , |v| v) == "--minify" ;
79
-
80
- if let Err ( e) = env:: set_current_dir ( Path :: new ( path) ) {
81
- eprintln ! (
82
- "\n {}Error{}: Failed to set current directory: {}" ,
83
- COLOR_RED , COLOR_RESET , e
84
- ) ;
85
- process:: exit ( 1 ) ;
86
- }
87
- let tsconfig = get_compiler_options ( ) . unwrap_or_else ( |e| {
88
- eprintln ! (
89
- "\n {}Error{}: Could not load tsconfig.json. Is the provided directory a typescript project? ({})" ,
90
- COLOR_RED , COLOR_RESET , e
91
- ) ;
92
- process:: exit ( 1 ) ;
93
- } ) ;
94
-
95
- let dir = list_files_in_directory ( Path :: new ( "." ) . to_path_buf ( ) , tsconfig. exclude ) ;
96
-
97
- let mut used_classnames: HashMap < String , HashSet < UsedClassName > > = Default :: default ( ) ;
98
- let mut defined_classnames: HashMap < String , HashSet < ClassName > > = Default :: default ( ) ;
99
-
100
- for entry in & dir {
101
- let path = entry. replace ( "\\ " , "/" ) ;
102
-
103
- if path. ends_with ( ".tsx" ) {
104
- let code = fs:: read_to_string ( entry) ?;
105
- let imported_css = extract_default_css_imports ( & code) . unwrap_or_else ( |e| {
106
- eprintln ! ( "Could not parse file: {}\n {}" , entry, e) ;
107
- process:: exit ( 1 ) ;
108
- } ) ;
109
-
110
- for ( mut style_path, class_names) in imported_css {
111
- process_relative_import ( Path :: new ( entry) , & mut style_path) ?;
112
- replace_aliases ( & mut style_path, tsconfig. compiler_options . paths . clone ( ) ) ;
113
-
114
- let used_fields = extract_used_classes ( & code, & class_names, path. clone ( ) )
115
- . unwrap_or_else ( |e| {
116
- eprintln ! ( "Could not parse file: {}\n {}" , entry, e) ;
117
- process:: exit ( 1 ) ;
118
- } ) ;
119
-
120
- used_classnames
121
- . entry ( style_path)
122
- . or_insert_with ( HashSet :: new)
123
- . extend ( used_fields) ;
124
- }
125
- } else if path. ends_with ( ".module.css" ) {
126
- let code = fs:: read_to_string ( entry) ?;
127
- let classes = extract_classes ( & code) ;
128
- defined_classnames
129
- . entry ( path)
130
- . or_insert_with ( HashSet :: new)
131
- . extend ( classes) ;
132
- }
133
- }
134
-
135
- let mut files_count = 0 ;
136
- let mut errors_count = 0 ;
137
-
138
- for ( css_file, mut classes_tsx) in defined_classnames. clone ( ) {
139
- if let Some ( used_css) = used_classnames. get ( & css_file) {
140
- let used_css_flatten: Vec < String > =
141
- used_css. iter ( ) . map ( |v| v. class_name . clone ( ) ) . collect ( ) ;
142
- classes_tsx. retain ( |v| !used_css_flatten. contains ( & v. class_name ) ) ;
143
- }
144
-
145
- if classes_tsx. is_empty ( ) {
146
- continue ;
147
- }
148
-
149
- files_count += 1 ;
150
- errors_count += classes_tsx. len ( ) ;
151
-
152
- if !minify {
153
- println ! ( "{}{}{}" , COLOR_BLUE , css_file, COLOR_RESET ) ;
154
- }
155
-
156
- for extra in classes_tsx {
157
- if !minify {
158
- println ! (
159
- "{}{}:{} {}Warn{}: Unused class `{}` found." ,
160
- COLOR_YELLOW ,
161
- extra. line_index + 1 ,
162
- extra. column_index + 1 ,
163
- COLOR_YELLOW ,
164
- COLOR_RESET ,
165
- extra. class_name
166
- ) ;
167
- } else {
168
- println ! (
169
- "{}:{}:{}:{}:\" {}\" : Unused class found." ,
170
- css_file,
171
- extra. line_index + 1 ,
172
- extra. column_index + 1 ,
173
- extra. class_name. len( ) ,
174
- extra. class_name
175
- ) ;
176
- }
177
- }
178
-
179
- if !minify {
180
- println ! ( ) ;
181
- }
182
- }
183
-
184
- let mut undefined_classes: HashMap < String , HashSet < UsedClassName > > = HashMap :: new ( ) ;
185
-
186
- for ( tsx_file, mut classes) in used_classnames {
187
- if let Some ( defined_css) = defined_classnames. get ( & tsx_file) {
188
- let defined_css: HashSet < String > =
189
- defined_css. iter ( ) . map ( |v| v. class_name . clone ( ) ) . collect ( ) ;
190
- classes. retain ( |v| !defined_css. contains ( v. class_name . as_str ( ) ) ) ;
191
- }
192
-
193
- if classes. is_empty ( ) {
194
- continue ;
195
- }
196
-
197
- files_count += 1 ;
198
- errors_count += classes. len ( ) ;
199
-
200
- for extra in classes {
201
- undefined_classes
202
- . entry ( extra. file_name . clone ( ) )
203
- . or_insert_with ( HashSet :: new)
204
- . insert ( extra) ;
205
- }
206
- }
207
-
208
- for undefined in undefined_classes {
209
- if !minify {
210
- println ! ( "{}{}{}" , COLOR_BLUE , undefined. 0 , COLOR_RESET ) ;
211
- }
212
- for extra in undefined. 1 {
213
- if !minify {
214
- println ! (
215
- "{}{}:{} {}Warn{}: Undefined class `{}` was used." ,
216
- COLOR_YELLOW ,
217
- extra. line,
218
- extra. column + 1 ,
219
- COLOR_YELLOW ,
220
- COLOR_RESET ,
221
- extra. class_name
222
- ) ;
223
- } else {
224
- println ! (
225
- "{}:{}:{}:{}:\" {}\" : Undefined class was used." ,
226
- undefined. 0 ,
227
- extra. line,
228
- extra. column + 1 ,
229
- extra. class_name. len( ) ,
230
- extra. class_name
231
- ) ;
232
- }
233
- }
234
-
235
- if !minify {
236
- println ! ( ) ;
237
- }
238
- }
239
-
240
- if !minify {
241
- if errors_count == 0 {
242
- println ! ( "{}✔{} No CSS lint warnings found" , COLOR_GREEN , COLOR_RESET ) ;
243
- } else {
244
- println ! (
245
- "Found {}{} warnings{} in {} files" ,
246
- COLOR_YELLOW , errors_count, COLOR_RESET , files_count
247
- ) ;
248
- }
249
- }
250
-
251
42
Ok ( ( ) )
252
43
}
0 commit comments