UNPKG

11 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.getModulesPath = exports.createForProject = exports.YarnPackageManager = exports.NpmPackageManager = exports.isUsingYarn = void 0;
7const json_file_1 = __importDefault(require("@expo/json-file"));
8const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
9const ansi_regex_1 = __importDefault(require("ansi-regex"));
10const find_yarn_workspace_root_1 = __importDefault(require("find-yarn-workspace-root"));
11const fs_1 = require("fs");
12const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
13const path_1 = __importDefault(require("path"));
14const rimraf_1 = __importDefault(require("rimraf"));
15const split_1 = __importDefault(require("split"));
16const stream_1 = require("stream");
17const isYarnOfflineAsync_1 = __importDefault(require("./utils/isYarnOfflineAsync"));
18/**
19 * Disable various postinstall scripts
20 * - https://github.com/opencollective/opencollective-postinstall/pull/9
21 */
22const disableAdsEnv = { DISABLE_OPENCOLLECTIVE: '1', ADBLOCK: '1' };
23const ansi = `(?:${ansi_regex_1.default().source})*`;
24const npmPeerDependencyWarningPattern = new RegExp(`${ansi}npm${ansi} ${ansi}WARN${ansi}.+You must install peer dependencies yourself\\.\n`, 'g');
25const yarnPeerDependencyWarningPattern = new RegExp(`${ansi}warning${ansi} "[^"]+" has (?:unmet|incorrect) peer dependency "[^"]+"\\.\n`, 'g');
26/**
27 * Returns true if the project is using yarn, false if the project is using npm.
28 *
29 * @param projectRoot
30 */
31function isUsingYarn(projectRoot) {
32 const workspaceRoot = find_yarn_workspace_root_1.default(projectRoot);
33 if (workspaceRoot) {
34 return fs_1.existsSync(path_1.default.join(workspaceRoot, 'yarn.lock'));
35 }
36 return fs_1.existsSync(path_1.default.join(projectRoot, 'yarn.lock'));
37}
38exports.isUsingYarn = isUsingYarn;
39class NpmStderrTransform extends stream_1.Transform {
40 _transform(chunk, encoding, callback) {
41 this.push(chunk.toString().replace(npmPeerDependencyWarningPattern, ''));
42 callback();
43 }
44}
45class YarnStderrTransform extends stream_1.Transform {
46 _transform(chunk, encoding, callback) {
47 this.push(chunk.toString().replace(yarnPeerDependencyWarningPattern, ''));
48 callback();
49 }
50}
51class NpmPackageManager {
52 constructor({ cwd, log, silent }) {
53 this.log = log || console.log;
54 this.options = {
55 env: {
56 ...process.env,
57 ...disableAdsEnv,
58 },
59 cwd,
60 ...(silent
61 ? { ignoreStdio: true }
62 : {
63 stdio: ['inherit', 'inherit', 'pipe'],
64 }),
65 };
66 }
67 get name() {
68 return 'npm';
69 }
70 async installAsync() {
71 await this._runAsync(['install']);
72 }
73 async addGlobalAsync(...names) {
74 if (!names.length)
75 return this.installAsync();
76 await this._runAsync(['install', '--global', ...names]);
77 }
78 async addAsync(...names) {
79 if (!names.length)
80 return this.installAsync();
81 const { versioned, unversioned } = this._parseSpecs(names);
82 if (versioned.length) {
83 await this._patchAsync(versioned, 'dependencies');
84 await this._runAsync(['install']);
85 }
86 if (unversioned.length) {
87 await this._runAsync(['install', '--save', ...unversioned.map(spec => spec.raw)]);
88 }
89 }
90 async addDevAsync(...names) {
91 if (!names.length)
92 return this.installAsync();
93 const { versioned, unversioned } = this._parseSpecs(names);
94 if (versioned.length) {
95 await this._patchAsync(versioned, 'devDependencies');
96 await this._runAsync(['install']);
97 }
98 if (unversioned.length) {
99 await this._runAsync(['install', '--save-dev', ...unversioned.map(spec => spec.raw)]);
100 }
101 }
102 async removeAsync(...names) {
103 await this._runAsync(['uninstall', ...names]);
104 }
105 async versionAsync() {
106 const { stdout } = await spawn_async_1.default('npm', ['--version'], { stdio: 'pipe' });
107 return stdout.trim();
108 }
109 async getConfigAsync(key) {
110 const { stdout } = await spawn_async_1.default('npm', ['config', 'get', key], { stdio: 'pipe' });
111 return stdout.trim();
112 }
113 async removeLockfileAsync() {
114 if (!this.options.cwd) {
115 throw new Error('cwd required for NpmPackageManager.removeLockfileAsync');
116 }
117 const lockfilePath = path_1.default.join(this.options.cwd, 'package-lock.json');
118 if (fs_1.existsSync(lockfilePath)) {
119 rimraf_1.default.sync(lockfilePath);
120 }
121 }
122 async cleanAsync() {
123 if (!this.options.cwd) {
124 throw new Error('cwd required for NpmPackageManager.cleanAsync');
125 }
126 const nodeModulesPath = path_1.default.join(this.options.cwd, 'node_modules');
127 if (fs_1.existsSync(nodeModulesPath)) {
128 rimraf_1.default.sync(nodeModulesPath);
129 }
130 }
131 // Private
132 async _runAsync(args) {
133 if (!this.options.ignoreStdio) {
134 this.log(`> npm ${args.join(' ')}`);
135 }
136 // Have spawnAsync consume stdio but we don't actually do anything with it if it's ignored
137 const promise = spawn_async_1.default('npm', [...args], { ...this.options, ignoreStdio: false });
138 if (promise.child.stderr && !this.options.ignoreStdio) {
139 promise.child.stderr
140 .pipe(split_1.default(/\r?\n/, (line) => line + '\n'))
141 .pipe(new NpmStderrTransform())
142 .pipe(process.stderr);
143 }
144 return promise;
145 }
146 _parseSpecs(names) {
147 const result = { versioned: [], unversioned: [] };
148 names
149 .map(name => npm_package_arg_1.default(name))
150 .forEach(spec => {
151 if (spec.rawSpec) {
152 result.versioned.push(spec);
153 }
154 else {
155 result.unversioned.push(spec);
156 }
157 });
158 return result;
159 }
160 async _patchAsync(specs, packageType) {
161 const pkgPath = path_1.default.join(this.options.cwd || '.', 'package.json');
162 const pkg = await json_file_1.default.readAsync(pkgPath);
163 specs.forEach(spec => {
164 pkg[packageType] = pkg[packageType] || {};
165 // @ts-ignore
166 pkg[packageType][spec.name] = spec.rawSpec;
167 });
168 await json_file_1.default.writeAsync(pkgPath, pkg, { json5: false });
169 }
170}
171exports.NpmPackageManager = NpmPackageManager;
172class YarnPackageManager {
173 constructor({ cwd, log, silent }) {
174 this.log = log || console.log;
175 this.options = {
176 env: {
177 ...process.env,
178 ...disableAdsEnv,
179 },
180 cwd,
181 ...(silent
182 ? { ignoreStdio: true }
183 : {
184 stdio: ['inherit', 'inherit', 'pipe'],
185 }),
186 };
187 }
188 get name() {
189 return 'Yarn';
190 }
191 async withOfflineSupportAsync(...args) {
192 if (await isYarnOfflineAsync_1.default()) {
193 args.push('--offline');
194 }
195 // TODO: Maybe prompt about being offline and using local yarn cache.
196 return args;
197 }
198 async installAsync() {
199 const args = await this.withOfflineSupportAsync('install');
200 await this._runAsync(args);
201 }
202 async addGlobalAsync(...names) {
203 if (!names.length)
204 return this.installAsync();
205 const args = await this.withOfflineSupportAsync('global', 'add');
206 args.push(...names);
207 await this._runAsync(args);
208 }
209 async addAsync(...names) {
210 if (!names.length)
211 return this.installAsync();
212 const args = await this.withOfflineSupportAsync('add');
213 args.push(...names);
214 await this._runAsync(args);
215 }
216 async addDevAsync(...names) {
217 if (!names.length)
218 return this.installAsync();
219 const args = await this.withOfflineSupportAsync('add', '--dev');
220 args.push(...names);
221 await this._runAsync(args);
222 }
223 async removeAsync(...names) {
224 await this._runAsync(['remove', ...names]);
225 }
226 async versionAsync() {
227 const { stdout } = await spawn_async_1.default('yarnpkg', ['--version'], { stdio: 'pipe' });
228 return stdout.trim();
229 }
230 async getConfigAsync(key) {
231 const { stdout } = await spawn_async_1.default('yarnpkg', ['config', 'get', key], { stdio: 'pipe' });
232 return stdout.trim();
233 }
234 async removeLockfileAsync() {
235 if (!this.options.cwd) {
236 throw new Error('cwd required for YarnPackageManager.removeLockfileAsync');
237 }
238 const lockfilePath = path_1.default.join(this.options.cwd, 'yarn-lock.json');
239 if (fs_1.existsSync(lockfilePath)) {
240 rimraf_1.default.sync(lockfilePath);
241 }
242 }
243 async cleanAsync() {
244 if (!this.options.cwd) {
245 throw new Error('cwd required for YarnPackageManager.cleanAsync');
246 }
247 const nodeModulesPath = path_1.default.join(this.options.cwd, 'node_modules');
248 if (fs_1.existsSync(nodeModulesPath)) {
249 rimraf_1.default.sync(nodeModulesPath);
250 }
251 }
252 // Private
253 async _runAsync(args) {
254 if (!this.options.ignoreStdio) {
255 this.log(`> yarn ${args.join(' ')}`);
256 }
257 // Have spawnAsync consume stdio but we don't actually do anything with it if it's ignored
258 const promise = spawn_async_1.default('yarnpkg', args, { ...this.options, ignoreStdio: false });
259 if (promise.child.stderr && !this.options.ignoreStdio) {
260 promise.child.stderr.pipe(new YarnStderrTransform()).pipe(process.stderr);
261 }
262 return promise;
263 }
264}
265exports.YarnPackageManager = YarnPackageManager;
266function createForProject(projectRoot, options = {}) {
267 let PackageManager;
268 if (options.npm) {
269 PackageManager = NpmPackageManager;
270 }
271 else if (options.yarn) {
272 PackageManager = YarnPackageManager;
273 }
274 else if (isUsingYarn(projectRoot)) {
275 PackageManager = YarnPackageManager;
276 }
277 else {
278 PackageManager = NpmPackageManager;
279 }
280 return new PackageManager({ cwd: projectRoot, log: options.log, silent: options.silent });
281}
282exports.createForProject = createForProject;
283function getModulesPath(projectRoot) {
284 const workspaceRoot = find_yarn_workspace_root_1.default(path_1.default.resolve(projectRoot)); // Absolute path or null
285 if (workspaceRoot) {
286 return path_1.default.resolve(workspaceRoot, 'node_modules');
287 }
288 return path_1.default.resolve(projectRoot, 'node_modules');
289}
290exports.getModulesPath = getModulesPath;
291//# sourceMappingURL=NodePackageManagers.js.map
\No newline at end of file