1- use cow_utils:: CowUtils ;
21use oxc_ast:: {
32 AstKind ,
43 ast:: { JSXAttributeItem , JSXAttributeName } ,
@@ -24,38 +23,36 @@ pub struct TextEncodingIdentifierCase;
2423declare_oxc_lint ! (
2524 /// ### What it does
2625 ///
27- /// This rule aims to enforce consistent case for text encoding identifiers.
28- ///
29- /// Enforces `'utf8'` for UTF-8 encoding
30- /// Enforces `'ascii'` for ASCII encoding.
26+ /// This rule enforces consistent casing for text encoding identifiers, specifically:
27+ /// - `'utf8'` instead of `'UTF-8'` or `'utf-8'`
28+ /// - `'ascii'` instead of `'ASCII'`
3129 ///
3230 /// ### Why is this bad?
3331 ///
34- /// - Inconsistency in text encoding identifiers can make the code harder to read and understand.
35- /// - The ECMAScript specification does not define the case sensitivity of text encoding identifiers, but it is common practice to use lowercase.
32+ /// Inconsistent casing of encoding identifiers reduces code readability and
33+ /// can lead to subtle confusion across a codebase. Although casing is not
34+ /// strictly enforced by ECMAScript or Node.js, using lowercase is the
35+ /// conventional and widely recognized style.
3636 ///
3737 /// ### Examples
3838 ///
3939 /// Examples of **incorrect** code for this rule:
4040 /// ```javascript
4141 /// import fs from 'node:fs/promises';
4242 /// async function bad() {
43- /// await fs.readFile(file, 'UTF-8');
44- ///
45- /// await fs.readFile(file, 'ASCII');
46- ///
47- /// const string = buffer.toString('utf-8');
43+ /// await fs.readFile(file, 'UTF-8');
44+ /// await fs.readFile(file, 'ASCII');
45+ /// const string = buffer.toString('utf-8');
4846 /// }
4947 /// ```
5048 ///
5149 /// Examples of **correct** code for this rule:
5250 /// ```javascript
51+ /// import fs from 'node:fs/promises';
5352 /// async function good() {
54- /// await fs.readFile(file, 'utf8');
55- ///
56- /// await fs.readFile(file, 'ascii');
57- ///
58- /// const string = buffer.toString('utf8');
53+ /// await fs.readFile(file, 'utf8');
54+ /// await fs.readFile(file, 'ascii');
55+ /// const string = buffer.toString('utf8');
5956 /// }
6057 /// ```
6158 TextEncodingIdentifierCase ,
@@ -67,79 +64,50 @@ declare_oxc_lint!(
6764impl Rule for TextEncodingIdentifierCase {
6865 fn run < ' a > ( & self , node : & AstNode < ' a > , ctx : & LintContext < ' a > ) {
6966 let ( s, span) = match node. kind ( ) {
70- AstKind :: StringLiteral ( string_lit) => ( & string_lit. value , string_lit. span ) ,
71- AstKind :: JSXText ( jsx_text) => ( & jsx_text. value , jsx_text. span ) ,
72- _ => {
73- return ;
74- }
67+ AstKind :: StringLiteral ( string_lit) => ( string_lit. value . as_str ( ) , string_lit. span ) ,
68+ AstKind :: JSXText ( jsx_text) => ( jsx_text. value . as_str ( ) , jsx_text. span ) ,
69+ _ => return ,
7570 } ;
76- let s = s. as_str ( ) ;
77-
7871 if s == "utf-8" && is_jsx_meta_elem_with_charset_attr ( node. id ( ) , ctx) {
7972 return ;
8073 }
81-
82- let Some ( replacement) = get_replacement ( s) else {
74+ let replacement = if s. eq_ignore_ascii_case ( "utf8" ) || s. eq_ignore_ascii_case ( "utf-8" ) {
75+ "utf8"
76+ } else if s. eq_ignore_ascii_case ( "ascii" ) {
77+ "ascii"
78+ } else {
8379 return ;
8480 } ;
85-
86- if replacement == s {
87- return ;
81+ if replacement != s {
82+ ctx. diagnostic_with_fix (
83+ text_encoding_identifier_case_diagnostic ( span, replacement, s) ,
84+ |fixer| fixer. replace ( Span :: new ( span. start + 1 , span. end - 1 ) , replacement) ,
85+ ) ;
8886 }
89-
90- ctx. diagnostic_with_fix (
91- text_encoding_identifier_case_diagnostic ( span, replacement, s) ,
92- |fixer| fixer. replace ( Span :: new ( span. start + 1 , span. end - 1 ) , replacement) ,
93- ) ;
94- }
95- }
96-
97- fn get_replacement ( node : & str ) -> Option < & ' static str > {
98- if !matches ! ( node. len( ) , 4 | 5 ) {
99- return None ;
10087 }
101-
102- let node_lower = node. cow_to_ascii_lowercase ( ) ;
103-
104- if node_lower == "utf-8" || node_lower == "utf8" {
105- return Some ( "utf8" ) ;
106- }
107-
108- if node_lower == "ascii" {
109- return Some ( "ascii" ) ;
110- }
111-
112- None
11388}
11489
11590fn is_jsx_meta_elem_with_charset_attr ( id : NodeId , ctx : & LintContext ) -> bool {
11691 let Some ( parent) = ctx. nodes ( ) . parent_node ( id) else {
11792 return false ;
11893 } ;
119-
12094 let AstKind :: JSXAttributeItem ( JSXAttributeItem :: Attribute ( jsx_attr) ) = parent. kind ( ) else {
12195 return false ;
12296 } ;
123-
12497 let JSXAttributeName :: Identifier ( ident) = & jsx_attr. name else {
12598 return false ;
12699 } ;
127100 if !ident. name . eq_ignore_ascii_case ( "charset" ) {
128101 return false ;
129102 }
130-
131103 let Some ( AstKind :: JSXOpeningElement ( opening_elem) ) = ctx. nodes ( ) . parent_kind ( parent. id ( ) )
132104 else {
133105 return false ;
134106 } ;
135-
136- let Some ( tag_name) = opening_elem. name . get_identifier_name ( ) else { return false } ;
137-
138- if !tag_name. eq_ignore_ascii_case ( "meta" ) {
139- return false ;
140- }
141-
142- true
107+ opening_elem
108+ . name
109+ . get_identifier_name ( )
110+ . is_some_and ( |tag_name| tag_name. eq_ignore_ascii_case ( "meta" ) )
143111}
144112
145113#[ test]
0 commit comments