Skip to content

Commit 9028f9a

Browse files
jdaltonarcanis
authored andcommitted
Support Windows paths for pnp. (#6447)
* Support Windows paths for pnp. * Update config.js * Update en.js * Fixes lint * Updates the changelog
1 parent 0c8c302 commit 9028f9a

5 files changed

Lines changed: 39 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Please add one entry in this file for each change in Yarn's behavior. Use the sa
44

55
## Master
66

7+
- Adds initial support for PnP on Windows
8+
9+
[#6447](https://github.com/yarnpkg/yarn/pull/6447) - [**John-David Dalton**](https://twitter.com/jdalton)
10+
711
- Adds a special logic to PnP for ESLint compatibility (temporary, until [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125) is fixed)
812

913
[#6449](https://github.com/yarnpkg/yarn/pull/6449) - [**Maël Nison**](https://twitter.com/arcanis)

src/config.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,16 @@ export default class Config {
396396
}
397397

398398
if (process.platform === 'win32') {
399-
if (this.plugnplayEnabled) {
400-
this.reporter.warn(this.reporter.lang('plugnplayWindowsSupport'));
399+
const cacheRootFolderDrive = path.parse(this._cacheRootFolder).root;
400+
const lockfileFolderDrive = path.parse(this.lockfileFolder).root;
401+
402+
if (cacheRootFolderDrive !== lockfileFolderDrive) {
403+
if (this.plugnplayEnabled) {
404+
this.reporter.warn(this.reporter.lang('plugnplayWindowsSupport'));
405+
}
406+
this.plugnplayEnabled = false;
407+
this.plugnplayPersist = false;
401408
}
402-
this.plugnplayEnabled = false;
403-
this.plugnplayPersist = false;
404409
}
405410

406411
this.plugnplayShebang = String(this.getOption('plugnplay-shebang') || '') || '/usr/bin/env node';

src/reporters/lang/en.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,7 @@ const messages = {
357357

358358
unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.",
359359

360-
plugnplayWindowsSupport:
361-
"Plug'n'Play is ignored on Windows for now - contributions welcome! https://github.com/yarnpkg/yarn/issues/6402",
360+
plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives",
362361

363362
packageInstalledWithBinaries: 'Installed $0 with binaries:',
364363
packageHasBinaries: '$0 has binaries:',

src/util/generate-pnp-map-api.tpl.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@ const blacklistedLocator = {name: NaN, reference: NaN};
2222
const patchedModules = new Map();
2323
const fallbackLocators = [topLevelLocator];
2424

25-
// Splits a require request into its components, or return null if the request is a file path
26-
const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/;
25+
// Matches backslashes of Windows paths
26+
const backwardSlashRegExp = /\\/g;
27+
28+
// Matches if the path must point to a directory (ie ends with /)
29+
const isDirRegExp = /\/$/;
2730

2831
// Matches if the path starts with a valid path qualifier (./, ../, /)
2932
// eslint-disable-next-line no-unused-vars
3033
const isStrictRegExp = /^\.{0,2}\//;
3134

32-
// Matches if the path must point to a directory (ie ends with /)
33-
const isDirRegExp = /\/$/;
35+
// Splits a require request into its components, or return null if the request is a file path
36+
const pathRegExp = /^(?!\.{0,2}(?:\/|$))((?:@[^\/]+\/)?[^\/]+)\/?(.*|)$/;
3437

3538
// Keep a reference around ("module" is a common name in this context, so better rename it to something more significant)
3639
const pnpModule = module;
@@ -229,6 +232,15 @@ function makeFakeModule(path) {
229232
return fakeModule;
230233
}
231234

235+
/**
236+
* Normalize path to posix format.
237+
*/
238+
239+
// eslint-disable-next-line no-unused-vars
240+
function normalizePath(fsPath) {
241+
return process.platform === 'win32' ? fsPath.replace(backwardSlashRegExp, '/') : fsPath;
242+
}
243+
232244
/**
233245
* Forward the resolution to the next resolver (usually the native one)
234246
*/

src/util/generate-pnp-map.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const crypto = require('crypto');
1111
const invariant = require('invariant');
1212
const path = require('path');
1313

14+
const backwardSlashRegExp = /\\/g;
15+
1416
const OFFLINE_CACHE_EXTENSION = `.zip`;
1517

1618
type PackageInformation = {|
@@ -100,7 +102,7 @@ function generateFindPackageLocator(packageInformationStores: PackageInformation
100102

101103
// Generate a function that, given a file path, returns the associated package name
102104
code += `exports.findPackageLocator = function findPackageLocator(location) {\n`;
103-
code += ` let relativeLocation = path.relative(__dirname, location);\n`;
105+
code += ` let relativeLocation = normalizePath(path.relative(__dirname, location));\n`;
104106
code += `\n`;
105107
code += ` if (!relativeLocation.match(isStrictRegExp))\n`;
106108
code += ` relativeLocation = \`./\${relativeLocation}\`;\n`;
@@ -136,7 +138,7 @@ async function getPackageInformationStores(
136138
const blacklistedLocations: Set<string> = new Set();
137139

138140
const getCachePath = (fsPath: string) => {
139-
const cacheRelativePath = path.relative(config.cacheFolder, fsPath);
141+
const cacheRelativePath = normalizePath(path.relative(config.cacheFolder, fsPath));
140142

141143
// if fsPath is not inside cacheRelativePath, we just skip it
142144
if (cacheRelativePath.match(/^\.\.\//)) {
@@ -164,8 +166,12 @@ async function getPackageInformationStores(
164166
return path.resolve(offlineCacheFolder, `${cacheEntry}${OFFLINE_CACHE_EXTENSION}`, internalPath.join('/'));
165167
};
166168

169+
const normalizePath = (fsPath: string) => {
170+
return process.platform === 'win32' ? fsPath.replace(backwardSlashRegExp, '/') : fsPath;
171+
};
172+
167173
const normalizeDirectoryPath = (fsPath: string) => {
168-
let relativePath = path.relative(targetDirectory, resolveOfflineCacheFolder(fsPath));
174+
let relativePath = normalizePath(path.relative(targetDirectory, resolveOfflineCacheFolder(fsPath)));
169175

170176
if (!relativePath.match(/^\.{0,2}\//)) {
171177
relativePath = `./${relativePath}`;

0 commit comments

Comments
 (0)