@@ -14,6 +14,12 @@ import semver from "semver"
1414import { readPatch } from "./patch/read"
1515import { packageIsDevDependency } from "./packageIsDevDependency"
1616
17+ class PatchApplicationError extends Error {
18+ constructor ( msg : string ) {
19+ super ( msg )
20+ }
21+ }
22+
1723// don't want to exit(1) on postinsall locally.
1824// see https://github.com/ds300/patch-package/issues/86
1925const shouldExitPostinstallWithError = isCi || process . env . NODE_ENV === "test"
@@ -46,39 +52,35 @@ function getInstalledPackageVersion({
4652 if ( process . env . NODE_ENV === "production" && isDevOnly ) {
4753 return null
4854 }
49- console . error (
55+
56+ let err =
5057 `${ chalk . red ( "Error:" ) } Patch file found for package ${ posix . basename (
5158 pathSpecifier ,
52- ) } ` + ` which is not present at ${ relative ( "." , packageDir ) } ` ,
53- )
59+ ) } ` + ` which is not present at ${ relative ( "." , packageDir ) } `
5460
5561 if ( ! isDevOnly && process . env . NODE_ENV === "production" ) {
56- console . error (
57- `
62+ err += `
63+
5864 If this package is a dev dependency, rename the patch file to
5965
6066 ${ chalk . bold ( patchFilename . replace ( ".patch" , ".dev.patch" ) ) }
61- ` ,
62- )
67+ `
6368 }
64-
65- throw new Error ( "applyPatches" )
69+ throw new PatchApplicationError ( err )
6670 }
6771
6872 const { version } = require ( join ( packageDir , "package.json" ) )
6973 // normalize version for `npm ci`
7074 const result = semver . valid ( version )
7175 if ( result === null ) {
72- console . error (
76+ throw new PatchApplicationError (
7377 `${ chalk . red (
7478 "Error:" ,
7579 ) } Version string '${ version } ' cannot be parsed from ${ join (
7680 packageDir ,
7781 "package.json" ,
7882 ) } `,
7983 )
80-
81- throw new Error ( "applyPatches" )
8284 }
8385
8486 return result as string
@@ -87,12 +89,10 @@ function getInstalledPackageVersion({
8789export function applyPatchesForApp ( {
8890 appPath,
8991 reverse,
90- ignoreErrors,
9192 patchDir,
9293} : {
9394 appPath : string
9495 reverse : boolean
95- ignoreErrors : boolean
9696 patchDir : string
9797} ) : void {
9898 const patchesDirectory = join ( appPath , patchDir )
@@ -103,14 +103,18 @@ export function applyPatchesForApp({
103103 return
104104 }
105105
106- let hasFailed = false
107- files . forEach ( ( filename , idx ) => {
106+ const errors : string [ ] = [ ]
107+ const warnings : string [ ] = [ ]
108+
109+ for ( const filename of files ) {
108110 try {
109111 const packageDetails = getPackageDetailsFromPatchFilename ( filename )
110112
111113 if ( ! packageDetails ) {
112- console . warn ( `Unrecognized patch file in patches directory ${ filename } ` )
113- return
114+ warnings . push (
115+ `Unrecognized patch file in patches directory ${ filename } ` ,
116+ )
117+ continue
114118 }
115119
116120 const {
@@ -140,7 +144,7 @@ export function applyPatchesForApp({
140144 pathSpecifier ,
141145 ) } @${ version } ${ chalk . blue ( "✔" ) } `,
142146 )
143- return
147+ continue
144148 }
145149
146150 if (
@@ -154,59 +158,76 @@ export function applyPatchesForApp({
154158 // yay patch was applied successfully
155159 // print warning if version mismatch
156160 if ( installedPackageVersion !== version ) {
157- printVersionMismatchWarning ( {
158- packageName : name ,
159- actualVersion : installedPackageVersion ,
160- originalVersion : version ,
161- pathSpecifier,
162- path,
163- } )
161+ warnings . push (
162+ createVersionMismatchWarning ( {
163+ packageName : name ,
164+ actualVersion : installedPackageVersion ,
165+ originalVersion : version ,
166+ pathSpecifier,
167+ path,
168+ } ) ,
169+ )
164170 } else {
165171 console . log (
166172 `${ chalk . bold ( pathSpecifier ) } @${ version } ${ chalk . green ( "✔" ) } ` ,
167173 )
168174 }
169- } else {
175+ } else if ( installedPackageVersion === version ) {
170176 // completely failed to apply patch
171177 // TODO: propagate useful error messages from patch application
172- if ( installedPackageVersion === version ) {
173- printBrokenPatchFileError ( {
178+ errors . push (
179+ createBrokenPatchFileError ( {
174180 packageName : name ,
175181 patchFileName : filename ,
176182 pathSpecifier,
177183 path,
178- } )
179- } else {
180- printPatchApplictionFailureError ( {
184+ } ) ,
185+ )
186+ } else {
187+ errors . push (
188+ createPatchApplictionFailureError ( {
181189 packageName : name ,
182190 actualVersion : installedPackageVersion ,
183191 originalVersion : version ,
184192 patchFileName : filename ,
185193 path,
186194 pathSpecifier,
187- } )
188- }
189-
190- throw new Error ( "applyPatches" )
191- }
192- } catch ( err ) {
193- if ( err . message !== "applyPatches" ) {
194- throw err
195- }
196- if ( ! ignoreErrors ) {
197- exit ( )
198- }
199- hasFailed = true
200- if ( idx < files . length - 1 ) {
201- console . warn (
202- `${ chalk . yellow ( "Warning:" ) } Option ${ chalk . bold (
203- "--ignore-errors" ,
204- ) } was set, moving on to next patch.`,
195+ } ) ,
205196 )
206197 }
198+ } catch ( error ) {
199+ if ( error instanceof PatchApplicationError ) {
200+ errors . push ( error . message )
201+ } else {
202+ errors . push ( createUnexpectedError ( { filename, error } ) )
203+ }
207204 }
208- } )
209- if ( hasFailed ) {
205+ }
206+
207+ for ( const warning of warnings ) {
208+ console . warn ( warning )
209+ }
210+ for ( const error of errors ) {
211+ console . error ( error )
212+ }
213+
214+ const problemsSummary = [ ]
215+ if ( warnings . length ) {
216+ problemsSummary . push ( chalk . yellow ( `${ warnings . length } warning(s)` ) )
217+ }
218+ if ( errors . length ) {
219+ problemsSummary . push ( chalk . red ( `${ errors . length } error(s)` ) )
220+ }
221+
222+ if ( problemsSummary . length ) {
223+ console . error ( "---" )
224+ console . error (
225+ "patch-package finished with" ,
226+ problemsSummary . join ( ", " ) + "." ,
227+ )
228+ }
229+
230+ if ( errors . length ) {
210231 exit ( )
211232 }
212233}
@@ -236,7 +257,7 @@ export function applyPatch({
236257 return true
237258}
238259
239- function printVersionMismatchWarning ( {
260+ function createVersionMismatchWarning ( {
240261 packageName,
241262 actualVersion,
242263 originalVersion,
@@ -249,8 +270,8 @@ function printVersionMismatchWarning({
249270 pathSpecifier : string
250271 path : string
251272} ) {
252- console . warn ( `
253- ${ chalk . red ( "Warning:" ) } patch-package detected a patch file version mismatch
273+ return `
274+ ${ chalk . yellow ( "Warning:" ) } patch-package detected a patch file version mismatch
254275
255276 Don't worry! This is probably fine. The patch was still applied
256277 successfully. Here's the deets:
@@ -274,10 +295,10 @@ ${chalk.red("Warning:")} patch-package detected a patch file version mismatch
274295 ${ chalk . bold ( `patch-package ${ pathSpecifier } ` ) }
275296
276297 to update the version in the patch file name and make this warning go away.
277- ` )
298+ `
278299}
279300
280- function printBrokenPatchFileError ( {
301+ function createBrokenPatchFileError ( {
281302 packageName,
282303 patchFileName,
283304 path,
@@ -288,7 +309,7 @@ function printBrokenPatchFileError({
288309 path : string
289310 pathSpecifier : string
290311} ) {
291- console . error ( `
312+ return `
292313${ chalk . red . bold ( "**ERROR**" ) } ${ chalk . red (
293314 `Failed to apply patch for package ${ chalk . bold ( packageName ) } at path` ,
294315 ) }
@@ -310,10 +331,10 @@ ${chalk.red.bold("**ERROR**")} ${chalk.red(
310331
311332 https://github.com/ds300/patch-package/issues
312333
313- ` )
334+ `
314335}
315336
316- function printPatchApplictionFailureError ( {
337+ function createPatchApplictionFailureError ( {
317338 packageName,
318339 actualVersion,
319340 originalVersion,
@@ -328,7 +349,7 @@ function printPatchApplictionFailureError({
328349 path : string
329350 pathSpecifier : string
330351} ) {
331- console . error ( `
352+ return `
332353${ chalk . red . bold ( "**ERROR**" ) } ${ chalk . red (
333354 `Failed to apply patch for package ${ chalk . bold ( packageName ) } at path` ,
334355 ) }
@@ -356,5 +377,22 @@ ${chalk.red.bold("**ERROR**")} ${chalk.red(
356377 Patch file: patches/${ patchFileName }
357378 Patch was made for version: ${ chalk . green . bold ( originalVersion ) }
358379 Installed version: ${ chalk . red . bold ( actualVersion ) }
359- ` )
380+ `
381+ }
382+
383+ function createUnexpectedError ( {
384+ filename,
385+ error,
386+ } : {
387+ filename : string
388+ error : Error
389+ } ) {
390+ return `
391+ ${ chalk . red . bold ( "**ERROR**" ) } ${ chalk . red (
392+ `Failed to apply patch file ${ chalk . bold ( filename ) } ` ,
393+ ) }
394+
395+ ${ error . stack }
396+
397+ `
360398}
0 commit comments