@mindbase/mindbase 1.0.0
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/LICENSE +201 -0
- package/bin/gitlog.ts +3 -0
- package/bin/iconfont-editor.ts +3 -0
- package/bin/index.ts +29 -0
- package/bin/nodeclear.ts +3 -0
- package/bin/npmpublish.ts +3 -0
- package/bin/shared.ts +141 -0
- package/package.json +63 -0
- package/scripts/ensure-tsx.cjs +18 -0
- package/src/clear/app.ts +152 -0
- package/src/clear/config.ts +108 -0
- package/src/clear/file-cleaner.ts +137 -0
- package/src/clear/index.ts +28 -0
- package/src/clear/scanner.ts +154 -0
- package/src/gitlog/app.ts +272 -0
- package/src/gitlog/config.ts +91 -0
- package/src/gitlog/display.ts +178 -0
- package/src/gitlog/index.ts +5 -0
- package/src/gitlog/log-fetcher.ts +150 -0
- package/src/gitlog/pager.ts +178 -0
- package/src/gitlog/scanner.ts +60 -0
- package/src/iconfont/frontend/index.html +12 -0
- package/src/iconfont/frontend/src/App.vue +14 -0
- package/src/iconfont/frontend/src/main.ts +8 -0
- package/src/iconfont/frontend/src/views/IconEditor.vue +819 -0
- package/src/iconfont/frontend/vite.config.ts +15 -0
- package/src/iconfont/lib/css-generator.js +37 -0
- package/src/iconfont/lib/font-builder.js +82 -0
- package/src/iconfont/lib/glyph-extractor.js +69 -0
- package/src/iconfont/server/api.js +256 -0
- package/src/iconfont/server/index.js +64 -0
- package/src/index.ts +0 -0
- package/src/publish/app.ts +316 -0
- package/src/publish/builder.ts +120 -0
- package/src/publish/dependency.ts +144 -0
- package/src/publish/detector.ts +93 -0
- package/src/publish/index.ts +66 -0
- package/src/publish/npm-query.ts +244 -0
- package/src/publish/registry/adapters/npm.ts +128 -0
- package/src/publish/registry/registry-manager.ts +107 -0
- package/src/publish/scanner.ts +90 -0
- package/src/publish/types.ts +98 -0
- package/src/publish/version.ts +108 -0
- package/src/shared/config-manager.ts +57 -0
- package/src/shared/index.ts +1 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
WorkspaceType,
|
|
3
|
+
Workspace,
|
|
4
|
+
Package,
|
|
5
|
+
DependencyAnalysis,
|
|
6
|
+
PublishProgress,
|
|
7
|
+
PublishOptions,
|
|
8
|
+
PublishResult
|
|
9
|
+
} from './types.js';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
detectWorkspace,
|
|
13
|
+
checkPublishReadiness
|
|
14
|
+
} from './detector.js';
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
scanPackages,
|
|
18
|
+
getPackageDependencies,
|
|
19
|
+
findPackageDependencies
|
|
20
|
+
} from './scanner.js';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
analyzeDependencies,
|
|
24
|
+
checkCircularDependencies,
|
|
25
|
+
getDependencyTree,
|
|
26
|
+
groupByLevel
|
|
27
|
+
} from './dependency.js';
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
bumpVersion,
|
|
31
|
+
bumpVersions,
|
|
32
|
+
updatePackageVersion,
|
|
33
|
+
applyVersionChanges,
|
|
34
|
+
suggestBumpType,
|
|
35
|
+
parseVersion,
|
|
36
|
+
compareVersions,
|
|
37
|
+
isValidVersion,
|
|
38
|
+
type BumpType
|
|
39
|
+
} from './version.js';
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
detectBuildConfig,
|
|
43
|
+
detectBuildConfigs,
|
|
44
|
+
filterPackagesNeedingBuild,
|
|
45
|
+
getBuildScript,
|
|
46
|
+
type BuildInfo
|
|
47
|
+
} from './builder.js';
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
RegistryManager,
|
|
51
|
+
registryManager,
|
|
52
|
+
type RegistryConfig,
|
|
53
|
+
type Publisher
|
|
54
|
+
} from './registry/registry-manager.js';
|
|
55
|
+
|
|
56
|
+
export { NpmPublisher } from './registry/adapters/npm.js';
|
|
57
|
+
|
|
58
|
+
// 重新导出 npm 查询功能
|
|
59
|
+
export {
|
|
60
|
+
NpmPackageQuery,
|
|
61
|
+
quickQuery as queryPackage,
|
|
62
|
+
packageExists,
|
|
63
|
+
getLatestVersion,
|
|
64
|
+
type PackageQueryResult,
|
|
65
|
+
type QueryOptions
|
|
66
|
+
} from './npm-query.js';
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* NPM 包查询结果
|
|
5
|
+
*/
|
|
6
|
+
export interface PackageQueryResult {
|
|
7
|
+
/** 包是否存在 */
|
|
8
|
+
exists: boolean;
|
|
9
|
+
/** 包名 */
|
|
10
|
+
name: string;
|
|
11
|
+
/** 包描述 */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** 分发标签(latest, beta, next 等) */
|
|
14
|
+
distTags: { [tag: string]: string };
|
|
15
|
+
/** 所有版本号 */
|
|
16
|
+
allVersions: string[];
|
|
17
|
+
/** 最新稳定版 */
|
|
18
|
+
latestVersion: string;
|
|
19
|
+
/** Beta 版本 */
|
|
20
|
+
betaVersion?: string;
|
|
21
|
+
/** Next 版本 */
|
|
22
|
+
nextVersion?: string;
|
|
23
|
+
/** 稳定版本列表 */
|
|
24
|
+
stableVersions: string[];
|
|
25
|
+
/** 预发布版本列表 */
|
|
26
|
+
prereleaseVersions: string[];
|
|
27
|
+
/** 创建时间 */
|
|
28
|
+
createdAt?: string;
|
|
29
|
+
/** 最后修改时间 */
|
|
30
|
+
modifiedAt?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 查询选项
|
|
35
|
+
*/
|
|
36
|
+
export interface QueryOptions {
|
|
37
|
+
/** 请求超时时间(毫秒) */
|
|
38
|
+
timeout?: number;
|
|
39
|
+
/** 是否使用缓存 */
|
|
40
|
+
cache?: boolean;
|
|
41
|
+
/** 缓存存活时间(毫秒) */
|
|
42
|
+
cacheTTL?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 缓存项
|
|
47
|
+
*/
|
|
48
|
+
interface CacheItem {
|
|
49
|
+
data: PackageQueryResult;
|
|
50
|
+
timestamp: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* NPM 包查询服务
|
|
55
|
+
*/
|
|
56
|
+
export class NpmPackageQuery {
|
|
57
|
+
private baseUrl = 'https://registry.npmjs.org';
|
|
58
|
+
private cache = new Map<string, CacheItem>();
|
|
59
|
+
private options: Required<QueryOptions>;
|
|
60
|
+
|
|
61
|
+
constructor(options: QueryOptions = {}) {
|
|
62
|
+
this.options = {
|
|
63
|
+
timeout: 10000,
|
|
64
|
+
cache: true,
|
|
65
|
+
cacheTTL: 300000, // 5 分钟
|
|
66
|
+
...options
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 查询包信息
|
|
72
|
+
*/
|
|
73
|
+
async query(packageName: string): Promise<PackageQueryResult> {
|
|
74
|
+
// 检查缓存
|
|
75
|
+
if (this.options.cache) {
|
|
76
|
+
const cached = this.cache.get(packageName);
|
|
77
|
+
if (cached && Date.now() - cached.timestamp < this.options.cacheTTL) {
|
|
78
|
+
return cached.data;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const result = await this.fetchPackageInfo(packageName);
|
|
84
|
+
|
|
85
|
+
// 更新缓存
|
|
86
|
+
if (this.options.cache) {
|
|
87
|
+
this.cache.set(packageName, {
|
|
88
|
+
data: result,
|
|
89
|
+
timestamp: Date.now()
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return result;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
throw new Error(`查询包 '${packageName}' 失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 获取分发标签
|
|
101
|
+
*/
|
|
102
|
+
async getDistTags(packageName: string): Promise<{ [tag: string]: string }> {
|
|
103
|
+
const info = await this.query(packageName);
|
|
104
|
+
return info.distTags;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 获取所有版本
|
|
109
|
+
*/
|
|
110
|
+
async getAllVersions(packageName: string): Promise<string[]> {
|
|
111
|
+
const info = await this.query(packageName);
|
|
112
|
+
return info.allVersions;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 获取指定标签的版本
|
|
117
|
+
*/
|
|
118
|
+
async getTagVersion(packageName: string, tag: string): Promise<string | undefined> {
|
|
119
|
+
const distTags = await this.getDistTags(packageName);
|
|
120
|
+
return distTags[tag];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 批量查询
|
|
125
|
+
*/
|
|
126
|
+
async bulkQuery(packageNames: string[]): Promise<Map<string, PackageQueryResult>> {
|
|
127
|
+
const results = new Map<string, PackageQueryResult>();
|
|
128
|
+
const promises = packageNames.map(async (name) => {
|
|
129
|
+
try {
|
|
130
|
+
const result = await this.query(name);
|
|
131
|
+
results.set(name, result);
|
|
132
|
+
} catch {
|
|
133
|
+
// 查询失败时返回不存在的结果
|
|
134
|
+
results.set(name, {
|
|
135
|
+
exists: false,
|
|
136
|
+
name,
|
|
137
|
+
distTags: {},
|
|
138
|
+
allVersions: [],
|
|
139
|
+
latestVersion: '',
|
|
140
|
+
stableVersions: [],
|
|
141
|
+
prereleaseVersions: []
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await Promise.all(promises);
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 清除缓存
|
|
152
|
+
*/
|
|
153
|
+
clearCache(): void {
|
|
154
|
+
this.cache.clear();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 从 NPM registry 获取包信息
|
|
159
|
+
*/
|
|
160
|
+
private async fetchPackageInfo(packageName: string): Promise<PackageQueryResult> {
|
|
161
|
+
const controller = new AbortController();
|
|
162
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
const response = await fetch(`${this.baseUrl}/${packageName}`, {
|
|
166
|
+
signal: controller.signal
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
clearTimeout(timeoutId);
|
|
170
|
+
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
if (response.status === 404) {
|
|
173
|
+
return {
|
|
174
|
+
exists: false,
|
|
175
|
+
name: packageName,
|
|
176
|
+
distTags: {},
|
|
177
|
+
allVersions: [],
|
|
178
|
+
latestVersion: '',
|
|
179
|
+
stableVersions: [],
|
|
180
|
+
prereleaseVersions: []
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`HTTP 请求失败: ${response.status}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const packageData = await response.json() as any;
|
|
187
|
+
const distTags = packageData['dist-tags'] || {};
|
|
188
|
+
const allVersions = Object.keys(packageData.versions || {});
|
|
189
|
+
|
|
190
|
+
// 分类版本
|
|
191
|
+
const stableVersions: string[] = [];
|
|
192
|
+
const prereleaseVersions: string[] = [];
|
|
193
|
+
|
|
194
|
+
for (const version of allVersions) {
|
|
195
|
+
if (semver.prerelease(version)) {
|
|
196
|
+
prereleaseVersions.push(version);
|
|
197
|
+
} else {
|
|
198
|
+
stableVersions.push(version);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
exists: true,
|
|
204
|
+
name: packageData.name,
|
|
205
|
+
description: packageData.description,
|
|
206
|
+
distTags,
|
|
207
|
+
allVersions,
|
|
208
|
+
latestVersion: distTags.latest || '',
|
|
209
|
+
betaVersion: distTags.beta,
|
|
210
|
+
nextVersion: distTags.next,
|
|
211
|
+
stableVersions,
|
|
212
|
+
prereleaseVersions,
|
|
213
|
+
createdAt: packageData.time?.created,
|
|
214
|
+
modifiedAt: packageData.time?.modified
|
|
215
|
+
};
|
|
216
|
+
} finally {
|
|
217
|
+
clearTimeout(timeoutId);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 快速查询(静态方法,不使用缓存)
|
|
224
|
+
*/
|
|
225
|
+
export async function quickQuery(packageName: string): Promise<PackageQueryResult> {
|
|
226
|
+
const query = new NpmPackageQuery({ cache: false });
|
|
227
|
+
return query.query(packageName);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 查询包是否存在
|
|
232
|
+
*/
|
|
233
|
+
export async function packageExists(packageName: string): Promise<boolean> {
|
|
234
|
+
const result = await quickQuery(packageName);
|
|
235
|
+
return result.exists;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 获取包的最新版本
|
|
240
|
+
*/
|
|
241
|
+
export async function getLatestVersion(packageName: string): Promise<string | null> {
|
|
242
|
+
const result = await quickQuery(packageName);
|
|
243
|
+
return result.latestVersion || null;
|
|
244
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fsExtra from 'fs-extra';
|
|
3
|
+
const { readJsonSync } = fsExtra;
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import type { Publisher } from '../registry-manager.js';
|
|
6
|
+
import type { PublishOptions, PublishResult } from '../../types.js';
|
|
7
|
+
import type { PackageQueryResult } from '../../npm-query.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* NPM 发布器
|
|
11
|
+
*/
|
|
12
|
+
export class NpmPublisher implements Publisher {
|
|
13
|
+
constructor(
|
|
14
|
+
private registryUrl: string,
|
|
15
|
+
private queryFn?: (packageName: string) => Promise<PackageQueryResult>
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 发布包
|
|
20
|
+
*/
|
|
21
|
+
async publish(pkgPath: string, options: PublishOptions = {}): Promise<PublishResult> {
|
|
22
|
+
try {
|
|
23
|
+
const args = ['publish'];
|
|
24
|
+
|
|
25
|
+
if (options.dryRun) {
|
|
26
|
+
args.push('--dry-run');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (options.registryId) {
|
|
30
|
+
// 使用指定的注册源
|
|
31
|
+
const registry = this.getRegistryUrl(options.registryId);
|
|
32
|
+
args.push('--registry', registry);
|
|
33
|
+
} else if (this.registryUrl !== 'https://registry.npmjs.org/') {
|
|
34
|
+
args.push('--registry', this.registryUrl);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 执行发布命令
|
|
38
|
+
execSync(`npm publish ${args.join(' ')}`, {
|
|
39
|
+
cwd: pkgPath,
|
|
40
|
+
stdio: 'pipe'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
success: 1,
|
|
45
|
+
failed: 0,
|
|
46
|
+
published: [this.getPackageName(pkgPath)],
|
|
47
|
+
failures: []
|
|
48
|
+
};
|
|
49
|
+
} catch (error) {
|
|
50
|
+
return {
|
|
51
|
+
success: 0,
|
|
52
|
+
failed: 1,
|
|
53
|
+
published: [],
|
|
54
|
+
failures: [{
|
|
55
|
+
name: this.getPackageName(pkgPath),
|
|
56
|
+
error: error instanceof Error ? error.message : String(error)
|
|
57
|
+
}]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 检查包是否存在
|
|
64
|
+
*/
|
|
65
|
+
async exists(packageName: string): Promise<boolean> {
|
|
66
|
+
if (!this.queryFn) {
|
|
67
|
+
// 默认使用 fetch
|
|
68
|
+
try {
|
|
69
|
+
const response = await fetch(`${this.registryUrl}${packageName}`);
|
|
70
|
+
return response.ok;
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const result = await this.queryFn(packageName);
|
|
78
|
+
return result.exists;
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 获取包信息
|
|
86
|
+
*/
|
|
87
|
+
async getPackageInfo(packageName: string): Promise<any> {
|
|
88
|
+
if (!this.queryFn) {
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(`${this.registryUrl}${packageName}`);
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
throw new Error(`包 ${packageName} 不存在`);
|
|
93
|
+
}
|
|
94
|
+
return response.json();
|
|
95
|
+
} catch {
|
|
96
|
+
throw new Error(`获取包信息失败: ${packageName}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const result = await this.queryFn(packageName);
|
|
101
|
+
if (!result.exists) {
|
|
102
|
+
throw new Error(`包 ${packageName} 不存在`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 获取包名
|
|
110
|
+
*/
|
|
111
|
+
private getPackageName(pkgPath: string): string {
|
|
112
|
+
try {
|
|
113
|
+
const packageJson = readJsonSync(join(pkgPath, 'package.json'));
|
|
114
|
+
return packageJson.name || '';
|
|
115
|
+
} catch {
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 获取注册源 URL
|
|
122
|
+
*/
|
|
123
|
+
private getRegistryUrl(registryId: string): string {
|
|
124
|
+
// 这里可以根据 registryId 返回不同的 URL
|
|
125
|
+
// 简化实现,直接返回默认的
|
|
126
|
+
return this.registryUrl;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { PublishOptions, PublishResult } from '../types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 注册源配置
|
|
5
|
+
*/
|
|
6
|
+
export interface RegistryConfig {
|
|
7
|
+
/** 注册源 ID */
|
|
8
|
+
id: string;
|
|
9
|
+
/** 注册源名称 */
|
|
10
|
+
name: string;
|
|
11
|
+
/** 注册源 URL */
|
|
12
|
+
url: string;
|
|
13
|
+
/** 是否是默认 */
|
|
14
|
+
isDefault?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 发布器接口
|
|
19
|
+
*/
|
|
20
|
+
export interface Publisher {
|
|
21
|
+
/** 发布包 */
|
|
22
|
+
publish(pkgPath: string, options: PublishOptions): Promise<PublishResult>;
|
|
23
|
+
/** 检查包是否存在 */
|
|
24
|
+
exists(packageName: string): Promise<boolean>;
|
|
25
|
+
/** 获取包信息 */
|
|
26
|
+
getPackageInfo(packageName: string): Promise<any>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 注册源管理器
|
|
31
|
+
*/
|
|
32
|
+
export class RegistryManager {
|
|
33
|
+
private registries: Map<string, RegistryConfig> = new Map();
|
|
34
|
+
private publishers: Map<string, Publisher> = new Map();
|
|
35
|
+
|
|
36
|
+
constructor() {
|
|
37
|
+
// 默认 npm 注册源
|
|
38
|
+
this.addRegistry({
|
|
39
|
+
id: 'npm',
|
|
40
|
+
name: 'npm',
|
|
41
|
+
url: 'https://registry.npmjs.org/',
|
|
42
|
+
isDefault: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 添加注册源
|
|
48
|
+
*/
|
|
49
|
+
addRegistry(config: RegistryConfig): void {
|
|
50
|
+
this.registries.set(config.id, config);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 获取注册源配置
|
|
55
|
+
*/
|
|
56
|
+
getRegistry(id: string): RegistryConfig | undefined {
|
|
57
|
+
return this.registries.get(id);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 获取所有注册源
|
|
62
|
+
*/
|
|
63
|
+
getAllRegistries(): RegistryConfig[] {
|
|
64
|
+
return Array.from(this.registries.values());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 获取默认注册源
|
|
69
|
+
*/
|
|
70
|
+
getDefaultRegistry(): RegistryConfig {
|
|
71
|
+
return this.registries.get('npm')!;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 注册发布器
|
|
76
|
+
*/
|
|
77
|
+
registerPublisher(id: string, publisher: Publisher): void {
|
|
78
|
+
this.publishers.set(id, publisher);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 获取发布器
|
|
83
|
+
*/
|
|
84
|
+
getPublisher(id?: string): Publisher {
|
|
85
|
+
const registryId = id || 'npm';
|
|
86
|
+
const publisher = this.publishers.get(registryId);
|
|
87
|
+
|
|
88
|
+
if (!publisher) {
|
|
89
|
+
throw new Error(`未找到注册源: ${registryId}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return publisher;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 发布包
|
|
97
|
+
*/
|
|
98
|
+
async publish(pkgPath: string, options: PublishOptions = {}): Promise<PublishResult> {
|
|
99
|
+
const registryId = options.registryId || 'npm';
|
|
100
|
+
const publisher = this.getPublisher(registryId);
|
|
101
|
+
|
|
102
|
+
return publisher.publish(pkgPath, options);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 创建全局实例
|
|
107
|
+
export const registryManager = new RegistryManager();
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import type { Workspace, Package } from './types.js';
|
|
5
|
+
import { checkPublishReadiness } from './detector.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 扫描工作空间中的包
|
|
9
|
+
*/
|
|
10
|
+
export async function scanPackages(workspace: Workspace): Promise<Package[]> {
|
|
11
|
+
const packages: Package[] = [];
|
|
12
|
+
|
|
13
|
+
if (workspace.type === 'single') {
|
|
14
|
+
const pkg = scanPackage(workspace.rootPath);
|
|
15
|
+
if (pkg) {
|
|
16
|
+
packages.push(pkg);
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
// 使用 glob 匹配所有 package.json
|
|
20
|
+
const patternList = workspace.patterns.map(p =>
|
|
21
|
+
join(workspace.rootPath, p, 'package.json')
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const files = await glob(patternList.join(' '), {
|
|
25
|
+
cwd: workspace.rootPath,
|
|
26
|
+
absolute: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const pkgDir = join(file, '..');
|
|
31
|
+
const pkg = scanPackage(pkgDir);
|
|
32
|
+
if (pkg && !pkg.private) {
|
|
33
|
+
packages.push(pkg);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return packages;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 扫描单个包
|
|
43
|
+
*/
|
|
44
|
+
function scanPackage(pkgPath: string): Package | null {
|
|
45
|
+
const packageJsonPath = join(pkgPath, 'package.json');
|
|
46
|
+
|
|
47
|
+
if (!existsSync(packageJsonPath)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
name: packageJson.name || '',
|
|
56
|
+
path: pkgPath,
|
|
57
|
+
relativePath: relative(process.cwd(), pkgPath),
|
|
58
|
+
version: packageJson.version || '0.0.0',
|
|
59
|
+
private: packageJson.private || false,
|
|
60
|
+
description: packageJson.description,
|
|
61
|
+
hasBuildScript: !!(packageJson.scripts && packageJson.scripts.build),
|
|
62
|
+
dependencies: Object.keys(packageJson.dependencies || {}),
|
|
63
|
+
devDependencies: Object.keys(packageJson.devDependencies || {})
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 获取包的依赖项
|
|
72
|
+
*/
|
|
73
|
+
export function getPackageDependencies(pkg: Package): string[] {
|
|
74
|
+
return [...pkg.dependencies, ...pkg.devDependencies];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 查找包之间的依赖关系
|
|
79
|
+
*/
|
|
80
|
+
export function findPackageDependencies(
|
|
81
|
+
packages: Package[],
|
|
82
|
+
targetPkg: Package
|
|
83
|
+
): Package[] {
|
|
84
|
+
const deps = getPackageDependencies(targetPkg);
|
|
85
|
+
const pkgMap = new Map(packages.map(p => [p.name, p]));
|
|
86
|
+
|
|
87
|
+
return deps
|
|
88
|
+
.map(name => pkgMap.get(name))
|
|
89
|
+
.filter((p): p is Package => !!p && !p.private);
|
|
90
|
+
}
|