1 | const open = require('open');
|
2 | const chalk = require('chalk');
|
3 | const fetch = require('node-fetch');
|
4 |
|
5 | const {
|
6 | exit,
|
7 | readFile,
|
8 | writeFile,
|
9 | geneDashLine,
|
10 | printMessages,
|
11 | printSuccess,
|
12 | getCurrentRegistry,
|
13 | getRegistries,
|
14 | isLowerCaseEqual,
|
15 | isRegistryNotFound,
|
16 | isInternalRegistry,
|
17 | } = require('./helpers');
|
18 |
|
19 | const { NRMRC, NPMRC, AUTH, EMAIL, ALWAYS_AUTH, REPOSITORY, REGISTRY, HOME } = require('./constants');
|
20 |
|
21 | async function onList() {
|
22 | const currentRegistry = await getCurrentRegistry();
|
23 | const registries = await getRegistries();
|
24 | const keys = Object.keys(registries);
|
25 | const length = Math.max(...keys.map(key => key.length)) + 3;
|
26 |
|
27 | const messages = keys.map(key => {
|
28 | const registry = registries[key];
|
29 | const prefix = isLowerCaseEqual(registry[REGISTRY], currentRegistry) ? chalk.green.bold('* ') : ' ';
|
30 | return prefix + key + geneDashLine(key, length) + registry[REGISTRY];
|
31 | });
|
32 |
|
33 | printMessages(messages);
|
34 | }
|
35 |
|
36 | async function onCurrent({ showUrl }) {
|
37 | const currentRegistry = await getCurrentRegistry();
|
38 | let usingUnknownRegistry = true;
|
39 | const registries = await getRegistries();
|
40 | for (const name in registries) {
|
41 | const registry = registries[name];
|
42 | if (isLowerCaseEqual(registry[REGISTRY], currentRegistry)) {
|
43 | usingUnknownRegistry = false;
|
44 | printMessages([`You are using ${chalk.green(showUrl ? registry[REGISTRY] : name)} registry.`]);
|
45 | }
|
46 | }
|
47 | if (usingUnknownRegistry) {
|
48 | printMessages([
|
49 | `Your current registry(${currentRegistry}) is not included in the nrm registries.`,
|
50 | `Use the ${chalk.green('nrm add <registry> <url> [home]')} command to add your registry.`,
|
51 | ]);
|
52 | }
|
53 | }
|
54 |
|
55 | async function onUse(name) {
|
56 | if (await isRegistryNotFound(name)) {
|
57 | return;
|
58 | }
|
59 |
|
60 | const registries = await getRegistries();
|
61 | const registry = registries[name];
|
62 | const npmrc = await readFile(NPMRC);
|
63 | await writeFile(NPMRC, Object.assign(npmrc, registry));
|
64 |
|
65 | printSuccess(`The registry has been changed to '${name}'.`);
|
66 | }
|
67 |
|
68 | async function onDelete(name) {
|
69 | if (await isRegistryNotFound(name) || await isInternalRegistry(name, 'delete')) {
|
70 | return;
|
71 | }
|
72 |
|
73 | const customRegistries = await readFile(NRMRC);
|
74 | const registry = customRegistries[name];
|
75 | delete customRegistries[name];
|
76 | await writeFile(NRMRC, customRegistries);
|
77 | printSuccess(`The registry '${name}' has been deleted successfully.`);
|
78 |
|
79 | const currentRegistry = await getCurrentRegistry();
|
80 | if (currentRegistry === registry[REGISTRY]) {
|
81 | await onUse('npm');
|
82 | }
|
83 | }
|
84 |
|
85 | async function onAdd(name, url, home) {
|
86 | const registries = await getRegistries();
|
87 | const registryNames = Object.keys(registries);
|
88 | const registryUrls = registryNames.map(name => registries[name][REGISTRY]);
|
89 | if (registryNames.includes(name) || registryUrls.some(eachUrl => isLowerCaseEqual(eachUrl, url))) {
|
90 | return exit('The registry name or url is already included in the nrm registries. Please make sure that the name and url are unique.');
|
91 | }
|
92 |
|
93 | const newRegistry = {};
|
94 | newRegistry[REGISTRY] = /\/$/.test(url) ? url : url + '/';
|
95 | if (home) {
|
96 | newRegistry[HOME] = home;
|
97 | }
|
98 | const customRegistries = await readFile(NRMRC);
|
99 | const newCustomRegistries = Object.assign(customRegistries, { [name]: newRegistry });
|
100 | await writeFile(NRMRC, newCustomRegistries);
|
101 | printSuccess(`Add registry ${name} success, run ${chalk.green('nrm use ' + name)} command to use ${name} registry.`);
|
102 | }
|
103 |
|
104 | async function onLogin(name, base64, { alwaysAuth, username, password, email }) {
|
105 | if (await isRegistryNotFound(name) || await isInternalRegistry(name, 'set authorization information of')) {
|
106 | return;
|
107 | }
|
108 |
|
109 | const customRegistries = await readFile(NRMRC);
|
110 | const registry = customRegistries[name];
|
111 | if (base64) {
|
112 | registry[AUTH] = base64;
|
113 | } else if (username && password) {
|
114 | registry[AUTH] = Buffer.from(`${username}:${password}`).toString('base64');
|
115 | } else {
|
116 | return exit('Authorization information in base64 format or username & password is required');
|
117 | }
|
118 |
|
119 | if (alwaysAuth) {
|
120 | registry[ALWAYS_AUTH] = true;
|
121 | }
|
122 |
|
123 | if (email) {
|
124 | registry[EMAIL] = email;
|
125 | }
|
126 |
|
127 | Object.assign(customRegistries, { [name]: registry });
|
128 | await writeFile(NRMRC, customRegistries);
|
129 | printSuccess(`Set the authorization information of the registry '${name}' success.`);
|
130 |
|
131 | const currentRegistry = await getCurrentRegistry();
|
132 | if (currentRegistry === registry[REGISTRY]) {
|
133 | const npmrc = await readFile(NPMRC);
|
134 | await writeFile(NPMRC, Object.assign(npmrc, {
|
135 | [AUTH]: registry[AUTH],
|
136 | [ALWAYS_AUTH]: registry[ALWAYS_AUTH],
|
137 | [EMAIL]: registry[EMAIL],
|
138 | }));
|
139 | }
|
140 | }
|
141 |
|
142 | async function onSetRepository(name, repo) {
|
143 | if (await isRegistryNotFound(name) || await isInternalRegistry(name, 'set repository of')) {
|
144 | return;
|
145 | }
|
146 |
|
147 | const customRegistries = await readFile(NRMRC);
|
148 | const registry = customRegistries[name];
|
149 | registry[REPOSITORY] = repo;
|
150 | await writeFile(NRMRC, customRegistries);
|
151 | printSuccess(`Set the ${REPOSITORY} of registry '${name}' successfully.`);
|
152 |
|
153 | const currentRegistry = await getCurrentRegistry();
|
154 | if (currentRegistry && registry[REGISTRY] === currentRegistry) {
|
155 | const npmrc = await readFile(NPMRC);
|
156 | Object.assign(npmrc, { [REPOSITORY]: repo });
|
157 | await writeFile(NPMRC, npmrc);
|
158 | printSuccess(`Set repository attribute of npmrc successfully`);
|
159 | }
|
160 | }
|
161 |
|
162 | async function onSetScope(scopeName, url) {
|
163 | const scopeRegistryKey = `${scopeName}:${REGISTRY}`;
|
164 | const npmrc = await readFile(NPMRC);
|
165 | Object.assign(npmrc, { [scopeRegistryKey]: url });
|
166 | await writeFile(NPMRC, npmrc);
|
167 | printSuccess(`Set scope '${scopeRegistryKey}=${url}' success.`);
|
168 | }
|
169 |
|
170 | async function onDeleteScope(scopeName) {
|
171 | const scopeRegistryKey = `${scopeName}:${REGISTRY}`;
|
172 | const npmrc = await readFile(NPMRC);
|
173 | if (npmrc[scopeRegistryKey]) {
|
174 | delete npmrc[scopeRegistryKey];
|
175 | await writeFile(NPMRC, npmrc);
|
176 | printSuccess(`Delete scope '${scopeRegistryKey}' success.`);
|
177 | }
|
178 | }
|
179 |
|
180 | async function onSetAttribute(name, { attr, value }) {
|
181 | if (await isRegistryNotFound(name) || await isInternalRegistry(name, 'set attribute of')) {
|
182 | return;
|
183 | }
|
184 |
|
185 | if (REPOSITORY === attr) {
|
186 | return exit(`Use the ${chalk.green('nrm set-hosted-repo <name> <repo>')} command to set repository.`);
|
187 | }
|
188 | const customRegistries = await readFile(NRMRC);
|
189 | const registry = customRegistries[name];
|
190 | Object.assign(registry, { [attr]: value });
|
191 | await writeFile(NRMRC, customRegistries);
|
192 | printSuccess(`Set attribute '${attr}=${value}' of the registry '${name}' successfully.`);
|
193 |
|
194 | const currentRegistry = await getCurrentRegistry();
|
195 | if (currentRegistry === registry[REGISTRY]) {
|
196 | const npmrc = await readFile(NPMRC);
|
197 | await writeFile(NPMRC, Object.assign(npmrc, { [attr]: value }));
|
198 | }
|
199 | }
|
200 |
|
201 | async function onRename(name, newName) {
|
202 | if (await isRegistryNotFound(name) || await isInternalRegistry(name, 'rename')) {
|
203 | return;
|
204 | }
|
205 | if (name === newName) {
|
206 | return exit('The names cannot be the same.');
|
207 | }
|
208 |
|
209 | if (!await isRegistryNotFound(newName, false)) {
|
210 | return exit(`The new registry name '${newName}' is already exist.`);
|
211 | }
|
212 | const customRegistries = await readFile(NRMRC);
|
213 | customRegistries[newName] = JSON.parse(JSON.stringify(customRegistries[name]));
|
214 | delete customRegistries[name];
|
215 | await writeFile(NRMRC, customRegistries);
|
216 | printSuccess(`The registry '${name}' has been renamed to '${newName}'.`);
|
217 | }
|
218 |
|
219 | async function onHome(name, browser) {
|
220 | if (await isRegistryNotFound(name)) {
|
221 | return;
|
222 | }
|
223 |
|
224 | const registries = await getRegistries();
|
225 | if (!registries[name][HOME]) {
|
226 | return exit(`The homepage of registry '${name}' is not found.`);
|
227 | }
|
228 | open(registries[name][HOME], browser ? { app: { name: browser } } : undefined);
|
229 | }
|
230 |
|
231 | async function onTest(target) {
|
232 | const registries = await getRegistries();
|
233 | const timeout = 5000;
|
234 |
|
235 | if (target && await isRegistryNotFound(target)) {
|
236 | return exit();
|
237 | }
|
238 |
|
239 | const sources = target ? { [target]: registries[target] } : registries;
|
240 |
|
241 | const results = await Promise.all(Object.keys(sources).map(async name => {
|
242 | const { registry } = sources[name];
|
243 | const start = Date.now();
|
244 | let status = false;
|
245 | let isTimeout = false;
|
246 | try {
|
247 | const response = await fetch(registry + 'nrm', { timeout });
|
248 | status = response.ok;
|
249 | } catch (error) {
|
250 | isTimeout = error.type === 'request-timeout';
|
251 | }
|
252 | return {
|
253 | name,
|
254 | registry,
|
255 | success: status,
|
256 | time: Date.now() - start,
|
257 | isTimeout
|
258 | };
|
259 | }));
|
260 |
|
261 | const [fastest] = results.filter(each => each.success).map(each => each.time).sort((a, b) => a - b);
|
262 |
|
263 | const messages = [];
|
264 | const currentRegistry = await getCurrentRegistry();
|
265 | const errorMsg = chalk.red(' (Fetch error, if this is your private registry, please ignore)');
|
266 | const timeoutMsg = chalk.yellow(` (Fetch timeout over ${timeout} ms)`);
|
267 | const length = Math.max(...Object.keys(sources).map(key => key.length)) + 3;
|
268 | results.forEach(({ registry, success, time, name, isTimeout }) => {
|
269 | const isFastest = time === fastest;
|
270 | const prefix = registry === currentRegistry ? chalk.green('* ') : ' ';
|
271 | let suffix = (isFastest && !target) ? chalk.bgGreenBright(time + ' ms') : isTimeout ? 'timeout' : `${time} ms`;
|
272 | if (!success) {
|
273 | suffix += isTimeout ? timeoutMsg : errorMsg;
|
274 | }
|
275 | messages.push(prefix + name + geneDashLine(name, length) + suffix);
|
276 | });
|
277 | printMessages(messages);
|
278 | return messages;
|
279 | }
|
280 |
|
281 | module.exports = {
|
282 | onList,
|
283 | onCurrent,
|
284 | onUse,
|
285 | onAdd,
|
286 | onDelete,
|
287 | onRename,
|
288 | onHome,
|
289 | onSetRepository,
|
290 | onSetScope,
|
291 | onDeleteScope,
|
292 | onSetAttribute,
|
293 | onTest,
|
294 | onLogin,
|
295 | };
|