-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
index.ts
135 lines (116 loc) Β· 4.74 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
import {Hooks as CoreHooks, Plugin, Project, SettingsType} from '@yarnpkg/core';
import {Filename, PortablePath, npath, ppath, xfs} from '@yarnpkg/fslib';
import {Hooks as StageHooks} from '@yarnpkg/plugin-stage';
import semver from 'semver';
import {PnpLinker} from './PnpLinker';
import unplug from './commands/unplug';
import * as jsInstallUtils from './jsInstallUtils';
import * as pnpUtils from './pnpUtils';
export {jsInstallUtils};
export {pnpUtils};
export const getPnpPath = (project: Project) => {
const mainFilename = `.pnp.cjs`;
const otherFilename = `.pnp.js`;
return {
main: ppath.join(project.cwd, mainFilename as Filename),
other: ppath.join(project.cwd, otherFilename as Filename),
esmLoader: ppath.join(project.cwd, `experimental-pnp-esm-loader.js` as Filename),
};
};
export const quotePathIfNeeded = (path: string) => {
return /\s/.test(path) ? JSON.stringify(path) : path;
};
async function setupScriptEnvironment(project: Project, env: {[key: string]: string}, makePathWrapper: (name: string, argv0: string, args: Array<string>) => Promise<void>) {
const pnpPath = getPnpPath(project);
let pnpRequire = `--require ${quotePathIfNeeded(npath.fromPortablePath(pnpPath.main))}`;
if (pnpPath.main.endsWith(`.cjs`) && xfs.existsSync(pnpPath.esmLoader))
pnpRequire = `${pnpRequire} --experimental-loader file:///${npath.fromPortablePath(pnpPath.esmLoader).replace(/\\/g, `/`)}`;
if (pnpPath.main.includes(` `) && semver.lt(process.versions.node, `12.0.0`))
throw new Error(`Expected the build location to not include spaces when using Node < 12.0.0 (${process.versions.node})`);
if (xfs.existsSync(pnpPath.main)) {
let nodeOptions = env.NODE_OPTIONS || ``;
const pnpRegularExpression = /\s*--require\s+\S*\.pnp\.c?js\s*/g;
const esmLoaderExpression = /\s*--experimental-loader\s+\S*experimental-pnp-esm-loader\.js\s*/;
nodeOptions = nodeOptions.replace(pnpRegularExpression, ` `).replace(esmLoaderExpression, ` `).trim();
nodeOptions = nodeOptions ? `${pnpRequire} ${nodeOptions}` : pnpRequire;
env.NODE_OPTIONS = nodeOptions;
}
}
async function populateYarnPaths(project: Project, definePath: (path: PortablePath | null) => void) {
const pnpPath = getPnpPath(project);
definePath(pnpPath.main);
definePath(pnpPath.other);
definePath(pnpPath.esmLoader);
definePath(project.configuration.get(`pnpDataPath`));
definePath(project.configuration.get(`pnpUnpluggedFolder`));
}
declare module '@yarnpkg/core' {
interface ConfigurationValueMap {
nodeLinker: string;
pnpMode: string;
pnpShebang: string;
pnpIgnorePatterns: Array<string>;
pnpEnableInlining: boolean;
pnpFallbackMode: string;
pnpUnpluggedFolder: PortablePath;
pnpDataPath: PortablePath;
}
}
const plugin: Plugin<CoreHooks & StageHooks> = {
hooks: {
populateYarnPaths,
setupScriptEnvironment,
},
configuration: {
nodeLinker: {
description: `The linker used for installing Node packages, one of: "pnp", "node-modules"`,
type: SettingsType.STRING,
default: `pnp`,
},
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,
},
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`,
},
pnpDataPath: {
description: `Path of the file where the PnP data (used by the loader) must be written`,
type: SettingsType.ABSOLUTE_PATH,
default: `./.pnp.data.json`,
},
},
linkers: [
PnpLinker,
],
commands: [
unplug,
],
};
export {PnpInstaller, PnpLinker} from './PnpLinker';
// eslint-disable-next-line arca/no-default-export
export default plugin;