@@ -27,13 +27,58 @@ const findReactDeclarationWithDefaultImport = (
27
27
return undefined ;
28
28
} ;
29
29
30
+ function createFixer ( context : Rule . RuleContext , source : SourceCode , options : Options ) {
31
+ return function * fix ( fixer : Rule . RuleFixer ) {
32
+ const pragma = options . runtime === 'classic' ? '@jsx jsx' : '@jsxImportSource @compiled/react' ;
33
+ const reactImport = findReactDeclarationWithDefaultImport ( source ) ;
34
+ if ( reactImport ) {
35
+ const [ declaration , defaultImport ] = reactImport ;
36
+ const [ defaultImportVariable ] = context . getDeclaredVariables ( defaultImport ) ;
37
+
38
+ if ( defaultImportVariable && defaultImportVariable . references . length === 0 ) {
39
+ if ( declaration . specifiers . length === 1 ) {
40
+ // Only the default specifier exists and it isn't used - remove the whole declaration!
41
+ yield fixer . remove ( declaration ) ;
42
+ } else {
43
+ // Multiple specifiers exist but the default one isn't used - remove the default specifier!
44
+ yield fixer . replaceText ( declaration , removeImportFromDeclaration ( declaration , [ ] ) ) ;
45
+ }
46
+ }
47
+ }
48
+
49
+ yield fixer . insertTextBefore ( source . ast . body [ 0 ] , `/** ${ pragma } */\n` ) ;
50
+
51
+ const compiledImports = findCompiledImportDeclarations ( context ) ;
52
+
53
+ if ( options . runtime === 'classic' && ! findDeclarationWithImport ( compiledImports , 'jsx' ) ) {
54
+ // jsx import is missing time to add one
55
+ if ( compiledImports . length === 0 ) {
56
+ // No import exists, add a new one!
57
+ yield fixer . insertTextBefore (
58
+ source . ast . body [ 0 ] ,
59
+ "import { jsx } from '@compiled/react';\n"
60
+ ) ;
61
+ } else {
62
+ // An import exists with no JSX! Let's add one to the first found.
63
+ const [ firstCompiledImport ] = compiledImports ;
64
+
65
+ yield fixer . replaceText (
66
+ firstCompiledImport ,
67
+ addImportToDeclaration ( firstCompiledImport , [ 'jsx' ] )
68
+ ) ;
69
+ }
70
+ }
71
+ } ;
72
+ }
73
+
30
74
export const jsxPragmaRule : Rule . RuleModule = {
31
75
meta : {
32
76
docs : {
33
77
url : 'https://github.com/atlassian-labs/compiled/tree/master/packages/eslint-plugin/src/rules/jsx-pragma' ,
34
78
} ,
35
79
fixable : 'code' ,
36
80
messages : {
81
+ missingPragmaXCSS : 'Applying xcss prop to className requires the jsx pragma in scope.' ,
37
82
missingPragma : 'To use the `css` prop you must set the {{ pragma }} pragma.' ,
38
83
preferJsxImportSource :
39
84
'Use of the jsxImportSource pragma (automatic runtime) is preferred over the jsx pragma (classic runtime).' ,
@@ -121,66 +166,38 @@ export const jsxPragmaRule: Rule.RuleModule = {
121
166
}
122
167
} ,
123
168
169
+ 'JSXOpeningElement[name.name=/^[a-z]+$/] > JSXAttribute[name.name=/^className$/]' : (
170
+ node : Rule . Node
171
+ ) => {
172
+ if ( node . type !== 'JSXAttribute' || jsxPragma || jsxImportSourcePragma ) {
173
+ return ;
174
+ }
175
+
176
+ if (
177
+ node . value ?. type === 'JSXExpressionContainer' &&
178
+ node . value . expression . type === 'Identifier' &&
179
+ / [ X x ] c s s $ / . test ( node . value . expression . name )
180
+ ) {
181
+ context . report ( {
182
+ node,
183
+ messageId : 'missingPragmaXCSS' ,
184
+ fix : createFixer ( context , source , options ) ,
185
+ } ) ;
186
+ }
187
+ } ,
188
+
124
189
JSXAttribute ( node : any ) {
125
190
if ( jsxPragma || jsxImportSourcePragma || node . name . name !== 'css' ) {
126
191
return ;
127
192
}
128
193
129
- const pragma =
130
- options . runtime === 'classic' ? '@jsx jsx' : '@jsxImportSource @compiled/react' ;
131
-
132
194
context . report ( {
133
195
messageId : 'missingPragma' ,
134
196
data : {
135
197
pragma : options . runtime === 'classic' ? 'jsx' : 'jsxImportSource' ,
136
198
} ,
137
199
node,
138
- * fix ( fixer ) {
139
- const reactImport = findReactDeclarationWithDefaultImport ( source ) ;
140
- if ( reactImport ) {
141
- const [ declaration , defaultImport ] = reactImport ;
142
- const [ defaultImportVariable ] = context . getDeclaredVariables ( defaultImport ) ;
143
-
144
- if ( defaultImportVariable && defaultImportVariable . references . length === 0 ) {
145
- if ( declaration . specifiers . length === 1 ) {
146
- // Only the default specifier exists and it isn't used - remove the whole declaration!
147
- yield fixer . remove ( declaration ) ;
148
- } else {
149
- // Multiple specifiers exist but the default one isn't used - remove the default specifier!
150
- yield fixer . replaceText (
151
- declaration ,
152
- removeImportFromDeclaration ( declaration , [ ] )
153
- ) ;
154
- }
155
- }
156
- }
157
-
158
- yield fixer . insertTextBefore ( source . ast . body [ 0 ] , `/** ${ pragma } */\n` ) ;
159
-
160
- const compiledImports = findCompiledImportDeclarations ( context ) ;
161
-
162
- if (
163
- options . runtime === 'classic' &&
164
- ! findDeclarationWithImport ( compiledImports , 'jsx' )
165
- ) {
166
- // jsx import is missing time to add one
167
- if ( compiledImports . length === 0 ) {
168
- // No import exists, add a new one!
169
- yield fixer . insertTextBefore (
170
- source . ast . body [ 0 ] ,
171
- "import { jsx } from '@compiled/react';\n"
172
- ) ;
173
- } else {
174
- // An import exists with no JSX! Let's add one to the first found.
175
- const [ firstCompiledImport ] = compiledImports ;
176
-
177
- yield fixer . replaceText (
178
- firstCompiledImport ,
179
- addImportToDeclaration ( firstCompiledImport , [ 'jsx' ] )
180
- ) ;
181
- }
182
- }
183
- } ,
200
+ fix : createFixer ( context , source , options ) ,
184
201
} ) ;
185
202
} ,
186
203
} ;
0 commit comments