@@ -172,85 +172,151 @@ def _process_node(cls, node: Node, code: bytes, codeFile: CodeFileModel):
172172 cls ._process_node (child , code , codeFile )
173173
174174 @classmethod
175- def _process_import_clause_node (cls , node : Node , code : bytes ) -> Tuple [List [str ], List [Optional [str ]]]:
176- names = []
177- aliases = []
175+ def _process_import_node (cls , node : Node , code : bytes , codeFile : CodeFileModel ):
176+ """
177+ Process different types of import statements:
178+ 1. Side-effect imports: import './App.css'
179+ 2. Default imports: import React from 'react'
180+ 3. Named imports: import { useState } from 'react'
181+ 4. Namespace imports: import * as React from 'react'
182+ 5. Type-only imports: import type { User } from './types'
183+ 6. Mixed imports: import React, { useState } from 'react'
184+ """
178185
179- for child in node .children :
180- if child .type == "named_imports" :
181- for import_child in child .children :
182- if import_child .type == "import_specifier" :
183- current_name = None
184- current_alias = None
185- next_is_alias = False
186-
187- for alias_child in import_child .children :
188- if alias_child .type == "identifier" and not next_is_alias :
189- current_name = cls ._get_content (code , alias_child )
190- elif alias_child .type == "as" :
191- next_is_alias = True
192- elif alias_child .type == "identifier" and next_is_alias :
193- current_alias = cls ._get_content (code , alias_child )
194- next_is_alias = False
195-
196- if current_name :
197- names .append (current_name )
198- aliases .append (current_alias )
199-
200- elif child .type == "identifier" :
201- name = cls ._get_content (code , child )
202- if name :
203- names .append (name )
204- aliases .append (None )
186+ # Debug: Print the full import statement
187+ import_text = cls ._get_content (code , node )
188+ print (f"Processing import: { import_text } " )
205189
206- return names , aliases
207-
208- @classmethod
209- def _process_import_node (cls , node : Node , code : bytes , codeFile : CodeFileModel ):
190+ # Initialize variables
210191 source = None
211192 names = []
212193 aliases = []
213- next_is_from_import = False
214- next_is_import = False
194+ is_type_only = False
195+ is_namespace = False
196+ namespace_alias = None
215197
198+ # First pass: identify import type and extract source
216199 for child in node .children :
217- if child .type == "import" :
218- next_is_import = True
219- elif child .type == "import_clause" and next_is_import :
220- names , aliases = cls ._process_import_clause_node (child , code )
221- next_is_import = False
222- elif next_is_import :
223- source = cls ._get_content (code , child )
224- next_is_import = False
225- elif child .type == "from" :
226- next_is_from_import = True
227- elif child .type == "string" and next_is_from_import :
228- source = cls ._get_content (code , child )
229- if names and source is None :
230- source = names [0 ] if len (names ) == 1 else None
231- if source :
232- names = []
233- aliases = []
234-
200+ child_text = cls ._get_content (code , child )
201+ print (f" Child: { child .type } = '{ child_text } '" )
202+
203+ # Check for type-only import
204+ if child .type == "type" or child_text == "type" :
205+ is_type_only = True
206+
207+ # Extract source (the string literal)
208+ elif child .type == "string" :
209+ source = child_text .strip ("'\" " ) # Remove quotes
210+
211+ # Second pass: process import clause if it exists
212+ import_clause = None
213+ for child in node .children :
214+ if child .type == "import_clause" :
215+ import_clause = child
216+ break
217+
218+ if import_clause :
219+ names , aliases , is_namespace , namespace_alias = cls ._process_import_clause_node (
220+ import_clause , code
221+ )
222+
223+ # Handle different import types
235224 if source :
236- if names :
225+ if is_namespace and namespace_alias :
226+ # Namespace import: import * as React from 'react'
227+ importStatement = ImportStatement (
228+ source = source ,
229+ name = "*" , # Indicates namespace import
230+ alias = namespace_alias ,
231+ is_type_only = is_type_only
232+ )
233+ codeFile .add_import (importStatement )
234+ cls ._generate_unique_import_id (codeFile .imports [- 1 ])
235+
236+ elif names :
237+ # Named imports or default + named imports
237238 for name , alias in zip (names , aliases ):
238239 importStatement = ImportStatement (
239240 source = source ,
240241 name = name ,
241- alias = alias
242+ alias = alias ,
243+ is_type_only = is_type_only
242244 )
243245 codeFile .add_import (importStatement )
244246 cls ._generate_unique_import_id (codeFile .imports [- 1 ])
245247 else :
248+ # Side-effect import: import './App.css'
246249 importStatement = ImportStatement (
247250 source = source ,
248251 name = None ,
249- alias = None
252+ alias = None ,
253+ is_type_only = is_type_only ,
254+ is_side_effect = True
250255 )
251256 codeFile .add_import (importStatement )
252257 cls ._generate_unique_import_id (codeFile .imports [- 1 ])
253258
259+ @classmethod
260+ def _process_import_clause_node (cls , node : Node , code : bytes ) -> Tuple [List [str ], List [str ], bool , Optional [str ]]:
261+ """
262+ Process import_clause node to extract names and aliases.
263+ Returns: (names, aliases, is_namespace, namespace_alias)
264+ """
265+ names = []
266+ aliases = []
267+ is_namespace = False
268+ namespace_alias = None
269+
270+ def process_node_recursively (current_node : Node ):
271+ nonlocal names , aliases , is_namespace , namespace_alias
272+
273+ node_text = cls ._get_content (code , current_node )
274+ print (f" Processing clause node: { current_node .type } = '{ node_text } '" )
275+
276+ if current_node .type == "namespace_import" :
277+ # Handle: * as React
278+ is_namespace = True
279+ for child in current_node .children :
280+ if child .type == "identifier" :
281+ namespace_alias = cls ._get_content (code , child )
282+
283+ elif current_node .type == "identifier" :
284+ # Default import or named import identifier
285+ identifier = cls ._get_content (code , current_node )
286+ names .append (identifier )
287+ aliases .append (None ) # No alias by default
288+
289+ elif current_node .type == "import_specifier" :
290+ # Named import with possible alias: { name } or { name as alias }
291+ name = None
292+ alias = None
293+
294+ for child in current_node .children :
295+ child_text = cls ._get_content (code , child )
296+ if child .type == "identifier" :
297+ if name is None :
298+ name = child_text
299+ else :
300+ alias = child_text # This is the alias part
301+
302+ if name :
303+ names .append (name )
304+ aliases .append (alias )
305+
306+ elif current_node .type == "named_imports" :
307+ # Process children of named_imports (the part inside {})
308+ for child in current_node .children :
309+ if child .type not in ["{" , "}" , "," ]: # Skip punctuation
310+ process_node_recursively (child )
311+
312+ else :
313+ # Recursively process children for other node types
314+ for child in current_node .children :
315+ process_node_recursively (child )
316+
317+ process_node_recursively (node )
318+ return names , aliases , is_namespace , namespace_alias
319+
254320 @classmethod
255321 def _process_class_node (cls , node : Node , code : bytes , codeFile : CodeFileModel , node_type :Literal ["class" , "interface" , "type" ]= "class" ):
256322 # TODO add support for modifiers at variables, classes i.e
0 commit comments