@@ -228,53 +228,82 @@ const defaultOptions: JsdocOptions = {
228228 jsdocBracketSpacing : options . jsdocBracketSpacing . default ,
229229} ;
230230
231+ const parserCache = new Map < string , prettier . Parser > ( ) ;
232+
233+ function getMergedParser (
234+ originalParser : prettier . Parser ,
235+ parserName : string ,
236+ ) : prettier . Parser {
237+ let cached = parserCache . get ( parserName ) ;
238+ if ( ! cached ) {
239+ cached = mergeParsers ( originalParser , parserName ) ;
240+ parserCache . set ( parserName , cached ) ;
241+ }
242+
243+ return cached ;
244+ }
245+
231246const parsers = {
232247 // JS - Babel
233248 get babel ( ) {
234- const parser = parserBabel . parsers . babel ;
235- return mergeParsers ( parser , "babel" ) ;
249+ return getMergedParser ( parserBabel . parsers . babel , "babel" ) ;
236250 } ,
237251 get "babel-flow" ( ) {
238- const parser = parserBabel . parsers [ "babel-flow" ] ;
239- return mergeParsers ( parser , "babel-flow" ) ;
252+ return getMergedParser ( parserBabel . parsers [ "babel-flow" ] , "babel-flow" ) ;
240253 } ,
241254 get "babel-ts" ( ) {
242- const parser = parserBabel . parsers [ "babel-ts" ] ;
243- return mergeParsers ( parser , "babel-ts" ) ;
255+ return getMergedParser ( parserBabel . parsers [ "babel-ts" ] , "babel-ts" ) ;
244256 } ,
245257 // JS - Flow
246258 get flow ( ) {
247- const parser = parserFlow . parsers . flow ;
248- return mergeParsers ( parser , "flow" ) ;
259+ return getMergedParser ( parserFlow . parsers . flow , "flow" ) ;
249260 } ,
250261 // JS - TypeScript
251262 get typescript ( ) : prettier . Parser {
252- const parser = parserTypescript . parsers . typescript ;
253-
254- return mergeParsers ( parser , "typescript" ) ;
255- // require("./parser-typescript").parsers.typescript;
263+ return getMergedParser ( parserTypescript . parsers . typescript , "typescript" ) ;
256264 } ,
257265 get "jsdoc-parser" ( ) {
258266 // Backward compatible, don't use this in new version since 1.0.0
259- const parser = parserBabel . parsers [ "babel-ts" ] ;
260-
261- return mergeParsers ( parser , "babel-ts" ) ;
267+ return getMergedParser ( parserBabel . parsers [ "babel-ts" ] , "babel-ts" ) ;
262268 } ,
263269} ;
264270
265271function mergeParsers ( originalParser : prettier . Parser , parserName : string ) {
266- const jsDocParse = getParser ( originalParser . parse , parserName ) as any ;
267- let hasPreprocessed = false ;
272+ // Chaining plugins can re-resolve parsers and re-enter this parser during the
273+ // same format call. Recursive entries fall back to Prettier's raw parser so
274+ // the chain can unwind, while separate options objects still format normally.
275+ const activePreprocesses = new WeakSet < prettier . ParserOptions > ( ) ;
276+ const activeParses = new WeakSet < prettier . ParserOptions > ( ) ;
277+
278+ const innerParse = getParser ( originalParser . parse , parserName ) ;
279+ const jsDocParse = async (
280+ text : string ,
281+ parsersOrOptions : any ,
282+ maybeOptions ?: any ,
283+ ) => {
284+ const options = ( maybeOptions ??
285+ parsersOrOptions ) as prettier . ParserOptions ;
286+
287+ if ( activeParses . has ( options ) ) {
288+ return originalParser . parse ( text , options ) ;
289+ }
290+
291+ activeParses . add ( options ) ;
292+ try {
293+ return await innerParse ( text , parsersOrOptions , maybeOptions ) ;
294+ } finally {
295+ activeParses . delete ( options ) ;
296+ }
297+ } ;
268298
269299 const jsDocPreprocess = ( text : string , options : prettier . ParserOptions ) => {
270300 normalizeOptions ( options as any ) ;
271301
272- // Prevent infinite recursion by checking if we've already preprocessed
273- if ( hasPreprocessed ) {
302+ if ( activePreprocesses . has ( options ) ) {
274303 return text ;
275304 }
276305
277- hasPreprocessed = true ;
306+ activePreprocesses . add ( options ) ;
278307 try {
279308 const tsPluginParser = findPluginByParser ( parserName , options ) ;
280309
@@ -288,7 +317,7 @@ function mergeParsers(originalParser: prettier.Parser, parserName: string) {
288317 tsPluginParser ?. preprocess || originalParser . preprocess ;
289318 return preprocess ? preprocess ( text , options ) : text ;
290319 } finally {
291- hasPreprocessed = false ;
320+ activePreprocesses . delete ( options ) ;
292321 }
293322 } ;
294323
0 commit comments