jpm-pkg 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/jpm.js +7 -1
- package/package.json +1 -1
- package/src/commands/audit.js +70 -41
- package/src/commands/base-command.js +62 -0
- package/src/commands/config.js +94 -51
- package/src/commands/info.js +111 -64
- package/src/commands/init.js +117 -72
- package/src/commands/install.js +121 -112
- package/src/commands/list.js +126 -80
- package/src/commands/publish.js +155 -124
- package/src/commands/run.js +86 -52
- package/src/commands/search.js +56 -32
- package/src/commands/uninstall.js +47 -30
- package/src/commands/update.js +92 -51
- package/src/commands/x.js +134 -96
- package/src/core/cache.js +188 -87
- package/src/core/lockfile.js +73 -26
- package/src/core/package-json.js +119 -1
- package/src/core/registry.js +182 -143
- package/src/core/resolver.js +60 -36
package/src/commands/list.js
CHANGED
|
@@ -2,102 +2,148 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
|
+
const BaseCommand = require('./base-command');
|
|
5
6
|
const PackageJSON = require('../core/package-json');
|
|
6
7
|
const { formatBytes } = require('../utils/fs');
|
|
7
|
-
const logger = require('../utils/logger');
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (!fs.existsSync(nodeModules)) {
|
|
18
|
-
logger.warn('No node_modules found. Run `jpm install` first.');
|
|
19
|
-
return;
|
|
9
|
+
/**
|
|
10
|
+
* ListCommand handles the 'jpm list', 'jpm ls', and 'jpm peek' commands.
|
|
11
|
+
* It visualizes the installed dependency tree and package sizes.
|
|
12
|
+
*/
|
|
13
|
+
class ListCommand extends BaseCommand {
|
|
14
|
+
constructor() {
|
|
15
|
+
super('list');
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Executes the listing and visualization of dependencies.
|
|
20
|
+
*
|
|
21
|
+
* @param {string[]} args - Optional arguments
|
|
22
|
+
* @param {Object} flags - CLI flags (e.g., --depth, --json)
|
|
23
|
+
* @returns {Promise<void>}
|
|
24
|
+
*/
|
|
25
|
+
async run(args, flags) {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const depth = parseInt(flags.depth ?? flags.d ?? '0', 10);
|
|
28
|
+
const isJson = flags.json;
|
|
29
|
+
const nodeModules = path.join(cwd, 'node_modules');
|
|
30
|
+
|
|
31
|
+
const pkgJson = PackageJSON.fromDir(cwd);
|
|
32
|
+
|
|
33
|
+
if (!fs.existsSync(nodeModules)) {
|
|
34
|
+
this.logger.warn('No node_modules found. Run `jpm install` first.');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
// 1. Collect installed packages
|
|
39
|
+
const installed = [];
|
|
40
|
+
for (const entry of fs.readdirSync(nodeModules, { withFileTypes: true })) {
|
|
41
|
+
if (entry.name.startsWith('.')) continue;
|
|
42
|
+
|
|
43
|
+
if (entry.name.startsWith('@') && entry.isDirectory()) {
|
|
44
|
+
const scopeDir = path.join(nodeModules, entry.name);
|
|
45
|
+
for (const scoped of fs.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
46
|
+
const pkg = this._readPkg(path.join(scopeDir, scoped.name));
|
|
47
|
+
if (pkg) installed.push(pkg);
|
|
48
|
+
}
|
|
49
|
+
} else if (entry.isDirectory()) {
|
|
50
|
+
const pkg = this._readPkg(path.join(nodeModules, entry.name));
|
|
31
51
|
if (pkg) installed.push(pkg);
|
|
32
52
|
}
|
|
33
|
-
} else if (entry.isDirectory()) {
|
|
34
|
-
const pkg = readPkg(path.join(nodeModules, entry.name));
|
|
35
|
-
if (pkg) installed.push(pkg);
|
|
36
53
|
}
|
|
37
|
-
}
|
|
38
54
|
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
// 2. Sort results alphabetically
|
|
56
|
+
installed.sort((a, b) => a.name.localeCompare(b.name));
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
// 3. Handle JSON output mode
|
|
59
|
+
if (isJson) {
|
|
60
|
+
process.stdout.write(JSON.stringify({
|
|
61
|
+
name: pkgJson.name,
|
|
62
|
+
dependencies: this._toObj(installed)
|
|
63
|
+
}, null, 2) + '\n');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 4. Render terminal tree view
|
|
68
|
+
this.logger.log(`\n${this.logger.c.bold(pkgJson.name)}@${pkgJson.version}`);
|
|
69
|
+
|
|
70
|
+
const directDeps = new Set([
|
|
71
|
+
...Object.keys(pkgJson.dependencies),
|
|
72
|
+
...Object.keys(pkgJson.devDependencies),
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const total = installed.length;
|
|
76
|
+
let totalSize = 0;
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < installed.length; i++) {
|
|
79
|
+
const pkg = installed[i];
|
|
80
|
+
const isLast = i === installed.length - 1;
|
|
81
|
+
const devMark = Object.keys(pkgJson.devDependencies).includes(pkg.name)
|
|
82
|
+
? this.logger.c.gray(' dev')
|
|
83
|
+
: '';
|
|
84
|
+
|
|
85
|
+
const conn = isLast ? '└── ' : '├── ';
|
|
86
|
+
const nameStr = this.logger.c.cyan(pkg.name);
|
|
87
|
+
const verStr = this.logger.c.gray(`@${pkg.version}`);
|
|
88
|
+
this.logger.log(`${conn}${nameStr}${verStr}${devMark}`);
|
|
89
|
+
|
|
90
|
+
if (depth > 0 && pkg.dependencies) {
|
|
91
|
+
const subDeps = Object.entries(pkg.dependencies);
|
|
92
|
+
subDeps.forEach(([depName, depRange], j) => {
|
|
93
|
+
const isLastSub = j === subDeps.length - 1;
|
|
94
|
+
const ext = isLast ? ' ' : '│ ';
|
|
95
|
+
const subConn = isLastSub ? '└── ' : '├── ';
|
|
96
|
+
this.logger.log(`${ext}${subConn}${this.logger.c.gray(depName)} ${this.logger.c.gray(depRange)}`);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
46
99
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const directDeps = new Set([
|
|
50
|
-
...Object.keys(pkgJson.dependencies),
|
|
51
|
-
...Object.keys(pkgJson.devDependencies),
|
|
52
|
-
]);
|
|
53
|
-
|
|
54
|
-
const total = installed.length;
|
|
55
|
-
let totalSize = 0;
|
|
56
|
-
|
|
57
|
-
for (let i = 0; i < installed.length; i++) {
|
|
58
|
-
const pkg = installed[i];
|
|
59
|
-
const isLast = i === installed.length - 1;
|
|
60
|
-
const isDir = directDeps.has(pkg.name);
|
|
61
|
-
const devMark = Object.keys(pkgJson.devDependencies).includes(pkg.name)
|
|
62
|
-
? logger.c.gray(' dev')
|
|
63
|
-
: '';
|
|
64
|
-
|
|
65
|
-
const conn = isLast ? '└── ' : '├── ';
|
|
66
|
-
const nameStr = logger.c.cyan(pkg.name);
|
|
67
|
-
const verStr = logger.c.gray(`@${pkg.version}`);
|
|
68
|
-
logger.log(`${conn}${nameStr}${verStr}${devMark}`);
|
|
69
|
-
|
|
70
|
-
if (depth > 0 && pkg.dependencies) {
|
|
71
|
-
const subDeps = Object.entries(pkg.dependencies);
|
|
72
|
-
subDeps.forEach(([depName, depRange], j) => {
|
|
73
|
-
const isLastSub = j === subDeps.length - 1;
|
|
74
|
-
const ext = isLast ? ' ' : '│ ';
|
|
75
|
-
const subConn = isLastSub ? '└── ' : '├── ';
|
|
76
|
-
logger.log(`${ext}${subConn}${logger.c.gray(depName)} ${logger.c.gray(depRange)}`);
|
|
77
|
-
});
|
|
100
|
+
totalSize += pkg.size || 0;
|
|
78
101
|
}
|
|
79
102
|
|
|
80
|
-
|
|
103
|
+
this.logger.log(`\n${total} packages ${formatBytes(totalSize)}`);
|
|
81
104
|
}
|
|
82
105
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Reads package metadata and calculates directory size.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} dir - Directory path to the package
|
|
110
|
+
* @returns {Object|null} Package data object or null on failure
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
_readPkg(dir) {
|
|
114
|
+
const pkgJsonFile = path.join(dir, 'package.json');
|
|
91
115
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
116
|
+
const data = JSON.parse(fs.readFileSync(pkgJsonFile, 'utf8'));
|
|
117
|
+
let size = 0;
|
|
118
|
+
try {
|
|
119
|
+
// Shallow size calculation (top-level files only)
|
|
120
|
+
for (const file of fs.readdirSync(dir)) {
|
|
121
|
+
const s = fs.statSync(path.join(dir, file));
|
|
122
|
+
if (s.isFile()) size += s.size;
|
|
123
|
+
}
|
|
124
|
+
} catch (err) { }
|
|
125
|
+
return {
|
|
126
|
+
name: data.name,
|
|
127
|
+
version: data.version,
|
|
128
|
+
dependencies: data.dependencies,
|
|
129
|
+
size
|
|
130
|
+
};
|
|
131
|
+
} catch (err) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
100
135
|
|
|
101
|
-
|
|
102
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Converts an array of package objects into a structured object for JSON output.
|
|
138
|
+
*
|
|
139
|
+
* @param {Object[]} arr - Array of package metadata
|
|
140
|
+
* @returns {Object}
|
|
141
|
+
* @private
|
|
142
|
+
*/
|
|
143
|
+
_toObj(arr) {
|
|
144
|
+
return Object.fromEntries(arr.map(p => [p.name, { version: p.version }]));
|
|
145
|
+
}
|
|
103
146
|
}
|
|
147
|
+
|
|
148
|
+
module.exports = ListCommand;
|
|
149
|
+
|
package/src/commands/publish.js
CHANGED
|
@@ -2,147 +2,178 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
4
|
const path = require('node:path');
|
|
5
|
-
const crypto = require('node:crypto');
|
|
6
5
|
const tar = require('tar');
|
|
6
|
+
const BaseCommand = require('./base-command');
|
|
7
7
|
const PackageJSON = require('../core/package-json');
|
|
8
8
|
const integrity = require('../security/integrity');
|
|
9
|
-
const { getJSON } = require('../utils/http');
|
|
10
|
-
const { tempDir
|
|
9
|
+
const { getJSON, request } = require('../utils/http');
|
|
10
|
+
const { tempDir } = require('../utils/fs');
|
|
11
11
|
const { Spinner } = require('../utils/progress');
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const errors = pkgJson.validate();
|
|
21
|
-
if (errors.length) {
|
|
22
|
-
logger.error('package.json validation failed:');
|
|
23
|
-
errors.forEach(e => logger.error(` ${e}`));
|
|
24
|
-
process.exit(1);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* PublishCommand handles the 'jpm publish' and 'jpm ship' commands.
|
|
15
|
+
* It validates a package, packs it into a tarball, and uploads it to the registry.
|
|
16
|
+
*/
|
|
17
|
+
class PublishCommand extends BaseCommand {
|
|
18
|
+
constructor() {
|
|
19
|
+
super('publish');
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Executes the package publishing process.
|
|
24
|
+
*
|
|
25
|
+
* @param {string[]} args - Optional arguments
|
|
26
|
+
* @param {Object} flags - CLI flags (e.g., --otp)
|
|
27
|
+
* @returns {Promise<void>}
|
|
28
|
+
*/
|
|
29
|
+
async run(args, flags) {
|
|
30
|
+
const cwd = process.cwd();
|
|
31
|
+
const pkgJson = PackageJSON.fromDir(cwd);
|
|
32
|
+
|
|
33
|
+
// 1. Validate package configuration
|
|
34
|
+
const errors = pkgJson.validate();
|
|
35
|
+
if (errors.length) {
|
|
36
|
+
this.logger.error('package.json validation failed:');
|
|
37
|
+
errors.forEach(e => this.logger.error(` ${e}`));
|
|
38
|
+
throw new Error('Package validation failed.');
|
|
39
|
+
}
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
const { name, version } = pkgJson;
|
|
42
|
+
const registryUrl = this.config.registry.replace(/\/$/, '');
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
const token = config.get('//registry.npmjs.org/:_authToken') || config.get('_authToken');
|
|
34
|
-
if (!token) {
|
|
35
|
-
logger.error('Not logged in. Set _authToken in ~/.jpmrc or run: npm login');
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
44
|
+
this.logger.section(`Publishing ${name}@${version}`);
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
process.exit(1);
|
|
45
|
-
} catch (err) {
|
|
46
|
-
if (err.status !== 404) {
|
|
47
|
-
spinner.warn('Could not verify version uniqueness, continuing...');
|
|
48
|
-
} else {
|
|
49
|
-
spinner.succeed('Version check passed');
|
|
46
|
+
// 2. Resolve authentication token
|
|
47
|
+
const token = this.config.get('//registry.npmjs.org/:_authToken') || this.config.get('_authToken');
|
|
48
|
+
if (!token) {
|
|
49
|
+
this.logger.error('Not logged in. Set _authToken in ~/.jpmrc or run: npm login');
|
|
50
|
+
throw new Error('Authentication required.');
|
|
50
51
|
}
|
|
51
|
-
}
|
|
52
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
|
-
|
|
53
|
+
// 3. Prevent overwriting existing versions
|
|
54
|
+
const spinner = new Spinner('Checking if version exists...').start();
|
|
55
|
+
try {
|
|
56
|
+
await getJSON(`${registryUrl}/${encodeURIComponent(name)}/${version}`);
|
|
57
|
+
spinner.fail(`Version ${name}@${version} already exists in registry`);
|
|
58
|
+
throw new Error(`Version ${version} already exists.`);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err.status !== 404) {
|
|
61
|
+
spinner.warn('Could not verify version uniqueness, continuing...');
|
|
62
|
+
} else {
|
|
63
|
+
spinner.succeed('Version check passed');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 4. Create and pack tarball
|
|
68
|
+
const tmp = tempDir('jpm-publish-');
|
|
69
|
+
const tgz = path.join(tmp, `${name.replace('@', '').replace('/', '-')}-${version}.tgz`);
|
|
70
|
+
|
|
71
|
+
const packSpinner = new Spinner('Packing tarball...').start();
|
|
72
|
+
const ignore = this._getIgnoreList(cwd);
|
|
73
|
+
|
|
74
|
+
await tar.create(
|
|
75
|
+
{ gzip: true, file: tgz, cwd, prefix: 'package' },
|
|
76
|
+
this._getFilesToPack(cwd, ignore)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const tgzStat = fs.statSync(tgz);
|
|
80
|
+
const shasum = await integrity.hashFile(tgz, 'sha1', 'hex');
|
|
81
|
+
const integrityH = await integrity.generateIntegrity(tgz);
|
|
82
|
+
const tgzBase64 = fs.readFileSync(tgz).toString('base64');
|
|
83
|
+
|
|
84
|
+
packSpinner.succeed(`Packed ${this.logger.c.gray(`(${(tgzStat.size / 1024).toFixed(1)} KB)`)}`);
|
|
85
|
+
|
|
86
|
+
// 5. Construct registry payload
|
|
87
|
+
const body = {
|
|
88
|
+
_id: name,
|
|
89
|
+
name,
|
|
90
|
+
'dist-tags': { latest: version },
|
|
91
|
+
versions: {
|
|
92
|
+
[version]: {
|
|
93
|
+
...pkgJson.data,
|
|
94
|
+
dist: {
|
|
95
|
+
shasum,
|
|
96
|
+
integrity: integrityH,
|
|
97
|
+
tarball: `${registryUrl}/${encodeURIComponent(name)}/-/${name}-${version}.tgz`,
|
|
98
|
+
},
|
|
85
99
|
},
|
|
86
100
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// 6. PUT to registry
|
|
98
|
-
const uploadSpinner = new Spinner('Uploading to registry...').start();
|
|
99
|
-
const { request } = require('../utils/http');
|
|
100
|
-
const bodyStr = JSON.stringify(body);
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const res = await request(`${registry}/${encodeURIComponent(name)}`, {
|
|
104
|
-
method: 'PUT',
|
|
105
|
-
headers: {
|
|
106
|
-
'Content-Type': 'application/json',
|
|
107
|
-
'Authorization': `Bearer ${token}`,
|
|
108
|
-
'Content-Length': Buffer.byteLength(bodyStr),
|
|
109
|
-
...(flags.otp ? { 'npm-otp': flags.otp } : {}),
|
|
101
|
+
_attachments: {
|
|
102
|
+
[`${name}-${version}.tgz`]: {
|
|
103
|
+
content_type: 'application/octet-stream',
|
|
104
|
+
data: tgzBase64,
|
|
105
|
+
length: tgzStat.size,
|
|
106
|
+
},
|
|
110
107
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// 6. Submit to registry
|
|
111
|
+
const uploadSpinner = new Spinner('Uploading to registry...').start();
|
|
112
|
+
const bodyStr = JSON.stringify(body);
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const res = await request(`${registryUrl}/${encodeURIComponent(name)}`, {
|
|
116
|
+
method: 'PUT',
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
'Authorization': `Bearer ${token}`,
|
|
120
|
+
'Content-Length': Buffer.byteLength(bodyStr),
|
|
121
|
+
...(flags.otp ? { 'npm-otp': flags.otp } : {}),
|
|
122
|
+
},
|
|
123
|
+
body: bodyStr,
|
|
124
|
+
retries: 1,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (res.status < 200 || res.status >= 300) {
|
|
128
|
+
uploadSpinner.fail(`Publish failed: HTTP ${res.status} — ${res.body.slice(0, 200)}`);
|
|
129
|
+
throw new Error(`Registry responded with status ${res.status}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
uploadSpinner.succeed('Published!');
|
|
133
|
+
this.logger.success(`\n+ ${name}@${version}`);
|
|
134
|
+
this.logger.log(this.logger.c.gray(`${registryUrl}/${encodeURIComponent(name)}`));
|
|
135
|
+
} catch (err) {
|
|
136
|
+
uploadSpinner.fail(`Publish error: ${err.message}`);
|
|
137
|
+
throw err;
|
|
118
138
|
}
|
|
119
|
-
|
|
120
|
-
uploadSpinner.succeed('Published!');
|
|
121
|
-
logger.success(`\n+ ${name}@${version}`);
|
|
122
|
-
logger.log(logger.c.gray(`${registry}/${encodeURIComponent(name)}`));
|
|
123
|
-
} catch (err) {
|
|
124
|
-
uploadSpinner.fail(`Publish error: ${err.message}`);
|
|
125
|
-
process.exit(1);
|
|
126
139
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Generates a list of files to ignore during packing.
|
|
143
|
+
*
|
|
144
|
+
* @param {string} dir - Project root directory
|
|
145
|
+
* @returns {Set<string>} Set of ignored patterns/filenames
|
|
146
|
+
* @private
|
|
147
|
+
*/
|
|
148
|
+
_getIgnoreList(dir) {
|
|
149
|
+
const defaults = new Set(['node_modules', '.git', '.DS_Store', '*.log', 'coverage', '.jpm-lock.json']);
|
|
150
|
+
const ignoreFile = path.join(dir, '.npmignore');
|
|
151
|
+
if (fs.existsSync(ignoreFile)) {
|
|
152
|
+
fs.readFileSync(ignoreFile, 'utf8').split('\n').forEach(l => {
|
|
153
|
+
const t = l.trim();
|
|
154
|
+
if (t && !t.startsWith('#')) defaults.add(t);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return defaults;
|
|
137
158
|
}
|
|
138
|
-
return defaults;
|
|
139
|
-
}
|
|
140
159
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Scans the directory for files that should be included in the tarball.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} dir - Directory to scan
|
|
164
|
+
* @param {Set<string>} ignore - Set of ignored patterns
|
|
165
|
+
* @returns {string[]} List of files to pack
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
168
|
+
_getFilesToPack(dir, ignore) {
|
|
169
|
+
const files = [];
|
|
170
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
171
|
+
if ([...ignore].some(ig => entry === ig || entry.startsWith(ig.replace('*', '')))) continue;
|
|
172
|
+
files.push(entry);
|
|
173
|
+
}
|
|
174
|
+
return files.length ? files : ['.'];
|
|
146
175
|
}
|
|
147
|
-
return files.length ? files : ['.'];
|
|
148
176
|
}
|
|
177
|
+
|
|
178
|
+
module.exports = PublishCommand;
|
|
179
|
+
|