@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.
Files changed (45) hide show
  1. package/LICENSE +201 -0
  2. package/bin/gitlog.ts +3 -0
  3. package/bin/iconfont-editor.ts +3 -0
  4. package/bin/index.ts +29 -0
  5. package/bin/nodeclear.ts +3 -0
  6. package/bin/npmpublish.ts +3 -0
  7. package/bin/shared.ts +141 -0
  8. package/package.json +63 -0
  9. package/scripts/ensure-tsx.cjs +18 -0
  10. package/src/clear/app.ts +152 -0
  11. package/src/clear/config.ts +108 -0
  12. package/src/clear/file-cleaner.ts +137 -0
  13. package/src/clear/index.ts +28 -0
  14. package/src/clear/scanner.ts +154 -0
  15. package/src/gitlog/app.ts +272 -0
  16. package/src/gitlog/config.ts +91 -0
  17. package/src/gitlog/display.ts +178 -0
  18. package/src/gitlog/index.ts +5 -0
  19. package/src/gitlog/log-fetcher.ts +150 -0
  20. package/src/gitlog/pager.ts +178 -0
  21. package/src/gitlog/scanner.ts +60 -0
  22. package/src/iconfont/frontend/index.html +12 -0
  23. package/src/iconfont/frontend/src/App.vue +14 -0
  24. package/src/iconfont/frontend/src/main.ts +8 -0
  25. package/src/iconfont/frontend/src/views/IconEditor.vue +819 -0
  26. package/src/iconfont/frontend/vite.config.ts +15 -0
  27. package/src/iconfont/lib/css-generator.js +37 -0
  28. package/src/iconfont/lib/font-builder.js +82 -0
  29. package/src/iconfont/lib/glyph-extractor.js +69 -0
  30. package/src/iconfont/server/api.js +256 -0
  31. package/src/iconfont/server/index.js +64 -0
  32. package/src/index.ts +0 -0
  33. package/src/publish/app.ts +316 -0
  34. package/src/publish/builder.ts +120 -0
  35. package/src/publish/dependency.ts +144 -0
  36. package/src/publish/detector.ts +93 -0
  37. package/src/publish/index.ts +66 -0
  38. package/src/publish/npm-query.ts +244 -0
  39. package/src/publish/registry/adapters/npm.ts +128 -0
  40. package/src/publish/registry/registry-manager.ts +107 -0
  41. package/src/publish/scanner.ts +90 -0
  42. package/src/publish/types.ts +98 -0
  43. package/src/publish/version.ts +108 -0
  44. package/src/shared/config-manager.ts +57 -0
  45. 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
+ }