@@ -342,6 +342,8 @@ type StripEdit = {
342342 replacement ?: string
343343}
344344
345+ const MAX_TYPESCRIPT_STRIP_PASSES = 5
346+
345347const hasStringProperty = < K extends string > (
346348 value : unknown ,
347349 key : K ,
@@ -486,6 +488,67 @@ const applyStripEdits = (magic: MagicString, edits: StripEdit[]) => {
486488 return changed
487489}
488490
491+ const stripTypeScriptSyntax = (
492+ source : string ,
493+ sourceType : TranspileSourceType ,
494+ ) : TranspileJsxSourceResult => {
495+ let currentCode = source
496+ let changed = false
497+ let reachedStripPassLimit = true
498+
499+ for ( let pass = 0 ; pass < MAX_TYPESCRIPT_STRIP_PASSES ; pass += 1 ) {
500+ const parsed = parseSync (
501+ 'transpile-jsx-source.tsx' ,
502+ currentCode ,
503+ createModuleParserOptions ( sourceType ) ,
504+ )
505+ const error = parsed . errors [ 0 ]
506+ if ( error ) {
507+ throw new Error ( formatParserError ( error ) )
508+ }
509+
510+ const edits = collectTypeScriptStripEdits ( currentCode , parsed . program )
511+ if ( ! edits . length ) {
512+ reachedStripPassLimit = false
513+ break
514+ }
515+
516+ const magic = new MagicString ( currentCode )
517+ const passChanged = applyStripEdits ( magic , edits )
518+ if ( ! passChanged ) {
519+ reachedStripPassLimit = false
520+ break
521+ }
522+
523+ currentCode = magic . toString ( )
524+ changed = true
525+ }
526+
527+ if ( reachedStripPassLimit ) {
528+ const parsed = parseSync (
529+ 'transpile-jsx-source.tsx' ,
530+ currentCode ,
531+ createModuleParserOptions ( sourceType ) ,
532+ )
533+ const error = parsed . errors [ 0 ]
534+ if ( error ) {
535+ throw new Error ( formatParserError ( error ) )
536+ }
537+
538+ const remainingEdits = collectTypeScriptStripEdits ( currentCode , parsed . program )
539+ if ( remainingEdits . length ) {
540+ throw new Error (
541+ `[jsx] TypeScript strip did not converge after ${ MAX_TYPESCRIPT_STRIP_PASSES } passes (${ remainingEdits . length } removable TypeScript nodes remain).` ,
542+ )
543+ }
544+ }
545+
546+ return {
547+ code : currentCode ,
548+ changed,
549+ }
550+ }
551+
489552export function transpileJsxSource (
490553 source : string ,
491554 options : TranspileJsxSourceOptions = { } ,
@@ -506,32 +569,36 @@ export function transpileJsxSource(
506569 throw new Error ( formatParserError ( firstError ) )
507570 }
508571
509- const magic = new MagicString ( source )
510- const stripChanged =
511- typescriptMode === 'strip'
512- ? applyStripEdits ( magic , collectTypeScriptStripEdits ( source , parsed . program ) )
513- : false
514-
515572 const jsxRoots = collectRootJsxNodes ( parsed . program )
516- if ( ! jsxRoots . length ) {
573+ const jsxMagic = new MagicString ( source )
574+
575+ if ( jsxRoots . length ) {
576+ const builder = new SourceJsxReactBuilder (
577+ source ,
578+ createElementRef ,
579+ fragmentRef ,
580+ typescriptMode === 'strip' ,
581+ )
582+
583+ jsxRoots . sort ( compareByRangeStartDesc ) . forEach ( node => {
584+ jsxMagic . overwrite ( node . range [ 0 ] , node . range [ 1 ] , builder . compile ( node ) )
585+ } )
586+ }
587+
588+ const jsxCode = jsxRoots . length ? jsxMagic . toString ( ) : source
589+ const jsxChanged = jsxRoots . length > 0
590+
591+ if ( typescriptMode !== 'strip' ) {
517592 return {
518- code : stripChanged ? magic . toString ( ) : source ,
519- changed : stripChanged ,
593+ code : jsxCode ,
594+ changed : jsxChanged ,
520595 }
521596 }
522597
523- const builder = new SourceJsxReactBuilder (
524- source ,
525- createElementRef ,
526- fragmentRef ,
527- typescriptMode === 'strip' ,
528- )
529- jsxRoots . sort ( compareByRangeStartDesc ) . forEach ( node => {
530- magic . overwrite ( node . range [ 0 ] , node . range [ 1 ] , builder . compile ( node ) )
531- } )
598+ const stripResult = stripTypeScriptSyntax ( jsxCode , sourceType )
532599
533600 return {
534- code : magic . toString ( ) ,
535- changed : true ,
601+ code : stripResult . code ,
602+ changed : jsxChanged || stripResult . changed ,
536603 }
537604}
0 commit comments