From 9c6522eabc94686d5418de48270898fde5e0102a Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 27 Sep 2018 12:56:31 -0700 Subject: [PATCH 1/5] Support Windows paths for pnp. --- src/config.js | 8 -------- src/util/generate-pnp-map-api.tpl.js | 20 ++++++++++++++++---- src/util/generate-pnp-map.js | 12 +++++++++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/config.js b/src/config.js index 4374375b9b..86a636b36c 100644 --- a/src/config.js +++ b/src/config.js @@ -395,14 +395,6 @@ export default class Config { this.plugnplayEnabled = false; } - if (process.platform === 'win32') { - if (this.plugnplayEnabled) { - this.reporter.warn(this.reporter.lang('plugnplayWindowsSupport')); - } - this.plugnplayEnabled = false; - this.plugnplayPersist = false; - } - this.plugnplayShebang = String(this.getOption('plugnplay-shebang') || '') || '/usr/bin/env node'; this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist') || '') || null; diff --git a/src/util/generate-pnp-map-api.tpl.js b/src/util/generate-pnp-map-api.tpl.js index ece2496ce8..1eeeab5cfa 100644 --- a/src/util/generate-pnp-map-api.tpl.js +++ b/src/util/generate-pnp-map-api.tpl.js @@ -22,15 +22,18 @@ const blacklistedLocator = {name: NaN, reference: NaN}; const patchedModules = new Map(); const fallbackLocators = [topLevelLocator]; -// Splits a require request into its components, or return null if the request is a file path -const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; +// Matches backslashes of Windows paths +const backwardSlashRegExp = /\\/g; + +// Matches if the path must point to a directory (ie ends with /) +const isDirRegExp = /\/$/; // Matches if the path starts with a valid path qualifier (./, ../, /) // eslint-disable-next-line no-unused-vars const isStrictRegExp = /^\.{0,2}\//; -// Matches if the path must point to a directory (ie ends with /) -const isDirRegExp = /\/$/; +// Splits a require request into its components, or return null if the request is a file path +const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/; // Keep a reference around ("module" is a common name in this context, so better rename it to something more significant) const pnpModule = module; @@ -229,6 +232,15 @@ function makeFakeModule(path) { return fakeModule; } +/** + * Normalize path to posix format. + */ + +// eslint-disable-next-line no-unused-vars +function normalizePath(fsPath) { + return process.platform === 'win32' ? fsPath.replace(backwardSlashRegExp, '/') : fsPath; +} + /** * Forward the resolution to the next resolver (usually the native one) */ diff --git a/src/util/generate-pnp-map.js b/src/util/generate-pnp-map.js index 3e78cdba74..7956721db9 100644 --- a/src/util/generate-pnp-map.js +++ b/src/util/generate-pnp-map.js @@ -11,6 +11,8 @@ const crypto = require('crypto'); const invariant = require('invariant'); const path = require('path'); +const backwardSlashRegExp = /\\/g; + const OFFLINE_CACHE_EXTENSION = `.zip`; type PackageInformation = {| @@ -100,7 +102,7 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation // Generate a function that, given a file path, returns the associated package name code += `exports.findPackageLocator = function findPackageLocator(location) {\n`; - code += ` let relativeLocation = path.relative(__dirname, location);\n`; + code += ` let relativeLocation = normalizePath(path.relative(__dirname, location));\n`; code += `\n`; code += ` if (!relativeLocation.match(isStrictRegExp))\n`; code += ` relativeLocation = \`./\${relativeLocation}\`;\n`; @@ -136,7 +138,7 @@ async function getPackageInformationStores( const blacklistedLocations: Set = new Set(); const getCachePath = (fsPath: string) => { - const cacheRelativePath = path.relative(config.cacheFolder, fsPath); + const cacheRelativePath = normalizePath(path.relative(config.cacheFolder, fsPath)); // if fsPath is not inside cacheRelativePath, we just skip it if (cacheRelativePath.match(/^\.\.\//)) { @@ -164,8 +166,12 @@ async function getPackageInformationStores( return path.resolve(offlineCacheFolder, `${cacheEntry}${OFFLINE_CACHE_EXTENSION}`, internalPath.join('/')); }; + const normalizePath = (fsPath: string) => { + return process.platform === 'win32' ? fsPath.replace(backwardSlashRegExp, '/') : fsPath; + }; + const normalizeDirectoryPath = (fsPath: string) => { - let relativePath = path.relative(targetDirectory, resolveOfflineCacheFolder(fsPath)); + let relativePath = normalizePath(path.relative(targetDirectory, resolveOfflineCacheFolder(fsPath))); if (!relativePath.match(/^\.{0,2}\//)) { relativePath = `./${relativePath}`; From 868d596bd110043a8fe2d568bbd898d9fe8d077a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 1 Oct 2018 16:38:00 +0100 Subject: [PATCH 2/5] Update config.js --- src/config.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/config.js b/src/config.js index 86a636b36c..5e2380a352 100644 --- a/src/config.js +++ b/src/config.js @@ -395,6 +395,19 @@ export default class Config { this.plugnplayEnabled = false; } + if (process.platform === 'win32') { + const cacheRootFolderDrive = path.parse(this._cacheRootFolder).root; + const lockfileFolderDrive = path.parse(this.lockfileFolder).root; + + if (cacheRootFolderDrive !== lockfileFolderDrive) { + if (this.plugnplayEnabled) { + this.reporter.warn(this.reporter.lang('plugnplayWindowsSupport')); + } + this.plugnplayEnabled = false; + this.plugnplayPersist = false; + } + } + this.plugnplayShebang = String(this.getOption('plugnplay-shebang') || '') || '/usr/bin/env node'; this.plugnplayBlacklist = String(this.getOption('plugnplay-blacklist') || '') || null; From c67995f8f2ea6da309f83355644bc4a412fd4906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 1 Oct 2018 16:39:55 +0100 Subject: [PATCH 3/5] Update en.js --- src/reporters/lang/en.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index 9e5f679069..9d9a365e67 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -358,7 +358,7 @@ const messages = { unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", plugnplayWindowsSupport: - "Plug'n'Play is ignored on Windows for now - contributions welcome! https://github.com/yarnpkg/yarn/issues/6402", + "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', From 0fbd26b83a0c5be59ff5f507d93823c492e7f4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Mon, 1 Oct 2018 17:15:00 +0100 Subject: [PATCH 4/5] Fixes lint --- src/config.js | 2 +- src/reporters/lang/en.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/config.js b/src/config.js index 5e2380a352..225d41066f 100644 --- a/src/config.js +++ b/src/config.js @@ -395,7 +395,7 @@ export default class Config { this.plugnplayEnabled = false; } - if (process.platform === 'win32') { + if (process.platform === 'win32') { const cacheRootFolderDrive = path.parse(this._cacheRootFolder).root; const lockfileFolderDrive = path.parse(this.lockfileFolder).root; diff --git a/src/reporters/lang/en.js b/src/reporters/lang/en.js index 9d9a365e67..1f0468c23b 100644 --- a/src/reporters/lang/en.js +++ b/src/reporters/lang/en.js @@ -357,8 +357,7 @@ const messages = { unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", - plugnplayWindowsSupport: - "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", + plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', From 77e32188d658d9384115a9c5f68a257959b01f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Tue, 2 Oct 2018 11:01:48 +0100 Subject: [PATCH 5/5] Updates the changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6117ff09e9..3013ef545b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa ## Master +- Adds initial support for PnP on Windows + + [#6447](https://github.com/yarnpkg/yarn/pull/6447) - [**John-David Dalton**](https://twitter.com/jdalton) + - Adds a special logic to PnP for ESLint compatibility (temporary, until [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125) is fixed) [#6449](https://github.com/yarnpkg/yarn/pull/6449) - [**Maƫl Nison**](https://twitter.com/arcanis)