diff --git a/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap b/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap index 734a41f3..f0ac31dc 100644 --- a/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap +++ b/integration-tests/delete-scripts/__snapshots__/delete-scripts.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test delete-scripts: a patch file got produced 1`] = ` "SNAPSHOT: a patch file got produced +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index e90aec3..f2b8b0a 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap b/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap index 9bffcbf4..2c491ecd 100644 --- a/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap +++ b/integration-tests/file-mode-changes/__snapshots__/file-mode-changes.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test file-mode-changes: the patch file 1`] = ` "SNAPSHOT: the patch file +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package prettier +# +# declared package: +# prettier: file:/mocked/path/to/prettier-1.16.0.tgz#104dd25f5ee3d0c9d0a6ce4bb40ced8481d51219 +# diff --git a/node_modules/prettier/bin-prettier.js b/node_modules/prettier/bin-prettier.js old mode 100755 new mode 100644 diff --git a/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap b/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap index ee54e635..e29cac23 100644 --- a/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap +++ b/integration-tests/happy-path-npm/__snapshots__/happy-path-npm.test.ts.snap @@ -17,6 +17,14 @@ END SNAPSHOT" exports[`Test happy-path-npm: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.1.3.tgz +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index 26f73ff..d4cc4af 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap b/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap index 0b22e347..39c683ba 100644 --- a/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap +++ b/integration-tests/happy-path-yarn/__snapshots__/happy-path-yarn.test.ts.snap @@ -17,6 +17,14 @@ END SNAPSHOT" exports[`Test happy-path-yarn: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package left-pad +# +# declared package: +# left-pad: file:/mocked/path/to/left-pad-1.1.3.tgz#612f61c033f3a9e08e939f1caebeea41b6f3199a +# diff --git a/node_modules/left-pad/index.js b/node_modules/left-pad/index.js index 26f73ff..b083802 100644 --- a/node_modules/left-pad/index.js diff --git a/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap b/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap index e5b5c464..ef3f0866 100644 --- a/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap +++ b/integration-tests/ignore-whitespace/__snapshots__/ignore-whitespace.test.ts.snap @@ -9,6 +9,14 @@ END SNAPSHOT" exports[`Test ignore-whitespace: line a changed 1`] = ` "SNAPSHOT: line a changed +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package alphabet +# +# declared package: +# alphabet: file:/mocked/path/to/alphabet +# diff --git a/node_modules/alphabet/index.js b/node_modules/alphabet/index.js index 7811d3b..454414b 100644 --- a/node_modules/alphabet/index.js diff --git a/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap b/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap index 1c31fe46..0fd38fe7 100644 --- a/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap +++ b/integration-tests/ignores-scripts-when-making-patch/__snapshots__/ignores-scripts-when-making-patch.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test ignores-scripts-when-making-patch: a patch file got produced 1`] = ` "SNAPSHOT: a patch file got produced +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package naughty-package +# +# declared package: +# naughty-package: file:/mocked/path/to/naughty-package +# diff --git a/node_modules/naughty-package/postinstall.sh b/node_modules/naughty-package/postinstall.sh index 3784520..c4af29c 100755 --- a/node_modules/naughty-package/postinstall.sh diff --git a/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap b/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap index d9aeefa1..8f18bb45 100644 --- a/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap +++ b/integration-tests/include-exclude-paths/__snapshots__/include-exclude-paths.test.ts.snap @@ -2,6 +2,14 @@ exports[`Test include-exclude-paths: exclude all but flip 1`] = ` "SNAPSHOT: exclude all but flip +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude '^(?!.*flip)' +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/flip.js b/node_modules/lodash/flip.js index c28dd78..584b377 100644 --- a/node_modules/lodash/flip.js @@ -17,6 +25,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: modified package.json 1`] = ` "SNAPSHOT: modified package.json +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude '^$' +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/package.json b/node_modules/lodash/package.json index 028960d..7d346f3 100644 --- a/node_modules/lodash/package.json @@ -35,6 +51,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: no base files 1`] = ` "SNAPSHOT: no base files +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --exclude base +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/flip.js b/node_modules/lodash/flip.js index c28dd78..584b377 100644 --- a/node_modules/lodash/flip.js @@ -64,6 +88,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: only __.js being deleted 1`] = ` "SNAPSHOT: only __.js being deleted +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --include __ +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/fp/__.js b/node_modules/lodash/fp/__.js deleted file mode 100644 index 4af98de..0000000 @@ -76,6 +108,14 @@ END SNAPSHOT" exports[`Test include-exclude-paths: only base files, no clone files 1`] = ` "SNAPSHOT: only base files, no clone files +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package lodash --include base --exclude clone +# +# declared package: +# lodash: file:/mocked/path/to/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae +# diff --git a/node_modules/lodash/_baseClamp.js b/node_modules/lodash/_baseClamp.js index a1c5692..c52e38e 100644 --- a/node_modules/lodash/_baseClamp.js diff --git a/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap b/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap index 1dfdf267..56a74428 100644 --- a/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap +++ b/integration-tests/lerna-canary/__snapshots__/lerna-canary.test.ts.snap @@ -25,6 +25,14 @@ END SNAPSHOT" exports[`Test lerna-canary: the patch looks like this 1`] = ` "SNAPSHOT: the patch looks like this +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package @parcel/codeframe +# +# declared package: +# @parcel/codeframe: file:/mocked/path/to/codeframe-2.0.0-nightly.137.tgz#b8bfc2ccf223d6a26eaad193fc26c029f7e14d4f +# diff --git a/node_modules/@parcel/codeframe/src/codeframe.js b/node_modules/@parcel/codeframe/src/codeframe.js index 2bf2c1c..ef0695b 100644 --- a/node_modules/@parcel/codeframe/src/codeframe.js diff --git a/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap b/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap index 420488cc..18b3afa8 100644 --- a/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap +++ b/integration-tests/nested-packages/__snapshots__/nested-packages.test.ts.snap @@ -25,6 +25,14 @@ END SNAPSHOT" exports[`Test nested-packages: the patch file contents 1`] = ` "SNAPSHOT: the patch file contents +# generated by patch-package 0.0.0 on 1980-01-01 00:00:00 +# +# command: +# npx patch-package wrap-ansi/string-width +# +# declared package: +# string-width: file:/mocked/path/to/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e +# diff --git a/node_modules/wrap-ansi/node_modules/string-width/index.js b/node_modules/wrap-ansi/node_modules/string-width/index.js index bbc49d2..6407f49 100644 --- a/node_modules/wrap-ansi/node_modules/string-width/index.js diff --git a/integration-tests/runIntegrationTest.ts b/integration-tests/runIntegrationTest.ts index 3e788a2a..620e6303 100644 --- a/integration-tests/runIntegrationTest.ts +++ b/integration-tests/runIntegrationTest.ts @@ -7,7 +7,7 @@ import { resolveRelativeFileDependencies } from "../src/resolveRelativeFileDepen export const patchPackageTarballPath = resolve( fs .readdirSync(".") - .filter(nm => nm.match(/^patch-package\.test\.\d+\.tgz$/))[0], + .filter((nm) => nm.match(/^patch-package\.test\.\d+\.tgz$/))[0], ) export function runIntegrationTest({ @@ -18,7 +18,10 @@ export function runIntegrationTest({ shouldProduceSnapshots: boolean }) { describe(`Test ${projectName}:`, () => { - const tmpDir = tmp.dirSync({ unsafeCleanup: true }) + const tmpDir = tmp.dirSync({ + unsafeCleanup: true, + prefix: "patch-package.test-integration.", + }) fs.copySync(join(__dirname, projectName), tmpDir.name, { recursive: true, }) @@ -64,7 +67,7 @@ export function runIntegrationTest({ expect(snapshots && snapshots.length).toBeTruthy() }) if (snapshots) { - snapshots.forEach(snapshot => { + snapshots.forEach((snapshot) => { const snapshotDescriptionMatch = snapshot.match(/SNAPSHOT: (.*)/) if (snapshotDescriptionMatch) { it(snapshotDescriptionMatch[1], () => { @@ -80,5 +83,7 @@ export function runIntegrationTest({ expect(snapshots && snapshots.length).toBeFalsy() }) } + + tmpDir.removeCallback() }) } diff --git a/package.json b/package.json index bf67ee95..c87d76b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "patch-package", - "version": "6.4.7", + "name": "@milahu/patch-package-with-pnpm-support", + "version": "6.4.8", "description": "Fix broken node modules with no fuss", "main": "dist/index.js", "repository": "github:ds300/patch-package", @@ -13,13 +13,14 @@ "patch-package": "./index.js" }, "scripts": { - "prepublishOnly": "yarn run clean && yarn run build", + "prepublishOnly": "npm run clean && npm run build", "build": "tsc --project tsconfig.build.json", "new-integration-test": "ts-node integration-tests/newIntegrationTest.ts", "clean": "rimraf dist patch-package.test*.tgz", "format": "prettier --no-semi --write --trailing-comma=all src{/**,}/*.ts integration-tests{/**,}/*.ts property-based-tests{/**,}/*.ts", "prepack": "rimraf dist/**/*.test.js", - "test": "./run-tests.sh --runInBand" + "test": "./run-tests.sh --runInBand", + "prepare": "npm run build" }, "husky": { "hooks": { @@ -54,13 +55,13 @@ "@types/fs-extra": "^5.0.5", "@types/is-ci": "^1.1.0", "@types/jest": "^24.0.11", - "@types/minimist": "^1.2.0", "@types/node": "^11.11.6", "@types/rimraf": "^2.0.2", "@types/semver": "^5.5.0", "@types/tmp": "^0.0.34", "husky": "^1.3.1", "jest": "^24.5.0", + "js-yaml": "^4.0.0", "lint-staged": "^8.1.5", "np": "^7.4.0", "prettier": "^2.2.1", @@ -71,17 +72,19 @@ "typescript": "^4.2.2" }, "dependencies": { + "@types/dashdash": "^1.14.0", "@yarnpkg/lockfile": "^1.1.0", "chalk": "^2.4.2", "cross-spawn": "^6.0.5", + "dashdash": "^2.0.0", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^7.0.1", "is-ci": "^2.0.0", "klaw-sync": "^6.0.0", - "minimist": "^1.2.0", "open": "^7.4.2", "rimraf": "^2.6.3", "semver": "^5.6.0", + "shlex": "^2.0.2", "slash": "^2.0.0", "tmp": "^0.0.33" }, diff --git a/property-based-tests/executeTestCase.ts b/property-based-tests/executeTestCase.ts index 87d19a77..011b923e 100644 --- a/property-based-tests/executeTestCase.ts +++ b/property-based-tests/executeTestCase.ts @@ -24,32 +24,31 @@ jest.mock("fs-extra", () => { setWorkingFiles, getWorkingFiles, ensureDirSync: jest.fn(), - readFileSync: jest.fn(path => getWorkingFiles()[path].contents), + readFileSync: jest.fn((filePath) => getWorkingFiles()[filePath].contents), writeFileSync: jest.fn( - (path: string, contents: string, opts?: { mode?: number }) => { - getWorkingFiles()[path] = { + (filePath: string, contents: string, opts?: { mode?: number }) => { + getWorkingFiles()[filePath] = { contents, mode: opts && typeof opts.mode === "number" ? opts.mode : 0o644, } }, ), - unlinkSync: jest.fn(path => delete getWorkingFiles()[path]), + unlinkSync: jest.fn((filePath) => delete getWorkingFiles()[filePath]), moveSync: jest.fn((from, to) => { getWorkingFiles()[to] = getWorkingFiles()[from] delete getWorkingFiles()[from] }), - statSync: jest.fn(path => getWorkingFiles()[path]), - chmodSync: jest.fn((path, mode) => { - const { contents } = getWorkingFiles()[path] - getWorkingFiles()[path] = { contents, mode } + statSync: jest.fn((filePath) => getWorkingFiles()[filePath]), + chmodSync: jest.fn((filePath, mode) => { + const { contents } = getWorkingFiles()[filePath] + getWorkingFiles()[filePath] = { contents, mode } }), } }) function writeFiles(cwd: string, files: Files): void { const mkdirpSync = require("fs-extra/lib/mkdirs/index.js").mkdirpSync - const writeFileSync = require("fs").writeFileSync - Object.keys(files).forEach(filePath => { + Object.keys(files).forEach((filePath) => { if (!filePath.startsWith(".git/")) { mkdirpSync(path.join(cwd, path.dirname(filePath))) writeFileSync(path.join(cwd, filePath), files[filePath].contents, { @@ -62,7 +61,7 @@ function writeFiles(cwd: string, files: Files): void { function removeLeadingSpaceOnBlankLines(patchFileContents: string): string { return patchFileContents .split("\n") - .map(line => (line === " " ? "" : line)) + .map((line) => (line === " " ? "" : line)) .join("\n") } @@ -83,7 +82,11 @@ export function executeTestCase(testCase: TestCase) { } } - const tmpDir = tmp.dirSync({ unsafeCleanup: true, mode: 0o100777 }) + const tmpDir = tmp.dirSync({ + unsafeCleanup: true, + mode: 0o100777, + prefix: "patch-package.test-property.", + }) spawnSafeSync("git", ["init"], { cwd: tmpDir.name }) @@ -145,4 +148,6 @@ export function executeTestCase(testCase: TestCase) { expect(fs.getWorkingFiles()).toEqual(testCase.cleanFiles) }) }) + + tmpDir.removeCallback() } diff --git a/property-based-tests/testCases.ts b/property-based-tests/testCases.ts index 8fef3bb8..8875f754 100644 --- a/property-based-tests/testCases.ts +++ b/property-based-tests/testCases.ts @@ -121,7 +121,7 @@ function insertLinesIntoFile(file: File): File { function getUniqueFilename(files: Files) { let filename = makeFileName() const ks = Object.keys(files) - while (ks.some(k => k.startsWith(filename))) { + while (ks.some((k) => k.startsWith(filename))) { filename = makeFileName() } return filename diff --git a/run-tests.sh b/run-tests.sh index 894d5268..07ca4847 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -10,3 +10,6 @@ yarn version --new-version 0.0.0 --no-git-tag-version --no-commit-hooks yarn pack --filename patch-package.test.$(date +%s).tgz yarn version --new-version $version --no-git-tag-version --no-commit-hooks yarn jest "$@" + +# workaround for https://github.com/yarnpkg/yarn/issues/6685 +rm -rf /tmp/yarn--* || true diff --git a/src/applyPatches.ts b/src/applyPatches.ts index adbe2dc2..c2759c52 100644 --- a/src/applyPatches.ts +++ b/src/applyPatches.ts @@ -189,7 +189,7 @@ export function applyPatchesForApp({ }), ) } - } catch (error) { + } catch (error: any) { if (error instanceof PatchApplicationError) { errors.push(error.message) } else { @@ -379,14 +379,15 @@ function createUnexpectedError({ error, }: { filename: string - error: Error + error: any }) { + var stack = (error instanceof Error) ? error.stack : error return ` ${chalk.red.bold("**ERROR**")} ${chalk.red( `Failed to apply patch file ${chalk.bold(filename)}`, )} -${error.stack} +${stack} ` } diff --git a/src/detectPackageManager.ts b/src/detectPackageManager.ts index 00976527..1be8a810 100644 --- a/src/detectPackageManager.ts +++ b/src/detectPackageManager.ts @@ -4,7 +4,7 @@ import chalk from "chalk" import process from "process" import findWorkspaceRoot from "find-yarn-workspace-root" -export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap" +export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap" | "pnpm" function printNoYarnLockfileError() { console.error(` @@ -64,6 +64,8 @@ export const detectPackageManager = ( } } else if (yarnLockExists || findWorkspaceRoot()) { return "yarn" + } else if (fs.existsSync(join(appRootPath, "pnpm-lock.yaml"))) { + return "pnpm" } else { printNoLockfilesError() process.exit(1) diff --git a/src/filterFiles.ts b/src/filterFiles.ts index 60983b32..c707cd72 100644 --- a/src/filterFiles.ts +++ b/src/filterFiles.ts @@ -8,10 +8,10 @@ export function removeIgnoredFiles( excludePaths: RegExp, ) { klawSync(dir, { nodir: true }) - .map(item => item.path.slice(`${dir}/`.length)) + .map((item) => item.path.slice(`${dir}/`.length)) .filter( - relativePath => + (relativePath) => !relativePath.match(includePaths) || relativePath.match(excludePaths), ) - .forEach(relativePath => removeSync(join(dir, relativePath))) + .forEach((relativePath) => removeSync(join(dir, relativePath))) } diff --git a/src/getPackageResolution.ts b/src/getPackageResolution.ts index 5c8c158b..71431a6e 100644 --- a/src/getPackageResolution.ts +++ b/src/getPackageResolution.ts @@ -5,15 +5,21 @@ import { readFileSync, existsSync } from "fs-extra" import { parse as parseYarnLockFile } from "@yarnpkg/lockfile" import findWorkspaceRoot from "find-yarn-workspace-root" import { getPackageVersion } from "./getPackageVersion" +//import { execSync } from "child_process" + +//const isVerbose = global.patchPackageIsVerbose +const isDebug = global.patchPackageIsDebug export function getPackageResolution({ packageDetails, packageManager, appPath, + appPackageJson, }: { packageDetails: PackageDetails packageManager: PackageManager appPath: string + appPackageJson: any }) { if (packageManager === "yarn") { let lockFilePath = "yarn.lock" @@ -56,21 +62,125 @@ export function getPackageResolution({ console.warn( `Ambigious lockfile entries for ${packageDetails.pathSpecifier}. Using version ${installedVersion}`, ) - return installedVersion + return { version: installedVersion } } if (resolutions[0]) { - return resolutions[0] + return { version: resolutions[0] } } const resolution = entries[0][0].slice(packageDetails.name.length + 1) // resolve relative file path if (resolution.startsWith("file:.")) { - return `file:${resolve(appPath, resolution.slice("file:".length))}` + return { + version: `file:${resolve(appPath, resolution.slice("file:".length))}`, + } } + return { version: resolution } + } else if (packageManager === "pnpm") { + // WORKAROUND for pnpm bug? pnpm-lock.yaml says version 1.2.3 for linked packages, not link:../../path/to/package + const declaredVersion = + (appPackageJson.dependencies && + appPackageJson.dependencies[packageDetails.name]) || + (appPackageJson.devDependencies && + appPackageJson.devDependencies[packageDetails.name]) + if (isDebug) { + console.log( + `patch-package/getPackageResolution: declaredVersion = ${declaredVersion}`, + ) + } + + // TODO validate: declaredVersion must not be wildcard + return { version: declaredVersion } - return resolution + // TODO dont use lockfiles at all? + // package versions should be pinned in /package.json, so it works with all package managers at all times + /* + const lockfile = require("js-yaml").load( + require("fs").readFileSync(join(appPath, "pnpm-lock.yaml"), "utf8"), + ) + if (isDebug) { + console.log(`patch-package/getPackageResolution: appPath = ${appPath}`) + console.log(`patch-package/getPackageResolution: packageDetails:`) + console.dir(packageDetails) + console.log( + `patch-package/getPackageResolution: packageDetails.name = ${packageDetails.name}`, + ) + console.log( + `patch-package/getPackageResolution: lockfile.dependencies[packageDetails.name] = ${ + lockfile.dependencies[packageDetails.name] + }`, + ) + console.log( + `patch-package/getPackageResolution: lockfile.devDependencies[packageDetails.name] = ${ + lockfile.devDependencies[packageDetails.name] + }`, + ) + } + let resolvedVersion = + (lockfile.dependencies && lockfile.dependencies[packageDetails.name]) || + (lockfile.devDependencies && + lockfile.devDependencies[packageDetails.name]) + if (declaredVersion.startsWith("link:")) { + // WORKAROUND + if (isDebug) { + console.log( + `patch-package/getPackageResolution: using declaredVersion ${declaredVersion}, not resolvedVersion ${resolvedVersion}`, + ) + } + resolvedVersion = declaredVersion + } + if (isDebug) { + console.log( + `patch-package/getPackageResolution: resolvedVersion = ${resolvedVersion}`, + ) + } + if (resolvedVersion.startsWith("link:")) { + const localPath = resolve(resolvedVersion.slice(5)) + if (isVerbose) { + console.log( + `patch-package/getPackageResolution: pnpm installed ${packageDetails.name} from ${localPath}`, + ) + } + if (existsSync(localPath + "/.git")) { + // we hope that the originCommit will be available for future downloads + // otherwise our patch will not work ... + // ideally, we would use the last stable release before originCommit from npm or github + function exec(cmd: string) { + return execSync(cmd, { + cwd: localPath, + windowsHide: true, + encoding: "utf8", + }).trim() + } + const originUrl = exec("git remote get-url origin") + // TODO what if the upstream repo is not called "origin"? + const originCommit = exec("git rev-parse origin/HEAD") // npm needs the long commit hash + resolvedVersion = `git+${originUrl}#${originCommit}` + if (isVerbose) { + console.log( + `patch-package/getPackageResolution: using ${packageDetails.name} version ${resolvedVersion} from git origin/HEAD in ${localPath}`, + ) + } + return { version: resolvedVersion, originCommit } + } + const pkgJson = localPath + "/package.json" + if (existsSync(pkgJson)) { + resolvedVersion = require(pkgJson).version + console.warn( + `warning: using ${packageDetails.name} version ${resolvedVersion} from ${pkgJson}`, + ) + return { version: resolvedVersion } + } + } + if (isVerbose) { + console.log( + `patch-package/getPackageResolution: using ${packageDetails.name} version ${resolvedVersion}`, + ) + } + return { version: resolvedVersion } + */ } else { const lockfile = require(join( appPath, @@ -91,7 +201,7 @@ export function getPackageResolution({ entry.dependencies && packageDetails.name in entry.dependencies, ) const pkg = relevantStackEntry.dependencies[packageDetails.name] - return pkg.resolved || pkg.from || pkg.version + return { version: pkg.resolved || pkg.from || pkg.version } } } @@ -107,6 +217,7 @@ if (require.main === module) { appPath: process.cwd(), packageDetails, packageManager: detectPackageManager(process.cwd(), null), + appPackageJson: {}, // TODO? }), ) } diff --git a/src/index.ts b/src/index.ts index a4691a28..a2772799 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,31 +1,30 @@ import chalk from "chalk" import process from "process" -import minimist from "minimist" +import dashdash from "dashdash" -import { applyPatchesForApp } from "./applyPatches" import { getAppRootPath } from "./getAppRootPath" -import { makePatch } from "./makePatch" -import { makeRegExp } from "./makeRegExp" -import { detectPackageManager } from "./detectPackageManager" import { join } from "./path" -import { normalize, sep } from "path" -import slash = require("slash") -import isCi from "is-ci" const appPath = getAppRootPath() -const argv = minimist(process.argv.slice(2), { - boolean: [ - "use-yarn", - "case-sensitive-path-filtering", - "reverse", - "help", - "version", - "error-on-fail", - "create-issue", - ], - string: ["patch-dir"], -}) -const packageNames = argv._ + +var dashdashOptions = [ + { name: "use-yarn", type: "bool" }, + { name: "create-issue", type: "bool" }, + { name: "case-sensitive-path-filtering", type: "bool" }, + { name: "reverse", type: "bool" }, + { names: ["help", "h"], type: "bool" }, + { names: ["version", "v"], type: "bool" }, + { name: "error-on-fail", type: "bool" }, + { name: "verbose", type: "bool" }, + { name: "debug", type: "bool" }, + { name: "patch-dir", type: "string" }, + { name: "include", type: "string" }, + { name: "exclude", type: "string" }, +]; + +const argv = dashdash.parse({ options: dashdashOptions }); + +const packageNames = argv._args console.log( chalk.bold("patch-package"), @@ -33,12 +32,29 @@ console.log( require(join(__dirname, "../package.json")).version, ) -if (argv.version || argv.v) { +// used in imported modules +const isDebug = global.patchPackageIsDebug = argv.debug +global.patchPackageIsVerbose = isDebug || argv.verbose + +if (isDebug) { + console.log(`patch-package/index: argv:`) + console.dir(argv) +} + +import { applyPatchesForApp } from "./applyPatches" +import { makePatch } from "./makePatch" +import { makeRegExp } from "./makeRegExp" +import { detectPackageManager } from "./detectPackageManager" +import { normalize, sep } from "path" +import slash = require("slash") +import isCi from "is-ci" + +if (argv.version) { // noop -} else if (argv.help || argv.h) { +} else if (argv.help) { printHelp() } else { - const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep)) + const patchDir = slash(normalize((argv.patch_dir || "patches") + sep)) if (patchDir.startsWith("/")) { throw new Error("--patch-dir must be a relative path") } @@ -47,19 +63,23 @@ if (argv.version || argv.v) { argv.include, "include", /.*/, - argv["case-sensitive-path-filtering"], + argv.case_sensitive_path_filtering, ) const excludePaths = makeRegExp( argv.exclude, "exclude", /package\.json$/, - argv["case-sensitive-path-filtering"], + argv.case_sensitive_path_filtering, ) const packageManager = detectPackageManager( appPath, - argv["use-yarn"] ? "yarn" : null, + argv.use_yarn ? "yarn" : null, ) - const createIssue = argv["create-issue"] + if (isDebug) { + console.log(`patch-package/index: packageManager = ${packageManager}`) + } + + const createIssue = argv.create_issue packageNames.forEach((packagePathSpecifier: string) => { makePatch({ packagePathSpecifier, @@ -73,11 +93,11 @@ if (argv.version || argv.v) { }) } else { console.log("Applying patches...") - const reverse = !!argv["reverse"] + const reverse = argv.reverse // don't want to exit(1) on postinsall locally. // see https://github.com/ds300/patch-package/issues/86 const shouldExitWithError = - !!argv["error-on-fail"] || isCi || process.env.NODE_ENV === "test" + argv.error_on_fail || isCi || process.env.NODE_ENV === "test" applyPatchesForApp({ appPath, reverse, patchDir, shouldExitWithError }) } } diff --git a/src/makePatch.ts b/src/makePatch.ts index 13696703..78f5fb2a 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -1,5 +1,6 @@ import chalk from "chalk" import { join, dirname, resolve } from "./path" +import { basename } from "path" import { spawnSafeSync } from "./spawnSafe" import { PackageManager } from "./detectPackageManager" import { removeIgnoredFiles } from "./filterFiles" @@ -10,6 +11,11 @@ import { unlinkSync, mkdirpSync, realpathSync, + renameSync, + /* + lstatSync, + readlinkSync, + */ } from "fs-extra" import { sync as rimraf } from "rimraf" import { copySync } from "fs-extra" @@ -29,6 +35,11 @@ import { maybePrintIssueCreationPrompt, openIssueCreationLink, } from "./createIssue" +import { quote as shlexQuote } from "shlex" + +const isVerbose = global.patchPackageIsVerbose +const isDebug = global.patchPackageIsDebug +const isTest = process.env.NODE_ENV == 'test' function printNoPackageFoundError( packageName: string, @@ -68,36 +79,62 @@ export function makePatch({ const packagePath = join(appPath, packageDetails.path) const packageJsonPath = join(packagePath, "package.json") + if (isDebug) { + console.log(`patch-package/makePatch: appPath = ${appPath}`) + console.log(`patch-package/makePatch: packagePath = ${packagePath}`) + console.log(`patch-package/makePatch: appPackageJson:`) + console.dir(appPackageJson) + } + if (!existsSync(packageJsonPath)) { printNoPackageFoundError(packagePathSpecifier, packageJsonPath) process.exit(1) } - const tmpRepo = dirSync({ unsafeCleanup: true }) - const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path) - const tmpRepoNpmRoot = tmpRepoPackagePath.slice( - 0, - -`/node_modules/${packageDetails.name}`.length, - ) + const tmpRepo = dirSync({ + unsafeCleanup: true, + prefix: "patch-package.tmpRepo.", + }) - const tmpRepoPackageJsonPath = join(tmpRepoNpmRoot, "package.json") + function cleanup() { + tmpRepo.removeCallback() + } try { + // finally: cleanup() + + const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path) + const tmpRepoNpmRoot = tmpRepoPackagePath.slice( + 0, + -`/node_modules/${packageDetails.name}`.length, + ) + + const tmpRepoPackageJsonPath = join(tmpRepoNpmRoot, "package.json") + const patchesDir = resolve(join(appPath, patchDir)) console.info(chalk.grey("•"), "Creating temporary folder") + if (isDebug) { + console.log( + `patch-package/makePatch: tmpRepoNpmRoot = ${tmpRepoNpmRoot}`, + ) + } + + const resolvedVersion = getPackageResolution({ + packageDetails, + packageManager, + appPath, + appPackageJson, + }) + // make a blank package.json mkdirpSync(tmpRepoNpmRoot) writeFileSync( tmpRepoPackageJsonPath, JSON.stringify({ dependencies: { - [packageDetails.name]: getPackageResolution({ - packageDetails, - packageManager, - appPath, - }), + [packageDetails.name]: resolvedVersion.version, }, resolutions: resolveRelativeFileDependencies( appPath, @@ -106,9 +143,115 @@ export function makePatch({ }), ) - const packageVersion = getPackageVersion( - join(resolve(packageDetails.path), "package.json"), + const declaredVersion = (() => { + var v = resolvedVersion.version + // https://docs.npmjs.com/cli/v7/configuring-npm/package-json + // ://[[:]@][:][:][/][# | #semver:] + // pnpm uses link: protocol instead of file: + // TODO add more protocols? + var m = v.match(/^(file|link|http|https|git|git\+https|git\+http|git\+ssh|git\+file|github):(.+)$/) + if (m) { + var protocol = m[1] + var location = m[2] + var isGit = protocol.startsWith('git') + var gitCommit = (isGit && location.includes("#")) ? location.split('#').slice(-1)[0] : null + if (isDebug) { + console.dir({ loc: 'get declaredVersion', isGit, gitCommit }); + } + if (isGit && !gitCommit) { + var error = new Error(`found wildcard git version ${v}. \ +package.json must pin the exact version of ${packageDetails.name} \ +in the format :#. \ +commitHash is the full hash with 40 chars.`) + delete error.stack + throw error + /* too complex + // guess commit hash of installed package + var stats = lstatSync(packageDetails.path) + if (stats.isSymbolicLink()) { + var linkTarget = readlinkSync(packageDetails.path) + if (linkTarget.startsWith(".pnpm")) { + var match = linkTarget.match(/^\.pnpm\/[^/]+@([0-9a-f]{10})_[0-9a-f]{32}\//) + if (match) { + gitCommit = match[1] + if (isDebug) console.log(`parsed gitCommit ${gitCommit} from pnpm symlink`) + } + } + } + */ + } + if (isGit) { + return { full: v, protocol, location, gitCommit } + } + else { + // sample: https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e + // hash is sha1sum of tgz file + // -> use version number from package's package.json + var version = getPackageVersion(join(resolve(packageDetails.path), "package.json")) + if (isVerbose) { + console.log(`patch-package/makePatch: using version ${version} from ${packageDetails.name}/package.json`) + } + return { version } + } + } + // https://docs.npmjs.com/about-semantic-versioning + if (!v.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) { + var exactPart = v.match(/^[^~]([0-9]+\.[0-9]+\.[0-9]+)$/) + var exampleVersion = '1.2.3' + if (exactPart) { + exampleVersion = exactPart[1] + } + console.warn(`patch-package/makePatch: warning: found wildcard version. \ +to ensure successful patching, package.json should pin the exact version of ${packageDetails.name} \ +in the format .., for example: "${packageDetails.name}": "${exampleVersion}"`) + } + return { full: v, version: v } + })() + + if (isDebug) { + //console.log(`patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`) + console.log(`patch-package/makePatch: declaredVersion.version = ${declaredVersion.version}`) + console.log(`patch-package/makePatch: declaredVersion.gitCommit = ${declaredVersion.gitCommit}`) + console.log(`patch-package/makePatch: declaredVersion.full = ${declaredVersion.full}`) + } + + const packageVersion = ( + declaredVersion.version || declaredVersion.gitCommit || declaredVersion.full + ) + + // originCommit is more precise than pkg.version + if (isDebug) { + //console.log(`patch-package/makePatch: resolvedVersion.originCommit = ${resolvedVersion.originCommit}`) + console.log(`patch-package/makePatch: resolvedVersion.version = ${resolvedVersion.version}`) + console.log(`patch-package/makePatch: packageVersion = ${packageVersion}`) + } + + //const packageVersion = + // resolvedVersion.originCommit || + // getPackageVersion(join(resolve(packageDetails.path), "package.json")) + + // this is broken when installing from git -> version can be a pseudo-version like 1.0.0-canary + //const packageVersion = getPackageVersion(join(resolve(packageDetails.path), "package.json")) + + // TODO rename resolvedVersion -> declaredVersion + + // FIXME false positive + // test integration-tests/create-issue/create-issue.test.ts + // -> patching left-pad prompts to submit an issue + // https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e + // hash is sha checksum of tgz file -> just use the version 1.3.0 + /* + const packageVersion = ( + !resolvedVersion.version.match(/^(file:|link:)/) ? resolvedVersion.version : + getPackageVersion(join(resolve(packageDetails.path), "package.json")) ) + */ + + if (isDebug) { + console.log(`patch-package/makePatch: getPackageVersion -> ${getPackageVersion(join(resolve(packageDetails.path), "package.json"))}`) + console.log(`patch-package/makePatch: package path = ${packageDetails.path}`) + console.log(`patch-package/makePatch: package path resolved = ${resolve(packageDetails.path)}`) + } // copy .npmrc/.yarnrc in case packages are hosted in private registry // tslint:disable-next-line:align @@ -131,7 +274,7 @@ export function makePatch({ cwd: tmpRepoNpmRoot, logStdErrOnError: false, }) - } catch (e) { + } catch (e: any) { // try again while ignoring scripts in case the script depends on // an implicit context which we havn't reproduced spawnSafeSync( @@ -143,26 +286,44 @@ export function makePatch({ ) } } else { + const npmCmd = packageManager === "pnpm" ? "pnpm" : "npm" console.info( chalk.grey("•"), - `Installing ${packageDetails.name}@${packageVersion} with npm`, + `Installing ${packageDetails.name}@${packageVersion} with ${npmCmd}`, ) try { // try first without ignoring scripts in case they are required // this works in 99.99% of cases - spawnSafeSync(`npm`, ["i", "--force"], { + if (isVerbose) { + console.log( + `patch-package/makePatch: run "${npmCmd} install --force" in ${tmpRepoNpmRoot}`, + ) + } + spawnSafeSync(npmCmd, ["install", "--force"], { cwd: tmpRepoNpmRoot, logStdErrOnError: false, - stdio: "ignore", + stdio: isVerbose ? "inherit" : "ignore", }) - } catch (e) { + } catch (e: any) { // try again while ignoring scripts in case the script depends on // an implicit context which we havn't reproduced - spawnSafeSync(`npm`, ["i", "--ignore-scripts", "--force"], { + if (isVerbose) { + console.log( + `patch-package/makePatch: run "${npmCmd} install --ignore-scripts --force" in ${tmpRepoNpmRoot}`, + ) + } + spawnSafeSync(npmCmd, ["install", "--ignore-scripts", "--force"], { cwd: tmpRepoNpmRoot, - stdio: "ignore", + stdio: isVerbose ? "inherit" : "ignore", }) } + if (packageManager === "pnpm") { + // workaround for `git diff`: replace symlink with hardlink + const pkgPath = tmpRepoNpmRoot + "/node_modules/" + packageDetails.name + const realPath = realpathSync(pkgPath) + unlinkSync(pkgPath) // rm symlink + renameSync(realPath, pkgPath) + } } const git = (...args: string[]) => @@ -185,6 +346,7 @@ export function makePatch({ git("config", "--local", "user.email", "patch@pack.age") // remove ignored files first + // use CLI options --exclude and --include removeIgnoredFiles(tmpRepoPackagePath, includePaths, excludePaths) git("add", "-f", packageDetails.path) @@ -193,8 +355,21 @@ export function makePatch({ // replace package with user's version rimraf(tmpRepoPackagePath) + if (isVerbose) { + console.log( + `patch-package/makePatch: copy ${realpathSync( + packagePath, + )} to ${tmpRepoPackagePath}`, + ) + } + // pnpm installs packages as symlinks, copySync would copy only the symlink - copySync(realpathSync(packagePath), tmpRepoPackagePath) + const srcPath = realpathSync(packagePath) + copySync(srcPath, tmpRepoPackagePath, { + filter: (path) => { + return !path.startsWith(srcPath + "/node_modules/") + }, + }) // remove nested node_modules just to be safe rimraf(join(tmpRepoPackagePath, "node_modules")) @@ -202,11 +377,14 @@ export function makePatch({ rimraf(join(tmpRepoPackagePath, ".git")) // also remove ignored files like before + // use CLI options --exclude and --include removeIgnoredFiles(tmpRepoPackagePath, includePaths, excludePaths) // stage all files git("add", "-f", packageDetails.path) + const ignorePaths = ["package-lock.json", "pnpm-lock.yaml"] + // get diff of changes const diffResult = git( "diff", @@ -214,6 +392,9 @@ export function makePatch({ "--no-color", "--ignore-space-at-eol", "--no-ext-diff", + ...ignorePaths.map( + (path) => `:(exclude,top)${packageDetails.path}/${path}`, + ), ) if (diffResult.stdout.length === 0) { @@ -221,15 +402,17 @@ export function makePatch({ `⁉️ Not creating patch file for package '${packagePathSpecifier}'`, ) console.warn(`⁉️ There don't appear to be any changes.`) + cleanup() process.exit(1) return } try { parsePatchFile(diffResult.stdout.toString()) - } catch (e) { + } catch (e: any) { + if (!(e instanceof Error)) return if ( - (e as Error).message.includes("Unexpected file mode string: 120000") + e.message.includes("Unexpected file mode string: 120000") ) { console.error(` ⛔️ ${chalk.red.bold("ERROR")} @@ -272,6 +455,7 @@ export function makePatch({ `) } + cleanup() process.exit(1) return } @@ -284,6 +468,50 @@ export function makePatch({ } }) + const patchPackageVersion = require("../package.json").version + + // patchfiles are parsed in patch/parse.ts function parsePatchLines + // -> header comments are ignored + let diffHeader = "" + const dateStr = ( + isTest ? '1980-01-01 00:00:00' : // mock date + new Date().toLocaleString("lt") + ) + diffHeader += `# generated by patch-package ${patchPackageVersion} on ${dateStr}\n` + diffHeader += `#\n` + const prettyArgv = process.argv.slice() + if (prettyArgv[0].match(/node/)) { + prettyArgv[0] = "npx" + } + if (prettyArgv[1].match(/patch-package/)) { + prettyArgv[1] = "patch-package" + } + diffHeader += `# command:\n` + diffHeader += `# ${prettyArgv.map((a) => shlexQuote(a)).join(" ")}\n` + diffHeader += `#\n` + diffHeader += `# declared package:\n` + // TODO rename resolvedVersion.version to declaredVersion + const declaredPackageStr = ( + isTest ? (() => { + const v = resolvedVersion.version + const b = basename(v) + if (b != v) return `file:/mocked/path/to/${b}` // mock path // TODO keep the relative path? as declared in /package.json. see getPackageResolution "resolve relative file path" + return v + })() : + resolvedVersion.version + ) + diffHeader += `# ${packageDetails.name}: ${declaredPackageStr}\n` + /* redundant. this is visible from command, sample: npx patch-package wrap-ansi/string-width -> packageNames: wrap-ansi, string-width + if (packageDetails.packageNames.length > 1) { + diffHeader += `#\n` + diffHeader += `# package names:\n` + packageDetails.packageNames.forEach((packageName) => { + diffHeader += `# ${packageName}\n` + }) + } + */ + diffHeader += `#\n` + const patchFileName = createPatchFileName({ packageDetails, packageVersion, @@ -291,10 +519,9 @@ export function makePatch({ const patchPath = join(patchesDir, patchFileName) if (!existsSync(dirname(patchPath))) { - // scoped package - mkdirSync(dirname(patchPath)) + mkdirSync(dirname(patchPath), { recursive: true }) } - writeFileSync(patchPath, diffResult.stdout) + writeFileSync(patchPath, diffHeader + diffResult.stdout) console.log( `${chalk.green("✔")} Created file ${join(patchDir, patchFileName)}\n`, ) @@ -307,11 +534,11 @@ export function makePatch({ } else { maybePrintIssueCreationPrompt(packageDetails, packageManager) } - } catch (e) { - console.error(e) + } catch (e: any) { + //console.error(e) throw e } finally { - tmpRepo.removeCallback() + cleanup() } } diff --git a/src/packageIsDevDependency.ts b/src/packageIsDevDependency.ts index 2719c9be..330cb83d 100644 --- a/src/packageIsDevDependency.ts +++ b/src/packageIsDevDependency.ts @@ -14,5 +14,7 @@ export function packageIsDevDependency({ return false } const { devDependencies } = require(packageJsonPath) - return Boolean(devDependencies && devDependencies[packageDetails.packageNames[0]]) + return Boolean( + devDependencies && devDependencies[packageDetails.packageNames[0]], + ) } diff --git a/src/patch/apply.ts b/src/patch/apply.ts index c2601bae..0c21b61f 100644 --- a/src/patch/apply.ts +++ b/src/patch/apply.ts @@ -7,7 +7,7 @@ export const executeEffects = ( effects: ParsedPatchFile, { dryRun }: { dryRun: boolean }, ) => { - effects.forEach(eff => { + effects.forEach((eff) => { switch (eff.type) { case "file deletion": if (dryRun) { diff --git a/src/patch/parse.ts b/src/patch/parse.ts index 97fb533d..51ff53bd 100644 --- a/src/patch/parse.ts +++ b/src/patch/parse.ts @@ -175,7 +175,16 @@ function parsePatchLines( const line = lines[i] if (state === "parsing header") { - if (line.startsWith("@@")) { + if (line.startsWith("#")) { + // ignore metadata comment line in header + // in the unidiff format, all header lines before `--- a/` are comment lines + // git-diff uses these comment lines to store metadata + // https://stackoverflow.com/questions/18979120 + if (global.patchPackageIsDebug) { + console.log(`patch-package/patch/parse: ignore comment line: ${line}`) + } + continue + } else if (line.startsWith("@@")) { state = "parsing hunks" currentFilePatch.hunks = [] i-- @@ -206,9 +215,10 @@ function parsePatchLines( } else if (line.startsWith("rename to ")) { currentFilePatch.renameTo = line.slice("rename to ".length).trim() } else if (line.startsWith("index ")) { - const match = line.match(/(\w+)\.\.(\w+)/) + const match = line.match(/(\w+)\.\.(\w+)/) // TODO match whole line + //const match = line.match(/^index (\w+)\.\.(\w+)$/) if (!match) { - continue + continue // TODO handle parse error? } currentFilePatch.beforeHash = match[1] currentFilePatch.afterHash = match[2] diff --git a/src/patchFs.ts b/src/patchFs.ts index 9786365e..13d9d49c 100644 --- a/src/patchFs.ts +++ b/src/patchFs.ts @@ -5,7 +5,7 @@ export const getPatchFiles = (patchesDir: string) => { try { return klawSync(patchesDir, { nodir: true }) .map(({ path }) => relative(patchesDir, path)) - .filter(path => path.endsWith(".patch")) + .filter((path) => path.endsWith(".patch")) } catch (e) { return [] } diff --git a/src/spawnSafe.ts b/src/spawnSafe.ts index 3ea042f7..baf7d8a3 100644 --- a/src/spawnSafe.ts +++ b/src/spawnSafe.ts @@ -1,35 +1,35 @@ -import { sync as spawnSync } from "cross-spawn" -import { SpawnOptions } from "child_process" - -export interface SpawnSafeOptions extends SpawnOptions { - throwOnError?: boolean - logStdErrOnError?: boolean - maxBuffer?: number -} - -const defaultOptions: SpawnSafeOptions = { - logStdErrOnError: true, - throwOnError: true, -} - -export const spawnSafeSync = ( - command: string, - args?: string[], - options?: SpawnSafeOptions, -) => { - const mergedOptions = Object.assign({}, defaultOptions, options) - const result = spawnSync(command, args, options) - if (result.error || result.status !== 0) { - if (mergedOptions.logStdErrOnError) { - if (result.stderr) { - console.error(result.stderr.toString()) - } else if (result.error) { - console.error(result.error) - } - } - if (mergedOptions.throwOnError) { - throw result - } - } - return result -} +import { sync as spawnSync } from "cross-spawn" +import { SpawnOptions } from "child_process" + +export interface SpawnSafeOptions extends SpawnOptions { + throwOnError?: boolean + logStdErrOnError?: boolean + maxBuffer?: number +} + +const defaultOptions: SpawnSafeOptions = { + logStdErrOnError: true, + throwOnError: true, +} + +export const spawnSafeSync = ( + command: string, + args?: string[], + options?: SpawnSafeOptions, +) => { + const mergedOptions = Object.assign({}, defaultOptions, options) + const result = spawnSync(command, args, options) + if (result.error || result.status !== 0) { + if (mergedOptions.logStdErrOnError) { + if (result.stderr) { + console.error(result.stderr.toString()) + } else if (result.error) { + console.error(result.error) + } + } + if (mergedOptions.throwOnError) { + throw result + } + } + return result +} diff --git a/src/types/nodejs.global.d.ts b/src/types/nodejs.global.d.ts new file mode 100644 index 00000000..fd1fe845 --- /dev/null +++ b/src/types/nodejs.global.d.ts @@ -0,0 +1,6 @@ +declare namespace NodeJS { + interface Global { + patchPackageIsVerbose: boolean + patchPackageIsDebug: boolean + } +} diff --git a/tslint.json b/tslint.json index ea76ddb6..e33715fa 100644 --- a/tslint.json +++ b/tslint.json @@ -17,7 +17,9 @@ "no-trailing-whitespace": [false], "object-literal-key-quotes": [false], "max-line-length": false, - "no-default-export": true + "no-default-export": true, + "no-namespace": false, + "comment-format": false }, "rulesDirectory": [] }