This repository has been archived by the owner on Feb 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
142 lines (126 loc) · 3.89 KB
/
index.js
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
'use strict';
const fs = require('fs');
const { resolve, join, basename, dirname, sep } = require('path');
const cp = require('child_process');
const { promisify } = require('util');
const exec = promisify(cp.exec);
const readdirp = require('readdirp');
const semver = require('semver');
const readFile = promisify(fs.readFile);
const fsAccess = promisify(fs.access);
async function exists(path) {
try {
await fsAccess(path);
return true;
} catch (error) {
return false;
}
}
const readJSON = async path => {
const data = await readFile(path, 'utf-8');
const json = JSON.parse(data);
return json;
};
const AT = '@';
const readVersions = async (root, filterer, namespaces) => {
const moduleRoot = join(root, 'node_modules');
const entries = await readdirp.promise(moduleRoot, {
fileFilter: 'package.json',
directoryFilter(entry) {
if (entry.path.startsWith(AT) && entry.basename.startsWith(AT)) {
return namespaces.has(entry.basename);
}
return filterer.has(entry.path.replace(sep, '/'));
},
depth: 2
});
const output = {};
for (const entry of entries) {
const path = join(moduleRoot, entry.path);
const data = await readJSON(path);
output[data.name] = data.version;
}
return output;
};
async function checkDeps(root, includeDevDeps = false) {
const pth = resolve(join(root, 'package.json'));
const pkg = await readJSON(pth);
const deps = pkg.dependencies || {};
if (includeDevDeps) {
const dev = pkg.devDependencies || {};
Object.assign(deps, dev);
}
const filterer = new Set();
const namespaces = new Set();
Object.keys(deps).forEach(dep => {
if (dep.startsWith(AT)) {
namespaces.add(dirname(dep));
}
filterer.add(dep);
});
if (Object.keys(deps).length === 0) {
return [];
}
const installed = await readVersions(root, filterer, namespaces);
const needUpdate = Object.keys(deps).filter(name => {
if (!installed.hasOwnProperty(name)) return true;
const range = deps[name];
const actualVer = installed[name];
// TODO: Better check for URLs. Maybe use private npm properties.
if (/\//.test(range)) return false;
// Skip check for version = latest.
if (range === 'latest') return false;
// e.g. semver('1.0.0', '^1')
if (semver.satisfies(actualVer, range)) return false;
return true;
});
return needUpdate;
}
// Force colors in `exec` outputs
process.env.FORCE_COLOR = 'true';
process.env.NPM_CONFIG_COLOR = 'always';
const _cache = {};
function installed(cmd) {
if (cmd in _cache) {
return _cache[cmd];
}
// shell: true must be set for this test to work on non *nixes.
// TODO: async version
_cache[cmd] = !cp.spawnSync(cmd, ['--version'], { shell: true }).error;
return _cache[cmd];
}
async function getInstallCmd(rootPath) {
const pkgPath = join(rootPath, 'package.json');
if (!(await exists(pkgPath))) return;
if (installed('yarn')) {
const lockPath = join(rootPath, 'yarn.lock');
if (await exists(lockPath)) return 'yarn';
}
if (installed('pnpm')) {
const lockPath = join(rootPath, 'shrinkwrap.yaml');
const lockPath2 = join(rootPath, 'pnpm-lock.yaml');
if (await exists(lockPath) || await exists(lockPath2)) return 'pnpm';
}
return 'npm';
}
async function installDeps(rootPath = '.', options = {}) {
const logger = options.logger || console;
const env = process.env.NODE_ENV === 'production' ? '--production' : '';
const prevDir = process.cwd();
if (rootPath !== '.') process.chdir(rootPath);
try {
const cmd = await getInstallCmd(rootPath);
if (!cmd) return;
logger.info(`Installing packages with ${cmd}...`);
await exec(`${cmd} install ${env}`);
return true;
} catch (error) {
error.code = 'INSTALL_DEPS_FAILED';
logger.error(error);
throw error;
} finally {
if (rootPath !== '.') process.chdir(prevDir);
}
}
exports.checkDeps = checkDeps;
exports.installDeps = installDeps;