@@ -76,6 +76,11 @@ module.exports = {
7676 const allowList = context . options [ 0 ] ?. allowList ?? [ ] ;
7777 // Maps local names to imported names of imports
7878 const localToImportedNameMap = new Map ( ) ;
79+ let namespaceImportName ;
80+
81+ const isDisallowed = function ( fn ) {
82+ return EMBER_RUNLOOP_FUNCTIONS . includes ( fn ) && ! allowList . includes ( fn ) ;
83+ } ;
7984
8085 /**
8186 * Reports a node with usage of a disallowed runloop function
@@ -109,38 +114,50 @@ module.exports = {
109114 if ( EMBER_RUNLOOP_FUNCTIONS . includes ( importedName ) ) {
110115 localToImportedNameMap . set ( spec . local . name , importedName ) ;
111116 }
117+ } else if ( spec . type === 'ImportNamespaceSpecifier' ) {
118+ namespaceImportName = spec . local . name ;
112119 }
113120 }
114121 }
115122 } ,
116123
117124 CallExpression ( node ) {
125+ const callee = node . callee ;
126+
118127 // Examples: run(...), later(...)
119- if ( node . callee . type === 'Identifier' ) {
120- const name = node . callee . name ;
121- const runloopFn = localToImportedNameMap . get ( name ) ;
122- const isNotAllowed = runloopFn && ! allowList . includes ( runloopFn ) ;
123- if ( isNotAllowed ) {
124- report ( node , runloopFn , name ) ;
128+ if ( callee . type === 'Identifier' ) {
129+ const localName = callee . name ;
130+ const runloopFn = localToImportedNameMap . get ( localName ) ;
131+
132+ if ( runloopFn && isDisallowed ( runloopFn ) ) {
133+ report ( node , runloopFn , localName ) ;
125134 }
135+
136+ return ;
126137 }
127138
128- // runloop functions (aside from run itself) can chain onto `run`, so we need to check for this
129- // Examples: run.later(...), run.schedule(...)
130- if ( node . callee . type === 'MemberExpression' && node . callee . object ?. type === 'Identifier' ) {
131- const objectName = node . callee . object . name ;
132- const objectRunloopFn = localToImportedNameMap . get ( objectName ) ;
133-
134- if ( objectRunloopFn === 'run' && node . callee . property ?. type === 'Identifier' ) {
135- const runloopFn = node . callee . property . name ;
136-
137- if (
138- EMBER_RUNLOOP_FUNCTIONS . includes ( runloopFn ) &&
139- runloopFn !== 'run' &&
140- ! allowList . includes ( runloopFn )
141- ) {
142- report ( node , runloopFn , `${ objectName } .${ runloopFn } ` ) ;
143- }
139+ if (
140+ callee . type === 'MemberExpression' &&
141+ callee . object . type === 'Identifier' &&
142+ callee . property . type === 'Identifier'
143+ ) {
144+ const objectName = callee . object . name ;
145+ const methodName = callee . property . name ;
146+
147+ // runloop functions (aside from run itself) can chain onto `run`, so we need to check for this
148+ // Examples: run.later(...), run.schedule(...)
149+ if (
150+ localToImportedNameMap . get ( objectName ) === 'run' &&
151+ isDisallowed ( methodName ) &&
152+ methodName !== 'run'
153+ ) {
154+ report ( node , methodName , `${ objectName } .${ methodName } ` ) ;
155+ return ;
156+ }
157+
158+ // Example: `import * as runloop from '@ember/runloop'` -> `runloop.later(...)`
159+ if ( objectName === namespaceImportName && isDisallowed ( methodName ) ) {
160+ report ( node , methodName , `${ objectName } .${ methodName } ` ) ;
144161 }
145162 }
146163 } ,
0 commit comments