@@ -32,30 +32,32 @@ const AST_NODE_TYPES = Object.freeze({
32
32
function checkNodeLocation (
33
33
path : NodePath ,
34
34
line : number ,
35
- column : number ,
35
+ column ? : number | null = null ,
36
36
) : boolean {
37
37
const { start, end} = path . node . loc ;
38
38
39
39
if ( line < start . line || line > end . line ) {
40
40
return false ;
41
41
}
42
42
43
- // Column numbers are representated differently between tools/engines.
44
- // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
45
- //
46
- // In practice this will probably never matter,
47
- // because this code matches the 1-based Error stack location for the hook Identifier (e.g. useState)
48
- // with the larger 0-based VariableDeclarator (e.g. [foo, setFoo] = useState())
49
- // so the ranges should always overlap.
50
- //
51
- // For more info see https://github.com/facebook/react/pull/21833#discussion_r666831276
52
- column -= 1 ;
53
-
54
- if (
55
- ( line === start . line && column < start . column ) ||
56
- ( line === end . line && column > end . column )
57
- ) {
58
- return false ;
43
+ if ( column !== null ) {
44
+ // Column numbers are representated differently between tools/engines.
45
+ // Error.prototype.stack columns are 1-based (like most IDEs) but ASTs are 0-based.
46
+ //
47
+ // In practice this will probably never matter,
48
+ // because this code matches the 1-based Error stack location for the hook Identifier (e.g. useState)
49
+ // with the larger 0-based VariableDeclarator (e.g. [foo, setFoo] = useState())
50
+ // so the ranges should always overlap.
51
+ //
52
+ // For more info see https://github.com/facebook/react/pull/21833#discussion_r666831276
53
+ column - = 1 ;
54
+
55
+ if (
56
+ ( line === start . line && column < start . column ) ||
57
+ ( line === end . line && column > end . column )
58
+ ) {
59
+ return false ;
60
+ }
59
61
}
60
62
61
63
return true ;
@@ -122,15 +124,35 @@ export function getHookName(
122
124
) : string | null {
123
125
const hooksFromAST = getPotentialHookDeclarationsFromAST ( originalSourceAST ) ;
124
126
125
- const potentialReactHookASTNode = hooksFromAST . find ( node => {
126
- const nodeLocationCheck = checkNodeLocation (
127
- node ,
128
- originalSourceLineNumber ,
129
- originalSourceColumnNumber ,
130
- ) ;
131
- const hookDeclaractionCheck = isConfirmedHookDeclaration ( node ) ;
132
- return nodeLocationCheck && hookDeclaractionCheck ;
133
- } ) ;
127
+ let potentialReactHookASTNode = null ;
128
+ if ( originalSourceColumnNumber === 0 ) {
129
+ // This most likely indicates a source map type like 'cheap-module-source-map'
130
+ // that intentionally drops column numbers for compilation speed in DEV builds.
131
+ // In this case, we can assume there's probably only one hook per line (true in most cases)
132
+ // and just fail if we find more than one match.
133
+ const matchingNodes = hooksFromAST . filter ( node => {
134
+ const nodeLocationCheck = checkNodeLocation (
135
+ node ,
136
+ originalSourceLineNumber ,
137
+ ) ;
138
+ const hookDeclaractionCheck = isConfirmedHookDeclaration ( node ) ;
139
+ return nodeLocationCheck && hookDeclaractionCheck ;
140
+ } ) ;
141
+
142
+ if ( matchingNodes . length === 1 ) {
143
+ potentialReactHookASTNode = matchingNodes [ 0 ] ;
144
+ }
145
+ } else {
146
+ potentialReactHookASTNode = hooksFromAST . find ( node => {
147
+ const nodeLocationCheck = checkNodeLocation (
148
+ node ,
149
+ originalSourceLineNumber ,
150
+ originalSourceColumnNumber ,
151
+ ) ;
152
+ const hookDeclaractionCheck = isConfirmedHookDeclaration ( node ) ;
153
+ return nodeLocationCheck && hookDeclaractionCheck ;
154
+ } ) ;
155
+ }
134
156
135
157
if ( ! potentialReactHookASTNode ) {
136
158
return null ;
0 commit comments