1- """
2- Approach A: jscodeshift/recast via Node.js subprocess.
1+ """Approach A: jscodeshift/recast via Node.js subprocess.
32
43This approach:
541. Writes a jscodeshift transform script
3029@dataclass
3130class JsCodeshiftResult :
3231 """Result from jscodeshift transformation."""
32+
3333 success : bool
3434 output : str
3535 error : Optional [str ] = None
@@ -46,12 +46,7 @@ def __init__(self):
4646 def _check_node_available (self ) -> bool :
4747 """Check if Node.js is available."""
4848 try :
49- result = subprocess .run (
50- ['node' , '--version' ],
51- capture_output = True ,
52- text = True ,
53- timeout = 5
54- )
49+ result = subprocess .run (["node" , "--version" ], check = False , capture_output = True , text = True , timeout = 5 )
5550 return result .returncode == 0
5651 except (subprocess .SubprocessError , FileNotFoundError ):
5752 return False
@@ -60,24 +55,14 @@ def _check_jscodeshift_available(self) -> bool:
6055 """Check if jscodeshift is available via npx."""
6156 try :
6257 result = subprocess .run (
63- ['npx' , 'jscodeshift' , '--version' ],
64- capture_output = True ,
65- text = True ,
66- timeout = 10
58+ ["npx" , "jscodeshift" , "--version" ], check = False , capture_output = True , text = True , timeout = 10
6759 )
6860 return result .returncode == 0
6961 except (subprocess .SubprocessError , FileNotFoundError ):
7062 return False
7163
72- def _create_transform_script (
73- self ,
74- function_name : str ,
75- new_source : str ,
76- start_line : int ,
77- end_line : int ,
78- ) -> str :
79- """
80- Create a jscodeshift transform script.
64+ def _create_transform_script (self , function_name : str , new_source : str , start_line : int , end_line : int ) -> str :
65+ """Create a jscodeshift transform script.
8166
8267 Args:
8368 function_name: Name of function to replace
@@ -87,11 +72,12 @@ def _create_transform_script(
8772
8873 Returns:
8974 JavaScript transform script
75+
9076 """
9177 # Escape the new source for embedding in JS string
9278 escaped_source = json .dumps (new_source )
9379
94- return f'''
80+ return f"""
9581// jscodeshift transform to replace function by line number
9682module.exports = function(fileInfo, api) {{
9783 const j = api.jscodeshift;
@@ -180,23 +166,17 @@ def _create_transform_script(
180166
181167 return root.toSource({{ quote: 'single' }});
182168}};
183- '''
184-
185- def _create_simple_transform_script (
186- self ,
187- start_line : int ,
188- end_line : int ,
189- new_source : str ,
190- ) -> str :
191- """
192- Create a simpler transform script that uses line-based replacement.
169+ """
170+
171+ def _create_simple_transform_script (self , start_line : int , end_line : int , new_source : str ) -> str :
172+ """Create a simpler transform script that uses line-based replacement.
193173
194174 This fallback approach uses recast to parse, does line-based replacement,
195175 and uses recast to output (preserving formatting).
196176 """
197177 escaped_source = json .dumps (new_source )
198178
199- return f'''
179+ return f"""
200180// Simple line-based replacement using recast for parsing/printing
201181const recast = require('recast');
202182
@@ -237,18 +217,12 @@ def _create_simple_transform_script(
237217
238218 return [...before, ...adjustedNewLines, ...after].join('\\ n');
239219}};
240- '''
220+ """
241221
242222 def replace_function (
243- self ,
244- source : str ,
245- function_name : str ,
246- new_function : str ,
247- start_line : int ,
248- end_line : int ,
223+ self , source : str , function_name : str , new_function : str , start_line : int , end_line : int
249224 ) -> JsCodeshiftResult :
250- """
251- Replace a function using jscodeshift.
225+ """Replace a function using jscodeshift.
252226
253227 Args:
254228 source: Original source code
@@ -259,31 +233,33 @@ def replace_function(
259233
260234 Returns:
261235 JsCodeshiftResult with success status and output
236+
262237 """
263238 with tempfile .TemporaryDirectory () as tmpdir :
264239 tmpdir_path = Path (tmpdir )
265240
266241 # Write source file
267- source_file = tmpdir_path / ' source.js'
242+ source_file = tmpdir_path / " source.js"
268243 source_file .write_text (source )
269244
270245 # Write transform script
271- transform_file = tmpdir_path / 'transform.js'
272- transform_script = self ._create_transform_script (
273- function_name , new_function , start_line , end_line
274- )
246+ transform_file = tmpdir_path / "transform.js"
247+ transform_script = self ._create_transform_script (function_name , new_function , start_line , end_line )
275248 transform_file .write_text (transform_script )
276249
277250 try :
278251 # Run jscodeshift
279252 result = subprocess .run (
280253 [
281- 'npx' , 'jscodeshift' ,
282- '-t' , str (transform_file ),
254+ "npx" ,
255+ "jscodeshift" ,
256+ "-t" ,
257+ str (transform_file ),
283258 str (source_file ),
284- ' --print' , # Print output to stdout instead of modifying file
285- ' --dry' , # Don't actually write
259+ " --print" , # Print output to stdout instead of modifying file
260+ " --dry" , # Don't actually write
286261 ],
262+ check = False ,
287263 capture_output = True ,
288264 text = True ,
289265 timeout = 30 ,
@@ -298,40 +274,23 @@ def replace_function(
298274 # Fallback: read the file
299275 output = source_file .read_text ()
300276
301- return JsCodeshiftResult (
302- success = True ,
303- output = output ,
304- )
305- else :
306- return JsCodeshiftResult (
307- success = False ,
308- output = source , # Return original on failure
309- error = f"jscodeshift failed with code { result .returncode } " ,
310- stderr = result .stderr ,
311- )
312-
313- except subprocess .TimeoutExpired :
277+ return JsCodeshiftResult (success = True , output = output )
314278 return JsCodeshiftResult (
315279 success = False ,
316- output = source ,
317- error = "jscodeshift timed out" ,
280+ output = source , # Return original on failure
281+ error = f"jscodeshift failed with code { result .returncode } " ,
282+ stderr = result .stderr ,
318283 )
284+
285+ except subprocess .TimeoutExpired :
286+ return JsCodeshiftResult (success = False , output = source , error = "jscodeshift timed out" )
319287 except Exception as e :
320- return JsCodeshiftResult (
321- success = False ,
322- output = source ,
323- error = str (e ),
324- )
288+ return JsCodeshiftResult (success = False , output = source , error = str (e ))
325289
326290 def replace_function_simple (
327- self ,
328- source : str ,
329- start_line : int ,
330- end_line : int ,
331- new_function : str ,
291+ self , source : str , start_line : int , end_line : int , new_function : str
332292 ) -> JsCodeshiftResult :
333- """
334- Replace a function using simple line-based approach via Node.js.
293+ """Replace a function using simple line-based approach via Node.js.
335294
336295 This is a fallback that still uses Node.js but with simpler logic.
337296
@@ -343,6 +302,7 @@ def replace_function_simple(
343302
344303 Returns:
345304 JsCodeshiftResult with success status and output
305+
346306 """
347307 # For simplicity, let's just use the text-based approach
348308 # but run through Node.js for consistency testing
@@ -351,21 +311,13 @@ def replace_function_simple(
351311 replacer = TextBasedReplacer ()
352312 result = replacer .replace_function (source , start_line , end_line , new_function )
353313
354- return JsCodeshiftResult (
355- success = True ,
356- output = result ,
357- )
314+ return JsCodeshiftResult (success = True , output = result )
358315
359316
360317def replace_function_jscodeshift (
361- source : str ,
362- function_name : str ,
363- new_function : str ,
364- start_line : int ,
365- end_line : int ,
318+ source : str , function_name : str , new_function : str , start_line : int , end_line : int
366319) -> str :
367- """
368- Convenience function for jscodeshift replacement.
320+ """Convenience function for jscodeshift replacement.
369321
370322 Args:
371323 source: Original source code
@@ -376,6 +328,7 @@ def replace_function_jscodeshift(
376328
377329 Returns:
378330 Modified source code (or original if failed)
331+
379332 """
380333 replacer = JsCodeshiftReplacer ()
381334 result = replacer .replace_function (source , function_name , new_function , start_line , end_line )
@@ -384,8 +337,6 @@ def replace_function_jscodeshift(
384337
385338# Test the implementation
386339if __name__ == "__main__" :
387- from test_cases import get_test_cases
388-
389340 replacer = JsCodeshiftReplacer ()
390341
391342 # Check if jscodeshift is available
@@ -402,21 +353,15 @@ def replace_function_jscodeshift(
402353 print ()
403354
404355 # Test with a simple case first
405- simple_source = ''' function add(a, b) {
356+ simple_source = """ function add(a, b) {
406357 return a + b;
407358}
408- '''
409- simple_new = ''' function add(a, b) {
359+ """
360+ simple_new = """ function add(a, b) {
410361 return (a + b) | 0;
411- }'''
412-
413- result = replacer .replace_function (
414- simple_source ,
415- "add" ,
416- simple_new ,
417- start_line = 1 ,
418- end_line = 3 ,
419- )
362+ }"""
363+
364+ result = replacer .replace_function (simple_source , "add" , simple_new , start_line = 1 , end_line = 3 )
420365
421366 print ("Simple test result:" )
422367 print (f" Success: { result .success } " )
0 commit comments