-
Notifications
You must be signed in to change notification settings - Fork 255
/
actions.js
327 lines (283 loc) · 10.1 KB
/
actions.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
const open = require('open');
const chalk = require('chalk');
const select = require('@inquirer/select').default;
const { fetch } = require('undici');
const path = require('path');
const {
exit,
readFile,
writeFile,
geneDashLine,
printMessages,
printSuccess,
getCurrentRegistry,
getRegistries,
isLowerCaseEqual,
isRegistryNotFound,
isInternalRegistry,
} = require('./helpers');
const process = require('./process');
const { NRMRC, NPMRC, AUTH, EMAIL, ALWAYS_AUTH, REPOSITORY, REGISTRY, HOME } = require('./constants');
async function onList() {
const currentRegistry = await getCurrentRegistry();
const registries = await getRegistries();
const keys = Object.keys(registries);
const length = Math.max(...keys.map((key) => key.length)) + 3;
const messages = keys.map((key) => {
const registry = registries[key];
const prefix = isLowerCaseEqual(registry[REGISTRY], currentRegistry) ? chalk.green.bold('* ') : ' ';
return prefix + key + geneDashLine(key, length) + registry[REGISTRY];
});
printMessages(messages);
}
async function onCurrent({ showUrl }) {
const currentRegistry = await getCurrentRegistry();
const registries = await getRegistries();
const matchedRegistry = Object.entries(registries).find(([_name, registry]) =>
isLowerCaseEqual(registry[REGISTRY], currentRegistry),
);
// not find equal registry
if (!matchedRegistry) {
printMessages([
`Your current registry(${currentRegistry}) is not included in the nrm registries.`,
`Use the ${chalk.green('nrm add <registry> <url> [home]')} command to add your registry.`,
]);
return;
}
const [name, registry] = matchedRegistry;
printMessages([`You are using ${chalk.green(showUrl ? registry[REGISTRY] : name)} registry.`]);
}
async function onUse(name, { local }) {
const registries = await getRegistries();
// if name is undefined, select the registry alias from list
if (name === undefined) {
name = await select({
message: 'Please select the registry you want to use',
choices: Object.keys(registries),
});
}
if (await isRegistryNotFound(name)) {
return;
}
const registry = registries[name];
if (local) {
// switch local registry
const localNPMRCPath = path.resolve(process.cwd(), '.npmrc');
const npmrc = await readFile(localNPMRCPath);
await writeFile(localNPMRCPath, Object.assign(npmrc, registry));
} else {
// switch global registry
const npmrc = await readFile(NPMRC);
await writeFile(NPMRC, Object.assign(npmrc, registry));
}
printSuccess(`The registry has been changed to '${name}'.`);
}
async function onDelete(name) {
if ((await isRegistryNotFound(name)) || (await isInternalRegistry(name, 'delete'))) {
return;
}
const customRegistries = await readFile(NRMRC);
const registry = customRegistries[name];
delete customRegistries[name];
await writeFile(NRMRC, customRegistries);
printSuccess(`The registry '${name}' has been deleted successfully.`);
const currentRegistry = await getCurrentRegistry();
if (currentRegistry === registry[REGISTRY]) {
await onUse('npm');
}
}
async function onAdd(name, url, home) {
const registries = await getRegistries();
const registryNames = Object.keys(registries);
const registryUrls = registryNames.map((name) => registries[name][REGISTRY]);
if (registryNames.includes(name) || registryUrls.some((eachUrl) => isLowerCaseEqual(eachUrl, url))) {
return exit(
'The registry name or url is already included in the nrm registries. Please make sure that the name and url are unique.',
);
}
const newRegistry = {};
newRegistry[REGISTRY] = /\/$/.test(url) ? url : url + '/';
if (home) {
newRegistry[HOME] = home;
}
const customRegistries = await readFile(NRMRC);
const newCustomRegistries = Object.assign(customRegistries, { [name]: newRegistry });
await writeFile(NRMRC, newCustomRegistries);
printSuccess(`Add registry ${name} success, run ${chalk.green('nrm use ' + name)} command to use ${name} registry.`);
}
async function onLogin(name, base64, { alwaysAuth, username, password, email }) {
if ((await isRegistryNotFound(name)) || (await isInternalRegistry(name, 'set authorization information of'))) {
return;
}
const customRegistries = await readFile(NRMRC);
const registry = customRegistries[name];
if (base64) {
registry[AUTH] = base64;
} else if (username && password) {
registry[AUTH] = Buffer.from(`${username}:${password}`).toString('base64');
} else {
return exit('Authorization information in base64 format or username & password is required');
}
if (alwaysAuth) {
registry[ALWAYS_AUTH] = true;
}
if (email) {
registry[EMAIL] = email;
}
Object.assign(customRegistries, { [name]: registry });
await writeFile(NRMRC, customRegistries);
printSuccess(`Set the authorization information of the registry '${name}' success.`);
const currentRegistry = await getCurrentRegistry();
if (currentRegistry === registry[REGISTRY]) {
const npmrc = await readFile(NPMRC);
await writeFile(
NPMRC,
Object.assign(npmrc, {
[AUTH]: registry[AUTH],
[ALWAYS_AUTH]: registry[ALWAYS_AUTH],
[EMAIL]: registry[EMAIL],
}),
);
}
}
async function onSetRepository(name, repo) {
if ((await isRegistryNotFound(name)) || (await isInternalRegistry(name, 'set repository of'))) {
return;
}
const customRegistries = await readFile(NRMRC);
const registry = customRegistries[name];
registry[REPOSITORY] = repo;
await writeFile(NRMRC, customRegistries);
printSuccess(`Set the ${REPOSITORY} of registry '${name}' successfully.`);
const currentRegistry = await getCurrentRegistry();
if (currentRegistry && registry[REGISTRY] === currentRegistry) {
const npmrc = await readFile(NPMRC);
Object.assign(npmrc, { [REPOSITORY]: repo });
await writeFile(NPMRC, npmrc);
printSuccess(`Set repository attribute of npmrc successfully`);
}
}
async function onSetScope(scopeName, url) {
const scopeRegistryKey = `${scopeName}:${REGISTRY}`;
const npmrc = await readFile(NPMRC);
Object.assign(npmrc, { [scopeRegistryKey]: url });
await writeFile(NPMRC, npmrc);
printSuccess(`Set scope '${scopeRegistryKey}=${url}' success.`);
}
async function onDeleteScope(scopeName) {
const scopeRegistryKey = `${scopeName}:${REGISTRY}`;
const npmrc = await readFile(NPMRC);
if (npmrc[scopeRegistryKey]) {
delete npmrc[scopeRegistryKey];
await writeFile(NPMRC, npmrc);
printSuccess(`Delete scope '${scopeRegistryKey}' success.`);
}
}
async function onSetAttribute(name, { attr, value }) {
if ((await isRegistryNotFound(name)) || (await isInternalRegistry(name, 'set attribute of'))) {
return;
}
if (REPOSITORY === attr) {
return exit(`Use the ${chalk.green('nrm set-hosted-repo <name> <repo>')} command to set repository.`);
}
const customRegistries = await readFile(NRMRC);
const registry = customRegistries[name];
Object.assign(registry, { [attr]: value });
await writeFile(NRMRC, customRegistries);
printSuccess(`Set attribute '${attr}=${value}' of the registry '${name}' successfully.`);
const currentRegistry = await getCurrentRegistry();
if (currentRegistry === registry[REGISTRY]) {
const npmrc = await readFile(NPMRC);
await writeFile(NPMRC, Object.assign(npmrc, { [attr]: value }));
}
}
async function onRename(name, newName) {
if ((await isRegistryNotFound(name)) || (await isInternalRegistry(name, 'rename'))) {
return;
}
if (name === newName) {
return exit('The names cannot be the same.');
}
if (!(await isRegistryNotFound(newName, false))) {
return exit(`The new registry name '${newName}' is already exist.`);
}
const customRegistries = await readFile(NRMRC);
customRegistries[newName] = JSON.parse(JSON.stringify(customRegistries[name]));
delete customRegistries[name];
await writeFile(NRMRC, customRegistries);
printSuccess(`The registry '${name}' has been renamed to '${newName}'.`);
}
async function onHome(name, browser) {
if (await isRegistryNotFound(name)) {
return;
}
const registries = await getRegistries();
if (!registries[name][HOME]) {
return exit(`The homepage of registry '${name}' is not found.`);
}
open(registries[name][HOME], browser ? { app: { name: browser } } : undefined);
}
async function onTest(target) {
const registries = await getRegistries();
const timeout = 5000;
if (target && (await isRegistryNotFound(target))) {
return exit();
}
const sources = target ? { [target]: registries[target] } : registries;
const results = await Promise.all(
Object.keys(sources).map(async (name) => {
const { registry } = sources[name];
const start = Date.now();
let status = false;
let isTimeout = false;
try {
const response = await fetch(registry + 'nrm', { signal: AbortSignal.timeout(timeout) });
status = response.ok;
} catch (error) {
isTimeout = error.name === 'TimeoutError';
}
return {
name,
registry,
success: status,
time: Date.now() - start,
isTimeout,
};
}),
);
const [fastest] = results
.filter((each) => each.success)
.map((each) => each.time)
.sort((a, b) => a - b);
const messages = [];
const currentRegistry = await getCurrentRegistry();
const errorMsg = chalk.red(' (Fetch error, if this is your private registry, please ignore)');
const timeoutMsg = chalk.yellow(` (Fetch timeout over ${timeout} ms)`);
const length = Math.max(...Object.keys(sources).map((key) => key.length)) + 3;
results.forEach(({ registry, success, time, name, isTimeout }) => {
const isFastest = time === fastest;
const prefix = registry === currentRegistry ? chalk.green('* ') : ' ';
let suffix = isFastest && !target ? chalk.bgGreenBright(time + ' ms') : isTimeout ? 'timeout' : `${time} ms`;
if (!success) {
suffix += isTimeout ? timeoutMsg : errorMsg;
}
messages.push(prefix + name + geneDashLine(name, length) + suffix);
});
printMessages(messages);
return messages;
}
module.exports = {
onList,
onCurrent,
onUse,
onAdd,
onDelete,
onRename,
onHome,
onSetRepository,
onSetScope,
onDeleteScope,
onSetAttribute,
onTest,
onLogin,
};