@@ -8,6 +8,7 @@ const Components = require('../util/Components');
8
8
const docsUrl = require ( '../util/docsUrl' ) ;
9
9
const isAssignmentLHS = require ( '../util/ast' ) . isAssignmentLHS ;
10
10
const report = require ( '../util/report' ) ;
11
+ const testReactVersion = require ( '../util/version' ) . testReactVersion ;
11
12
12
13
const DEFAULT_OPTION = 'always' ;
13
14
@@ -94,6 +95,8 @@ module.exports = {
94
95
const destructureInSignature = ( context . options [ 1 ] && context . options [ 1 ] . destructureInSignature ) || 'ignore' ;
95
96
const sfcParams = createSFCParams ( ) ;
96
97
98
+ // set to save renamed var of useContext
99
+ const contextSet = new Set ( ) ;
97
100
/**
98
101
* @param {ASTNode } node We expect either an ArrowFunctionExpression,
99
102
* FunctionDeclaration, or FunctionExpression
@@ -128,7 +131,7 @@ module.exports = {
128
131
function handleSFCUsage ( node ) {
129
132
const propsName = sfcParams . propsName ( ) ;
130
133
const contextName = sfcParams . contextName ( ) ;
131
- // props.aProp || context.aProp
134
+ // props.aProp
132
135
const isPropUsed = (
133
136
( propsName && node . object . name === propsName )
134
137
|| ( contextName && node . object . name === contextName )
@@ -142,6 +145,16 @@ module.exports = {
142
145
} ,
143
146
} ) ;
144
147
}
148
+
149
+ // const foo = useContext(aContext);
150
+ // foo.aProp
151
+ const isContextUsed = contextSet . has ( node . object . name ) && ! isAssignmentLHS ( node ) ;
152
+ if ( isContextUsed && configuration === 'always' ) {
153
+ context . report ( {
154
+ node,
155
+ message : `Must use destructuring ${ node . object . name } assignment` ,
156
+ } ) ;
157
+ }
145
158
}
146
159
147
160
function isInClassProperty ( node ) {
@@ -176,8 +189,9 @@ module.exports = {
176
189
}
177
190
}
178
191
179
- return {
192
+ const hasHooks = testReactVersion ( context , '>= 16.9' ) ;
180
193
194
+ return {
181
195
FunctionDeclaration : handleStatelessComponent ,
182
196
183
197
ArrowFunctionExpression : handleStatelessComponent ,
@@ -212,13 +226,29 @@ module.exports = {
212
226
const SFCComponent = components . get ( context . getScope ( node ) . block ) ;
213
227
214
228
const destructuring = ( node . init && node . id && node . id . type === 'ObjectPattern' ) ;
229
+ const identifier = ( node . init && node . id && node . id . type === 'Identifier' ) ;
215
230
// let {foo} = props;
216
- const destructuringSFC = destructuring && ( node . init . name === 'props' || node . init . name === 'context' ) ;
231
+ const destructuringSFC = destructuring && node . init . name === 'props' ;
232
+ // let {foo} = useContext(aContext);
233
+ const destructuringUseContext = hasHooks && destructuring && node . init . callee && node . init . callee . name === 'useContext' ;
234
+ // let foo = useContext(aContext);
235
+ const assignUseContext = hasHooks && identifier && node . init . callee && node . init . callee . name === 'useContext' ;
217
236
// let {foo} = this.props;
218
237
const destructuringClass = destructuring && node . init . object && node . init . object . type === 'ThisExpression' && (
219
238
node . init . property . name === 'props' || node . init . property . name === 'context' || node . init . property . name === 'state'
220
239
) ;
221
240
241
+ if ( SFCComponent && assignUseContext ) {
242
+ contextSet . add ( node . id . name ) ;
243
+ }
244
+
245
+ if ( SFCComponent && destructuringUseContext && configuration === 'never' ) {
246
+ context . report ( {
247
+ node,
248
+ message : `Must never use destructuring ${ node . init . callee . name } assignment` ,
249
+ } ) ;
250
+ }
251
+
222
252
if ( SFCComponent && destructuringSFC && configuration === 'never' ) {
223
253
report ( context , messages . noDestructAssignment , 'noDestructAssignment' , {
224
254
node,
0 commit comments