@mindbase/node-tools 1.3.11 → 1.3.13
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/README.md +13 -2
- package/bin/publish.js +1 -2
- package/package.json +8 -2
- package/src/clear/cleaner.js +13 -32
- package/src/common/ui/pagination.js +9 -0
- package/src/common/ui/single-select.js +50 -5
- package/src/git-log/ui.js +48 -11
- package/src/publish/registry/project-config.js +126 -50
- package/src/publish/ui.js +12 -0
package/README.md
CHANGED
|
@@ -154,9 +154,20 @@ npmpublish project --init
|
|
|
154
154
|
### 配置文件
|
|
155
155
|
|
|
156
156
|
- **全局配置**: `~/.node-tools-publish.json` - 存储注册源和 token
|
|
157
|
-
- **项目配置**:
|
|
157
|
+
- **项目配置**: `package.json` 的 `publishConfig` 字段
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"publishConfig": {
|
|
162
|
+
"defaultRegistries": ["npm", "codeup"],
|
|
163
|
+
"defaultTokens": {
|
|
164
|
+
"codeup": "token-1"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
158
169
|
|
|
159
|
-
>
|
|
170
|
+
> 兼容性提示: 如果存在旧版 `.node-tools-publish.json` 文件,仍可正常使用,建议迁移到 `package.json`
|
|
160
171
|
|
|
161
172
|
---
|
|
162
173
|
|
package/bin/publish.js
CHANGED
|
@@ -222,8 +222,7 @@ program
|
|
|
222
222
|
|
|
223
223
|
await projectConfig.initConfig(registryId, tokenId);
|
|
224
224
|
console.log(chalk.green('\n✓ 项目配置已初始化'));
|
|
225
|
-
console.log(chalk.gray(` 配置文件:
|
|
226
|
-
console.log(chalk.yellow(' 注意: 请将 .node-tools-publish.json 添加到 .gitignore'));
|
|
225
|
+
console.log(chalk.gray(` 配置文件: package.json (publishConfig)`));
|
|
227
226
|
} else {
|
|
228
227
|
projectConfig.showConfig();
|
|
229
228
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindbase/node-tools",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.13",
|
|
4
4
|
"description": "Node.js 开发工具集合:清理 node_modules、查看 Git 日志、发布包",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
"node": "20.20.0"
|
|
42
42
|
},
|
|
43
43
|
"publishConfig": {
|
|
44
|
-
"access": "public"
|
|
44
|
+
"access": "public",
|
|
45
|
+
"defaultRegistries": [
|
|
46
|
+
"npm-official"
|
|
47
|
+
],
|
|
48
|
+
"defaultTokens": {
|
|
49
|
+
"npm-official": "npm-official-1770867074417"
|
|
50
|
+
}
|
|
45
51
|
}
|
|
46
52
|
}
|
package/src/clear/cleaner.js
CHANGED
|
@@ -1,41 +1,22 @@
|
|
|
1
|
-
const
|
|
2
|
-
const { platform } = require("process");
|
|
1
|
+
const fs = require("fs");
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
let rmAvailable = null;
|
|
6
|
-
|
|
7
|
-
// 检测 rm 命令是否可用
|
|
8
|
-
function checkRmAvailable() {
|
|
9
|
-
if (rmAvailable !== null) return rmAvailable;
|
|
10
|
-
const result = spawnSync("rm", ["--version"], { shell: true });
|
|
11
|
-
rmAvailable = result.status === 0;
|
|
12
|
-
return rmAvailable;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// 执行删除命令
|
|
3
|
+
// 删除目录
|
|
16
4
|
function removeDir(path) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return result.status === 0;
|
|
23
|
-
} else {
|
|
24
|
-
const result = spawnSync("rm", ["-rf", path], { shell: true, stdio: "inherit" });
|
|
25
|
-
return result.status === 0;
|
|
5
|
+
try {
|
|
6
|
+
fs.rmSync(path, { recursive: true, force: true });
|
|
7
|
+
return true;
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
26
10
|
}
|
|
27
11
|
}
|
|
28
12
|
|
|
13
|
+
// 删除文件
|
|
29
14
|
function removeFile(path) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return result.status === 0;
|
|
36
|
-
} else {
|
|
37
|
-
const result = spawnSync("rm", [path], { shell: true, stdio: "inherit" });
|
|
38
|
-
return result.status === 0;
|
|
15
|
+
try {
|
|
16
|
+
fs.rmSync(path, { force: true });
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
39
20
|
}
|
|
40
21
|
}
|
|
41
22
|
|
|
@@ -58,6 +58,15 @@ class PagedDisplay {
|
|
|
58
58
|
this.currentPage = page;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 跳转到指定索引位置的记录
|
|
64
|
+
* @param {number} index - 记录的绝对索引(从0开始)
|
|
65
|
+
*/
|
|
66
|
+
goToIndex(index) {
|
|
67
|
+
const page = Math.floor(index / this.pageSize);
|
|
68
|
+
this.jumpToPage(page);
|
|
69
|
+
}
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
module.exports = { PagedDisplay };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 通用单选菜单组件
|
|
3
|
-
* 使用 readline
|
|
3
|
+
* 使用 readline 原生键盘处理,支持翻页
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const readline = require('readline');
|
|
@@ -23,19 +23,43 @@ function singleSelect(items, options = {}) {
|
|
|
23
23
|
|
|
24
24
|
let currentIndex = 0;
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// 计算可见条目数(不超过终端高度)
|
|
27
|
+
function getVisibleCount() {
|
|
28
|
+
const terminalHeight = process.stdout.rows || 24;
|
|
29
|
+
const titleLines = options.title ? 2 : 0; // 标题 + 空行
|
|
30
|
+
const hintLines = options.hint ? 2 : 0; // 空行 + 提示
|
|
31
|
+
const reservedLines = titleLines + hintLines + 1; // 预留 1 行余量
|
|
32
|
+
return Math.max(3, terminalHeight - reservedLines);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 显示选项(支持翻页窗口)
|
|
27
36
|
function display() {
|
|
28
37
|
console.clear();
|
|
29
38
|
if (options.title) {
|
|
30
39
|
console.log(options.title);
|
|
31
40
|
console.log('');
|
|
32
41
|
}
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
|
|
43
|
+
const visibleCount = getVisibleCount();
|
|
44
|
+
// 计算窗口位置:确保当前项在可见区域内
|
|
45
|
+
let windowStart = 0;
|
|
46
|
+
if (items.length > visibleCount) {
|
|
47
|
+
// 当前项接近窗口底部时,向上滚动
|
|
48
|
+
windowStart = Math.max(0, currentIndex - Math.floor(visibleCount / 2));
|
|
49
|
+
// 不超过最大窗口起始位置
|
|
50
|
+
windowStart = Math.min(windowStart, items.length - visibleCount);
|
|
51
|
+
}
|
|
52
|
+
const windowEnd = Math.min(windowStart + visibleCount, items.length);
|
|
53
|
+
|
|
54
|
+
// 显示可见窗口内的选项
|
|
55
|
+
for (let i = windowStart; i < windowEnd; i++) {
|
|
56
|
+
const item = items[i];
|
|
57
|
+
const isCurrent = i === currentIndex;
|
|
35
58
|
const prefix = isCurrent ? '> ' : ' ';
|
|
36
59
|
const color = isCurrent ? chalk.green : chalk.gray;
|
|
37
60
|
console.log(prefix + color(item.title));
|
|
38
|
-
}
|
|
61
|
+
}
|
|
62
|
+
|
|
39
63
|
if (options.hint) {
|
|
40
64
|
console.log('');
|
|
41
65
|
console.log(chalk.dim(options.hint));
|
|
@@ -55,6 +79,20 @@ function singleSelect(items, options = {}) {
|
|
|
55
79
|
} else if (key.name === 'down') {
|
|
56
80
|
currentIndex = Math.min(items.length - 1, currentIndex + 1);
|
|
57
81
|
display();
|
|
82
|
+
} else if (key.name === 'pageup' || key.name === 'left') {
|
|
83
|
+
const visibleCount = getVisibleCount();
|
|
84
|
+
currentIndex = Math.max(0, currentIndex - visibleCount);
|
|
85
|
+
display();
|
|
86
|
+
} else if (key.name === 'pagedown' || key.name === 'right') {
|
|
87
|
+
const visibleCount = getVisibleCount();
|
|
88
|
+
currentIndex = Math.min(items.length - 1, currentIndex + visibleCount);
|
|
89
|
+
display();
|
|
90
|
+
} else if (key.name === 'home') {
|
|
91
|
+
currentIndex = 0;
|
|
92
|
+
display();
|
|
93
|
+
} else if (key.name === 'end') {
|
|
94
|
+
currentIndex = items.length - 1;
|
|
95
|
+
display();
|
|
58
96
|
} else if (key.name === 'return') {
|
|
59
97
|
cleanup();
|
|
60
98
|
resolve(items[currentIndex].value);
|
|
@@ -67,13 +105,20 @@ function singleSelect(items, options = {}) {
|
|
|
67
105
|
}
|
|
68
106
|
};
|
|
69
107
|
|
|
108
|
+
// 终端大小变化时重新渲染
|
|
109
|
+
const resizeHandler = () => {
|
|
110
|
+
display();
|
|
111
|
+
};
|
|
112
|
+
|
|
70
113
|
const cleanup = () => {
|
|
71
114
|
process.stdin.removeListener('keypress', handler);
|
|
115
|
+
process.stdout.off('resize', resizeHandler);
|
|
72
116
|
process.stdin.setRawMode(false);
|
|
73
117
|
process.stdin.pause();
|
|
74
118
|
};
|
|
75
119
|
|
|
76
120
|
process.stdin.on('keypress', handler);
|
|
121
|
+
process.stdout.on('resize', resizeHandler);
|
|
77
122
|
});
|
|
78
123
|
}
|
|
79
124
|
|
package/src/git-log/ui.js
CHANGED
|
@@ -172,13 +172,26 @@ async function inputFilters (repos) {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
// 是否已初始化 keypress 事件
|
|
176
|
+
let keypressInitialized = false;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 确保输入流初始化(只执行一次)
|
|
180
|
+
*/
|
|
181
|
+
function ensureInputStreamInitialized() {
|
|
182
|
+
if (!keypressInitialized) {
|
|
183
|
+
readline.emitKeypressEvents(process.stdin);
|
|
184
|
+
keypressInitialized = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
175
188
|
/**
|
|
176
|
-
*
|
|
177
|
-
* @returns {Promise<string>}
|
|
189
|
+
* 等待日志导航按键(支持 resize)
|
|
190
|
+
* @returns {Promise<string>} 导航动作或 'resize'
|
|
178
191
|
*/
|
|
179
192
|
function waitForLogNavigation () {
|
|
180
193
|
return new Promise((resolve) => {
|
|
181
|
-
|
|
194
|
+
ensureInputStreamInitialized();
|
|
182
195
|
process.stdin.resume();
|
|
183
196
|
process.stdin.setRawMode(true);
|
|
184
197
|
|
|
@@ -198,13 +211,19 @@ function waitForLogNavigation () {
|
|
|
198
211
|
}
|
|
199
212
|
};
|
|
200
213
|
|
|
214
|
+
const resizeHandler = () => {
|
|
215
|
+
cleanup();
|
|
216
|
+
resolve('resize');
|
|
217
|
+
};
|
|
218
|
+
|
|
201
219
|
const cleanup = () => {
|
|
202
220
|
process.stdin.removeListener('keypress', handler);
|
|
203
|
-
process.
|
|
204
|
-
|
|
221
|
+
process.stdout.off('resize', resizeHandler);
|
|
222
|
+
// 不暂停 stdin,保持流处于活跃状态以便下次 resume
|
|
205
223
|
};
|
|
206
224
|
|
|
207
225
|
process.stdin.on('keypress', handler);
|
|
226
|
+
process.stdout.on('resize', resizeHandler);
|
|
208
227
|
});
|
|
209
228
|
}
|
|
210
229
|
|
|
@@ -243,18 +262,21 @@ function renderLogPage (page, totalCount) {
|
|
|
243
262
|
|
|
244
263
|
/**
|
|
245
264
|
* 计算动态分页大小
|
|
265
|
+
* 精确计算确保不超过终端高度
|
|
246
266
|
* @returns {number} 每页显示条数
|
|
247
267
|
*/
|
|
248
268
|
function calculateDynamicPageSize () {
|
|
249
269
|
const terminalHeight = process.stdout.rows || 24;
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
const
|
|
270
|
+
// 头部:标题1行 + 空行1行 + 提示1行 = 3行
|
|
271
|
+
const reservedLines = 3;
|
|
272
|
+
const availableLines = Math.max(terminalHeight - reservedLines, 5);
|
|
273
|
+
// 每条日志:仓库1行 + 提交1行 + 作者1行 + 日期1行 + 信息1行 + 分隔空行1行 = 6行
|
|
274
|
+
const linesPerLog = 6;
|
|
253
275
|
return Math.floor(availableLines / linesPerLog);
|
|
254
276
|
}
|
|
255
277
|
|
|
256
278
|
/**
|
|
257
|
-
*
|
|
279
|
+
* 显示日志(支持重新筛选和 resize)
|
|
258
280
|
* @param {array} logs - 日志列表
|
|
259
281
|
* @param {function} onRefilter - 重新筛选的回调
|
|
260
282
|
* @returns {Promise<void>}
|
|
@@ -267,8 +289,8 @@ async function displayLogs (logs, onRefilter) {
|
|
|
267
289
|
|
|
268
290
|
await withScreenSession(async (renderer) => {
|
|
269
291
|
// 创建分页显示(动态计算每页条数)
|
|
270
|
-
|
|
271
|
-
|
|
292
|
+
let pageSize = calculateDynamicPageSize();
|
|
293
|
+
let pagedDisplay = new PagedDisplay(logs, pageSize);
|
|
272
294
|
|
|
273
295
|
// 主循环
|
|
274
296
|
while (true) {
|
|
@@ -289,7 +311,22 @@ async function displayLogs (logs, onRefilter) {
|
|
|
289
311
|
onRefilter();
|
|
290
312
|
return;
|
|
291
313
|
} else if (action === 'exit') {
|
|
314
|
+
// 退出时恢复 stdin 状态
|
|
315
|
+
process.stdin.setRawMode(false);
|
|
316
|
+
process.stdin.pause();
|
|
292
317
|
break;
|
|
318
|
+
} else if (action === 'resize') {
|
|
319
|
+
// 终端大小改变,重新计算分页
|
|
320
|
+
const oldPageSize = pageSize;
|
|
321
|
+
pageSize = calculateDynamicPageSize();
|
|
322
|
+
if (oldPageSize !== pageSize) {
|
|
323
|
+
// 获取当前页第一条记录的绝对索引
|
|
324
|
+
const currentIndex = pagedDisplay.currentPage * pagedDisplay.pageSize;
|
|
325
|
+
// 重新创建分页器
|
|
326
|
+
pagedDisplay = new PagedDisplay(logs, pageSize);
|
|
327
|
+
// 尝试恢复到之前的位置
|
|
328
|
+
pagedDisplay.goToIndex(Math.min(currentIndex, logs.length - 1));
|
|
329
|
+
}
|
|
293
330
|
}
|
|
294
331
|
}
|
|
295
332
|
});
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 项目配置管理模块
|
|
3
|
-
*
|
|
3
|
+
* 从 package.json 的 publishConfig 字段读取项目默认配置
|
|
4
|
+
* 兼容旧的 .node-tools-publish.json 文件
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
const { existsSync, readFileSync, writeFileSync } = require('fs');
|
|
7
8
|
const { join } = require('path');
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const OLD_CONFIG_FILENAME = '.node-tools-publish.json';
|
|
11
|
+
const PACKAGE_JSON_FILENAME = 'package.json';
|
|
10
12
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
tokens: {} // { registryId: tokenId }
|
|
15
|
-
}
|
|
13
|
+
const DEFAULT_PUBLISH_CONFIG = {
|
|
14
|
+
defaultRegistries: [],
|
|
15
|
+
defaultTokens: {} // { registryId: tokenId }
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -21,103 +21,173 @@ const DEFAULT_PROJECT_CONFIG = {
|
|
|
21
21
|
class ProjectConfig {
|
|
22
22
|
constructor(projectPath) {
|
|
23
23
|
this.projectPath = projectPath;
|
|
24
|
-
this.
|
|
24
|
+
this.packageJsonPath = join(projectPath, PACKAGE_JSON_FILENAME);
|
|
25
|
+
this.oldConfigPath = join(projectPath, OLD_CONFIG_FILENAME);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
+
* 读取 package.json
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
-
if (!existsSync(this.
|
|
32
|
-
return
|
|
31
|
+
getPackageJson() {
|
|
32
|
+
if (!existsSync(this.packageJsonPath)) {
|
|
33
|
+
return {};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
try {
|
|
36
|
-
const content = readFileSync(this.
|
|
37
|
+
const content = readFileSync(this.packageJsonPath, 'utf-8');
|
|
37
38
|
return JSON.parse(content);
|
|
38
39
|
} catch (error) {
|
|
39
|
-
console.error('
|
|
40
|
-
return
|
|
40
|
+
console.error('package.json 读取失败');
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 保存 package.json
|
|
47
|
+
*/
|
|
48
|
+
setPackageJson(pkg) {
|
|
49
|
+
writeFileSync(this.packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 读取发布配置(兼容旧文件)
|
|
54
|
+
*/
|
|
55
|
+
getPublishConfig() {
|
|
56
|
+
const pkg = this.getPackageJson();
|
|
57
|
+
|
|
58
|
+
// 优先从 package.json.publishConfig 读取
|
|
59
|
+
if (pkg.publishConfig) {
|
|
60
|
+
return {
|
|
61
|
+
defaultRegistries: pkg.publishConfig.defaultRegistries || [],
|
|
62
|
+
defaultTokens: pkg.publishConfig.defaultTokens || {}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 兼容旧的 .node-tools-publish.json
|
|
67
|
+
if (existsSync(this.oldConfigPath)) {
|
|
68
|
+
try {
|
|
69
|
+
const content = readFileSync(this.oldConfigPath, 'utf-8');
|
|
70
|
+
const oldConfig = JSON.parse(content);
|
|
71
|
+
// 迁移提示
|
|
72
|
+
console.log(chalk.yellow('检测到旧配置文件,建议迁移到 package.json'));
|
|
73
|
+
return {
|
|
74
|
+
defaultRegistries: oldConfig.defaults?.registries || [],
|
|
75
|
+
defaultTokens: oldConfig.defaults?.tokens || {}
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// 忽略旧文件错误
|
|
79
|
+
}
|
|
41
80
|
}
|
|
81
|
+
|
|
82
|
+
return DEFAULT_PUBLISH_CONFIG;
|
|
42
83
|
}
|
|
43
84
|
|
|
44
85
|
/**
|
|
45
|
-
*
|
|
86
|
+
* 保存发布配置到 package.json
|
|
46
87
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
88
|
+
setPublishConfig(config) {
|
|
89
|
+
const pkg = this.getPackageJson();
|
|
90
|
+
|
|
91
|
+
// 确保 publishConfig 存在
|
|
92
|
+
if (!pkg.publishConfig) {
|
|
93
|
+
pkg.publishConfig = {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 保留 npm 标准 registry 字段
|
|
97
|
+
const npmRegistry = pkg.publishConfig.registry;
|
|
98
|
+
|
|
99
|
+
// 设置我们的配置
|
|
100
|
+
pkg.publishConfig.defaultRegistries = config.defaultRegistries;
|
|
101
|
+
pkg.publishConfig.defaultTokens = config.defaultTokens;
|
|
102
|
+
|
|
103
|
+
// 恢复 npm registry
|
|
104
|
+
if (npmRegistry) {
|
|
105
|
+
pkg.publishConfig.registry = npmRegistry;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.setPackageJson(pkg);
|
|
49
109
|
}
|
|
50
110
|
|
|
51
111
|
/**
|
|
52
112
|
* 获取默认源列表
|
|
53
113
|
*/
|
|
54
114
|
getDefaultRegistries() {
|
|
55
|
-
const config = this.
|
|
56
|
-
return config.
|
|
115
|
+
const config = this.getPublishConfig();
|
|
116
|
+
return config.defaultRegistries || [];
|
|
57
117
|
}
|
|
58
118
|
|
|
59
119
|
/**
|
|
60
120
|
* 设置默认源列表
|
|
61
121
|
*/
|
|
62
122
|
setDefaultRegistries(registryIds) {
|
|
63
|
-
const config = this.
|
|
64
|
-
config.
|
|
123
|
+
const config = this.getPublishConfig();
|
|
124
|
+
config.defaultRegistries = registryIds;
|
|
65
125
|
|
|
66
126
|
// 清理无效的 token 映射
|
|
67
127
|
const newTokens = {};
|
|
68
128
|
for (const registryId of registryIds) {
|
|
69
|
-
if (config.
|
|
70
|
-
newTokens[registryId] = config.
|
|
129
|
+
if (config.defaultTokens[registryId]) {
|
|
130
|
+
newTokens[registryId] = config.defaultTokens[registryId];
|
|
71
131
|
}
|
|
72
132
|
}
|
|
73
|
-
config.
|
|
133
|
+
config.defaultTokens = newTokens;
|
|
74
134
|
|
|
75
|
-
this.
|
|
135
|
+
this.setPublishConfig(config);
|
|
76
136
|
}
|
|
77
137
|
|
|
78
138
|
/**
|
|
79
139
|
* 获取指定源的默认 token ID
|
|
80
140
|
*/
|
|
81
141
|
getDefaultTokenId(registryId) {
|
|
82
|
-
const config = this.
|
|
83
|
-
return config.
|
|
142
|
+
const config = this.getPublishConfig();
|
|
143
|
+
return config.defaultTokens[registryId];
|
|
84
144
|
}
|
|
85
145
|
|
|
86
146
|
/**
|
|
87
147
|
* 设置指定源的默认 token ID
|
|
88
148
|
*/
|
|
89
149
|
setDefaultToken(registryId, tokenId) {
|
|
90
|
-
const config = this.
|
|
91
|
-
config.
|
|
92
|
-
this.
|
|
150
|
+
const config = this.getPublishConfig();
|
|
151
|
+
config.defaultTokens[registryId] = tokenId;
|
|
152
|
+
this.setPublishConfig(config);
|
|
93
153
|
}
|
|
94
154
|
|
|
95
155
|
/**
|
|
96
156
|
* 初始化项目配置
|
|
97
157
|
*/
|
|
98
158
|
async initConfig(defaultRegistryId, defaultTokenId) {
|
|
99
|
-
const config =
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
159
|
+
const config = {
|
|
160
|
+
defaultRegistries: [defaultRegistryId],
|
|
161
|
+
defaultTokens: {
|
|
162
|
+
[defaultRegistryId]: defaultTokenId
|
|
163
|
+
}
|
|
103
164
|
};
|
|
104
|
-
this.
|
|
165
|
+
this.setPublishConfig(config);
|
|
105
166
|
}
|
|
106
167
|
|
|
107
168
|
/**
|
|
108
169
|
* 显示配置
|
|
109
170
|
*/
|
|
110
171
|
showConfig() {
|
|
111
|
-
const config = this.
|
|
172
|
+
const config = this.getPublishConfig();
|
|
173
|
+
const pkg = this.getPackageJson();
|
|
112
174
|
|
|
113
|
-
console.log('
|
|
114
|
-
console.log(` 配置文件: ${this.
|
|
115
|
-
console.log(`\n默认源: ${config.
|
|
175
|
+
console.log('项目发布配置:');
|
|
176
|
+
console.log(` 配置文件: ${this.packageJsonPath}`);
|
|
177
|
+
console.log(`\n默认源: ${config.defaultRegistries.join(', ') || '未设置'}`);
|
|
116
178
|
|
|
117
179
|
console.log('\n默认 Tokens:');
|
|
118
|
-
|
|
180
|
+
if (Object.keys(config.defaultTokens).length === 0) {
|
|
181
|
+
console.log(' 未设置');
|
|
182
|
+
}
|
|
183
|
+
for (const [registryId, tokenId] of Object.entries(config.defaultTokens)) {
|
|
119
184
|
console.log(` ${registryId}: ${tokenId}`);
|
|
120
185
|
}
|
|
186
|
+
|
|
187
|
+
// 兼容性提示
|
|
188
|
+
if (existsSync(this.oldConfigPath)) {
|
|
189
|
+
console.log(chalk.yellow(`\n提示: 检测到旧配置文件 ${OLD_CONFIG_FILENAME},可删除`));
|
|
190
|
+
}
|
|
121
191
|
}
|
|
122
192
|
|
|
123
193
|
/**
|
|
@@ -128,12 +198,17 @@ class ProjectConfig {
|
|
|
128
198
|
const { spawn } = require('child_process');
|
|
129
199
|
const { platform } = process;
|
|
130
200
|
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
201
|
+
// 确保 publishConfig 字段存在
|
|
202
|
+
const pkg = this.getPackageJson();
|
|
203
|
+
if (!pkg.publishConfig) {
|
|
204
|
+
pkg.publishConfig = {
|
|
205
|
+
defaultRegistries: [],
|
|
206
|
+
defaultTokens: {}
|
|
207
|
+
};
|
|
208
|
+
this.setPackageJson(pkg);
|
|
134
209
|
}
|
|
135
210
|
|
|
136
|
-
console.log(`打开项目配置文件: ${this.
|
|
211
|
+
console.log(`打开项目配置文件: ${this.packageJsonPath}`);
|
|
137
212
|
|
|
138
213
|
// 优先使用 code(VS Code)
|
|
139
214
|
const editorCmd = process.env.EDITOR || (platform === 'win32' ? 'code' : 'vim');
|
|
@@ -143,7 +218,7 @@ class ProjectConfig {
|
|
|
143
218
|
? { shell: true, stdio: 'inherit' }
|
|
144
219
|
: { stdio: 'inherit' };
|
|
145
220
|
|
|
146
|
-
spawn('code', [this.
|
|
221
|
+
spawn('code', [this.packageJsonPath, '--wait'], spawnOptions)
|
|
147
222
|
.on('exit', (code) => {
|
|
148
223
|
if (code === 0) {
|
|
149
224
|
console.log('\n配置已保存');
|
|
@@ -153,20 +228,21 @@ class ProjectConfig {
|
|
|
153
228
|
})
|
|
154
229
|
.on('error', () => {
|
|
155
230
|
console.log('VS Code 不可用,使用默认编辑器...');
|
|
156
|
-
edit(this.
|
|
231
|
+
edit(this.packageJsonPath, (code) => {
|
|
157
232
|
console.log(code === 0 ? '\n配置已保存' : `\n编辑器退出,代码: ${code}`);
|
|
158
233
|
});
|
|
159
234
|
});
|
|
160
235
|
} else {
|
|
161
|
-
edit(this.
|
|
236
|
+
edit(this.packageJsonPath, (code) => {
|
|
162
237
|
console.log(code === 0 ? '\n配置已保存' : `\n编辑器退出,代码: ${code}`);
|
|
163
238
|
});
|
|
164
239
|
}
|
|
165
240
|
}
|
|
166
241
|
}
|
|
167
242
|
|
|
243
|
+
const chalk = require('chalk');
|
|
244
|
+
|
|
168
245
|
module.exports = {
|
|
169
246
|
ProjectConfig,
|
|
170
|
-
|
|
171
|
-
DEFAULT_PROJECT_CONFIG
|
|
247
|
+
DEFAULT_PUBLISH_CONFIG
|
|
172
248
|
};
|
package/src/publish/ui.js
CHANGED
|
@@ -423,6 +423,18 @@ async function showPublishResults(renderer, results, registries) {
|
|
|
423
423
|
* 运行发布流程
|
|
424
424
|
*/
|
|
425
425
|
async function runPublishFlow(targetPath, options) {
|
|
426
|
+
const { existsSync } = require('fs');
|
|
427
|
+
const { join } = require('path');
|
|
428
|
+
|
|
429
|
+
// 检查 package.json 是否存在
|
|
430
|
+
const packageJsonPath = join(targetPath, 'package.json');
|
|
431
|
+
if (!existsSync(packageJsonPath)) {
|
|
432
|
+
console.error(chalk.red('\n错误: 当前目录不是 npm 包或 npm 工作空间'));
|
|
433
|
+
console.error(chalk.yellow(`\n未找到 package.json 文件: ${packageJsonPath}`));
|
|
434
|
+
console.error(chalk.gray('\n请确保在正确的 npm 项目目录下执行此命令\n'));
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
|
|
426
438
|
return withScreenSession(async (renderer) => {
|
|
427
439
|
// 1. 扫描预览页
|
|
428
440
|
const scanResult = await showScanPreview(renderer, targetPath);
|