@@ -888,6 +888,43 @@ export function scanDeclarations(source: string, filename: string, keepComments:
888888 if ( ! inner )
889889 return '()'
890890
891+ // Fast path: if params are already in DTS-safe form, return as-is
892+ // Requirements: no newlines in raw string, all params typed (have ':'), no destructuring/defaults/decorators/rest/modifiers
893+ if ( rawParams . indexOf ( '\n' ) === - 1 && inner . indexOf ( ':' ) !== - 1
894+ && inner . indexOf ( '{' ) === - 1 && inner . indexOf ( '[' ) === - 1 && inner . indexOf ( '=' ) === - 1
895+ && inner . indexOf ( '@' ) === - 1 && inner . indexOf ( '...' ) === - 1 ) {
896+ // Verify every param has a type annotation: count colons at depth 0 vs commas at depth 0
897+ let colons = 0
898+ let commas = 0
899+ let depth = 0
900+ for ( let fi = 0 ; fi < inner . length ; fi ++ ) {
901+ const fc = inner . charCodeAt ( fi )
902+ if ( fc === CH_LPAREN || fc === CH_LANGLE || fc === CH_LBRACE ) depth ++
903+ else if ( fc === CH_RPAREN || fc === CH_RANGLE || fc === CH_RBRACE ) depth --
904+ else if ( depth === 0 ) {
905+ if ( fc === CH_COLON ) colons ++
906+ else if ( fc === CH_COMMA ) commas ++
907+ }
908+ }
909+ // Every param needs at least one colon (commas + 1 params)
910+ if ( colons >= commas + 1 ) {
911+ let hasModifier = false
912+ for ( let m = 0 ; m < PARAM_MODIFIERS . length ; m ++ ) {
913+ const mod = PARAM_MODIFIERS [ m ]
914+ const modIdx = inner . indexOf ( mod )
915+ if ( modIdx !== - 1 ) {
916+ const afterIdx = modIdx + mod . length
917+ if ( ( modIdx === 0 || ! isIdentChar ( inner . charCodeAt ( modIdx - 1 ) ) )
918+ && ( afterIdx >= inner . length || ! isIdentChar ( inner . charCodeAt ( afterIdx ) ) ) ) {
919+ hasModifier = true
920+ break
921+ }
922+ }
923+ }
924+ if ( ! hasModifier ) return rawParams
925+ }
926+ }
927+
891928 // Split parameters by comma at depth 0
892929 const params : string [ ] = [ ]
893930 let paramStart = 0
@@ -1313,7 +1350,7 @@ export function scanDeclarations(source: string, filename: string, keepComments:
13131350
13141351 // Build DTS text
13151352 const dtsParams = buildDtsParams ( rawParams )
1316- const text = ( isExported ? 'export ' : '' ) + ' declare function ' + ( name || 'default' ) + generics + dtsParams + ': ' + returnType + ';'
1353+ const text = ` ${ isExported ? 'export ' : '' } declare function ${ name || 'default' } ${ generics } ${ dtsParams } : ${ returnType } ;`
13171354 const comments = extractLeadingComments ( declStart )
13181355
13191356 // Record index if this function had a body (implementation signature for overloads)
@@ -1510,7 +1547,7 @@ export function scanDeclarations(source: string, filename: string, keepComments:
15101547 const body = cleanBraceBlock ( rawBody )
15111548
15121549 // Build DTS text
1513- const text = ( isExported ? 'export ' : '' ) + ' declare interface ' + name + generics + ( extendsClause ? ' extends ' + extendsClause : '' ) + ' ' + body
1550+ const text = ` ${ isExported ? 'export ' : '' } declare interface ${ name } ${ generics } ${ extendsClause ? ` extends ${ extendsClause } ` : '' } ${ body } `
15141551 const comments = extractLeadingComments ( declStart )
15151552
15161553 return {
@@ -1567,7 +1604,7 @@ export function scanDeclarations(source: string, filename: string, keepComments:
15671604 pos ++
15681605
15691606 // Build DTS text
1570- const text = ( isExported ? 'export ' : '' ) + ' type ' + name + generics + ' = ' + typeBody
1607+ const text = ` ${ isExported ? 'export ' : '' } type ${ name } ${ generics } = ${ typeBody } `
15711608 const comments = extractLeadingComments ( declStart )
15721609
15731610 return {
@@ -1681,7 +1718,7 @@ export function scanDeclarations(source: string, filename: string, keepComments:
16811718 const classBody = buildClassBodyDts ( )
16821719
16831720 // Build DTS text
1684- const text = ( isExported ? 'export ' : '' ) + ' declare ' + ( isAbstract ? 'abstract ' : '' ) + ' class ' + name + generics + ( extendsClause ? ' extends ' + extendsClause : '' ) + ( implementsList && implementsList . length > 0 ? ' implements ' + implementsList . join ( ', ' ) : '' ) + ' ' + classBody
1721+ const text = ` ${ isExported ? 'export ' : '' } declare ${ isAbstract ? 'abstract ' : '' } class ${ name } ${ generics } ${ extendsClause ? ` extends ${ extendsClause } ` : '' } ${ implementsList && implementsList . length > 0 ? ` implements ${ implementsList . join ( ', ' ) } ` : '' } ${ classBody } `
16851722 const comments = extractLeadingComments ( declStart )
16861723
16871724 return {
@@ -2484,7 +2521,7 @@ export function scanDeclarations(source: string, filename: string, keepComments:
24842521 const body = pos < len && source . charCodeAt ( pos ) === CH_LBRACE ? buildNamespaceBodyDts ( ) : '{}'
24852522
24862523 // Build DTS text
2487- const text = ( isExported ? 'export ' : '' ) + ' declare ' + keyword + ' ' + name + ' ' + body
2524+ const text = ` ${ isExported ? 'export ' : '' } declare ${ keyword } ${ name } ${ body } `
24882525 const comments = extractLeadingComments ( declStart )
24892526 const isAmbient = name . startsWith ( '\'' ) || name . startsWith ( '"' )
24902527
@@ -3066,24 +3103,29 @@ function resolveReferencedTypes(declarations: Declaration[], nonExportedTypes: M
30663103 const declNames = new Set < string > ( )
30673104 for ( const d of declarations ) declNames . add ( d . name )
30683105
3069- // Build initial combined text once (excluding imports )
3070- const combinedParts : string [ ] = [ ]
3106+ // Keep declaration texts as an array — search each part individually (avoids giant join allocation )
3107+ const textParts : string [ ] = [ ]
30713108 for ( let i = 0 ; i < declarations . length ; i ++ ) {
30723109 if ( declarations [ i ] . kind !== 'import' ) {
3073- combinedParts . push ( declarations [ i ] . text )
3110+ textParts . push ( declarations [ i ] . text )
30743111 }
30753112 }
3076- let combinedText = combinedParts . length > 1
3077- ? combinedParts . join ( '\n' )
3078- : ( combinedParts [ 0 ] || '' )
30793113
30803114 for ( ; ; ) {
30813115 // Collect referenced non-exported types not yet resolved
30823116 const toInsert : Declaration [ ] = [ ]
30833117 for ( const [ name , decl ] of nonExportedTypes ) {
30843118 if ( resolved . has ( name ) )
30853119 continue
3086- if ( combinedText && isWordInText ( name , combinedText ) ) {
3120+ // Search each text part individually with early break
3121+ let found = false
3122+ for ( let p = 0 ; p < textParts . length ; p ++ ) {
3123+ if ( isWordInText ( name , textParts [ p ] ) ) {
3124+ found = true
3125+ break
3126+ }
3127+ }
3128+ if ( found ) {
30873129 if ( ! declNames . has ( name ) ) {
30883130 toInsert . push ( decl )
30893131 declNames . add ( name )
@@ -3095,31 +3137,25 @@ function resolveReferencedTypes(declarations: Declaration[], nonExportedTypes: M
30953137 if ( toInsert . length === 0 )
30963138 break
30973139
3098- // Insert at correct source positions to preserve declaration order
3099- for ( const decl of toInsert ) {
3100- const declStart = decl . start ?? Number . POSITIVE_INFINITY
3101- let insertIdx = declarations . length
3102- for ( let i = 0 ; i < declarations . length ; i ++ ) {
3103- const candidateStart = declarations [ i ] . start ?? Number . POSITIVE_INFINITY
3104- if ( candidateStart > declStart ) {
3105- insertIdx = i
3106- break
3107- }
3140+ // Merge at correct source positions in a single O(n+k) pass (avoids O(k*n) splice)
3141+ toInsert . sort ( ( a , b ) => ( a . start ?? Infinity ) - ( b . start ?? Infinity ) )
3142+ const merged : Declaration [ ] = [ ]
3143+ let ti = 0
3144+ for ( let i = 0 ; i < declarations . length ; i ++ ) {
3145+ const candidateStart = declarations [ i ] . start ?? Infinity
3146+ while ( ti < toInsert . length && ( toInsert [ ti ] . start ?? Infinity ) <= candidateStart ) {
3147+ merged . push ( toInsert [ ti ++ ] )
31083148 }
3109- declarations . splice ( insertIdx , 0 , decl )
3149+ merged . push ( declarations [ i ] )
31103150 }
3151+ while ( ti < toInsert . length ) merged . push ( toInsert [ ti ++ ] )
3152+ declarations . length = 0
3153+ for ( let i = 0 ; i < merged . length ; i ++ ) declarations . push ( merged [ i ] )
31113154
3112- // Append newly inserted declaration text for next iteration checks
3113- if ( toInsert . length > 0 ) {
3114- const appendedParts : string [ ] = [ ]
3115- for ( const decl of toInsert ) {
3116- if ( decl . kind !== 'import' ) {
3117- appendedParts . push ( decl . text )
3118- }
3119- }
3120- if ( appendedParts . length > 0 ) {
3121- const appendedText = appendedParts . length > 1 ? appendedParts . join ( '\n' ) : appendedParts [ 0 ]
3122- combinedText = combinedText ? `${ combinedText } \n${ appendedText } ` : appendedText
3155+ // Append new texts to parts array for next iteration
3156+ for ( const decl of toInsert ) {
3157+ if ( decl . kind !== 'import' ) {
3158+ textParts . push ( decl . text )
31233159 }
31243160 }
31253161 }
0 commit comments