@talex-touch/utils 1.0.18 → 1.0.20
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/channel/index.ts +49 -1
- package/common/index.ts +2 -0
- package/common/search/gather.ts +45 -0
- package/common/search/index.ts +67 -0
- package/common/storage/constants.ts +16 -2
- package/common/storage/entity/index.ts +2 -1
- package/common/storage/entity/openers.ts +32 -0
- package/common/storage/entity/shortcut-settings.ts +22 -0
- package/common/storage/shortcut-storage.ts +58 -0
- package/common/utils/file.ts +62 -0
- package/common/{utils.ts → utils/index.ts} +14 -2
- package/common/utils/polling.ts +184 -0
- package/common/utils/task-queue.ts +108 -0
- package/common/utils/time.ts +374 -0
- package/core-box/README.md +8 -8
- package/core-box/builder/index.ts +6 -0
- package/core-box/builder/tuff-builder.example.ts.bak +258 -0
- package/core-box/builder/tuff-builder.ts +1162 -0
- package/core-box/index.ts +5 -2
- package/core-box/run-tests.sh +7 -0
- package/core-box/search.ts +1 -536
- package/core-box/tuff/index.ts +6 -0
- package/core-box/tuff/tuff-dsl.ts +1412 -0
- package/electron/clipboard-helper.ts +199 -0
- package/electron/env-tool.ts +36 -2
- package/electron/file-parsers/index.ts +8 -0
- package/electron/file-parsers/parsers/text-parser.ts +109 -0
- package/electron/file-parsers/registry.ts +92 -0
- package/electron/file-parsers/types.ts +58 -0
- package/electron/index.ts +3 -0
- package/eventbus/index.ts +0 -7
- package/index.ts +3 -1
- package/package.json +4 -29
- package/plugin/channel.ts +48 -16
- package/plugin/index.ts +194 -30
- package/plugin/log/types.ts +11 -0
- package/plugin/node/index.ts +4 -0
- package/plugin/node/logger-manager.ts +113 -0
- package/plugin/{log → node}/logger.ts +41 -7
- package/plugin/plugin-source.ts +74 -0
- package/plugin/preload.ts +5 -15
- package/plugin/providers/index.ts +2 -0
- package/plugin/providers/registry.ts +47 -0
- package/plugin/providers/types.ts +54 -0
- package/plugin/risk/index.ts +1 -0
- package/plugin/risk/types.ts +20 -0
- package/plugin/sdk/enum/bridge-event.ts +4 -0
- package/plugin/sdk/enum/index.ts +1 -0
- package/plugin/sdk/hooks/bridge.ts +68 -0
- package/plugin/sdk/hooks/index.ts +2 -1
- package/plugin/sdk/hooks/life-cycle.ts +2 -4
- package/plugin/sdk/index.ts +2 -0
- package/plugin/sdk/storage.ts +84 -0
- package/plugin/sdk/types.ts +2 -2
- package/plugin/sdk/window/index.ts +5 -3
- package/preload/index.ts +2 -0
- package/preload/loading.ts +15 -0
- package/preload/renderer.ts +41 -0
- package/renderer/hooks/arg-mapper.ts +79 -0
- package/renderer/hooks/index.ts +2 -0
- package/renderer/hooks/initialize.ts +198 -0
- package/renderer/index.ts +3 -0
- package/renderer/storage/app-settings.ts +2 -0
- package/renderer/storage/base-storage.ts +1 -0
- package/renderer/storage/openers.ts +11 -0
- package/renderer/touch-sdk/env.ts +106 -0
- package/renderer/touch-sdk/index.ts +108 -0
- package/renderer/touch-sdk/terminal.ts +85 -0
- package/renderer/touch-sdk/utils.ts +61 -0
- package/search/levenshtein-utils.ts +39 -0
- package/search/types.ts +16 -16
- package/types/index.ts +2 -1
- package/types/modules/base.ts +146 -0
- package/types/modules/index.ts +4 -0
- package/types/modules/module-lifecycle.ts +148 -0
- package/types/modules/module-manager.ts +99 -0
- package/types/modules/module.ts +112 -0
- package/types/touch-app-core.ts +16 -93
- package/core-box/types.ts +0 -384
- package/plugin/log/logger-manager.ts +0 -60
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { clipboard } from 'electron'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a file object from the clipboard
|
|
5
|
+
*/
|
|
6
|
+
interface ClipboardFileInfo {
|
|
7
|
+
/** File data as a buffer */
|
|
8
|
+
buffer: Buffer
|
|
9
|
+
/** MIME type of the file */
|
|
10
|
+
mimetype: string
|
|
11
|
+
/** Original filename */
|
|
12
|
+
originalname: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Possible return types from clipboard file operations
|
|
17
|
+
*/
|
|
18
|
+
export type ClipboardFileResult = string | ClipboardFileInfo
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Utility class for handling clipboard file operations across different platforms
|
|
22
|
+
*/
|
|
23
|
+
export class ClipboardHelper {
|
|
24
|
+
/**
|
|
25
|
+
* Check if the current platform is macOS
|
|
26
|
+
* @private
|
|
27
|
+
*/
|
|
28
|
+
private get isMac(): boolean {
|
|
29
|
+
return process.platform === 'darwin'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a unique identifier with specified length and radix
|
|
34
|
+
* @param length - Length of the generated string
|
|
35
|
+
* @param radix - Radix for number conversion (default: 16)
|
|
36
|
+
* @returns Generated unique identifier
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
private generateUuid(length: number, radix: number = 16): string {
|
|
40
|
+
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
|
|
41
|
+
const uuid: string[] = []
|
|
42
|
+
let i: number
|
|
43
|
+
|
|
44
|
+
radix = radix || chars.length
|
|
45
|
+
|
|
46
|
+
if (length) {
|
|
47
|
+
for (i = 0; i < length; i++) {
|
|
48
|
+
uuid[i] = chars[0 | (Math.random() * radix)]
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
let r: number
|
|
52
|
+
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
|
|
53
|
+
uuid[14] = '4'
|
|
54
|
+
|
|
55
|
+
for (i = 0; i < 36; i++) {
|
|
56
|
+
if (!uuid[i]) {
|
|
57
|
+
r = 0 | (Math.random() * 16)
|
|
58
|
+
uuid[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return uuid.join('')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Process clipboard files on macOS platform
|
|
68
|
+
* @returns Array of file paths or file info objects
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
private getClipboardFilesMac(): ClipboardFileResult[] {
|
|
72
|
+
let filePath: ClipboardFileResult[] = []
|
|
73
|
+
|
|
74
|
+
if (clipboard.has('NSFilenamesPboardType')) {
|
|
75
|
+
// Handle multiple files
|
|
76
|
+
const tagContent = clipboard.read('NSFilenamesPboardType').match(/<string>.*<\/string>/g)
|
|
77
|
+
filePath = tagContent ? tagContent.map(item => item.replace(/<string>|<\/string>/g, '')) : []
|
|
78
|
+
} else {
|
|
79
|
+
// Handle single file
|
|
80
|
+
const clipboardImage = clipboard.readImage('clipboard')
|
|
81
|
+
if (!clipboardImage.isEmpty()) {
|
|
82
|
+
// Handle image from clipboard
|
|
83
|
+
const png = clipboardImage.toPNG()
|
|
84
|
+
const fileInfo: ClipboardFileInfo = {
|
|
85
|
+
buffer: png,
|
|
86
|
+
mimetype: 'image/png',
|
|
87
|
+
originalname: this.generateUuid(8, 16) + '.png'
|
|
88
|
+
}
|
|
89
|
+
filePath = [fileInfo]
|
|
90
|
+
} else {
|
|
91
|
+
// Handle single file path
|
|
92
|
+
const fileUrl = clipboard.read('public.file-url')
|
|
93
|
+
if (fileUrl) {
|
|
94
|
+
filePath = [fileUrl.replace('file://', '')].filter(item => item)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return filePath
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Process clipboard files on Windows platform
|
|
104
|
+
* @returns Array of file paths or file info objects
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
private getClipboardFilesWindows(): ClipboardFileResult[] {
|
|
108
|
+
let filePath: ClipboardFileResult[] = []
|
|
109
|
+
|
|
110
|
+
if (clipboard.has('CF_HDROP')) {
|
|
111
|
+
// Handle multiple files
|
|
112
|
+
const rawFilePathStr = clipboard.readBuffer('CF_HDROP').toString('ucs2') || ''
|
|
113
|
+
let formatFilePathStr = [...rawFilePathStr]
|
|
114
|
+
.filter((_, index) => rawFilePathStr.charCodeAt(index) !== 0)
|
|
115
|
+
.join('')
|
|
116
|
+
.replace(/\\/g, '\\\\')
|
|
117
|
+
|
|
118
|
+
const drivePrefix = formatFilePathStr.match(/[a-zA-Z]:\\/)
|
|
119
|
+
|
|
120
|
+
if (drivePrefix) {
|
|
121
|
+
const drivePrefixIndex = formatFilePathStr.indexOf(drivePrefix[0])
|
|
122
|
+
if (drivePrefixIndex !== 0) {
|
|
123
|
+
formatFilePathStr = formatFilePathStr.substring(drivePrefixIndex)
|
|
124
|
+
}
|
|
125
|
+
filePath = formatFilePathStr
|
|
126
|
+
.split(drivePrefix[0])
|
|
127
|
+
.filter(item => item)
|
|
128
|
+
.map(item => drivePrefix[0] + item)
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// Handle single file
|
|
132
|
+
const clipboardImage = clipboard.readImage('clipboard')
|
|
133
|
+
if (!clipboardImage.isEmpty()) {
|
|
134
|
+
// Handle image from clipboard
|
|
135
|
+
const png = clipboardImage.toPNG()
|
|
136
|
+
const fileInfo: ClipboardFileInfo = {
|
|
137
|
+
buffer: png,
|
|
138
|
+
mimetype: 'image/png',
|
|
139
|
+
originalname: this.generateUuid(8, 16) + '.png'
|
|
140
|
+
}
|
|
141
|
+
filePath = [fileInfo]
|
|
142
|
+
} else {
|
|
143
|
+
// Handle single file path
|
|
144
|
+
try {
|
|
145
|
+
const fileName = clipboard.readBuffer('FileNameW').toString('ucs2').replace(RegExp(String.fromCharCode(0), 'g'), '')
|
|
146
|
+
if (fileName) {
|
|
147
|
+
filePath = [fileName]
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// Ignore read errors for non-file clipboard content
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return filePath
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Retrieves file paths or file information from the system clipboard
|
|
160
|
+
*
|
|
161
|
+
* This method handles both file paths and images from the clipboard across different platforms.
|
|
162
|
+
* On macOS, it uses NSFilenamesPboardType for multiple files and public.file-url for single files.
|
|
163
|
+
* On Windows, it uses CF_HDROP for multiple files and FileNameW for single files.
|
|
164
|
+
*
|
|
165
|
+
* @returns Array of file paths (strings) or file info objects containing buffer data for images
|
|
166
|
+
* @throws {Error} When clipboard access fails or platform is unsupported
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const clipboardHelper = new ClipboardHelper()
|
|
171
|
+
* const files = clipboardHelper.getClipboardFiles()
|
|
172
|
+
*
|
|
173
|
+
* files.forEach(file => {
|
|
174
|
+
* if (typeof file === 'string') {
|
|
175
|
+
* console.log('File path:', file)
|
|
176
|
+
* } else {
|
|
177
|
+
* console.log('Image file:', file.originalname, 'Size:', file.buffer.length)
|
|
178
|
+
* }
|
|
179
|
+
* })
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
public getClipboardFiles(): ClipboardFileResult[] {
|
|
183
|
+
try {
|
|
184
|
+
if (this.isMac) {
|
|
185
|
+
return this.getClipboardFilesMac()
|
|
186
|
+
} else {
|
|
187
|
+
return this.getClipboardFilesWindows()
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error('Failed to read clipboard files:', error)
|
|
191
|
+
return []
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Default export of ClipboardHelper class for convenience
|
|
198
|
+
*/
|
|
199
|
+
export default ClipboardHelper
|
package/electron/env-tool.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { exec, ExecException } from 'child_process'
|
|
1
|
+
import { exec, ExecException } from 'child_process'
|
|
2
|
+
import { platform } from 'process'
|
|
2
3
|
|
|
3
4
|
export interface IGlobalPkgResult {
|
|
4
5
|
exist: boolean
|
|
@@ -54,4 +55,37 @@ export function getNpmVersion(): Promise<string | null> {
|
|
|
54
55
|
resolve(stdout.trim())
|
|
55
56
|
})
|
|
56
57
|
})
|
|
57
|
-
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface OSAdapter<R, T> {
|
|
61
|
+
win32?: (payload: R) => T
|
|
62
|
+
darwin?: (payload: R) => T
|
|
63
|
+
linux?: (payload: R) => T
|
|
64
|
+
/**
|
|
65
|
+
* Executed before platform-specific functions.
|
|
66
|
+
* Its return value will be passed as a parameter to the platform-specific function.
|
|
67
|
+
*/
|
|
68
|
+
onBeforeExecute?: () => R
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* An adapter function that executes different logic depending on the operating system platform.
|
|
73
|
+
* @param options An object containing implementations for different platforms.
|
|
74
|
+
* @returns The execution result of the platform-specific function.
|
|
75
|
+
*/
|
|
76
|
+
export function withOSAdapter<R, T>(options: OSAdapter<R, T>): T | undefined {
|
|
77
|
+
const payload = options.onBeforeExecute?.()
|
|
78
|
+
|
|
79
|
+
const arg = payload as R
|
|
80
|
+
|
|
81
|
+
switch (platform) {
|
|
82
|
+
case 'win32':
|
|
83
|
+
return options.win32?.(arg)
|
|
84
|
+
case 'darwin':
|
|
85
|
+
return options.darwin?.(arg)
|
|
86
|
+
case 'linux':
|
|
87
|
+
return options.linux?.(arg)
|
|
88
|
+
default:
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import fs from 'fs/promises'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import {
|
|
4
|
+
FileParser,
|
|
5
|
+
FileParserContext,
|
|
6
|
+
FileParserProgress,
|
|
7
|
+
FileParserResult
|
|
8
|
+
} from '../types'
|
|
9
|
+
|
|
10
|
+
const TEXTUAL_EXTENSIONS = new Set(
|
|
11
|
+
[
|
|
12
|
+
'.txt',
|
|
13
|
+
'.md',
|
|
14
|
+
'.rtf',
|
|
15
|
+
'.json',
|
|
16
|
+
'.yaml',
|
|
17
|
+
'.yml',
|
|
18
|
+
'.xml',
|
|
19
|
+
'.csv',
|
|
20
|
+
'.log',
|
|
21
|
+
'.ini',
|
|
22
|
+
'.conf',
|
|
23
|
+
'.env',
|
|
24
|
+
'.html',
|
|
25
|
+
'.htm',
|
|
26
|
+
'.js',
|
|
27
|
+
'.ts',
|
|
28
|
+
'.tsx',
|
|
29
|
+
'.jsx',
|
|
30
|
+
'.py',
|
|
31
|
+
'.go',
|
|
32
|
+
'.rs',
|
|
33
|
+
'.java',
|
|
34
|
+
'.kt',
|
|
35
|
+
'.cs',
|
|
36
|
+
'.c',
|
|
37
|
+
'.cpp',
|
|
38
|
+
'.cc',
|
|
39
|
+
'.hpp',
|
|
40
|
+
'.m',
|
|
41
|
+
'.mm',
|
|
42
|
+
'.swift',
|
|
43
|
+
'.php',
|
|
44
|
+
'.rb',
|
|
45
|
+
'.sh',
|
|
46
|
+
'.bash',
|
|
47
|
+
'.zsh',
|
|
48
|
+
'.fish',
|
|
49
|
+
'.bat',
|
|
50
|
+
'.ps1',
|
|
51
|
+
'.sql'
|
|
52
|
+
].map((ext) => ext.toLowerCase())
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
export class TextFileParser implements FileParser {
|
|
56
|
+
readonly id = 'text-file-parser'
|
|
57
|
+
readonly priority = 100
|
|
58
|
+
readonly supportedExtensions = TEXTUAL_EXTENSIONS
|
|
59
|
+
|
|
60
|
+
async parse(
|
|
61
|
+
context: FileParserContext,
|
|
62
|
+
onProgress?: (progress: FileParserProgress) => void
|
|
63
|
+
): Promise<FileParserResult> {
|
|
64
|
+
const { filePath, extension, size, maxBytes } = context
|
|
65
|
+
if (maxBytes && size > maxBytes) {
|
|
66
|
+
return {
|
|
67
|
+
status: 'skipped',
|
|
68
|
+
reason: 'file-too-large',
|
|
69
|
+
totalBytes: size,
|
|
70
|
+
processedBytes: 0,
|
|
71
|
+
warnings: [
|
|
72
|
+
`File size ${(size / (1024 * 1024)).toFixed(2)}MB exceeds limit ${(maxBytes / (1024 * 1024)).toFixed(2)}MB`
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!TEXTUAL_EXTENSIONS.has(extension)) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'skipped',
|
|
80
|
+
reason: 'unsupported-extension'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const content = await fs.readFile(filePath, 'utf8')
|
|
86
|
+
if (onProgress) {
|
|
87
|
+
onProgress({ processedBytes: size, totalBytes: size, percentage: 1 })
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
status: 'success',
|
|
92
|
+
content,
|
|
93
|
+
metadata: {
|
|
94
|
+
length: content.length,
|
|
95
|
+
basename: path.basename(filePath)
|
|
96
|
+
},
|
|
97
|
+
processedBytes: size,
|
|
98
|
+
totalBytes: size
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
status: 'failed',
|
|
103
|
+
reason: error instanceof Error ? error.message : 'unknown-error'
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const textFileParser = new TextFileParser()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FileParser,
|
|
3
|
+
FileParserContext,
|
|
4
|
+
FileParserProgress,
|
|
5
|
+
FileParserResult,
|
|
6
|
+
FileParserSelectionOptions
|
|
7
|
+
} from './types'
|
|
8
|
+
|
|
9
|
+
interface RegisteredParser {
|
|
10
|
+
parser: FileParser
|
|
11
|
+
extensions: Set<string>
|
|
12
|
+
priority: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class FileParserRegistry {
|
|
16
|
+
private readonly parsers: RegisteredParser[] = []
|
|
17
|
+
|
|
18
|
+
register(parser: FileParser): void {
|
|
19
|
+
const extensions = new Set(
|
|
20
|
+
Array.from(parser.supportedExtensions).map((ext) => ext.trim().toLowerCase())
|
|
21
|
+
)
|
|
22
|
+
if (extensions.size === 0) {
|
|
23
|
+
throw new Error(`[FileParserRegistry] Parser ${parser.id} registered without extensions`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.parsers.push({ parser, extensions, priority: parser.priority ?? 0 })
|
|
27
|
+
this.parsers.sort((a, b) => b.priority - a.priority)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
unregister(parserId: string): void {
|
|
31
|
+
const index = this.parsers.findIndex(({ parser }) => parser.id === parserId)
|
|
32
|
+
if (index >= 0) {
|
|
33
|
+
this.parsers.splice(index, 1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getParsersForExtension(extension: string): FileParser[] {
|
|
38
|
+
if (!extension) return []
|
|
39
|
+
const normalized = extension.toLowerCase()
|
|
40
|
+
return this.parsers
|
|
41
|
+
.filter(({ extensions }) => extensions.has(normalized))
|
|
42
|
+
.map(({ parser }) => parser)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getPreferredParser(extension: string, options?: FileParserSelectionOptions): FileParser | null {
|
|
46
|
+
const [preferred] = this.getParsersForExtension(extension)
|
|
47
|
+
if (!preferred && options?.allowFallback) {
|
|
48
|
+
// Allow fallback to wildcard parsers if they exist in the registry
|
|
49
|
+
const wildcard = this.parsers.find(({ extensions }) => extensions.has('*'))
|
|
50
|
+
return wildcard?.parser ?? null
|
|
51
|
+
}
|
|
52
|
+
return preferred ?? null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async parseWithBestParser(
|
|
56
|
+
context: FileParserContext,
|
|
57
|
+
onProgress?: (progress: FileParserProgress) => void
|
|
58
|
+
): Promise<FileParserResult | null> {
|
|
59
|
+
const candidates = this.getParsersForExtension(context.extension)
|
|
60
|
+
const allParsers = context.extension !== '*' ? candidates : []
|
|
61
|
+
|
|
62
|
+
if (context.extension !== '*') {
|
|
63
|
+
const wildcard = this.getParsersForExtension('*')
|
|
64
|
+
allParsers.push(...wildcard)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const parser of allParsers) {
|
|
68
|
+
if (parser.canParse && !(await parser.canParse(context))) {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const result = await parser.parse(context, onProgress)
|
|
73
|
+
if (!result) {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
if (result.status !== 'skipped') {
|
|
77
|
+
return result
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(`[FileParserRegistry] Parser ${parser.id} failed:`, error)
|
|
81
|
+
return {
|
|
82
|
+
status: 'failed',
|
|
83
|
+
reason: error instanceof Error ? error.message : 'unknown-error'
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const fileParserRegistry = new FileParserRegistry()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type FileParserStatus = 'success' | 'skipped' | 'failed'
|
|
2
|
+
|
|
3
|
+
export interface FileParserContext {
|
|
4
|
+
filePath: string
|
|
5
|
+
extension: string
|
|
6
|
+
size: number
|
|
7
|
+
maxBytes?: number
|
|
8
|
+
metadata?: Record<string, any>
|
|
9
|
+
signal?: AbortSignal
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface FileParserProgress {
|
|
13
|
+
processedBytes?: number
|
|
14
|
+
totalBytes?: number
|
|
15
|
+
percentage?: number
|
|
16
|
+
message?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FileParserEmbedding {
|
|
20
|
+
provider: string
|
|
21
|
+
model: string
|
|
22
|
+
vector: number[]
|
|
23
|
+
metadata?: Record<string, any>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface FileParserResult {
|
|
27
|
+
status: FileParserStatus
|
|
28
|
+
content?: string
|
|
29
|
+
metadata?: Record<string, any>
|
|
30
|
+
tags?: string[]
|
|
31
|
+
warnings?: string[]
|
|
32
|
+
processedBytes?: number
|
|
33
|
+
totalBytes?: number
|
|
34
|
+
reason?: string
|
|
35
|
+
embeddings?: FileParserEmbedding[]
|
|
36
|
+
durationMs?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface FileParser {
|
|
40
|
+
readonly id: string
|
|
41
|
+
/** Higher priority parsers win when multiple support the same extension */
|
|
42
|
+
readonly priority?: number
|
|
43
|
+
readonly supportedExtensions: string[] | Set<string>
|
|
44
|
+
canParse?(context: FileParserContext): boolean | Promise<boolean>
|
|
45
|
+
parse(
|
|
46
|
+
context: FileParserContext,
|
|
47
|
+
onProgress?: (progress: FileParserProgress) => void
|
|
48
|
+
): Promise<FileParserResult>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface FileParserSelectionOptions {
|
|
52
|
+
allowFallback?: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FileParserRegistryOptions {
|
|
56
|
+
/** When true, registry falls back to lower priority parsers if the preferred one skips */
|
|
57
|
+
enableFallback?: boolean
|
|
58
|
+
}
|
package/eventbus/index.ts
CHANGED
|
@@ -70,13 +70,6 @@ export interface ITouchEventBus<E> {
|
|
|
70
70
|
*/
|
|
71
71
|
offAll(event: E): boolean;
|
|
72
72
|
|
|
73
|
-
/**
|
|
74
|
-
* UnSubscribe touch-app events all matched (any kind of events extends from TouchEvent)
|
|
75
|
-
* @param event EventName (extends from TouchEvent)
|
|
76
|
-
* @returns true if the event was added, otherwise false
|
|
77
|
-
*/
|
|
78
|
-
offAll(event: E): boolean;
|
|
79
|
-
|
|
80
73
|
/**
|
|
81
74
|
* Emit touch-app events (any kind of events extends from TouchEvent)
|
|
82
75
|
* @param event EventName (extends from TouchEvent)
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -5,53 +5,28 @@
|
|
|
5
5
|
"module": "./index.ts",
|
|
6
6
|
"license": "MPL-2.0",
|
|
7
7
|
"private": false,
|
|
8
|
-
"version": "1.0.
|
|
9
|
-
"exports": {
|
|
10
|
-
".": "./index.ts",
|
|
11
|
-
"./types": "./types/index.ts",
|
|
12
|
-
"./channel": "./channel/index.ts",
|
|
13
|
-
"./base": "./base/index.ts",
|
|
14
|
-
"./common": "./common/index.ts",
|
|
15
|
-
"./common/utils": "./common/utils.ts",
|
|
16
|
-
"./plugin": "./plugin/index.ts",
|
|
17
|
-
"./plugin/log/logger-manager": "./plugin/log/logger-manager.ts",
|
|
18
|
-
"./plugin/log/logger": "./plugin/log/logger.ts",
|
|
19
|
-
"./plugin/sdk": "./plugin/sdk.ts",
|
|
20
|
-
"./plugin/sdk/window": "./plugin/sdk/window.ts",
|
|
21
|
-
"./core-box": "./core-box/index.ts",
|
|
22
|
-
"./search/types": "./search/types.ts",
|
|
23
|
-
"./eventbus": "./eventbus/index.ts",
|
|
24
|
-
"./permission": "./permission/index.ts",
|
|
25
|
-
"./renderer": "./renderer/index.ts",
|
|
26
|
-
"./renderer/ref": "./renderer/ref.ts",
|
|
27
|
-
"./renderer/slots": "./renderer/slots.ts",
|
|
28
|
-
"./renderer/storage/app-settings": "./renderer/storage/app-settings.ts",
|
|
29
|
-
"./service": "./service/index.ts",
|
|
30
|
-
"./service/protocol": "./service/protocol/index.ts",
|
|
31
|
-
"./electron/env-tool": "./electron/env-tool.ts",
|
|
32
|
-
"./electron/download-manager": "./electron/download-manager.ts",
|
|
33
|
-
"./animation/": "./animation/"
|
|
34
|
-
},
|
|
8
|
+
"version": "1.0.20",
|
|
35
9
|
"scripts": {
|
|
36
10
|
"publish": "npm publish --access public"
|
|
37
11
|
},
|
|
38
12
|
"keywords": [
|
|
39
13
|
"vue",
|
|
40
14
|
"electron",
|
|
15
|
+
"launcher",
|
|
41
16
|
"talex-touch"
|
|
42
17
|
],
|
|
43
18
|
"repository": {
|
|
44
19
|
"url": "https://github.com/talex-touch/talex-touch.git",
|
|
45
20
|
"type": "git"
|
|
46
21
|
},
|
|
47
|
-
"description": "
|
|
22
|
+
"description": "Tuff series utils",
|
|
48
23
|
"dependencies": {
|
|
49
24
|
"@vueuse/core": "^13.6.0",
|
|
50
25
|
"path-browserify": "^1.0.1",
|
|
51
26
|
"vue": "^3.5.18"
|
|
52
27
|
},
|
|
53
28
|
"peerDependencies": {
|
|
54
|
-
"electron": "^
|
|
29
|
+
"electron": "^37.2.4",
|
|
55
30
|
"vue": "^3.5.15"
|
|
56
31
|
}
|
|
57
32
|
}
|