-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
index.ts
150 lines (134 loc) Β· 5.47 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import {Hooks as CoreHooks, Plugin, Project, SettingsType, WindowsLinkType} from '@yarnpkg/core';
import {Filename, PortablePath, npath, ppath, xfs} from '@yarnpkg/fslib';
import {Hooks as StageHooks} from '@yarnpkg/plugin-stage';
import {pathToFileURL} from 'url';
import {PnpLinker} from './PnpLinker';
import UnplugCommand from './commands/unplug';
import * as jsInstallUtils from './jsInstallUtils';
import * as pnpUtils from './pnpUtils';
export {UnplugCommand};
export {jsInstallUtils};
export {pnpUtils};
export const getPnpPath = (project: Project) => {
return {
cjs: ppath.join(project.cwd, Filename.pnpCjs),
data: ppath.join(project.cwd, Filename.pnpData),
esmLoader: ppath.join(project.cwd, Filename.pnpEsmLoader),
};
};
export const quotePathIfNeeded = (path: string) => {
return /\s/.test(path) ? JSON.stringify(path) : path;
};
async function setupScriptEnvironment(project: Project, env: NodeJS.ProcessEnv, makePathWrapper: (name: string, argv0: string, args: Array<string>) => Promise<void>) {
// We still support .pnp.js files to improve multi-project compatibility.
// TODO: Drop the question mark in the RegExp after .pnp.js files stop being used.
// TODO: Support `-r` as an alias for `--require` (in all packages)
const pnpRegularExpression = /\s*--require\s+\S*\.pnp\.c?js\s*/g;
const esmLoaderExpression = /\s*--experimental-loader\s+\S*\.pnp\.loader\.mjs\s*/;
const nodeOptions = (env.NODE_OPTIONS ?? ``)
.replace(pnpRegularExpression, ` `)
.replace(esmLoaderExpression, ` `)
.trim();
// We remove the PnP hook from NODE_OPTIONS because the process can have
// NODE_OPTIONS set while changing linkers, which affects build scripts.
if (project.configuration.get(`nodeLinker`) !== `pnp`) {
// When set to an empty string, some tools consider it as explicitly set
// to the empty value, and do not set their own value.
env.NODE_OPTIONS = nodeOptions ? nodeOptions : undefined;
return;
}
const pnpPath = getPnpPath(project);
let pnpRequire = `--require ${quotePathIfNeeded(npath.fromPortablePath(pnpPath.cjs))}`;
if (xfs.existsSync(pnpPath.esmLoader))
pnpRequire = `${pnpRequire} --experimental-loader ${pathToFileURL(npath.fromPortablePath(pnpPath.esmLoader)).href}`;
if (xfs.existsSync(pnpPath.cjs)) {
env.NODE_OPTIONS = nodeOptions ? `${pnpRequire} ${nodeOptions}` : pnpRequire;
}
}
async function populateYarnPaths(project: Project, definePath: (path: PortablePath | null) => void) {
const pnpPath = getPnpPath(project);
definePath(pnpPath.cjs);
definePath(pnpPath.data);
definePath(pnpPath.esmLoader);
definePath(project.configuration.get(`pnpUnpluggedFolder`));
}
declare module '@yarnpkg/core' {
interface ConfigurationValueMap {
nodeLinker: string;
winLinkType: string;
pnpMode: string;
pnpShebang: string;
pnpIgnorePatterns: Array<string>;
pnpEnableEsmLoader: boolean;
pnpEnableInlining: boolean;
pnpFallbackMode: string;
pnpUnpluggedFolder: PortablePath;
}
}
const plugin: Plugin<CoreHooks & StageHooks> = {
hooks: {
populateYarnPaths,
setupScriptEnvironment,
},
configuration: {
nodeLinker: {
description: `The linker used for installing Node packages, one of: "pnp", "pnpm", or "node-modules"`,
type: SettingsType.STRING,
default: `pnp`,
},
winLinkType: {
description: `Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.`,
type: SettingsType.STRING,
values: [
WindowsLinkType.JUNCTIONS,
WindowsLinkType.SYMLINKS,
],
default: WindowsLinkType.JUNCTIONS,
},
pnpMode: {
description: `If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.`,
type: SettingsType.STRING,
default: `strict`,
},
pnpShebang: {
description: `String to prepend to the generated PnP script`,
type: SettingsType.STRING,
default: `#!/usr/bin/env node`,
},
pnpIgnorePatterns: {
description: `Array of glob patterns; files matching them will use the classic resolution`,
type: SettingsType.STRING,
default: [],
isArray: true,
},
pnpEnableEsmLoader: {
description: `If true, Yarn will generate an ESM loader (\`.pnp.loader.mjs\`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.`,
type: SettingsType.BOOLEAN,
default: false,
},
pnpEnableInlining: {
description: `If true, the PnP data will be inlined along with the generated loader`,
type: SettingsType.BOOLEAN,
default: true,
},
pnpFallbackMode: {
description: `If true, the generated PnP loader will follow the top-level fallback rule`,
type: SettingsType.STRING,
default: `dependencies-only`,
},
pnpUnpluggedFolder: {
description: `Folder where the unplugged packages must be stored`,
type: SettingsType.ABSOLUTE_PATH,
default: `./.yarn/unplugged`,
},
},
linkers: [
PnpLinker,
],
commands: [
UnplugCommand,
],
};
export {PnpInstaller, PnpLinker} from './PnpLinker';
// eslint-disable-next-line arca/no-default-export
export default plugin;