trackswap 0.0.2 → 0.0.4

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 (83) hide show
  1. package/README.md +328 -281
  2. package/dist/FIT/base.d.ts +0 -30
  3. package/dist/FIT/decoder.d.ts +0 -48
  4. package/dist/FIT/encoder.d.ts +0 -97
  5. package/dist/FIT/mesg.d.ts +0 -3
  6. package/dist/FIT/middleware.d.ts +0 -15
  7. package/dist/FIT/plugins.d.ts +0 -9
  8. package/dist/FIT/processor.d.ts +0 -24
  9. package/dist/FIT/types/mesg_num.d.ts +102 -102
  10. package/dist/FIT/types/sport.d.ts +44 -44
  11. package/dist/FIT/types.d.ts +0 -35
  12. package/dist/GPX/base.d.ts +6 -50
  13. package/dist/GPX/converters.d.ts +0 -30
  14. package/dist/GPX/decoder.d.ts +0 -66
  15. package/dist/GPX/encoder.d.ts +0 -109
  16. package/dist/GPX/middleware.d.ts +0 -9
  17. package/dist/GPX/processor.d.ts +0 -18
  18. package/dist/GPX/types.d.ts +0 -108
  19. package/dist/TCX/base.d.ts +0 -33
  20. package/dist/TCX/converters.d.ts +0 -24
  21. package/dist/TCX/decoder.d.ts +0 -54
  22. package/dist/TCX/encoder.d.ts +0 -109
  23. package/dist/TCX/index.d.ts +4 -2
  24. package/dist/TCX/middleware.d.ts +11 -13
  25. package/dist/TCX/processor.d.ts +13 -21
  26. package/dist/TCX/types.d.ts +1 -13
  27. package/dist/TrackSwap.d.ts +37 -33
  28. package/dist/core/base.d.ts +0 -46
  29. package/dist/core/xml-utils.d.ts +0 -24
  30. package/dist/index.cjs +26 -0
  31. package/dist/index.js +26 -5
  32. package/dist/sport/base.d.ts +64 -0
  33. package/dist/sport/converters.d.ts +33 -0
  34. package/dist/sport/encoders.d.ts +34 -0
  35. package/dist/sport/index.d.ts +17 -0
  36. package/dist/sport/processor.d.ts +19 -0
  37. package/dist/types.d.ts +91 -13
  38. package/package.json +23 -5
  39. package/dist/FIT/base.js +0 -101
  40. package/dist/FIT/crc.js +0 -16
  41. package/dist/FIT/decoder.js +0 -323
  42. package/dist/FIT/encoder.js +0 -445
  43. package/dist/FIT/index.js +0 -13
  44. package/dist/FIT/mesg.js +0 -208
  45. package/dist/FIT/middleware.js +0 -206
  46. package/dist/FIT/plugins.js +0 -104
  47. package/dist/FIT/processor.js +0 -170
  48. package/dist/FIT/types/course_point.js +0 -58
  49. package/dist/FIT/types/event.js +0 -50
  50. package/dist/FIT/types/event_type.js +0 -19
  51. package/dist/FIT/types/file.js +0 -24
  52. package/dist/FIT/types/index.js +0 -297
  53. package/dist/FIT/types/mesg_num.js +0 -106
  54. package/dist/FIT/types/sport.js +0 -48
  55. package/dist/FIT/types.js +0 -1
  56. package/dist/FIT/util.js +0 -7
  57. package/dist/GPX/base.js +0 -56
  58. package/dist/GPX/converters.js +0 -352
  59. package/dist/GPX/decoder.js +0 -409
  60. package/dist/GPX/encoder.js +0 -513
  61. package/dist/GPX/extensions/index.js +0 -14
  62. package/dist/GPX/index.js +0 -11
  63. package/dist/GPX/middleware.js +0 -93
  64. package/dist/GPX/processor.js +0 -188
  65. package/dist/GPX/types.js +0 -1
  66. package/dist/GPX/util.js +0 -18
  67. package/dist/TCX/base.js +0 -62
  68. package/dist/TCX/converters.js +0 -333
  69. package/dist/TCX/decoder.js +0 -350
  70. package/dist/TCX/encoder.js +0 -513
  71. package/dist/TCX/index.js +0 -9
  72. package/dist/TCX/middleware.js +0 -93
  73. package/dist/TCX/processor.js +0 -197
  74. package/dist/TCX/types.js +0 -1
  75. package/dist/TrackSwap.js +0 -84
  76. package/dist/core/base.js +0 -138
  77. package/dist/core/decoder.d.ts +0 -66
  78. package/dist/core/decoder.js +0 -90
  79. package/dist/core/index.js +0 -4
  80. package/dist/core/processor.d.ts +0 -69
  81. package/dist/core/processor.js +0 -265
  82. package/dist/core/xml-utils.js +0 -140
  83. package/dist/types.js +0 -1
package/README.md CHANGED
@@ -1,18 +1,31 @@
1
- # TrackSwap - GPX 轨迹处理库
1
+ # TrackSwap - 多格式轨迹处理库
2
2
 
3
- 一个功能强大、插件化的 GPX 轨迹文件处理库,支持解析、编码、转换和扩展。
3
+ 一个强大的多格式轨迹文件处理库,支持 GPX、FIT、TCX 文件的解析、编码和格式转换。
4
4
 
5
- ## 🚀 快速开始
5
+ ---
6
6
 
7
- ### 安装
7
+ **🌐 Language / 语言**: [English](README_EN.md) | [中文](README.md)
8
+
9
+ ---
10
+
11
+ ## 🚀 特性
12
+
13
+ - 🔄 **多格式支持**: GPX 1.1、FIT、TCX 格式
14
+ - 🎯 **统一转换**: 任意格式之间相互转换
15
+ - 🤖 **自动检测**: 智能识别文件格式
16
+ - 🔧 **插件架构**: 基于插件的可扩展设计
17
+ - 🛡️ **类型安全**: 完整的 TypeScript 支持
18
+ - ⚡ **高性能**: 优化的解析和编码算法
19
+
20
+ ## 📦 安装
8
21
 
9
22
  ```bash
10
23
  npm install trackswap
11
24
  ```
12
25
 
13
- ## 📖 How to use
26
+ ## 🎯 快速开始
14
27
 
15
- 最简单的GPX文件处理:
28
+ ### 基本使用
16
29
 
17
30
  ```typescript
18
31
  import { TrackSwap } from 'trackswap';
@@ -20,364 +33,398 @@ import fs from 'fs';
20
33
 
21
34
  const trackSwap = new TrackSwap();
22
35
 
23
- // 解析GPX文件
24
- async function parseGPX() {
25
- const buffer = fs.readFileSync('track.gpx');
26
- const gpxData = await trackSwap.parseGPX(buffer);
27
-
28
- console.log('GPX版本:', gpxData?.version);
29
- console.log('轨迹数量:', gpxData?.trk?.length);
30
- }
36
+ // 解析 GPX 文件
37
+ const gpxBuffer = fs.readFileSync('track.gpx');
38
+ const gpxData = await trackSwap.parseGPX(gpxBuffer);
31
39
 
32
- // 从字符串解析
33
- async function parseFromString() {
34
- const xmlString = `<?xml version="1.0"?>
35
- <gpx version="1.1" creator="TrackSwap">
36
- <wpt lat="39.9042" lon="116.4074">
37
- <name>北京</name>
38
- </wpt>
39
- </gpx>`;
40
-
41
- const gpxData = await trackSwap.parseGPXString(xmlString);
42
- console.log('航路点:', gpxData?.wpt?.[0]?.name);
43
- }
44
- ```
40
+ // 解析 FIT 文件
41
+ const fitBuffer = fs.readFileSync('activity.fit');
42
+ const fitData = await trackSwap.parseFIT(fitBuffer);
45
43
 
44
+ // 解析 TCX 文件
45
+ const tcxBuffer = fs.readFileSync('workout.tcx');
46
+ const tcxData = await trackSwap.parseTCX(tcxBuffer);
47
+ ```
46
48
 
47
- ## 🔧 API 参考
49
+ ### 格式转换
48
50
 
49
- ### TrackSwap
51
+ ```typescript
52
+ // 🔄 自动检测格式并转换
53
+ const gpxBuffer = await trackSwap.convertFile(anyBuffer, 'gpx');
54
+ const fitBuffer = await trackSwap.convertFile(anyBuffer, 'fit');
55
+ const tcxBuffer = await trackSwap.convertFile(anyBuffer, 'tcx');
56
+
57
+ // 🎯 指定源格式转换(提升性能)
58
+ const convertedBuffer = await trackSwap.convertFile(
59
+ sourceBuffer,
60
+ 'fit', // 目标格式
61
+ 'gpx' // 源格式(可选)
62
+ );
63
+ ```
50
64
 
51
- | 方法 | 说明 | 参数 | 返回值 |
52
- |------|------|------|--------|
53
- | `parseGPX(buffer)` | 解析GPX Buffer | `Buffer` | `Promise<GPX11Type \| undefined>` |
54
- | `parseGPXString(xml)` | 解析GPX字符串 | `string` | `Promise<GPX11Type \| undefined>` |
55
- | `encodeGPX(data)` | 编码为Buffer | `GPX11Type` | `Promise<Buffer>` |
56
- | `encodeGPXString(data)` | 编码为字符串 | `GPX11Type` | `string` |
57
- | `getDecoder()` | 获取解码器实例 | - | `GPXDecoder` |
58
- | `getEncoder()` | 获取编码器实例 | - | `GPXEncoder` |
59
- | `destroy()` | 清理资源 | - | `Promise<void>` |
65
+ ### 自动解析
60
66
 
67
+ ```typescript
68
+ // 🤖 自动检测格式并解析
69
+ const parsedData = await trackSwap.parseFile(buffer);
61
70
 
71
+ // 🏃‍♂️ 解析并转换为统一的运动数据格式
72
+ const sportData = await trackSwap.parseToSport(buffer);
73
+ ```
62
74
 
63
- # GPX 流水线插件化解码器
75
+ ## 📖 详细使用指南
64
76
 
65
- 这是一个基于流水线(Pipeline)和插件架构的GPX文件解码器,采用了现代化的设计模式,支持完整的插件生命周期管理和中间件机制。
77
+ ### 1. 文件解析
66
78
 
67
- 🏗️ GPX解码器架构说明:
68
-
69
- ┌─────────────────────────────────────────────────────────────┐
70
- │ GPX解码器架构图 │
71
- ├─────────────────────────────────────────────────────────────┤
72
- │ │
73
- │ 🔧 固定核心处理器 (不可修改) │
74
- │ ┌─────────────────────────────────────────────────────────┐ │
75
- │ │ 1. TokenizeProcessor - XML → Tokens │ │
76
- │ │ 2. AstGenerateProcessor - Tokens → AST │ │
77
- │ │ 3. ConvertProcessor - AST → GPX对象 │ │
78
- │ │ 4. CompleteProcessor - 最终化处理 │ │
79
- │ └─────────────────────────────────────────────────────────┘ │
80
- │ │
81
- │ 🔌 可扩展中间件 (真正的扩展点) │
82
- │ ┌─────────────────────────────────────────────────────────┐ │
83
- │ │ • onTokenize() - Token增强、过滤 │ │
84
- │ │ • onAstGenerate() - AST结构增强 │ │
85
- │ │ • onConvert() - 转换结果增强 │ │
86
- │ │ • onComplete() - 最终结果处理 │ │
87
- │ │ • onError() - 错误处理 │ │
88
- │ └─────────────────────────────────────────────────────────┘ │
89
- │ │
90
- │ 📦 转换器插件 (支持优先级) │
91
- │ ┌─────────────────────────────────────────────────────────┐ │
92
- │ │ • 默认转换器:wpt, rte, trk, metadata... │ │
93
- │ │ • 自定义转换器:扩展标签、覆盖默认行为 │ │
94
- │ │ • 优先级系统:多转换器处理同一标签 │ │
95
- │ └─────────────────────────────────────────────────────────┘ │
96
- │ │
97
- └─────────────────────────────────────────────────────────────┘
98
-
99
- ## 📋 快速开始
79
+ #### GPX 文件处理
100
80
 
101
81
  ```typescript
102
- import { GPXDecoder } from './decoder';
103
- import { registerDefaultMiddlewares } from './converters';
82
+ // 从 Buffer 解析
83
+ const gpxData = await trackSwap.parseGPX(buffer);
104
84
 
105
- const decoder = new GPXDecoder();
106
- // 可选:注册默认中间件(性能监控、验证等)
107
- await registerDefaultMiddlewares(decoder);
85
+ // 从字符串解析
86
+ const gpxData = await trackSwap.parseGPXString(xmlString);
108
87
 
109
- // 解析GPX文件
110
- const buffer = fs.readFileSync('track.gpx');
111
- const gpxData = await decoder.parserByBuffer(buffer);
88
+ // 编码为 Buffer
89
+ const buffer = await trackSwap.encodeGPX(gpxData);
112
90
 
113
- // 销毁解码器
114
- await decoder.destroy();
91
+ // 编码为字符串
92
+ const xmlString = trackSwap.encodeGPXString(gpxData);
115
93
  ```
116
94
 
95
+ #### FIT 文件处理
117
96
 
118
- ## 🏗️ 架构设计
97
+ ```typescript
98
+ // 解析 FIT 文件
99
+ const fitData = await trackSwap.parseFIT(buffer);
119
100
 
120
- ### 自动注册的组件
101
+ // 编码为 Activity 文件
102
+ const activityBuffer = await trackSwap.encodeFIT(fitData);
121
103
 
122
- 创建`GPXDecoder`实例时,以下组件会自动注册:
104
+ // 编码为 Course 文件
105
+ const courseBuffer = await trackSwap.encodeFITCourse(fitData);
106
+ ```
123
107
 
124
- #### 🔧 核心流水线处理器(自动注册)
125
- - `TokenizeProcessor`: XML → Token数组
126
- - `AstGenerateProcessor`: Token数组 → AST
127
- - `ConvertProcessor`: AST → GPX对象
128
- - `CompleteProcessor`: 性能统计和清理
108
+ #### TCX 文件处理
129
109
 
130
- #### ✅ 默认转换器(自动注册)
131
- - `WptConverter`: 处理 `<wpt>`, `<trkpt>`, `<rtept>` 标签
132
- - `RteConverter`: 处理 `<rte>` 路线标签
133
- - `TrkConverter`: 处理 `<trk>` 轨迹标签
134
- - `TrksegConverter`: 处理 `<trkseg>` 轨迹段标签
135
- - `MetadataConverter`: 处理 `<metadata>` 元数据标签
136
- - `LinkConverter`: 处理 `<link>` 链接标签
137
- - `PersonConverter`: 处理 `<author>` 作者标签
138
- - `EmailConverter`: 处理 `<email>` 邮箱标签
139
- - `CopyrightConverter`: 处理 `<copyright>` 版权标签
140
- - `BoundsConverter`: 处理 `<bounds>` 边界标签
110
+ ```typescript
111
+ // 从 Buffer 解析
112
+ const tcxData = await trackSwap.parseTCX(buffer);
141
113
 
142
- #### 🔌 用户注册的组件
143
- - **自定义转换器**: 处理扩展标签或覆盖默认行为
144
- - **中间件**: 在流水线各阶段插入自定义逻辑
114
+ // 从字符串解析
115
+ const tcxData = await trackSwap.parseTCXString(xmlString);
145
116
 
146
- ### 流水线阶段
117
+ // 编码为 Buffer
118
+ const buffer = await trackSwap.encodeTCX(tcxData);
147
119
 
148
- ```
149
- Input Buffer → Tokenize → AST Generate → Convert → Complete → Output
150
- ↓ ↓ ↓ ↓ ↓
151
- 中间件钩子 中间件钩子 中间件钩子 中间件钩子 中间件钩子
120
+ // 编码为字符串
121
+ const xmlString = await trackSwap.encodeTCXString(tcxData);
152
122
  ```
153
123
 
154
- ## 🔧 创建转换器插件
124
+ ### 2. 格式转换
155
125
 
156
- ### 基础转换器
126
+ #### 统一转换方法
157
127
 
158
128
  ```typescript
159
- import { BaseConverter } from './decoder';
160
-
161
- class MyConverter extends BaseConverter {
162
- name = 'my-converter';
163
- supportedTags = ['custom-tag'];
164
- priority = 50; // 优先级,数字越小优先级越高
165
-
166
- convert(ast: TokenAST, context: DecoderContext): MyDataType | undefined {
167
- // 验证必要属性
168
- if (!this.hasRequiredAttributes(ast, ['required-attr'])) {
169
- return undefined;
170
- }
171
-
172
- const result: MyDataType = {
173
- value: this.parseFloat(ast.value),
174
- name: this.parseString(ast.attributes?.name)
175
- };
129
+ // 🔄 自动检测并转换
130
+ const result = await trackSwap.convertFile(sourceBuffer, 'gpx');
176
131
 
177
- // 处理子节点
178
- this.processChildren(ast, result, {
179
- 'child-tag': (child, target) => {
180
- target.childValue = this.parseString(child.value);
181
- }
182
- });
132
+ // 🎯 指定格式转换
133
+ const result = await trackSwap.convertFile(sourceBuffer, 'fit', 'gpx');
183
134
 
184
- return result;
185
- }
135
+ // 📊 支持的转换组合
136
+ // GPX ↔ FIT ↔ TCX (任意格式之间相互转换)
137
+ ```
186
138
 
187
- // 可选的生命周期钩子
188
- async initialize(context: DecoderContext): Promise<void> {
189
- console.log(`${this.name} 转换器初始化`);
190
- }
139
+ #### SportFileType 统一格式
191
140
 
192
- async destroy(context: DecoderContext): Promise<void> {
193
- console.log(`${this.name} 转换器销毁`);
194
- }
195
- }
141
+ ```typescript
142
+ // 转换为统一的运动数据格式
143
+ const gpxSport = await trackSwap.convertGPXToSport(gpxData);
144
+ const fitSport = await trackSwap.convertFITToSport(fitData);
145
+ const tcxSport = await trackSwap.convertTCXToSport(tcxData);
146
+
147
+ // 从统一格式转换回具体格式
148
+ const gpxData = await trackSwap.convertSportToGPX(sportData);
149
+ const fitData = await trackSwap.convertSportToFIT(sportData);
150
+ const tcxData = await trackSwap.convertSportToTCX(sportData);
196
151
  ```
197
152
 
198
- ### 注册和使用
153
+ ### 3. 智能解析
199
154
 
200
155
  ```typescript
201
- const decoder = new GPXDecoder(); // 默认转换器已就绪
202
- await decoder.registerConverter(new MyConverter());
156
+ // 🤖 自动检测格式
157
+ const format = trackSwap.detectFormat(buffer);
158
+ console.log(`检测到格式: ${format}`); // 'gpx' | 'fit' | 'tcx' | 'unknown'
203
159
 
204
- // 验证注册
205
- console.log(decoder.listConverters()); // 包含 'custom-tag' 和所有默认标签
206
- ```
160
+ // 📂 统一解析方法
161
+ const parsedData = await trackSwap.parseFile(buffer);
162
+ const parsedData = await trackSwap.parseFile(buffer, 'gpx'); // 指定格式
207
163
 
208
- ## 🔄 创建中间件插件
164
+ // 🏃‍♂️ 解析为统一格式
165
+ const sportData = await trackSwap.parseToSport(buffer);
166
+ const sportData = await trackSwap.parseToSport(buffer, 'fit'); // 指定格式
167
+ ```
209
168
 
210
- ### 基础中间件
169
+ ## 🔧 API 参考
211
170
 
212
- ```typescript
213
- import { BaseMiddleware } from './decoder';
171
+ ### TrackSwap 类
214
172
 
215
- class MyMiddleware extends BaseMiddleware {
216
- name = 'my-middleware';
217
- description = '我的自定义中间件';
173
+ #### 解析方法
218
174
 
219
- // Token处理阶段
220
- async onTokenize(tokens: Token[], context: DecoderContext): Promise<Token[]> {
221
- console.log(`处理了 ${tokens.length} 个token`);
222
- // 可以修改或过滤token
223
- return tokens.filter(token => token.type !== 'unwanted');
224
- }
175
+ | 方法 | 说明 | 参数 | 返回值 |
176
+ |------|------|------|--------|
177
+ | `parseGPX(buffer)` | 解析 GPX Buffer | `Buffer` | `Promise<GPX11Type \| undefined>` |
178
+ | `parseGPXString(xml)` | 解析 GPX 字符串 | `string` | `Promise<GPX11Type \| undefined>` |
179
+ | `parseFIT(buffer)` | 解析 FIT Buffer | `Buffer` | `Promise<FITFileType>` |
180
+ | `parseTCX(buffer)` | 解析 TCX Buffer | `Buffer` | `Promise<TCXFileType>` |
181
+ | `parseTCXString(xml)` | 解析 TCX 字符串 | `string` | `Promise<TCXFileType>` |
182
+ | `parseFile(buffer, type?)` | 统一解析方法 | `Buffer, string?` | `Promise<GPX11Type \| FITFileType \| TCXFileType>` |
183
+ | `parseToSport(buffer, type?)` | 解析为统一格式 | `Buffer, string?` | `Promise<SportFileType>` |
225
184
 
226
- // AST生成阶段
227
- async onAstGenerate(ast: TokenAST, context: DecoderContext): Promise<TokenAST> {
228
- // 可以修改AST结构
229
- this.addCustomProperties(ast);
230
- return ast;
231
- }
185
+ #### 编码方法
232
186
 
233
- // 转换阶段
234
- async onConvert(result: any, context: DecoderContext): Promise<any> {
235
- // 可以对转换结果进行后处理
236
- result.processedBy = this.name;
237
- return result;
238
- }
187
+ | 方法 | 说明 | 参数 | 返回值 |
188
+ |------|------|------|--------|
189
+ | `encodeGPX(data)` | 编码 GPX 为 Buffer | `GPX11Type` | `Promise<Buffer>` |
190
+ | `encodeGPXString(data)` | 编码 GPX 为字符串 | `GPX11Type` | `string` |
191
+ | `encodeFIT(data)` | 编码 FIT 为 Buffer | `FITFileType` | `Promise<Buffer>` |
192
+ | `encodeFITCourse(data)` | 编码 FIT Course | `FITFileType` | `Promise<Buffer>` |
193
+ | `encodeTCX(data)` | 编码 TCX 为 Buffer | `TCXFileType` | `Promise<Buffer>` |
194
+ | `encodeTCXString(data)` | 编码 TCX 为字符串 | `TCXFileType` | `Promise<string>` |
239
195
 
240
- // 完成阶段
241
- async onComplete(result: GPX11Type, context: DecoderContext): Promise<GPX11Type> {
242
- // 最终处理
243
- const performance = context.metadata.get('performance');
244
- console.log('处理完成,性能指标:', performance);
245
- return result;
246
- }
196
+ #### 转换方法
247
197
 
248
- // 错误处理
249
- async onError(error: Error, context: DecoderContext): Promise<void> {
250
- console.error(`中间件 ${this.name} 捕获错误:`, error.message);
251
- // 可以进行错误上报、恢复等操作
252
- }
198
+ | 方法 | 说明 | 参数 | 返回值 |
199
+ |------|------|------|--------|
200
+ | `convertFile(buffer, target, source?)` | 统一转换方法 | `Buffer, string, string?` | `Promise<Buffer>` |
201
+ | `convertGPXToSport(data)` | GPX → Sport | `GPX11Type` | `Promise<SportFileType>` |
202
+ | `convertFITToSport(data)` | FIT → Sport | `FITFileType` | `Promise<SportFileType>` |
203
+ | `convertTCXToSport(data)` | TCX → Sport | `TCXFileType` | `Promise<SportFileType>` |
204
+ | `convertSportToGPX(data)` | Sport → GPX | `SportFileType` | `Promise<GPX11Type>` |
205
+ | `convertSportToFIT(data)` | Sport → FIT | `SportFileType` | `Promise<FITFileType>` |
206
+ | `convertSportToTCX(data)` | Sport → TCX | `SportFileType` | `Promise<TCXFileType>` |
253
207
 
254
- private addCustomProperties(ast: TokenAST): void {
255
- // 添加自定义属性逻辑
256
- }
257
- }
258
- ```
208
+ #### 工具方法
259
209
 
260
- ### 注册中间件
210
+ | 方法 | 说明 | 参数 | 返回值 |
211
+ |------|------|------|--------|
212
+ | `detectFormat(buffer)` | 检测文件格式 | `Buffer` | `'gpx' \| 'fit' \| 'tcx' \| 'unknown'` |
213
+ | `getSportProcessor()` | 获取运动处理器 | - | `SportProcessor` |
214
+ | `destroy()` | 清理资源 | - | `Promise<void>` |
261
215
 
262
- ```typescript
263
- const decoder = new GPXDecoder();
264
- await decoder.registerMiddleware(new MyMiddleware());
216
+ ## 🌟 实际应用示例
265
217
 
266
- console.log(decoder.listMiddlewares()); // 包含 'my-middleware'
267
- ```
218
+ ### 批量格式转换
268
219
 
269
- ## 🎯 实际示例
220
+ ```typescript
221
+ import { TrackSwap } from 'trackswap';
222
+ import fs from 'fs';
223
+ import path from 'path';
270
224
 
271
- ### 最简洁的使用方式
225
+ async function batchConvert(inputDir: string, outputFormat: 'gpx' | 'fit' | 'tcx') {
226
+ const trackSwap = new TrackSwap();
227
+ const files = fs.readdirSync(inputDir);
228
+
229
+ for (const file of files) {
230
+ try {
231
+ const inputPath = path.join(inputDir, file);
232
+ const buffer = fs.readFileSync(inputPath);
233
+
234
+ // 🔄 自动检测并转换
235
+ const converted = await trackSwap.convertFile(buffer, outputFormat);
236
+
237
+ const outputPath = path.join(inputDir,
238
+ `${path.parse(file).name}.${outputFormat}`);
239
+ fs.writeFileSync(outputPath, converted);
240
+
241
+ console.log(`✅ 转换完成: ${file} → ${outputFormat}`);
242
+ } catch (error) {
243
+ console.error(`❌ 转换失败: ${file}`, error);
244
+ }
245
+ }
246
+
247
+ await trackSwap.destroy();
248
+ }
272
249
 
273
- ```typescript
274
- // 🎉 一行创建,立即可用!
275
- const decoder = new GPXDecoder();
276
- const result = await decoder.parserByBuffer(buffer);
250
+ // 使用示例
251
+ await batchConvert('./tracks', 'gpx');
277
252
  ```
278
253
 
279
- ### 带中间件的使用方式
254
+ ### 轨迹数据分析
280
255
 
281
256
  ```typescript
282
- import { registerDefaultMiddlewares } from './converters';
283
-
284
- const decoder = new GPXDecoder();
285
- await registerDefaultMiddlewares(decoder); // 性能监控、验证等
286
- const result = await decoder.parserByBuffer(buffer);
257
+ async function analyzeTrack(buffer: Buffer) {
258
+ const trackSwap = new TrackSwap();
259
+
260
+ // 🔍 检测格式
261
+ const format = trackSwap.detectFormat(buffer);
262
+ console.log(`文件格式: ${format}`);
263
+
264
+ // 📊 转换为统一格式进行分析
265
+ const sportData = await trackSwap.parseToSport(buffer);
266
+
267
+ // 分析数据
268
+ const analysis = {
269
+ totalDistance: sportData.summary?.totalDistance || 0,
270
+ totalTime: sportData.summary?.totalTime || 0,
271
+ avgSpeed: sportData.summary?.avgSpeed || 0,
272
+ maxSpeed: sportData.summary?.maxSpeed || 0,
273
+ trackPoints: sportData.tracks?.[0]?.segments?.[0]?.points?.length || 0
274
+ };
275
+
276
+ console.log('轨迹分析结果:', analysis);
277
+
278
+ await trackSwap.destroy();
279
+ return analysis;
280
+ }
287
281
  ```
288
282
 
289
- ### 自定义扩展处理
283
+ ### 多格式数据融合
290
284
 
291
285
  ```typescript
292
- // Garmin扩展转换器
293
- class GarminExtensionConverter extends BaseConverter {
294
- name = 'garmin-extension';
295
- supportedTags = ['gpxtpx:TrackPointExtension'];
296
-
297
- convert(ast: TokenAST, context: DecoderContext): GarminExtension {
298
- const extension: GarminExtension = {};
299
-
300
- this.processChildren(ast, extension, {
301
- 'gpxtpx:hr': (child, target) => target.heartRate = this.parseFloat(child.value),
302
- 'gpxtpx:cad': (child, target) => target.cadence = this.parseFloat(child.value),
303
- 'gpxtpx:atemp': (child, target) => target.airTemp = this.parseFloat(child.value),
304
- });
305
-
306
- return extension;
286
+ async function mergeMultiFormatTracks(files: { buffer: Buffer, name: string }[]) {
287
+ const trackSwap = new TrackSwap();
288
+ const allSportData: SportFileType[] = [];
289
+
290
+ // 🔄 将所有格式转换为统一格式
291
+ for (const file of files) {
292
+ try {
293
+ const sportData = await trackSwap.parseToSport(file.buffer);
294
+ sportData.metadata = { ...sportData.metadata, originalFile: file.name };
295
+ allSportData.push(sportData);
296
+ } catch (error) {
297
+ console.error(`解析失败: ${file.name}`, error);
298
+ }
307
299
  }
300
+
301
+ // 融合数据逻辑
302
+ const mergedData = mergeSportData(allSportData);
303
+
304
+ // 输出为不同格式
305
+ const results = {
306
+ gpx: await trackSwap.convertSportToGPX(mergedData),
307
+ fit: await trackSwap.convertSportToFIT(mergedData),
308
+ tcx: await trackSwap.convertSportToTCX(mergedData)
309
+ };
310
+
311
+ await trackSwap.destroy();
312
+ return results;
308
313
  }
309
-
310
- // 注册到已有解码器
311
- const decoder = new GPXDecoder();
312
- await decoder.registerConverter(new GarminExtensionConverter());
313
314
  ```
314
315
 
315
- ## 🛠️ 管理插件
316
-
317
- ```typescript
318
- const decoder = new GPXDecoder();
316
+ ## 🏗️ 架构设计
319
317
 
320
- // 查看默认注册的转换器
321
- console.log('默认转换器:', decoder.listConverters());
322
- // 输出: ['wpt', 'trkpt', 'rtept', 'rte', 'trk', 'trkseg', 'metadata', 'link', 'author', 'email', 'copyright', 'bounds']
318
+ TrackSwap 采用模块化架构,核心组件包括:
323
319
 
324
- // 注册自定义插件
325
- await decoder.registerConverter(customConverter);
326
- await decoder.registerMiddleware(customMiddleware);
320
+ ```
321
+ ┌─────────────────────────────────────────────────────────────┐
322
+ │ TrackSwap 架构图 │
323
+ ├─────────────────────────────────────────────────────────────┤
324
+ │ │
325
+ │ 🔧 核心处理模块 │
326
+ │ ┌─────────────────────────────────────────────────────────┐ │
327
+ │ │ • GPXDecoder/Encoder - GPX 文件处理 │ │
328
+ │ │ • FITDecoder/Encoder - FIT 文件处理 │ │
329
+ │ │ • TCXDecoder/Encoder - TCX 文件处理 │ │
330
+ │ │ • SportProcessor - 统一格式转换处理 │ │
331
+ │ └─────────────────────────────────────────────────────────┘ │
332
+ │ │
333
+ │ 🔄 转换引擎 │
334
+ │ ┌─────────────────────────────────────────────────────────┐ │
335
+ │ │ • GPXToSportConverter - GPX → SportFileType │ │
336
+ │ │ • FITToSportConverter - FIT → SportFileType │ │
337
+ │ │ • TCXToSportConverter - TCX → SportFileType │ │
338
+ │ │ • SportToGPXEncoder - SportFileType → GPX │ │
339
+ │ │ • SportToFITEncoder - SportFileType → FIT │ │
340
+ │ │ • SportToTCXEncoder - SportFileType → TCX │ │
341
+ │ └─────────────────────────────────────────────────────────┘ │
342
+ │ │
343
+ │ 🎯 统一接口 │
344
+ │ ┌─────────────────────────────────────────────────────────┐ │
345
+ │ │ • 自动格式检测 │ │
346
+ │ │ • 统一解析方法 │ │
347
+ │ │ • 统一转换方法 │ │
348
+ │ │ • 生命周期管理 │ │
349
+ │ └─────────────────────────────────────────────────────────┘ │
350
+ │ │
351
+ └─────────────────────────────────────────────────────────────┘
352
+ ```
327
353
 
328
- // 查看所有插件
329
- console.log('所有转换器:', decoder.listConverters());
330
- console.log('所有中间件:', decoder.listMiddlewares());
354
+ ## 🔍 支持的格式
331
355
 
332
- // 移除插件
333
- decoder.unregisterConverter('custom-tag');
334
- decoder.unregisterMiddleware('my-middleware');
356
+ ### GPX (GPS Exchange Format)
357
+ - ✅ GPX 1.1 标准
358
+ - ✅ 航路点 (Waypoints)
359
+ - ✅ 路线 (Routes)
360
+ - ✅ 轨迹 (Tracks)
361
+ - ✅ 元数据 (Metadata)
362
+ - ✅ 扩展属性
335
363
 
336
- // 销毁解码器
337
- await decoder.destroy();
338
- ```
364
+ ### FIT (Flexible and Interoperable Data Transfer)
365
+ - ✅ Activity 文件
366
+ - ✅ Course 文件
367
+ - ✅ 轨迹点数据
368
+ - ✅ 心率、速度、海拔等传感器数据
369
+ - ✅ Garmin 设备兼容
339
370
 
340
- ## 🔍 调试和监控
371
+ ### TCX (Training Center XML)
372
+ - ✅ 训练数据
373
+ - ✅ 运动轨迹
374
+ - ✅ 心率区间
375
+ - ✅ 圈速数据
376
+ - ✅ Garmin Connect 兼容
341
377
 
342
- 新架构提供了丰富的调试和监控能力:
378
+ ## 🛠️ 开发指南
343
379
 
344
- - **性能指标**: 自动收集各个阶段的处理时间
345
- - **错误处理**: 统一的错误处理机制
346
- - **插件状态**: 跟踪插件的生命周期状态
347
- - **上下文传递**: 丰富的上下文信息便于调试
348
- - **开箱即用**: 创建即可工作,无需配置
380
+ ### 环境要求
349
381
 
350
- ## 📚 API参考
382
+ - Node.js >= 16
383
+ - TypeScript >= 4.5
351
384
 
352
- ### GPXDecoder
385
+ ### 项目结构
353
386
 
354
- - `constructor()`: 创建解码器,自动注册默认转换器和流水线处理器
355
- - `registerConverter(plugin: IConverterPlugin)`: 注册自定义转换器
356
- - `registerMiddleware(plugin: IMiddlewarePlugin)`: 注册中间件
357
- - `getConverter(tag: string)`: 获取转换器
358
- - `unregisterConverter(tag: string)`: 移除转换器
359
- - `unregisterMiddleware(name: string)`: 移除中间件
360
- - `listConverters()`: 列出所有转换器
361
- - `listMiddlewares()`: 列出所有中间件
362
- - `initialize()`: 初始化解码器(自动调用)
363
- - `destroy()`: 销毁解码器
364
- - `parserByBuffer(buffer: Buffer)`: 解析GPX数据
387
+ ```
388
+ src/
389
+ ├── TrackSwap.ts # 主入口类
390
+ ├── GPX/ # GPX 模块
391
+ │ ├── decoder.ts
392
+ │ ├── encoder.ts
393
+ │ └── types.ts
394
+ ├── FIT/ # FIT 模块
395
+ │ ├── decoder.ts
396
+ │ ├── encoder.ts
397
+ │ └── types.ts
398
+ ├── TCX/ # TCX 模块
399
+ │ ├── decoder.ts
400
+ │ ├── encoder.ts
401
+ │ └── types.ts
402
+ ├── sport/ # 统一转换模块
403
+ │ ├── processor.ts
404
+ │ ├── converters.ts
405
+ │ ├── encoders.ts
406
+ │ └── base.ts
407
+ └── types.ts # 公共类型定义
408
+ ```
365
409
 
366
- ### BaseConverter
410
+ ### 贡献指南
367
411
 
368
- 提供转换器的基础实现和工具方法,详见"创建转换器插件"部分。
412
+ 1. Fork 项目
413
+ 2. 创建特性分支
414
+ 3. 提交更改
415
+ 4. 发起 Pull Request
369
416
 
370
- ### BaseMiddleware
417
+ ## 📄 许可证
371
418
 
372
- 提供中间件的基础实现,包含所有生命周期钩子的默认实现。
419
+ MIT License
373
420
 
374
- ## 🎊 总结
421
+ ## 🙏 致谢
375
422
 
376
- 现在的GPX解码器真正做到了**开箱即用**:
423
+ 感谢所有贡献者和开源社区的支持!
377
424
 
378
- 1. **创建即可用**: `new GPXDecoder()` 后立即支持所有标准GPX标签
379
- 2. **按需扩展**: 只需要注册自定义转换器和中间件
380
- 3. **零配置**: 无需了解内部流水线和默认转换器
381
- 4. **完全可控**: 仍然支持完整的插件化定制能力
425
+ ---
382
426
 
383
- 这个新架构让GPX解码变得更加简洁、易用而又不失灵活性! 🚀
427
+ <div align="center">
428
+ <strong>TrackSwap - 让轨迹数据处理变得简单</strong><br>
429
+ 🚀 高效 • 🔄 统一 • 🛡️ 安全 • 📈 可扩展
430
+ </div>