@talex-touch/utils 1.0.13 → 1.0.15
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/base/index.ts +181 -181
- package/channel/index.ts +108 -99
- package/common/index.ts +2 -39
- package/common/storage/constants.ts +3 -0
- package/common/storage/entity/app-settings.ts +47 -0
- package/common/storage/entity/index.ts +1 -0
- package/common/storage/index.ts +3 -0
- package/common/utils.ts +160 -0
- package/core-box/README.md +218 -0
- package/core-box/index.ts +7 -0
- package/core-box/search.ts +536 -0
- package/core-box/types.ts +384 -0
- package/electron/download-manager.ts +118 -0
- package/{common → electron}/env-tool.ts +56 -56
- package/electron/touch-core.ts +167 -0
- package/electron/window.ts +71 -0
- package/eventbus/index.ts +86 -87
- package/index.ts +5 -0
- package/package.json +55 -30
- package/permission/index.ts +48 -48
- package/plugin/channel.ts +203 -193
- package/plugin/index.ts +216 -121
- package/plugin/log/logger-manager.ts +60 -0
- package/plugin/log/logger.ts +75 -0
- package/plugin/log/types.ts +27 -0
- package/plugin/preload.ts +39 -39
- package/plugin/sdk/common.ts +27 -27
- package/plugin/sdk/hooks/life-cycle.ts +95 -95
- package/plugin/sdk/index.ts +18 -13
- package/plugin/sdk/service/index.ts +29 -29
- package/plugin/sdk/types.ts +578 -0
- package/plugin/sdk/window/index.ts +40 -40
- package/renderer/index.ts +2 -0
- package/renderer/ref.ts +54 -54
- package/renderer/slots.ts +124 -0
- package/renderer/storage/app-settings.ts +34 -0
- package/renderer/storage/base-storage.ts +335 -0
- package/renderer/storage/index.ts +1 -0
- package/search/types.ts +726 -0
- package/service/index.ts +67 -67
- package/service/protocol/index.ts +77 -77
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Box Type Definitions
|
|
3
|
+
* Universal types extracted from various parts of the project for reuse across the entire codebase
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IPluginIcon, IFeatureCommand } from '@talex-touch/utils/plugin';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Render mode enumeration for search result items
|
|
10
|
+
* Defines different ways to render search result content
|
|
11
|
+
*/
|
|
12
|
+
export enum RenderMode {
|
|
13
|
+
/** Standard text-based rendering */
|
|
14
|
+
STANDARD = 'standard',
|
|
15
|
+
/** URL-based rendering - loads and displays remote URL content */
|
|
16
|
+
URL = 'url',
|
|
17
|
+
/** HTML content rendering */
|
|
18
|
+
HTML = 'html',
|
|
19
|
+
/** JavaScript code rendering with syntax highlighting */
|
|
20
|
+
JAVASCRIPT = 'javascript',
|
|
21
|
+
/** JSX component rendering */
|
|
22
|
+
JSX = 'jsx',
|
|
23
|
+
/** Vue Single File Component rendering */
|
|
24
|
+
VUE_SFC = 'vue-sfc'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Render configuration for search result items
|
|
29
|
+
* Specifies how the search result should be displayed in the UI
|
|
30
|
+
*/
|
|
31
|
+
export interface IRenderConfig {
|
|
32
|
+
/** The rendering mode to use */
|
|
33
|
+
mode: RenderMode;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Content to render
|
|
37
|
+
* - For URL mode: The remote URL to load and display
|
|
38
|
+
* - For HTML mode: HTML content string
|
|
39
|
+
* - For code modes: Source code string
|
|
40
|
+
*/
|
|
41
|
+
content?: string;
|
|
42
|
+
|
|
43
|
+
/** Additional render options */
|
|
44
|
+
options?: {
|
|
45
|
+
/** Whether to enable syntax highlighting for code */
|
|
46
|
+
syntaxHighlight?: boolean;
|
|
47
|
+
/** Theme for code highlighting */
|
|
48
|
+
theme?: string;
|
|
49
|
+
/** Whether to show line numbers */
|
|
50
|
+
showLineNumbers?: boolean;
|
|
51
|
+
/** Custom CSS classes */
|
|
52
|
+
className?: string;
|
|
53
|
+
/** Inline styles */
|
|
54
|
+
style?: Record<string, string>;
|
|
55
|
+
/** Whether content is trusted (for HTML rendering) */
|
|
56
|
+
trusted?: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Preview configuration - provides metadata for URL previews
|
|
61
|
+
* Used to show rich preview information before loading the actual URL content
|
|
62
|
+
*/
|
|
63
|
+
preview?: {
|
|
64
|
+
/** Whether to show URL preview */
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
/** Preview image URL */
|
|
67
|
+
image?: string;
|
|
68
|
+
/** Preview title */
|
|
69
|
+
title?: string;
|
|
70
|
+
/** Preview description */
|
|
71
|
+
description?: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Search result item interface - unified data structure
|
|
77
|
+
* Compatible with SearchItem in app/core/src/views/box/search-box.ts
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const searchItem: ISearchItem = {
|
|
82
|
+
* name: "Example Result",
|
|
83
|
+
* desc: "This is an example search result",
|
|
84
|
+
* icon: { type: 'remix', value: 'search', init: async () => {} },
|
|
85
|
+
* push: false,
|
|
86
|
+
* names: ["Example Result"],
|
|
87
|
+
* keyWords: ["example", "result"],
|
|
88
|
+
* pluginType: "feature",
|
|
89
|
+
* type: "plugin",
|
|
90
|
+
* value: "example-plugin",
|
|
91
|
+
* render: {
|
|
92
|
+
* mode: RenderMode.STANDARD
|
|
93
|
+
* }
|
|
94
|
+
* };
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export interface ISearchItem {
|
|
98
|
+
/** Display name of the search result */
|
|
99
|
+
name: string;
|
|
100
|
+
|
|
101
|
+
/** Description or subtitle of the search result */
|
|
102
|
+
desc: string;
|
|
103
|
+
|
|
104
|
+
/** Icon configuration for visual representation */
|
|
105
|
+
icon: IPluginIcon;
|
|
106
|
+
|
|
107
|
+
/** Whether this item supports push mode functionality */
|
|
108
|
+
push: boolean;
|
|
109
|
+
|
|
110
|
+
/** List of feature commands associated with this item */
|
|
111
|
+
commands?: IFeatureCommand[];
|
|
112
|
+
|
|
113
|
+
/** Array of searchable names for this item */
|
|
114
|
+
names: string[];
|
|
115
|
+
|
|
116
|
+
/** Array of keywords for search matching */
|
|
117
|
+
keyWords: string[];
|
|
118
|
+
|
|
119
|
+
/** Type of plugin this item belongs to */
|
|
120
|
+
pluginType: string;
|
|
121
|
+
|
|
122
|
+
/** General type classification of the item */
|
|
123
|
+
type: string;
|
|
124
|
+
|
|
125
|
+
/** Associated value, typically the plugin name */
|
|
126
|
+
value: string;
|
|
127
|
+
|
|
128
|
+
/** Usage frequency counter for ranking */
|
|
129
|
+
amo?: number;
|
|
130
|
+
|
|
131
|
+
/** Matching information from search algorithms */
|
|
132
|
+
matched?: any;
|
|
133
|
+
|
|
134
|
+
/** Whether this item was matched by name */
|
|
135
|
+
matchedByName?: boolean;
|
|
136
|
+
|
|
137
|
+
/** Whether this item was matched by description */
|
|
138
|
+
descMatched?: boolean;
|
|
139
|
+
|
|
140
|
+
/** Whether this item was matched by abbreviation */
|
|
141
|
+
abridgeMatched?: boolean;
|
|
142
|
+
|
|
143
|
+
/** Unique identifier for this search item */
|
|
144
|
+
id?: string;
|
|
145
|
+
|
|
146
|
+
/** Action to execute when this item is selected */
|
|
147
|
+
action?: string;
|
|
148
|
+
|
|
149
|
+
/** Reference to original feature object for command matching */
|
|
150
|
+
originFeature?: ISearchItem;
|
|
151
|
+
|
|
152
|
+
/** Render configuration for custom display */
|
|
153
|
+
render?: IRenderConfig;
|
|
154
|
+
|
|
155
|
+
/** Additional properties for extensibility */
|
|
156
|
+
[key: string]: any;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Search mode enumeration
|
|
161
|
+
* Defines different modes of operation for the search box
|
|
162
|
+
*/
|
|
163
|
+
export enum BoxMode {
|
|
164
|
+
/** Standard input mode for text search */
|
|
165
|
+
INPUT = 0,
|
|
166
|
+
/** Command mode for executing specific commands */
|
|
167
|
+
COMMAND = 1,
|
|
168
|
+
/** Image mode for image-based search */
|
|
169
|
+
IMAGE = 2,
|
|
170
|
+
/** File mode for file-based operations */
|
|
171
|
+
FILE = 3,
|
|
172
|
+
/** Feature mode for plugin feature activation */
|
|
173
|
+
FEATURE = 4
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Search options configuration
|
|
178
|
+
* Configures how search operations should be performed
|
|
179
|
+
*/
|
|
180
|
+
export interface ISearchOptions {
|
|
181
|
+
/** The search mode to use */
|
|
182
|
+
mode: BoxMode;
|
|
183
|
+
|
|
184
|
+
/** Maximum number of results to return */
|
|
185
|
+
maxResults?: number;
|
|
186
|
+
|
|
187
|
+
/** Whether to enable fuzzy matching algorithms */
|
|
188
|
+
fuzzyMatch?: boolean;
|
|
189
|
+
|
|
190
|
+
/** Search timeout in milliseconds */
|
|
191
|
+
timeout?: number;
|
|
192
|
+
|
|
193
|
+
/** Whether to include cached results */
|
|
194
|
+
includeCached?: boolean;
|
|
195
|
+
|
|
196
|
+
/** Minimum confidence score for results */
|
|
197
|
+
minConfidence?: number;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Plugin search result push interface
|
|
202
|
+
* Used when plugins push search results to the core box
|
|
203
|
+
*/
|
|
204
|
+
export interface IPluginSearchResult {
|
|
205
|
+
/** Name of the plugin pushing the results */
|
|
206
|
+
pluginName: string;
|
|
207
|
+
|
|
208
|
+
/** Array of search result items */
|
|
209
|
+
items: ISearchItem[];
|
|
210
|
+
|
|
211
|
+
/** Timestamp when results were generated */
|
|
212
|
+
timestamp: number;
|
|
213
|
+
|
|
214
|
+
/** Original query that generated these results */
|
|
215
|
+
query: string;
|
|
216
|
+
|
|
217
|
+
/** Total number of results available */
|
|
218
|
+
total: number;
|
|
219
|
+
|
|
220
|
+
/** Whether more results are available */
|
|
221
|
+
hasMore?: boolean;
|
|
222
|
+
|
|
223
|
+
/** Metadata about the search operation */
|
|
224
|
+
metadata?: {
|
|
225
|
+
/** Time taken to generate results in milliseconds */
|
|
226
|
+
processingTime?: number;
|
|
227
|
+
/** Source of the results */
|
|
228
|
+
source?: string;
|
|
229
|
+
/** Confidence score of the overall result set */
|
|
230
|
+
confidence?: number;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Search result manager interface
|
|
236
|
+
* Manages search results within the core box
|
|
237
|
+
*/
|
|
238
|
+
export interface ISearchResultManager {
|
|
239
|
+
/** Push new search results to the manager */
|
|
240
|
+
pushItems(items: ISearchItem[]): void;
|
|
241
|
+
|
|
242
|
+
/** Clear all current search results */
|
|
243
|
+
clearItems(): void;
|
|
244
|
+
|
|
245
|
+
/** Get all current search results */
|
|
246
|
+
getItems(): ISearchItem[];
|
|
247
|
+
|
|
248
|
+
/** Update a specific search result item */
|
|
249
|
+
updateItem(id: string, item: Partial<ISearchItem>): boolean;
|
|
250
|
+
|
|
251
|
+
/** Remove a specific search result item */
|
|
252
|
+
removeItem(id: string): boolean;
|
|
253
|
+
|
|
254
|
+
/** Get the total count of search results */
|
|
255
|
+
getCount(): number;
|
|
256
|
+
|
|
257
|
+
/** Filter results based on criteria */
|
|
258
|
+
filterItems(predicate: (item: ISearchItem) => boolean): ISearchItem[];
|
|
259
|
+
|
|
260
|
+
/** Sort results using a comparison function */
|
|
261
|
+
sortItems(compareFn: (a: ISearchItem, b: ISearchItem) => number): void;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Generic data item interface
|
|
266
|
+
* Extended search item for various types of data processing results
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const dataItem: IDataItem = {
|
|
271
|
+
* name: "Translation Result",
|
|
272
|
+
* desc: "English to Chinese translation",
|
|
273
|
+
* // ... other ISearchItem properties
|
|
274
|
+
* source: "google-translate",
|
|
275
|
+
* dataType: "translation",
|
|
276
|
+
* originalData: "Hello World",
|
|
277
|
+
* processedData: "你好世界",
|
|
278
|
+
* confidence: 95
|
|
279
|
+
* };
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
export interface IDataItem extends ISearchItem {
|
|
283
|
+
/** Source service or system that generated this data */
|
|
284
|
+
source?: string;
|
|
285
|
+
|
|
286
|
+
/** Type of data processing performed */
|
|
287
|
+
dataType?: string;
|
|
288
|
+
|
|
289
|
+
/** Original input data before processing */
|
|
290
|
+
originalData?: any;
|
|
291
|
+
|
|
292
|
+
/** Processed output data */
|
|
293
|
+
processedData?: any;
|
|
294
|
+
|
|
295
|
+
/** Quality score of the processing result (0-100) */
|
|
296
|
+
quality?: number;
|
|
297
|
+
|
|
298
|
+
/** Whether this result was retrieved from cache */
|
|
299
|
+
cached?: boolean;
|
|
300
|
+
|
|
301
|
+
/** Processing time in milliseconds */
|
|
302
|
+
duration?: number;
|
|
303
|
+
|
|
304
|
+
/** Confidence level of the result (0-100) */
|
|
305
|
+
confidence?: number;
|
|
306
|
+
|
|
307
|
+
/** Additional metadata about the processing */
|
|
308
|
+
metadata?: Record<string, any>;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Application item interface
|
|
313
|
+
* Represents an application in search results
|
|
314
|
+
*/
|
|
315
|
+
export interface IAppItem extends ISearchItem {
|
|
316
|
+
/** File system path to the application */
|
|
317
|
+
path?: string;
|
|
318
|
+
|
|
319
|
+
/** Version string of the application */
|
|
320
|
+
version?: string;
|
|
321
|
+
|
|
322
|
+
/** File size in bytes */
|
|
323
|
+
size?: number;
|
|
324
|
+
|
|
325
|
+
/** Timestamp of last usage */
|
|
326
|
+
lastUsed?: number;
|
|
327
|
+
|
|
328
|
+
/** Application category */
|
|
329
|
+
category?: string;
|
|
330
|
+
|
|
331
|
+
/** Whether the application is currently running */
|
|
332
|
+
isRunning?: boolean;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* File item interface
|
|
337
|
+
* Represents a file in search results
|
|
338
|
+
*/
|
|
339
|
+
export interface IFileItem extends ISearchItem {
|
|
340
|
+
/** Full file system path */
|
|
341
|
+
filePath: string;
|
|
342
|
+
|
|
343
|
+
/** File size in bytes */
|
|
344
|
+
fileSize?: number;
|
|
345
|
+
|
|
346
|
+
/** MIME type of the file */
|
|
347
|
+
fileType?: string;
|
|
348
|
+
|
|
349
|
+
/** File extension */
|
|
350
|
+
extension?: string;
|
|
351
|
+
|
|
352
|
+
/** Last modified timestamp */
|
|
353
|
+
modifiedTime?: number;
|
|
354
|
+
|
|
355
|
+
/** Creation timestamp */
|
|
356
|
+
createdTime?: number;
|
|
357
|
+
|
|
358
|
+
/** Whether the file is currently accessible */
|
|
359
|
+
accessible?: boolean;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Feature item interface
|
|
364
|
+
* Represents a plugin feature in search results
|
|
365
|
+
*/
|
|
366
|
+
export interface IFeatureItem extends ISearchItem {
|
|
367
|
+
/** Unique identifier for the feature */
|
|
368
|
+
featureId: string;
|
|
369
|
+
|
|
370
|
+
/** Name of the plugin that owns this feature */
|
|
371
|
+
pluginName: string;
|
|
372
|
+
|
|
373
|
+
/** Detailed description of the feature */
|
|
374
|
+
featureDesc?: string;
|
|
375
|
+
|
|
376
|
+
/** Parameters required by the feature */
|
|
377
|
+
parameters?: Record<string, any>;
|
|
378
|
+
|
|
379
|
+
/** Whether the feature is currently enabled */
|
|
380
|
+
enabled?: boolean;
|
|
381
|
+
|
|
382
|
+
/** Feature category or group */
|
|
383
|
+
category?: string;
|
|
384
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { net } from 'electron'
|
|
2
|
+
import fse from 'fs-extra'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
interface DownloadItem {
|
|
6
|
+
url: string;
|
|
7
|
+
filename: string;
|
|
8
|
+
apply?: (filePath: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class DownloadManager {
|
|
12
|
+
private basePath: string;
|
|
13
|
+
private downloadQueue: DownloadItem[] = [];
|
|
14
|
+
private isDownloading = false;
|
|
15
|
+
|
|
16
|
+
constructor(basePath: string = '') {
|
|
17
|
+
this.basePath = basePath;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Add a download item to the queue
|
|
22
|
+
* @param item The download item object
|
|
23
|
+
*/
|
|
24
|
+
addDownload(item: DownloadItem): void {
|
|
25
|
+
this.downloadQueue.push(item);
|
|
26
|
+
if (!this.isDownloading) {
|
|
27
|
+
this.processQueue();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Add multiple download items to the queue
|
|
33
|
+
* @param items Array of download items
|
|
34
|
+
*/
|
|
35
|
+
addDownloads(items: DownloadItem[]): void {
|
|
36
|
+
this.downloadQueue.push(...items);
|
|
37
|
+
if (!this.isDownloading) {
|
|
38
|
+
this.processQueue();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Process the download queue
|
|
44
|
+
*/
|
|
45
|
+
private async processQueue(): Promise<void> {
|
|
46
|
+
if (this.downloadQueue.length === 0) {
|
|
47
|
+
this.isDownloading = false;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.isDownloading = true;
|
|
52
|
+
const item = this.downloadQueue.shift()!;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
console.log(`[DownloadManager] Starting to download ${item.filename} from ${item.url}`);
|
|
56
|
+
const filePath = await this.downloadFile(item.url, item.filename);
|
|
57
|
+
console.log(`[DownloadManager] Download ${item.filename} completed`);
|
|
58
|
+
|
|
59
|
+
if (item.apply) {
|
|
60
|
+
item.apply(filePath);
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`[DownloadManager] Download ${item.filename} failed:`, error);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.processQueue();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Download a single file
|
|
71
|
+
* @param url The download URL
|
|
72
|
+
* @param filename The filename to save as
|
|
73
|
+
* @returns The file path where the file is saved
|
|
74
|
+
*/
|
|
75
|
+
private downloadFile(url: string, filename: string): Promise<string> {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const request = net.request(url);
|
|
78
|
+
const filePath = this.basePath ? path.join(this.basePath, filename) : filename;
|
|
79
|
+
|
|
80
|
+
console.log(`[DownloadManager] File download request sent for ${filename}.`);
|
|
81
|
+
|
|
82
|
+
request.addListener('error', (error) => {
|
|
83
|
+
console.error(`[DownloadManager] Download request error for ${filename}:`, error);
|
|
84
|
+
reject(error);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
request.addListener('response', (response) => {
|
|
88
|
+
fse.createFileSync(filePath);
|
|
89
|
+
|
|
90
|
+
response.addListener('data', (chunk: any) => {
|
|
91
|
+
console.log(`[DownloadManager] Downloading ${filename}...`);
|
|
92
|
+
fse.appendFile(filePath, chunk, 'utf8');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
response.addListener('end', () => {
|
|
96
|
+
console.log(`[DownloadManager] Download ${filename} finished.`);
|
|
97
|
+
resolve(filePath);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
request.end();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Clear the download queue
|
|
107
|
+
*/
|
|
108
|
+
clearQueue(): void {
|
|
109
|
+
this.downloadQueue = [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get the number of items in the download queue
|
|
114
|
+
*/
|
|
115
|
+
getQueueLength(): number {
|
|
116
|
+
return this.downloadQueue.length;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import { exec, ExecException } from 'child_process';
|
|
2
|
-
|
|
3
|
-
export interface IGlobalPkgResult {
|
|
4
|
-
exist: boolean
|
|
5
|
-
error?: ExecException
|
|
6
|
-
name?: string
|
|
7
|
-
version?: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function checkGlobalPackageExist(packageName: string): Promise<IGlobalPkgResult> {
|
|
11
|
-
return new Promise((resolve, reject) => {
|
|
12
|
-
exec(`npm list -g ${packageName}`, (error, stdout, stderr) => {
|
|
13
|
-
if (error) {
|
|
14
|
-
reject({
|
|
15
|
-
exits: false,
|
|
16
|
-
error: error
|
|
17
|
-
});
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
if (stderr) {
|
|
21
|
-
reject({
|
|
22
|
-
exits: false,
|
|
23
|
-
error: stderr
|
|
24
|
-
});
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const lines = stdout.split('\n');
|
|
29
|
-
const lastLine = lines[lines.length -
|
|
30
|
-
const match = lastLine.match(/(\S+)@(\S+)/);
|
|
31
|
-
if (match) {
|
|
32
|
-
resolve({
|
|
33
|
-
exist: true,
|
|
34
|
-
name: match[1],
|
|
35
|
-
version: match[2]
|
|
36
|
-
} as IGlobalPkgResult);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
resolve({
|
|
41
|
-
exist: false
|
|
42
|
-
} as IGlobalPkgResult)
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Check npm version
|
|
49
|
-
export function getNpmVersion(): Promise<string | null> {
|
|
50
|
-
return new Promise((resolve) => {
|
|
51
|
-
exec(`npm --version`, (error, stdout, stderr) => {
|
|
52
|
-
if (error || stderr) resolve(null)
|
|
53
|
-
|
|
54
|
-
resolve(stdout.trim())
|
|
55
|
-
})
|
|
56
|
-
})
|
|
1
|
+
import { exec, ExecException } from 'child_process';
|
|
2
|
+
|
|
3
|
+
export interface IGlobalPkgResult {
|
|
4
|
+
exist: boolean
|
|
5
|
+
error?: ExecException
|
|
6
|
+
name?: string
|
|
7
|
+
version?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function checkGlobalPackageExist(packageName: string): Promise<IGlobalPkgResult> {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
exec(`npm list -g ${packageName}`, (error, stdout, stderr) => {
|
|
13
|
+
if (error) {
|
|
14
|
+
reject({
|
|
15
|
+
exits: false,
|
|
16
|
+
error: error
|
|
17
|
+
});
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (stderr) {
|
|
21
|
+
reject({
|
|
22
|
+
exits: false,
|
|
23
|
+
error: stderr
|
|
24
|
+
});
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const lines = stdout.split('\n');
|
|
29
|
+
const lastLine = lines[lines.length - 3];
|
|
30
|
+
const match = lastLine.match(/(\S+)@(\S+)/);
|
|
31
|
+
if (match) {
|
|
32
|
+
resolve({
|
|
33
|
+
exist: true,
|
|
34
|
+
name: match[1],
|
|
35
|
+
version: match[2]
|
|
36
|
+
} as IGlobalPkgResult);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
resolve({
|
|
41
|
+
exist: false
|
|
42
|
+
} as IGlobalPkgResult)
|
|
43
|
+
|
|
44
|
+
});
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check npm version
|
|
49
|
+
export function getNpmVersion(): Promise<string | null> {
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
exec(`npm --version`, (error, stdout, stderr) => {
|
|
52
|
+
if (error || stderr) resolve(null)
|
|
53
|
+
|
|
54
|
+
resolve(stdout.trim())
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
57
|
}
|