-
-
Notifications
You must be signed in to change notification settings - Fork 301
/
Copy pathutil.js
165 lines (140 loc) · 4.53 KB
/
util.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
import path from 'node:path';
import {pathExists} from 'path-exists';
import {execa} from 'execa';
import pTimeout from 'p-timeout';
import npmName from 'npm-name';
import chalk from 'chalk-template';
import * as util from '../util.js';
export const version = async () => {
const {stdout} = await execa('npm', ['--version']);
return stdout;
};
export const checkConnection = () => pTimeout(
(async () => {
try {
await execa('npm', ['ping']);
return true;
} catch {
throw new Error('Connection to npm registry failed');
}
})(), {
milliseconds: 15_000,
message: 'Connection to npm registry timed out',
},
);
export const username = async ({externalRegistry}) => {
const arguments_ = ['whoami'];
if (externalRegistry) {
arguments_.push('--registry', externalRegistry);
}
try {
const {stdout} = await execa('npm', arguments_);
return stdout;
} catch (error) {
const message = /ENEEDAUTH/.test(error.stderr)
? 'You must be logged in. Use `npm login` and try again.'
: 'Authentication error. Use `npm whoami` to troubleshoot.';
throw new Error(message);
}
};
const NPM_DEFAULT_REGISTRIES = new Set([
// https://docs.npmjs.com/cli/v10/using-npm/registry
'https://registry.npmjs.org',
// https://docs.npmjs.com/cli/v10/commands/npm-profile#registry
'https://registry.npmjs.org/',
]);
export const isExternalRegistry = package_ => {
const registry = package_.publishConfig?.registry;
return typeof registry === 'string' && !NPM_DEFAULT_REGISTRIES.has(registry);
};
export const collaborators = async package_ => {
const packageName = package_.name;
util.assert(typeof packageName === 'string', 'Package name is required');
const arguments_ = ['access', 'list', 'collaborators', packageName, '--json'];
if (isExternalRegistry(package_)) {
arguments_.push('--registry', package_.publishConfig.registry);
}
try {
const {stdout} = await execa('npm', arguments_);
return stdout;
} catch (error) {
// Ignore non-existing package error
if (error.stderr.includes('code E404')) {
return false;
}
throw error;
}
};
export const prereleaseTags = async packageName => {
util.assert(typeof packageName === 'string', 'Package name is required');
let tags = [];
try {
const {stdout} = await execa('npm', ['view', '--json', packageName, 'dist-tags']);
tags = Object.keys(JSON.parse(stdout))
.filter(tag => tag !== 'latest');
} catch (error) {
// HACK: NPM is mixing JSON with plain text errors. Luckily, the error
// always starts with 'npm ERR!' (unless you have a debugger attached)
// so as a solution, until npm/cli#2740 is fixed, we can remove anything
// starting with 'npm ERR!'
/** @type {string} */
const errorMessage = error.stderr;
const errorJSON = errorMessage
.split('\n')
.filter(error => !error.startsWith('npm ERR!'))
.join('\n');
if (((JSON.parse(errorJSON) || {}).error || {}).code !== 'E404') {
throw error;
}
}
if (tags.length === 0) {
tags.push('next');
}
return tags;
};
export const isPackageNameAvailable = async package_ => {
const arguments_ = [package_.name];
const availability = {
isAvailable: false,
isUnknown: false,
};
if (isExternalRegistry(package_)) {
arguments_.push({
registryUrl: package_.publishConfig.registry,
});
}
try {
availability.isAvailable = await npmName(...arguments_) || false;
} catch {
availability.isUnknown = true;
}
return availability;
};
export const verifyRecentNpmVersion = async () => {
const npmVersion = await version();
util.validateEngineVersionSatisfies('npm', npmVersion);
};
export const checkIgnoreStrategy = async ({files}, rootDirectory) => {
const npmignoreExistsInPackageRootDirectory = await pathExists(path.resolve(rootDirectory, '.npmignore'));
if (!files && !npmignoreExistsInPackageRootDirectory) {
console.log(chalk`
\n{bold.yellow Warning:} No {bold.cyan files} field specified in {bold.magenta package.json} nor is a {bold.magenta .npmignore} file present. Having one of those will prevent you from accidentally publishing development-specific files along with your package's source code to npm.
`);
}
};
export const getFilesToBePacked = async rootDirectory => {
const {stdout} = await execa('npm', [
'pack',
'--dry-run',
'--json',
'--silent',
// TODO: Remove this once [npm/cli#7354](https://github.com/npm/cli/issues/7354) is resolved.
'--foreground-scripts=false',
], {cwd: rootDirectory});
try {
const {files} = JSON.parse(stdout).at(0);
return files.map(file => file.path);
} catch (error) {
throw new Error('Failed to parse output of npm pack', {cause: error});
}
};