11import * as prettierEstreePlugin from 'prettier/plugins/estree' ;
22import type { Parser , ParserOptions , Plugin , SupportLanguage } from 'prettier' ;
33import {
4+ langFromPath ,
45 parse as parseWithYuku ,
56 type Comment ,
67 type Diagnostic ,
78 type ParseOptions ,
89 type ParseResult ,
9- type SourceLang ,
1010 type SourceType ,
1111} from 'yuku-parser' ;
1212
1313const AST_FORMAT = 'estree-yuku' ;
14- const JSX_REGEXP = / ^ [ ^ " ' ` ] * < \/ | ^ [ ^ / ] { 2 } .* \/ > / m;
1514const SOURCE_TYPE_COMBINATIONS : SourceType [ ] = [ 'module' , 'commonjs' ] ;
1615
1716type Range = [ start : number , end : number ] ;
@@ -200,15 +199,24 @@ const mergeNestedJsdocComments = (comments: PrettierComment[]): void => {
200199} ;
201200
202201const stripComments = ( originalText : string , comments : PrettierComment [ ] ) : string => {
203- let text = originalText ;
202+ if ( comments . length === 0 ) {
203+ return originalText ;
204+ }
204205
206+ const chunks : string [ ] = [ ] ;
207+ let cursor = 0 ;
208+
209+ // Yuku returns comments in source order, so mask each range while copying the source only once.
205210 for ( const comment of comments ) {
206211 const start = locStart ( comment ) ;
207212 const end = locEnd ( comment ) ;
208- text = text . slice ( 0 , start ) + text . slice ( start , end ) . replace ( / [ ^ \n ] / g, ' ' ) + text . slice ( end ) ;
213+ chunks . push ( originalText . slice ( cursor , start ) ) ;
214+ chunks . push ( originalText . slice ( start , end ) . replace ( / [ ^ \n ] / g, ' ' ) ) ;
215+ cursor = end ;
209216 }
210217
211- return text ;
218+ chunks . push ( originalText . slice ( cursor ) ) ;
219+ return chunks . join ( '' ) ;
212220} ;
213221
214222const setContentEnd = (
@@ -441,11 +449,7 @@ const parseWithOptions = (text: string, options: ParseOptions): ParseResult => {
441449 return result ;
442450} ;
443451
444- const getSourceType = ( filepath : unknown ) : SourceType | undefined => {
445- if ( typeof filepath !== 'string' ) {
446- return undefined ;
447- }
448-
452+ const getSourceType = ( filepath : string ) : SourceType | undefined => {
449453 if ( / \. (?: m j s | m t s ) $ / i. test ( filepath ) ) {
450454 return 'module' ;
451455 }
@@ -457,20 +461,6 @@ const getSourceType = (filepath: unknown): SourceType | undefined => {
457461 return undefined ;
458462} ;
459463
460- const getLanguageCombinations = ( text : string , filepath : unknown ) : SourceLang [ ] => {
461- if ( typeof filepath === 'string' ) {
462- if ( / \. (?: j s x | t s x ) $ / i. test ( filepath ) ) {
463- return [ 'tsx' ] ;
464- }
465-
466- if ( filepath . toLowerCase ( ) . endsWith ( '.d.ts' ) ) {
467- return [ 'dts' ] ;
468- }
469- }
470-
471- return JSX_REGEXP . test ( text ) ? [ 'tsx' , 'ts' , 'dts' ] : [ 'ts' , 'tsx' , 'dts' ] ;
472- } ;
473-
474464const tryCombinations = ( combinations : ( ( ) => ParseResult ) [ ] ) : ParseResult => {
475465 let firstError : unknown ;
476466 let hasError = false ;
@@ -505,9 +495,9 @@ const parseJavaScript = (text: string, options: ParserOptions<AstNode>): AstNode
505495
506496const parseTypeScript = ( text : string , options : ParserOptions < AstNode > ) : AstNode => {
507497 const sourceType = getSourceType ( options . filepath ) ;
508- const languages = getLanguageCombinations ( text , options . filepath ) ;
509- const combinations = ( sourceType ? [ sourceType ] : SOURCE_TYPE_COMBINATIONS ) . flatMap ( ( candidate ) =>
510- languages . map ( ( lang ) => ( ) => parseWithOptions ( text , { sourceType : candidate , lang } ) ) ,
498+ const lang = langFromPath ( options . filepath . toLowerCase ( ) ) ;
499+ const combinations = ( sourceType ? [ sourceType ] : SOURCE_TYPE_COMBINATIONS ) . map (
500+ ( candidate ) => ( ) => parseWithOptions ( text , { sourceType : candidate , lang } ) ,
511501 ) ;
512502 const { program, comments } = tryCombinations ( combinations ) ;
513503
0 commit comments