From 82c7e9a66583518d26291be0b7b4a3b3152fdff8 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Sat, 15 Feb 2020 15:47:15 +0000 Subject: [PATCH 1/2] bump prettier and typescript --- package.json | 4 ++-- yarn.lock | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 36ca58cd..e7350cb9 100644 --- a/package.json +++ b/package.json @@ -59,12 +59,12 @@ "jest": "^24.5.0", "lint-staged": "^8.1.5", "np": "^4.0.2", - "prettier": "^1.18.2", + "prettier": "^1.19.1", "randomstring": "^1.1.5", "ts-jest": "^24.0.0", "ts-node": "8.0.3", "tslint": "^5.14.0", - "typescript": "^3.6.3" + "typescript": "^3.7.5" }, "dependencies": { "@yarnpkg/lockfile": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 01e63123..e0d51a65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3713,10 +3713,10 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" - integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== +prettier@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== pretty-format@^24.5.0: version "24.5.0" @@ -4696,10 +4696,10 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -typescript@^3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da" - integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw== +typescript@^3.7.5: + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== uglify-js@^3.1.4: version "3.5.2" From 3fe24b3914fa9e70fdbd86b3d82fd40cde200825 Mon Sep 17 00:00:00 2001 From: David Sheldrick Date: Fri, 28 Feb 2020 10:30:35 +0000 Subject: [PATCH 2/2] Stash wip --- src/detectPackageManager.ts | 30 ++++++++- src/index.ts | 128 ++++++++++++++++++++---------------- src/makePatch.ts | 126 +++++++++++++++++++++++++++++++---- 3 files changed, 213 insertions(+), 71 deletions(-) diff --git a/src/detectPackageManager.ts b/src/detectPackageManager.ts index 00976527..fdeb7425 100644 --- a/src/detectPackageManager.ts +++ b/src/detectPackageManager.ts @@ -3,8 +3,10 @@ import { join } from "./path" import chalk from "chalk" import process from "process" import findWorkspaceRoot from "find-yarn-workspace-root" +import { spawnSafeSync } from "./spawnSafe" +import { parse } from "semver" -export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap" +export type PackageManager = "yarn" | "berry" | "npm" | "npm-shrinkwrap" function printNoYarnLockfileError() { console.error(` @@ -63,7 +65,31 @@ export const detectPackageManager = ( return shrinkWrapExists ? "npm-shrinkwrap" : "npm" } } else if (yarnLockExists || findWorkspaceRoot()) { - return "yarn" + try { + const version = spawnSafeSync("yarn", ["--version"], { + cwd: appRootPath, + }) + .stdout.toString() + .trim() + const majorVersion = parse(version)?.major ?? null + if (majorVersion === null) { + console.error(` +${chalk.red.bold("**ERROR**")} ${chalk.red( + `Unable to parse the result of 'yarn --version': "${version}" `, + )} +`) + process.exit(1) + } + + return majorVersion === 1 ? "yarn" : "berry" + } catch (e) { + console.error(` +${chalk.red.bold("**ERROR**")} ${chalk.red( + `Unable to execute 'yarn --version'`, + )} +`) + process.exit(1) + } } else { printNoLockfilesError() process.exit(1) diff --git a/src/index.ts b/src/index.ts index ae7bb733..53a61b57 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,65 +11,75 @@ import { join } from "./path" import { normalize, sep } from "path" import slash = require("slash") -const appPath = getAppRootPath() -const argv = minimist(process.argv.slice(2), { - boolean: [ - "use-yarn", - "case-sensitive-path-filtering", - "reverse", - "help", - "version", - ], - string: ["patch-dir"], -}) -const packageNames = argv._ - -console.log( - chalk.bold("patch-package"), - // tslint:disable-next-line:no-var-requires - require(join(__dirname, "../package.json")).version, -) - -if (argv.version || argv.v) { - // noop -} else if (argv.help || argv.h) { - printHelp() -} else { - const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep)) - if (patchDir.startsWith("/")) { - throw new Error("--patch-dir must be a relative path") - } - if (packageNames.length) { - const includePaths = makeRegExp( - argv.include, - "include", - /.*/, - argv["case-sensitive-path-filtering"], - ) - const excludePaths = makeRegExp( - argv.exclude, - "exclude", - /package\.json$/, - argv["case-sensitive-path-filtering"], - ) - const packageManager = detectPackageManager( - appPath, - argv["use-yarn"] ? "yarn" : null, - ) - packageNames.forEach((packagePathSpecifier: string) => { - makePatch({ - packagePathSpecifier, - appPath, - packageManager, - includePaths, - excludePaths, - patchDir, - }) - }) +async function main() { + const appPath = getAppRootPath() + const argv = minimist(process.argv.slice(2), { + boolean: [ + "use-yarn", + "case-sensitive-path-filtering", + "reverse", + "help", + "version", + ], + string: ["patch-dir"], + }) + const packageNames = argv._ + + console.log( + chalk.bold("patch-package"), + // tslint:disable-next-line:no-var-requires + require(join(__dirname, "../package.json")).version, + ) + + const packageManager = detectPackageManager( + appPath, + argv["use-yarn"] ? "yarn" : null, + ) + + if (argv.version || argv.v) { + // noop + } else if (argv.help || argv.h) { + printHelp() } else { - console.log("Applying patches...") - const reverse = !!argv["reverse"] - applyPatchesForApp({ appPath, reverse, patchDir }) + const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep)) + if (patchDir.startsWith("/")) { + throw new Error("--patch-dir must be a relative path") + } + if (packageNames.length) { + const includePaths = makeRegExp( + argv.include, + "include", + /.*/, + argv["case-sensitive-path-filtering"], + ) + const excludePaths = makeRegExp( + argv.exclude, + "exclude", + /package\.json$/, + argv["case-sensitive-path-filtering"], + ) + + for (const packagePathSpecifier of packageNames) { + await makePatch({ + packagePathSpecifier, + appPath, + packageManager, + includePaths, + excludePaths, + patchDir, + }) + } + } else { + if (packageManager === "berry") { + console.log( + "You're using yarn 2, so running `patch-package` without arguments has no effect! Instead your patches will be applied by yarn itself :)", + ) + process.exit(0) + } + console.log("Applying patches...") + const reverse = !!argv["reverse"] + applyPatchesForApp({ appPath, reverse, patchDir }) + } } } @@ -126,3 +136,5 @@ Usage: Make regexps used in --include or --exclude filters case-sensitive. `) } + +main() diff --git a/src/makePatch.ts b/src/makePatch.ts index c4c70bb5..8d11bed3 100644 --- a/src/makePatch.ts +++ b/src/makePatch.ts @@ -9,19 +9,22 @@ import { mkdirSync, unlinkSync, mkdirpSync, + readdirSync, } from "fs-extra" import { sync as rimraf } from "rimraf" import { copySync } from "fs-extra" -import { dirSync } from "tmp" import { getPatchFiles } from "./patchFs" import { getPatchDetailsFromCliString, getPackageDetailsFromPatchFilename, + PackageDetails, } from "./PackageDetails" import { resolveRelativeFileDependencies } from "./resolveRelativeFileDependencies" import { getPackageResolution } from "./getPackageResolution" import { parsePatchFile } from "./patch/parse" import { gzipSync } from "zlib" +import readline from "readline" +import { dirSync } from "tmp" function printNoPackageFoundError( packageName: string, @@ -32,9 +35,105 @@ function printNoPackageFoundError( File not found: ${packageJsonPath}`, ) + process.exit(1) +} + +function printNoUnpluggedPackageFound({ + packageName, + unpluggedDir, +}: { + packageName: string + unpluggedDir: string +}) { + console.error( + `Could not find an unnplugged version of ${packageName} in ${unpluggedDir}`, + ) + process.exit(1) } -export function makePatch({ +async function findRelativePackagePath({ + appPath, + packageDetails, + packageManager, +}: { + appPath: string + packageDetails: PackageDetails + packageManager: PackageManager +}): Promise { + if (packageManager === "berry") { + const unpluggedDir = join(appPath, ".yarn/unplugged") + if (!existsSync(unpluggedDir)) { + printNoUnpluggedPackageFound({ + packageName: packageDetails.name, + unpluggedDir, + }) + } + const dirs = readdirSync(unpluggedDir).filter( + name => + name.startsWith(packageDetails.name) && + name + .slice(packageDetails.name.length) + // optional protocol (e.g. npm) - optional version - hash + .match(/^(-\w+)?(-\d+\.\d+\.\d+.*?)?-[0-9a-f]+$/), + ) + if (dirs.length === 0) { + printNoUnpluggedPackageFound({ + packageName: packageDetails.name, + unpluggedDir, + }) + } + if (dirs.length > 1) { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }) + + return new Promise(resolvePromise => { + rl.question( + `There are mulitple unplugged versions of ${chalk.bold( + packageDetails.name, + )}\n\n` + + dirs + .map( + (dir, index) => + `${chalk.cyan.bold(index.toString())}${chalk.gray( + ")", + )} ${dir}`, + ) + .join("\n") + + "\n\n" + + `Please select a ${chalk.cyan.bold("version")} ` + + chalk.yellow.bold(">> "), + answer => { + const index = Number(answer.trim()) + if (index != null && index >= 0 && index < dirs.length) { + resolvePromise( + join( + ".yarn/unplugged", + dirs[index], + "node_modules", + packageDetails.name, + ), + ) + } else { + console.error(chalk.red.bold("That didn't work.")) + console.error( + `Please try again and provide a number in the range 0-${dirs.length - + 1}`, + ) + process.exit(1) + } + }, + ) + }) + } + return join(".yarn/unplugged", dirs[0], "node_modules", packageDetails.name) + } + + return packageDetails.path +} + +export async function makePatch({ packagePathSpecifier, appPath, packageManager, @@ -55,17 +154,22 @@ export function makePatch({ console.error("No such package", packagePathSpecifier) return } - const appPackageJson = require(join(appPath, "package.json")) - const packagePath = join(appPath, packageDetails.path) - const packageJsonPath = join(packagePath, "package.json") - - if (!existsSync(packageJsonPath)) { - printNoPackageFoundError(packagePathSpecifier, packageJsonPath) - process.exit(1) + const appJson = require(join(appPath, "package.json")) + const relativePackagePath = await findRelativePackagePath({ + appPath, + packageDetails, + packageManager, + }) + + const appPackageJsonPath = join(appPath, relativePackagePath, "package.json") + + if (!existsSync(appPackageJsonPath)) { + // won't happen with berry + printNoPackageFoundError(packagePathSpecifier, appPackageJsonPath) } const tmpRepo = dirSync({ unsafeCleanup: true }) - const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path) + const tmpRepoPackagePath = join(tmpRepo.name, relativePackagePath) const tmpRepoNpmRoot = tmpRepoPackagePath.slice( 0, -`/node_modules/${packageDetails.name}`.length, @@ -92,7 +196,7 @@ export function makePatch({ }, resolutions: resolveRelativeFileDependencies( appPath, - appPackageJson.resolutions || {}, + appJson.resolutions || {}, ), }), )