Skip to content

Commit fb040a3

Browse files
committed
feat(api): 增加现代异步API库支持并优化数据过滤与搜索功能
- 在README中添加现代异步API库使用示例和详细过滤器说明 - 提供纯函数工具以支持字符串、函数和对象形式的多样过滤 - 实现智能搜索功能,依据匹配度进行排序和优先级评分 - 优化API设计为异步优先,兼容Node.js和浏览器环境 - 统一数据获取策略,优先使用本地缓存,支持强制更新 - 规范错误处理,增加标准API错误码和统一错误创建函数
1 parent 06a8f95 commit fb040a3

File tree

2 files changed

+143
-59
lines changed

2 files changed

+143
-59
lines changed

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ An automated USB device ID database project that provides a CLI tool and data fi
1111
## 🚀 Features
1212

1313
- **CLI Tool**: Command-line interface for managing USB device data
14+
- **Modern API Library**: Async-first API with TypeScript support and pure function tools
1415
- **Auto Update**: Automatically checks and fetches the latest USB.IDS data every 24 hours
1516
- **Multi-format Support**: Provides both raw format and JSON format data files
1617
- **Web Interface**: Built-in web server for browsing and searching USB device data
1718
- **npm Distribution**: Distributes data files through npm package manager
1819
- **GitHub Pages**: Provides online viewing interface
1920
- **Version Management**: Smart version control based on content hash
2021
- **Data Statistics**: Provides vendor and device count statistics
22+
- **Environment Compatibility**: Works in both Node.js and browser environments
23+
- **Advanced Filtering**: Support for string, function, and object-based filtering
24+
- **Smart Search**: Intelligent search with relevance scoring and priority ranking
2125

2226
## 📦 Installation
2327

@@ -99,6 +103,86 @@ const versionInfo = JSON.parse(
99103
)
100104
```
101105

106+
### Using the API Library
107+
108+
The package provides a modern async API for accessing USB device data:
109+
110+
```javascript
111+
import {
112+
filterDevices,
113+
filterVendors,
114+
getDevice,
115+
getDevices,
116+
getUsbData,
117+
getVendor,
118+
getVendors,
119+
searchDevices,
120+
searchInData
121+
} from 'usb.ids'
122+
123+
// Get all vendors
124+
const allVendors = await getVendors()
125+
126+
// Get vendors with filter
127+
const appleVendors = await getVendors('Apple')
128+
const specificVendor = await getVendor('05ac')
129+
130+
// Get devices for a vendor
131+
const appleDevices = await getDevices('05ac')
132+
const filteredDevices = await getDevices('05ac', 'iPhone')
133+
134+
// Get a specific device
135+
const device = await getDevice('05ac', '12a8')
136+
137+
// Search devices across all vendors
138+
const searchResults = await searchDevices('iPhone')
139+
140+
// Get complete USB data
141+
const usbData = await getUsbData()
142+
143+
// Pure function tools for processing existing data
144+
const filteredVendors = filterVendors(usbData, 'Apple')
145+
const searchResults2 = searchInData(usbData, 'mouse')
146+
```
147+
148+
#### Filter Options
149+
150+
Filters can be strings, functions, or objects:
151+
152+
```javascript
153+
// String filter (searches in names and IDs)
154+
const vendors1 = await getVendors('Apple')
155+
156+
// Function filter
157+
const vendors2 = await getVendors(vendor => vendor.name.includes('Tech'))
158+
159+
// Object filter
160+
const vendors3 = await getVendors({
161+
id: '05ac',
162+
name: 'Apple',
163+
search: 'apple' // searches in both name and ID
164+
})
165+
166+
// Device filters work similarly
167+
const devices1 = await getDevices('05ac', 'iPhone')
168+
const devices2 = await getDevices('05ac', device => device.devname.includes('Pro'))
169+
const devices3 = await getDevices('05ac', {
170+
id: '12a8',
171+
name: 'iPhone',
172+
search: 'phone'
173+
})
174+
```
175+
176+
#### Force Update
177+
178+
All async functions accept an optional `forceUpdate` parameter:
179+
180+
```javascript
181+
// Force fetch fresh data from remote source
182+
const vendors = await getVendors(null, true)
183+
const device = await getDevice('05ac', '12a8', true)
184+
```
185+
102186
### Direct access to data files
103187

104188
The project provides the following data files:

src/api.ts

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
/**
2-
* USB 设备数据 API 模块
2+
* USB Device Data API Module
33
*
4-
* 数据获取策略:
5-
* 1. 优先使用本地 USB JSON 文件
6-
* 2. 如果本地文件不存在或过期,则从远程 URL 获取数据
7-
* 3. 获取后的数据会被缓存到本地,供下次使用
8-
* 4. 无论 Node.js 还是浏览器环境都遵循相同的策略
4+
* Data acquisition strategy:
5+
* 1. Prioritize local USB JSON files
6+
* 2. If local files don't exist or are expired, fetch data from remote URLs
7+
* 3. Downloaded data will be cached locally for future use
8+
* 4. The same strategy applies to both Node.js and browser environments
99
*
10-
* API 设计原则:
11-
* - 异步优先:所有数据获取操作都是异步的
12-
* - 纯函数工具:提供纯函数用于处理已有数据
13-
* - 环境兼容:在所有环境中保持一致的行为
10+
* API Design Principles:
11+
* - Async-first: All data acquisition operations are asynchronous
12+
* - Pure function tools: Provide pure functions for processing existing data
13+
* - Environment compatibility: Maintain consistent behavior across all environments
1414
*/
1515

1616
import type { UsbDevice, UsbIdsData, UsbVendor } from './types'
1717
import { USB_IDS_FILE, USB_IDS_SOURCE } from './config'
1818
import { fetchUsbIdsData } from './core'
1919

2020
// ===============================
21-
// 环境检测和工具函数
21+
// Environment Detection and Utility Functions
2222
// ===============================
2323

2424
/**
25-
* 可靠的环境检测
25+
* Reliable environment detection
2626
*/
2727
function isNodeEnvironment(): boolean {
2828
return typeof process !== 'undefined'
@@ -31,18 +31,18 @@ function isNodeEnvironment(): boolean {
3131
}
3232

3333
/**
34-
* 获取环境适配的根目录
34+
* Get environment-adapted root directory
3535
*/
3636
function getEnvironmentRoot(): string {
3737
return isNodeEnvironment() ? process.cwd() : '.'
3838
}
3939

4040
// ===============================
41-
// 错误处理
41+
// Error Handling
4242
// ===============================
4343

4444
/**
45-
* 创建标准化的 API 错误
45+
* Create standardized API error
4646
*/
4747
function createApiError(message: string, code: string, cause?: Error): Error {
4848
const error = new Error(message)
@@ -55,7 +55,7 @@ function createApiError(message: string, code: string, cause?: Error): Error {
5555
}
5656

5757
/**
58-
* 错误代码常量
58+
* Error code constants
5959
*/
6060
export const ERROR_CODES = {
6161
DATA_NOT_FOUND: 'DATA_NOT_FOUND',
@@ -64,7 +64,7 @@ export const ERROR_CODES = {
6464
} as const
6565

6666
// ===============================
67-
// 过滤器类型定义
67+
// Filter Type Definitions
6868
// ===============================
6969

7070
export type VendorFilter =
@@ -86,40 +86,40 @@ export type DeviceFilter =
8686
}
8787

8888
// ===============================
89-
// 数据获取策略
89+
// Data Acquisition Strategy
9090
// ===============================
9191

9292
/**
93-
* 获取USB设备数据(统一的数据获取策略)
94-
* 优先使用本地JSON文件,如果不存在则请求远程数据
93+
* Get USB device data (unified data acquisition strategy)
94+
* Prioritize local JSON files, fetch remote data if not available
9595
*/
9696
async function ensureData(forceUpdate = false): Promise<UsbIdsData> {
9797
try {
9898
const { data } = await fetchUsbIdsData(
9999
USB_IDS_SOURCE,
100-
USB_IDS_FILE, // 原始 .ids 文件作为 fallback(相对于 root
101-
getEnvironmentRoot(), // 根目录
102-
forceUpdate, // 是否强制更新
100+
USB_IDS_FILE, // Original .ids file as fallback (relative to root)
101+
getEnvironmentRoot(), // Root directory
102+
forceUpdate, // Whether to force update
103103
)
104104
return data
105105
}
106106
catch (error) {
107107
throw createApiError(
108-
`无法获取USB设备数据: ${(error as Error).message}`,
108+
`Failed to fetch USB device data: ${(error as Error).message}`,
109109
ERROR_CODES.NETWORK_ERROR,
110110
error as Error,
111111
)
112112
}
113113
}
114114

115115
// ===============================
116-
// 纯函数工具(用于处理已有数据)
116+
// Pure Function Tools (for processing existing data)
117117
// ===============================
118118

119119
/**
120-
* 过滤供应商数据(纯函数)
121-
* @param data USB数据
122-
* @param filter 过滤条件
120+
* Filter vendor data (pure function)
121+
* @param data USB data
122+
* @param filter Filter conditions
123123
*/
124124
export function filterVendors(data: UsbIdsData, filter?: VendorFilter): UsbVendor[] {
125125
const vendors = Object.values(data)
@@ -140,7 +140,7 @@ export function filterVendors(data: UsbIdsData, filter?: VendorFilter): UsbVendo
140140
return vendors.filter(filter)
141141
}
142142

143-
// 对象形式的过滤器
143+
// Object-based filter
144144
return vendors.filter((vendor) => {
145145
if (filter.id && !vendor.vendor.toLowerCase().includes(filter.id.toLowerCase())) {
146146
return false
@@ -158,9 +158,9 @@ export function filterVendors(data: UsbIdsData, filter?: VendorFilter): UsbVendo
158158
}
159159

160160
/**
161-
* 过滤设备数据(纯函数)
162-
* @param vendor 供应商数据
163-
* @param filter 过滤条件
161+
* Filter device data (pure function)
162+
* @param vendor Vendor data
163+
* @param filter Filter conditions
164164
*/
165165
export function filterDevices(vendor: UsbVendor, filter?: DeviceFilter): UsbDevice[] {
166166
const devices = Object.values(vendor.devices)
@@ -181,7 +181,7 @@ export function filterDevices(vendor: UsbVendor, filter?: DeviceFilter): UsbDevi
181181
return devices.filter(filter)
182182
}
183183

184-
// 对象形式的过滤器
184+
// Object-based filter
185185
return devices.filter((device) => {
186186
if (filter.id && !device.devid.toLowerCase().includes(filter.id.toLowerCase())) {
187187
return false
@@ -199,9 +199,9 @@ export function filterDevices(vendor: UsbVendor, filter?: DeviceFilter): UsbDevi
199199
}
200200

201201
/**
202-
* 在数据中搜索设备(纯函数)
203-
* @param data USB数据
204-
* @param query 搜索关键词
202+
* Search for devices in data (pure function)
203+
* @param data USB data
204+
* @param query Search query
205205
*/
206206
export function searchInData(
207207
data: UsbIdsData,
@@ -214,7 +214,7 @@ export function searchInData(
214214
const results: Array<{ vendor: UsbVendor, device: UsbDevice, priority: number }> = []
215215
const searchTerm = query.toLowerCase().trim()
216216

217-
// 优化的搜索算法,按匹配度排序
217+
// Optimized search algorithm, sorted by relevance
218218
Object.values(data).forEach((vendor) => {
219219
const vendorMatch = vendor.name.toLowerCase().includes(searchTerm)
220220
|| vendor.vendor.toLowerCase().includes(searchTerm)
@@ -224,7 +224,7 @@ export function searchInData(
224224
const deviceNameMatch = device.devname.toLowerCase().includes(searchTerm)
225225

226226
if (deviceIdMatch || deviceNameMatch || vendorMatch) {
227-
// 计算匹配度(精确匹配优先)
227+
// Calculate relevance score (exact matches prioritized)
228228
let priority = 0
229229
if (device.devid.toLowerCase() === searchTerm)
230230
priority += 100
@@ -240,20 +240,20 @@ export function searchInData(
240240
})
241241
})
242242

243-
// 按匹配度排序并移除优先级属性
243+
// Sort by relevance and remove priority property
244244
return results
245245
.sort((a, b) => b.priority - a.priority)
246246
.map(({ vendor, device }) => ({ vendor, device }))
247247
}
248248

249249
// ===============================
250-
// 公开 API 函数(异步)
250+
// Public API Functions (Async)
251251
// ===============================
252252

253253
/**
254-
* 获取所有符合条件的供应商
255-
* @param filter 过滤条件函数或供应商ID
256-
* @param forceUpdate 是否强制更新数据
254+
* Get all vendors matching the filter
255+
* @param filter Filter function or vendor ID
256+
* @param forceUpdate Whether to force data update
257257
*/
258258
export async function getVendors(
259259
filter?: VendorFilter,
@@ -264,9 +264,9 @@ export async function getVendors(
264264
}
265265

266266
/**
267-
* 获取符合条件的单个供应商
268-
* @param filter 过滤条件函数或供应商ID
269-
* @param forceUpdate 是否强制更新数据
267+
* Get a single vendor matching the filter
268+
* @param filter Filter function or vendor ID
269+
* @param forceUpdate Whether to force data update
270270
*/
271271
export async function getVendor(
272272
filter: VendorFilter,
@@ -277,10 +277,10 @@ export async function getVendor(
277277
}
278278

279279
/**
280-
* 获取供应商的所有设备
281-
* @param vendorId 供应商ID
282-
* @param filter 可选的设备过滤条件
283-
* @param forceUpdate 是否强制更新数据
280+
* Get all devices for a vendor
281+
* @param vendorId Vendor ID
282+
* @param filter Optional device filter conditions
283+
* @param forceUpdate Whether to force data update
284284
*/
285285
export async function getDevices(
286286
vendorId: string,
@@ -295,10 +295,10 @@ export async function getDevices(
295295
}
296296

297297
/**
298-
* 获取单个设备
299-
* @param vendorId 供应商ID
300-
* @param deviceId 设备ID
301-
* @param forceUpdate 是否强制更新数据
298+
* Get a single device
299+
* @param vendorId Vendor ID
300+
* @param deviceId Device ID
301+
* @param forceUpdate Whether to force data update
302302
*/
303303
export async function getDevice(
304304
vendorId: string,
@@ -313,9 +313,9 @@ export async function getDevice(
313313
}
314314

315315
/**
316-
* 搜索设备
317-
* @param query 搜索关键词
318-
* @param forceUpdate 是否强制更新数据
316+
* Search for devices
317+
* @param query Search query
318+
* @param forceUpdate Whether to force data update
319319
*/
320320
export async function searchDevices(
321321
query: string,
@@ -326,8 +326,8 @@ export async function searchDevices(
326326
}
327327

328328
/**
329-
* 获取完整的USB设备数据
330-
* @param forceUpdate 是否强制更新数据
329+
* Get complete USB device data
330+
* @param forceUpdate Whether to force data update
331331
*/
332332
export async function getUsbData(
333333
forceUpdate = false,

0 commit comments

Comments
 (0)