trackswap 0.0.14 → 0.0.16

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/README.md CHANGED
@@ -13,7 +13,8 @@
13
13
  - 🔄 **多格式支持**: GPX 1.1、FIT、TCX 格式
14
14
  - 🎯 **统一转换**: 任意格式之间相互转换
15
15
  - 🤖 **自动检测**: 智能识别文件格式
16
- - 🔧 **插件架构**: 基于插件的可扩展设计
16
+ - 🧩 **扩展系统**: 灵活的扩展架构,支持自定义数据处理
17
+ - 📊 **智能聚合**: 默认启用运动数据聚合(心率、功率、速度等)
17
18
  - 🛡️ **类型安全**: 完整的 TypeScript 支持
18
19
  - ⚡ **高性能**: 优化的解析和编码算法
19
20
 
@@ -69,11 +70,35 @@ const convertedBuffer = await trackSwap.convertFile(
69
70
  const parsedData = await trackSwap.parseFile(buffer);
70
71
 
71
72
  // 🏃‍♂️ 解析并转换为统一的运动数据格式
72
- const sportData = await trackSwap.parseToSport(buffer);
73
+ const sportData = await trackSwap.parseToActivity(buffer);
74
+ ```
75
+
76
+ ### 扩展系统
77
+
78
+ ```typescript
79
+ import { TrackSwap } from 'trackswap';
80
+ import { SlopeExtension } from 'trackswap/extensions';
81
+
82
+ // 🧩 使用扩展增强功能
83
+ const trackSwap = new TrackSwap()
84
+ .extend(new SlopeExtension()); // 添加坡度计算
85
+
86
+ // 📊 默认已启用基础指标聚合(心率、功率、速度、踏频等)
87
+ const result = await trackSwap.parseGPX(gpxBuffer);
88
+ // result 包含完整的聚合数据和坡度信息
89
+
90
+ // 🔗 链式添加多个扩展
91
+ const enhancedTrackSwap = new TrackSwap()
92
+ .extend(new SlopeExtension())
93
+ .extend(new CustomExtension());
73
94
  ```
74
95
 
75
96
  ## 📖 详细使用指南
76
97
 
98
+ ### 扩展系统
99
+
100
+ 详细的扩展开发和使用指南请参考:[扩展系统文档](EXTENSIONS.md)
101
+
77
102
  ### 1. 文件解析
78
103
 
79
104
  #### GPX 文件处理
@@ -140,14 +165,14 @@ const result = await trackSwap.convertFile(sourceBuffer, 'fit', 'gpx');
140
165
 
141
166
  ```typescript
142
167
  // 转换为统一的运动数据格式
143
- const gpxSport = await trackSwap.convertGPXToSport(gpxData);
144
- const fitSport = await trackSwap.convertFITToSport(fitData);
145
- const tcxSport = await trackSwap.convertTCXToSport(tcxData);
168
+ const gpxActivity = await trackSwap.convertGPXToActivity(gpxData);
169
+ const fitActivity = await trackSwap.convertFITToActivity(fitData);
170
+ const tcxActivity = await trackSwap.convertTCXToActivity(tcxData);
146
171
 
147
172
  // 从统一格式转换回具体格式
148
- const gpxData = await trackSwap.convertSportToGPX(sportData);
149
- const fitData = await trackSwap.convertSportToFIT(sportData);
150
- const tcxData = await trackSwap.convertSportToTCX(sportData);
173
+ const gpxData = await trackSwap.convertActivityToGPX(sportData);
174
+ const fitData = await trackSwap.convertActivityToFIT(sportData);
175
+ const tcxData = await trackSwap.convertActivityToTCX(sportData);
151
176
  ```
152
177
 
153
178
  ### 3. 智能解析
@@ -162,8 +187,8 @@ const parsedData = await trackSwap.parseFile(buffer);
162
187
  const parsedData = await trackSwap.parseFile(buffer, 'gpx'); // 指定格式
163
188
 
164
189
  // 🏃‍♂️ 解析为统一格式
165
- const sportData = await trackSwap.parseToSport(buffer);
166
- const sportData = await trackSwap.parseToSport(buffer, 'fit'); // 指定格式
190
+ const sportData = await trackSwap.parseToActivity(buffer);
191
+ const sportData = await trackSwap.parseToActivity(buffer, 'fit'); // 指定格式
167
192
  ```
168
193
 
169
194
  ## 🔧 API 参考
@@ -180,7 +205,7 @@ const sportData = await trackSwap.parseToSport(buffer, 'fit'); // 指定格式
180
205
  | `parseTCX(buffer)` | 解析 TCX Buffer | `Buffer` | `Promise<TCXFileType>` |
181
206
  | `parseTCXString(xml)` | 解析 TCX 字符串 | `string` | `Promise<TCXFileType>` |
182
207
  | `parseFile(buffer, type?)` | 统一解析方法 | `Buffer, string?` | `Promise<GPX11Type \| FITFileType \| TCXFileType>` |
183
- | `parseToSport(buffer, type?)` | 解析为统一格式 | `Buffer, string?` | `Promise<ActivityType>` |
208
+ | `parseToActivity(buffer, type?)` | 解析为统一格式 | `Buffer, string?` | `Promise<ActivityType>` |
184
209
 
185
210
  #### 编码方法
186
211
 
@@ -198,19 +223,19 @@ const sportData = await trackSwap.parseToSport(buffer, 'fit'); // 指定格式
198
223
  | 方法 | 说明 | 参数 | 返回值 |
199
224
  |------|------|------|--------|
200
225
  | `convertFile(buffer, target, source?)` | 统一转换方法 | `Buffer, string, string?` | `Promise<Buffer>` |
201
- | `convertGPXToSport(data)` | GPX → Sport | `GPX11Type` | `Promise<ActivityType>` |
202
- | `convertFITToSport(data)` | FIT → Sport | `FITFileType` | `Promise<ActivityType>` |
203
- | `convertTCXToSport(data)` | TCX → Sport | `TCXFileType` | `Promise<ActivityType>` |
204
- | `convertSportToGPX(data)` | Sport → GPX | `ActivityType` | `Promise<GPX11Type>` |
205
- | `convertSportToFIT(data)` | Sport → FIT | `ActivityType` | `Promise<FITFileType>` |
206
- | `convertSportToTCX(data)` | Sport → TCX | `ActivityType` | `Promise<TCXFileType>` |
226
+ | `convertGPXToActivity(data)` | GPX → Activity | `GPX11Type` | `Promise<ActivityType>` |
227
+ | `convertFITToActivity(data)` | FIT → Activity | `FITFileType` | `Promise<ActivityType>` |
228
+ | `convertTCXToActivity(data)` | TCX → Activity | `TCXFileType` | `Promise<ActivityType>` |
229
+ | `convertActivityToGPX(data)` | Activity → GPX | `ActivityType` | `Promise<GPX11Type>` |
230
+ | `convertActivityToFIT(data)` | Activity → FIT | `ActivityType` | `Promise<FITFileType>` |
231
+ | `convertActivityToTCX(data)` | Activity → TCX | `ActivityType` | `Promise<TCXFileType>` |
207
232
 
208
233
  #### 工具方法
209
234
 
210
235
  | 方法 | 说明 | 参数 | 返回值 |
211
236
  |------|------|------|--------|
212
237
  | `detectFormat(buffer)` | 检测文件格式 | `Buffer` | `'gpx' \| 'fit' \| 'tcx' \| 'unknown'` |
213
- | `getSportProcessor()` | 获取运动处理器 | - | `SportProcessor` |
238
+ | `getActivityProcessor()` | 获取运动处理器 | - | `ActivityProcessor` |
214
239
  | `destroy()` | 清理资源 | - | `Promise<void>` |
215
240
 
216
241
  ## 🌟 实际应用示例
@@ -262,7 +287,7 @@ async function analyzeTrack(buffer: Buffer) {
262
287
  console.log(`文件格式: ${format}`);
263
288
 
264
289
  // 📊 转换为统一格式进行分析
265
- const sportData = await trackSwap.parseToSport(buffer);
290
+ const sportData = await trackSwap.parseToActivity(buffer);
266
291
 
267
292
  // 分析数据
268
293
  const analysis = {
@@ -285,27 +310,27 @@ async function analyzeTrack(buffer: Buffer) {
285
310
  ```typescript
286
311
  async function mergeMultiFormatTracks(files: { buffer: Buffer, name: string }[]) {
287
312
  const trackSwap = new TrackSwap();
288
- const allSportData: ActivityType[] = [];
313
+ const allActivityData: ActivityType[] = [];
289
314
 
290
315
  // 🔄 将所有格式转换为统一格式
291
316
  for (const file of files) {
292
317
  try {
293
- const sportData = await trackSwap.parseToSport(file.buffer);
318
+ const sportData = await trackSwap.parseToActivity(file.buffer);
294
319
  sportData.metadata = { ...sportData.metadata, originalFile: file.name };
295
- allSportData.push(sportData);
320
+ allActivityData.push(sportData);
296
321
  } catch (error) {
297
322
  console.error(`解析失败: ${file.name}`, error);
298
323
  }
299
324
  }
300
325
 
301
326
  // 融合数据逻辑
302
- const mergedData = mergeSportData(allSportData);
327
+ const mergedData = mergeActivityData(allActivityData);
303
328
 
304
329
  // 输出为不同格式
305
330
  const results = {
306
- gpx: await trackSwap.convertSportToGPX(mergedData),
307
- fit: await trackSwap.convertSportToFIT(mergedData),
308
- tcx: await trackSwap.convertSportToTCX(mergedData)
331
+ gpx: await trackSwap.convertActivityToGPX(mergedData),
332
+ fit: await trackSwap.convertActivityToFIT(mergedData),
333
+ tcx: await trackSwap.convertActivityToTCX(mergedData)
309
334
  };
310
335
 
311
336
  await trackSwap.destroy();
@@ -327,17 +352,17 @@ TrackSwap 采用模块化架构,核心组件包括:
327
352
  │ │ • GPXDecoder/Encoder - GPX 文件处理 │ │
328
353
  │ │ • FITDecoder/Encoder - FIT 文件处理 │ │
329
354
  │ │ • TCXDecoder/Encoder - TCX 文件处理 │ │
330
- │ │ • SportProcessor - 统一格式转换处理 │ │
355
+ │ │ • ActivityProcessor - 统一格式转换处理 │ │
331
356
  │ └─────────────────────────────────────────────────────────┘ │
332
357
  │ │
333
358
  │ 🔄 转换引擎 │
334
359
  │ ┌─────────────────────────────────────────────────────────┐ │
335
- │ │ • GPXToSportConverter - GPX → ActivityType │ │
336
- │ │ • FITToSportConverter - FIT → ActivityType │ │
337
- │ │ • TCXToSportConverter - TCX → ActivityType │ │
338
- │ │ • SportToGPXEncoder - ActivityType → GPX │ │
339
- │ │ • SportToFITEncoder - ActivityType → FIT │ │
340
- │ │ • SportToTCXEncoder - ActivityType → TCX │ │
360
+ │ │ • GPXToActivityConverter - GPX → ActivityType │ │
361
+ │ │ • FITToActivityConverter - FIT → ActivityType │ │
362
+ │ │ • TCXToActivityConverter - TCX → ActivityType │ │
363
+ │ │ • ActivityToGPXEncoder - ActivityType → GPX │ │
364
+ │ │ • ActivityToFITEncoder - ActivityType → FIT │ │
365
+ │ │ • ActivityToTCXEncoder - ActivityType → TCX │ │
341
366
  │ └─────────────────────────────────────────────────────────┘ │
342
367
  │ │
343
368
  │ 🎯 统一接口 │
@@ -387,23 +412,23 @@ TrackSwap 采用模块化架构,核心组件包括:
387
412
  ```
388
413
  src/
389
414
  ├── 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
415
+ ├── activity/ # 活动处理模块
416
+ │ ├── extensions.ts # 扩展系统核心
417
+ │ ├── slope-extension.ts # 坡度计算扩展
418
+ │ ├── processor.ts # 活动处理器
419
+ │ └── pipeline.ts # 数据处理管道
420
+ ├── decoders/ # 解码器模块
421
+ │ ├── GPXDecoder.ts
422
+ │ ├── FITDecoder.ts
423
+ │ └── TCXDecoder.ts
424
+ ├── encoders/ # 编码器模块
425
+ │ ├── GPXEncoder.ts
426
+ │ ├── FITEncoder.ts
427
+ │ └── TCXEncoder.ts
428
+ ├── converters/ # 格式转换器
429
+ │ ├── GPXConverter.ts
430
+ │ ├── FITConverter.ts
431
+ │ └── TCXConverter.ts
407
432
  └── types.ts # 公共类型定义
408
433
  ```
409
434
 
@@ -427,4 +452,4 @@ MIT License
427
452
  <div align="center">
428
453
  <strong>TrackSwap - 让轨迹数据处理变得简单</strong><br>
429
454
  🚀 高效 • 🔄 统一 • 🛡️ 安全 • 📈 可扩展
430
- </div>
455
+ </div>
@@ -1,8 +1,8 @@
1
1
  import { FITFileType } from "./types.js";
2
2
  export interface FITEncoderOptions {
3
3
  compact?: boolean;
4
- defaultSport?: string;
5
- defaultSubSport?: string;
4
+ defaultActivity?: string;
5
+ defaultSubActivity?: string;
6
6
  }
7
7
  export declare class FITEncoder {
8
8
  private localNum;
@@ -1,4 +1,4 @@
1
- export declare enum Sport {
1
+ export declare enum Activity {
2
2
  GENERIC = 0,
3
3
  RUNNING = 1,
4
4
  CYCLING = 2,
@@ -110,7 +110,7 @@ export interface SessionMesgType {
110
110
  event?: string;
111
111
  eventType?: string;
112
112
  sport?: string;
113
- subSport?: string;
113
+ subActivity?: string;
114
114
  avgCadence?: number;
115
115
  maxCadence?: number;
116
116
  trigger?: number;
@@ -1,6 +1,6 @@
1
1
  import { TokenAST } from "../types.js";
2
2
  import { BaseTCXConverter } from "./base.js";
3
- import { TCXContext, ActivityType, ActivityLapType, TrackType, TrackpointType, PositionType, ActivityListType, MultiSportSessionType, AbstractSourceType } from "./types.js";
3
+ import { TCXContext, ActivityType, ActivityLapType, TrackType, TrackpointType, PositionType, ActivityListType, MultiActivitySessionType, AbstractSourceType } from "./types.js";
4
4
  export declare class PositionConverter extends BaseTCXConverter {
5
5
  name: string;
6
6
  supportedTags: string[];
@@ -33,10 +33,10 @@ export declare class ActivityListConverter extends BaseTCXConverter {
33
33
  supportedTags: string[];
34
34
  convert(ast: TokenAST, context: TCXContext): ActivityListType | undefined;
35
35
  }
36
- export declare class MultiSportSessionConverter extends BaseTCXConverter {
36
+ export declare class MultiActivitySessionConverter extends BaseTCXConverter {
37
37
  name: string;
38
38
  supportedTags: string[];
39
- convert(ast: TokenAST, context: TCXContext): MultiSportSessionType | undefined;
39
+ convert(ast: TokenAST, context: TCXContext): MultiActivitySessionType | undefined;
40
40
  }
41
41
  export declare class AbstractSourceConverter extends BaseTCXConverter {
42
42
  name: string;
@@ -20,9 +20,9 @@ export declare class TCXEncoder {
20
20
  private buildTrackpoint;
21
21
  private buildPosition;
22
22
  private buildCadence;
23
- private buildMultiSportSession;
24
- private buildFirstSport;
25
- private buildNextSport;
23
+ private buildMultiActivitySession;
24
+ private buildFirstActivity;
25
+ private buildNextActivity;
26
26
  private buildWorkouts;
27
27
  private buildCourses;
28
28
  private buildAuthor;
@@ -75,7 +75,7 @@ export interface HistoryType {
75
75
  Running?: HistoryFolderType;
76
76
  Biking?: HistoryFolderType;
77
77
  Other?: HistoryFolderType;
78
- MultiSport?: HistoryFolderType;
78
+ MultiActivity?: HistoryFolderType;
79
79
  Extensions?: ExtensionsType;
80
80
  }
81
81
  export interface HistoryFolderType {
@@ -94,10 +94,10 @@ export interface WeekType {
94
94
  }
95
95
  export interface ActivityListType {
96
96
  Activity?: ActivityType[];
97
- MultiSportSession?: MultiSportSessionType[];
97
+ MultiActivitySession?: MultiActivitySessionType[];
98
98
  }
99
99
  export interface ActivityType {
100
- Sport?: "Other" | "Running" | "Biking";
100
+ Activity?: "Other" | "Running" | "Biking";
101
101
  Id: string;
102
102
  Lap: ActivityLapType[];
103
103
  Notes?: string;
@@ -144,16 +144,16 @@ export interface CadenceType {
144
144
  export interface HeartRateInBeatsPerMinuteType {
145
145
  Value: number;
146
146
  }
147
- export interface MultiSportSessionType {
147
+ export interface MultiActivitySessionType {
148
148
  Id?: string;
149
- FirstSport?: FirstSportType;
150
- NextSport?: NextSportType[];
149
+ FirstActivity?: FirstActivityType;
150
+ NextActivity?: NextActivityType[];
151
151
  Notes?: string;
152
152
  }
153
- export interface FirstSportType {
153
+ export interface FirstActivityType {
154
154
  Activity?: ActivityType;
155
155
  }
156
- export interface NextSportType {
156
+ export interface NextActivityType {
157
157
  Transition?: ActivityLapType;
158
158
  Activity?: ActivityType;
159
159
  }
@@ -4,8 +4,9 @@ import { FITDecoder, FITEncoder } from "./FIT/index.js";
4
4
  import { FITFileType } from "./FIT/types.js";
5
5
  import { TCXDecoder, TCXEncoder } from "./TCX/index.js";
6
6
  import { TCXFileType } from "./TCX/types.js";
7
- import { SportProcessor } from "./sport/processor.js";
8
- import { ActivityType } from "./types.js";
7
+ import { ActivityProcessor } from "./activity/processor.js";
8
+ import { FileType } from "./types.js";
9
+ import { TrackSwapExtension } from "./activity/extensions/extensions.js";
9
10
  export declare class TrackSwap {
10
11
  private gpxDecoder;
11
12
  private gpxEncoder;
@@ -13,7 +14,8 @@ export declare class TrackSwap {
13
14
  private fitEncoder;
14
15
  private tcxDecoder;
15
16
  private tcxEncoder;
16
- private sportProcessor;
17
+ private activityProcessor;
18
+ private extensionManager;
17
19
  constructor();
18
20
  parseGPX(buffer: Buffer): Promise<GPX11Type | undefined>;
19
21
  parseGPXString(xmlString: string): Promise<GPX11Type | undefined>;
@@ -22,27 +24,31 @@ export declare class TrackSwap {
22
24
  parseFIT(buffer: Buffer): Promise<FITFileType>;
23
25
  encodeFIT(fitData: FITFileType): Promise<Buffer>;
24
26
  encodeFITCourse(fitData: FITFileType): Promise<Buffer>;
25
- parseTCX(buffer: Buffer): Promise<TCXFileType>;
26
27
  parseTCXString(xmlString: string): Promise<TCXFileType>;
28
+ parseTCX(buffer: Buffer): Promise<TCXFileType>;
27
29
  encodeTCX(tcxData: TCXFileType): Promise<Buffer>;
28
30
  encodeTCXString(tcxData: TCXFileType): Promise<string>;
29
- convertGPXToSport(gpxData: GPX11Type): Promise<ActivityType>;
30
- convertFITToSport(fitData: FITFileType): Promise<ActivityType>;
31
- convertTCXToSport(tcxData: TCXFileType): Promise<ActivityType>;
32
- convertSportToGPX(sportData: ActivityType): Promise<GPX11Type>;
33
- convertSportToFIT(sportData: ActivityType): Promise<FITFileType>;
34
- convertSportToTCX(sportData: ActivityType): Promise<TCXFileType>;
31
+ convertGPXToActivity(gpxData: GPX11Type): Promise<FileType>;
32
+ convertFITToActivity(fitData: FITFileType): Promise<FileType>;
33
+ convertTCXToActivity(tcxData: TCXFileType): Promise<FileType>;
34
+ convertActivityToGPX(file: FileType): Promise<GPX11Type>;
35
+ convertActivityToFIT(file: FileType): Promise<FITFileType>;
36
+ convertActivityToTCX(file: FileType): Promise<TCXFileType>;
35
37
  convertFile(sourceFile: Buffer, targetType: "gpx" | "fit" | "tcx", sourceType?: "gpx" | "fit" | "tcx"): Promise<Buffer>;
36
38
  detectFormat(buffer: Buffer): "gpx" | "fit" | "tcx" | "unknown";
37
39
  parseFile(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<GPX11Type | FITFileType | TCXFileType>;
38
- parseToSport(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<ActivityType>;
39
- getSportProcessor(): SportProcessor;
40
+ parseToActivity(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<FileType>;
41
+ getActivityProcessor(): ActivityProcessor;
40
42
  getGPXDecoder(): GPXDecoder;
41
43
  getGPXEncoder(): GPXEncoder;
42
44
  getFITDecoder(): FITDecoder;
43
45
  getFITEncoder(): FITEncoder;
44
46
  getTCXDecoder(): TCXDecoder;
45
47
  getTCXEncoder(): TCXEncoder;
48
+ extend(extension: TrackSwapExtension): TrackSwap;
49
+ removeExtension(extensionName: string): TrackSwap;
50
+ getExtensions(): TrackSwapExtension[];
51
+ processWithExtensions(file: FileType): FileType;
46
52
  destroy(): Promise<void>;
47
53
  }
48
54
  export default TrackSwap;