11import { bold , cyan , green , red } from "chalk"
22import * as fs from "fs"
33import * as path from "path"
4- import spawnSafeSync from "./spawnSafe "
5- import { getPatchFiles , removeGitHeadersFromPath } from "./patchFs "
4+ import { getPatchFiles } from "./patchFs "
5+ import { patch } from "./patch "
66
7- export default function findPatchFiles ( appPath : string , reverse : boolean ) {
8- const patchesDirectory = path . join ( appPath , "patches" )
7+ type OpaqueString < S extends string > = string & { type : S }
8+ export type AppPath = OpaqueString < "AppPath" >
9+ type PatchesDirectory = OpaqueString < "PatchesDirectory" >
10+ type FileName = OpaqueString < "FileName" >
11+ type PackageName = OpaqueString < "PackageName" >
12+ type PackageVersion = OpaqueString < "PackageVersion" >
13+
14+ function findPatchFiles ( patchesDirectory : PatchesDirectory ) : FileName [ ] {
915 if ( ! fs . existsSync ( patchesDirectory ) ) {
1016 return [ ]
1117 }
12- const files = getPatchFiles ( patchesDirectory ) . filter ( filename =>
13- filename . match ( / ^ .+ ( : | \+ ) .+ \. p a t c h $ / ) ,
14- )
18+
19+ return getPatchFiles ( patchesDirectory ) as FileName [ ]
20+ }
21+
22+ function getPatchDetailsFromFilename ( filename : FileName ) {
23+ // ok to coerce this, since we already filtered for valid package file names
24+ // in getPatchFiles
25+ const match = filename . match ( / ^ ( .+ ?) ( : | \+ ) ( .+ ) \. p a t c h $ / ) as string [ ]
26+ const packageName = match [ 1 ] as PackageName
27+ const version = match [ 3 ] as PackageVersion
28+
29+ return {
30+ packageName,
31+ version,
32+ }
33+ }
34+
35+ function getInstalledPackageVersion (
36+ appPath : AppPath ,
37+ packageName : PackageName ,
38+ ) {
39+ const packageDir = path . join ( appPath , "node_modules" , packageName )
40+ if ( ! fs . existsSync ( packageDir ) ) {
41+ console . warn (
42+ `${ red ( "Warning:" ) } Patch file found for package ${ path . posix . basename (
43+ packageDir ,
44+ ) } ` + ` which is not present at ${ packageDir } ` ,
45+ )
46+
47+ return null
48+ }
49+
50+ return require ( path . join ( packageDir , "package.json" ) )
51+ . version as PackageVersion
52+ }
53+
54+ export function applyPatchesForApp ( appPath : AppPath , reverse : boolean ) : void {
55+ // TODO: get rid of this line
56+ console . log ( "reverse" , reverse )
57+ const patchesDirectory = path . join ( appPath , "patches" ) as PatchesDirectory
58+ const files = findPatchFiles ( patchesDirectory )
1559
1660 if ( files . length === 0 ) {
1761 console . log ( cyan ( "No patch files found" ) )
1862 }
1963
2064 files . forEach ( filename => {
21- const match = filename . match ( / ^ ( .+ ?) ( : | \+ ) ( .+ ) \. p a t c h $ / ) as string [ ]
22- const packageName = match [ 1 ]
23- const version = match [ 3 ]
24- const packageDir = path . join ( appPath , "node_modules" , packageName )
25-
26- if ( ! fs . existsSync ( packageDir ) ) {
27- console . warn (
28- `${ red ( "Warning:" ) } Patch file found for package ${ packageName } ` +
29- ` which is not present at ${ packageDir } ` ,
30- )
31- return null
32- }
65+ const { packageName, version } = getPatchDetailsFromFilename ( filename )
66+
67+ const installedPackageVersion = getInstalledPackageVersion (
68+ appPath ,
69+ packageName ,
70+ )
3371
34- const packageJson = require ( path . join ( packageDir , "package.json" ) )
72+ if ( ! installedPackageVersion ) {
73+ return
74+ }
3575
3676 try {
37- applyPatch ( path . resolve ( patchesDirectory , filename ) , reverse )
77+ patch ( path . resolve ( patchesDirectory , filename ) as FileName /* , reverse */ )
3878
39- if ( packageJson . version !== version ) {
40- printVersionMismatchWarning ( packageName , packageJson . version , version )
79+ if ( installedPackageVersion !== version ) {
80+ printVersionMismatchWarning (
81+ packageName ,
82+ installedPackageVersion ,
83+ version ,
84+ )
4185 } else {
4286 console . log ( `${ bold ( packageName ) } @${ version } ${ green ( "✔" ) } ` )
4387 }
4488 } catch ( e ) {
4589 // completely failed to apply patch
46- if ( packageJson . version === version ) {
90+ if ( installedPackageVersion === version ) {
4791 printBrokenPatchFileError ( packageName , filename )
4892 } else {
4993 printPatchApplictionFailureError (
5094 packageName ,
51- packageJson . version ,
95+ installedPackageVersion ,
5296 version ,
5397 filename ,
5498 )
@@ -58,73 +102,10 @@ export default function findPatchFiles(appPath: string, reverse: boolean) {
58102 } )
59103}
60104
61- export function gitApplyArgs (
62- patchFilePath : string ,
63- {
64- reverse,
65- check,
66- } : {
67- reverse ?: boolean
68- check ?: boolean
69- } ,
70- ) {
71- const args = [ "apply" , "--ignore-whitespace" , "--whitespace=nowarn" ]
72- if ( reverse ) {
73- args . push ( "--reverse" )
74- }
75- if ( check ) {
76- args . push ( "--check" )
77- }
78-
79- args . push ( patchFilePath )
80-
81- return args
82- }
83-
84- export function applyPatch ( patchFilePath : string , reverse : boolean ) {
85- // first find out if the patch file was made by patch-package
86- const firstLine = fs
87- . readFileSync ( patchFilePath )
88- . slice ( 0 , "patch-package\n" . length )
89- . toString ( )
90-
91- // if not then remove git headers before applying to make sure git
92- // doesn't skip files that aren't in the index
93- if ( firstLine !== "patch-package\n" ) {
94- patchFilePath = removeGitHeadersFromPath ( patchFilePath )
95- }
96-
97- try {
98- spawnSafeSync (
99- "git" ,
100- gitApplyArgs ( patchFilePath , { reverse, check : true } ) ,
101- {
102- logStdErrOnError : false ,
103- } ,
104- )
105-
106- spawnSafeSync ( "git" , gitApplyArgs ( patchFilePath , { reverse } ) , {
107- logStdErrOnError : false ,
108- } )
109- } catch ( e ) {
110- // patch cli tool has no way to fail gracefully if patch was already
111- // applied, so to check, we need to try a dry-run of applying the patch in
112- // reverse, and if that works it means the patch was already applied
113- // sucessfully. Otherwise the patch just failed for some reason.
114- spawnSafeSync (
115- "git" ,
116- gitApplyArgs ( patchFilePath , { reverse : ! reverse , check : true } ) ,
117- {
118- logStdErrOnError : false ,
119- } ,
120- )
121- }
122- }
123-
124105function printVersionMismatchWarning (
125- packageName : string ,
126- actualVersion : string ,
127- originalVersion : string ,
106+ packageName : PackageName ,
107+ actualVersion : PackageVersion ,
108+ originalVersion : PackageVersion ,
128109) {
129110 console . warn ( `
130111${ red ( "Warning:" ) } patch-package detected a patch file version mismatch
@@ -150,7 +131,10 @@ ${red("Warning:")} patch-package detected a patch file version mismatch
150131` )
151132}
152133
153- function printBrokenPatchFileError ( packageName : string , patchFileName : string ) {
134+ function printBrokenPatchFileError (
135+ packageName : PackageName ,
136+ patchFileName : FileName ,
137+ ) {
154138 console . error ( `
155139${ red . bold ( "**ERROR**" ) } ${ red (
156140 `Failed to apply patch for package ${ bold ( packageName ) } ` ,
@@ -165,10 +149,10 @@ ${red.bold("**ERROR**")} ${red(
165149}
166150
167151function printPatchApplictionFailureError (
168- packageName : string ,
169- actualVersion : string ,
170- originalVersion : string ,
171- patchFileName : string ,
152+ packageName : PackageName ,
153+ actualVersion : PackageVersion ,
154+ originalVersion : PackageVersion ,
155+ patchFileName : FileName ,
172156) {
173157 console . error ( `
174158${ red . bold ( "**ERROR**" ) } ${ red (
0 commit comments