@@ -32,30 +32,32 @@ const AST_NODE_TYPES = Object.freeze({
3232function checkNodeLocation (
3333 path : NodePath ,
3434 line : number ,
35- column : number ,
35+ column ? : number = null ,
3636) : boolean {
3737 const { start, end} = path . node . loc ;
3838
3939 if ( line < start . line || line > end . line ) {
4040 return false ;
4141 }
4242
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+ }
5961 }
6062
6163 return true ;
@@ -122,15 +124,35 @@ export function getHookName(
122124) : string | null {
123125 const hooksFromAST = getPotentialHookDeclarationsFromAST ( originalSourceAST ) ;
124126
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+ }
134156
135157 if ( ! potentialReactHookASTNode ) {
136158 return null ;
0 commit comments