@@ -52,6 +52,30 @@ interface RcsOperation {
5252 numberOfLines : number ;
5353}
5454
55+ /**
56+ *
57+ */
58+ type AppliedPatchResult = {
59+ /**
60+ * The updated filter content after applying the patch, or just the original
61+ * filter content if the patch was not applied.
62+ */
63+ filterContent : string ;
64+
65+ /**
66+ * A promise that resolves via applied patch.
67+ * If the patch is not available, it resolves to null.
68+ */
69+ nextPatchTask ?: Promise < AppliedPatchResult | null > ;
70+ } ;
71+
72+ type ApplyPatchParamsWithRecursiveFlag = ApplyPatchParams & {
73+ /**
74+ * Indicates whether the patch is being applied recursively.
75+ */
76+ isRecursiveUpdate : boolean ,
77+ } ;
78+
5579/**
5680 * If the differential update is not available the server may signal about that
5781 * by returning one of the following responses.
@@ -331,16 +355,15 @@ export const extractBaseUrl = (filterUrl: string): string => {
331355 * 2. The {@link UnacceptableResponseError} if the network request returns an unacceptable status code.
332356 */
333357export const applyPatch = async ( params : ApplyPatchParams ) : Promise < string | null > => {
334- const tasks : Promise < string | null > [ ] = [ ] ;
335-
336- // Wrapper to hide the callStack parameter from the user.
337- // eslint-disable-next-line max-len
338- const applyPatchWrapper = async ( innerParams : ApplyPatchParams & { callStack : number , tasks : Promise < string | null > [ ] } ) : Promise < string | null > => {
358+ // Wrapper to hide the `isRecursiveUpdate` parameter from the user.
359+ const applyPatchWrapper = async (
360+ innerParams : ApplyPatchParamsWithRecursiveFlag ,
361+ ) : Promise < AppliedPatchResult | null > => {
339362 const {
340363 filterUrl,
341364 filterContent,
342365 verbose = false ,
343- callStack ,
366+ isRecursiveUpdate ,
344367 } = innerParams ;
345368
346369 const filterLines = splitByLines ( filterContent ) ;
@@ -354,7 +377,7 @@ export const applyPatch = async (params: ApplyPatchParams): Promise<string | nul
354377
355378 // If the patch has not expired yet, return the filter content without changes.
356379 if ( ! checkPatchExpired ( diffPath ) ) {
357- return filterContent ;
380+ return { filterContent } ;
358381 }
359382
360383 const log = createLogger ( verbose ) ;
@@ -366,13 +389,13 @@ export const applyPatch = async (params: ApplyPatchParams): Promise<string | nul
366389 baseUrl ,
367390 diffPath ,
368391 baseUrl . startsWith ( 'http://' ) || baseUrl . startsWith ( 'https://' ) ,
369- callStack > 0 ,
392+ isRecursiveUpdate ,
370393 log ,
371394 ) ;
372395
373396 // Update is not available yet.
374397 if ( res === null ) {
375- return filterContent ;
398+ return { filterContent } ;
376399 }
377400
378401 patch = res ;
@@ -400,55 +423,49 @@ export const applyPatch = async (params: ApplyPatchParams): Promise<string | nul
400423 }
401424
402425 try {
403- const promise = applyPatchWrapper ( {
426+ const nextPatchTask = applyPatchWrapper ( {
404427 filterUrl,
405428 filterContent : updatedFilter ,
406- callStack : callStack + 1 ,
429+ isRecursiveUpdate : true ,
407430 verbose,
408- tasks,
409431 } ) ;
410432
411- tasks . push ( promise ) ;
412-
413- return updatedFilter ;
433+ return { filterContent : updatedFilter , nextPatchTask } ;
414434 } catch ( e ) {
415435 // If we catch an error during the recursive update, we will return
416436 // the last successfully applied patch.
417- return updatedFilter ;
437+ return { filterContent : updatedFilter } ;
418438 }
419439 } ;
420440
421- tasks . push ( applyPatchWrapper ( Object . assign ( params , { callStack : 0 , tasks } ) ) ) ;
441+ const paramsWithRecursiveFlag = { ... params , isRecursiveUpdate : false } ;
422442
423- let task ;
443+ let task : Promise < AppliedPatchResult | null > | null = applyPatchWrapper ( paramsWithRecursiveFlag ) ;
424444 let latestFilter : string | null = null ;
425445
426446 // Apply patches until there are no more tasks to process.
427447 // This allows to apply multiple patches in a row if the filter supports it
428448 // without recursive calls, since applying patches can be a memory-intensive
429449 // operation, because of large amount of contexts for each function call.
430- do {
431- task = tasks . shift ( ) ;
432-
433- let freshFilter = null ;
450+ while ( task ) {
451+ let freshFilter : AppliedPatchResult | null = null ;
434452
435- try {
436- // eslint-disable-next-line no-await-in-loop
437- freshFilter = await task ;
438- } catch ( e ) {
439- // If we catch an error during the patch application, we will return
440- // the last successfully applied patch.
441- return latestFilter ;
442- }
453+ // Without try-await since we should throw an error in some cases and
454+ // all needed catches is inside the `applyPatchWrapper` function.
455+ // eslint-disable-next-line no-await-in-loop
456+ freshFilter = await task ;
443457
444458 // If there is no fresh filter, it means that the patch was not applied
445459 // or the filter does not support Diff-Path tag anymore.
446460 if ( ! freshFilter ) {
461+ // If there is no result, it means that the patch was not applied
462+ // or the filter does not support Diff-Path tag anymore.
447463 return latestFilter ;
448464 }
449465
450- latestFilter = freshFilter ;
451- } while ( task ) ;
466+ latestFilter = freshFilter . filterContent ;
467+ task = freshFilter . nextPatchTask || null ;
468+ }
452469
453470 return latestFilter ;
454471} ;
0 commit comments