trackswap 0.0.4 → 0.0.5
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/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,4 +23,4 @@
|
|
|
23
23
|
`)}buildPosition(e){let t=["<Position>"];return e.LatitudeDegrees&&t.push(`<LatitudeDegrees>${this.formatCoordinate(parseFloat(e.LatitudeDegrees))}</LatitudeDegrees>`),e.LongitudeDegrees&&t.push(`<LongitudeDegrees>${this.formatCoordinate(parseFloat(e.LongitudeDegrees))}</LongitudeDegrees>`),t.push("</Position>"),t.join("")}buildCadence(e){return`<Cadence><Low>${e.Low}</Low><High>${e.High}</High></Cadence>`}buildMultiSportSession(e){let t=["<MultiSportSession>"];return e.Id&&t.push(`<Id>${this.formatTime(e.Id)}</Id>`),e.FirstSport&&t.push(this.buildFirstSport(e.FirstSport)),e.NextSport&&e.NextSport.forEach(r=>{t.push(this.buildNextSport(r))}),this.addOptionalElement(t,"Notes",e.Notes),t.push("</MultiSportSession>"),t.join(`
|
|
24
24
|
`)}buildFirstSport(e){let t=["<FirstSport>"];return e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</FirstSport>"),t.join(`
|
|
25
25
|
`)}buildNextSport(e){let t=["<NextSport>"];return e.Transition&&t.push(`<Transition>${this.buildActivityLap(e.Transition)}</Transition>`),e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</NextSport>"),t.join(`
|
|
26
|
-
`)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:(0,Re.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\r/g," ").replace(/\n/g," ").replace(/\t/g,"	")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var I=class extends y{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(e){if(typeof e=="number")return e;if(e instanceof Date)return e.getTime();if(typeof e=="string"){let t=new Date(e);return isNaN(t.getTime())?void 0:t.getTime()}}}calculateDistance(e){if(e.length<2)return;let t=0;for(let r=1;r<e.length;r++){let i=e[r-1],n=e[r],o=6371e3,s=i.lat*Math.PI/180,a=n.lat*Math.PI/180,c=(n.lat-i.lat)*Math.PI/180,d=(n.lon-i.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(s)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),f=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=o*f}return t}calculateDuration(e){var i,n;if(e.length<2)return;let t=(i=e[0])==null?void 0:i.time,r=(n=e[e.length-1])==null?void 0:n.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},k=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}};var Ye={"gpxtpx:cad":"cadence","gpxtpx:hr":"heartRate","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Me=p=>p*(180/Math.pow(2,31));var F=h(require("dayjs"));function Ze(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ve=class extends I{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n!="string"&&typeof n!="number")r={...r,...this.convertGPXExtensions(n)};else if(typeof n<"u"&&n!=="undefined"){let o=Ye[i]||i;r[o]=n}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",creator:t.creator,fileType:"gpx"}};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.tracks=t.trk.map(i=>{var n;return{name:i.name,trackseg:((n=i.trkseg)==null?void 0:n.map(o=>({name:i.name,points:o.trkpt?this.convertWpts2Points(o.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(i=>({name:i.name,points:i.rtept?this.convertWpts2Points(i.rtept):[]}))),r}convertPoint(t){if(!t.lat||!t.lon)return;let{extensions:r}=t,i=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,time:this.convertTime(t.time),...i}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat&&n.lon){let o=this.convertPoint(n);o&&r.push(o)}}return r}},xe=class extends I{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"}};if((i=t.sessionMesgs)!=null&&i.length){r.tracks=[];for(let o of t.sessionMesgs)r.tracks.push({name:o.event,startTime:o.startTime?(0,F.default)(o.startTime).valueOf():void 0,distance:o.totalDistance,duration:o.totalElapsedTime,sport:o.sport,trackseg:this.convertFITLap2Trackseg(o==null?void 0:o.lapMesgs),__fit__sessionMesgType:o})}else if((n=t.courseMesgs)!=null&&n.length){r.routes=[];for(let o of t.courseMesgs)r.routes.push({name:o.event,points:this.convertLap2Points(o==null?void 0:o.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:i,altitude:n,timestamp:o,...s}=t;if(!(!r||!i))return{lat:Ze(Me(Number(i)),6),lon:Ze(Me(Number(r)),6),ele:n,time:o?(0,F.default)(o).valueOf():void 0,...s}}convertFITLap2Trackseg(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n==null?void 0:n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];r.push({points:o,duration:n.totalElapsedTime,distance:n.totalDistance,startTime:n.startTime?(0,F.default)(n.startTime).valueOf():void 0,endTime:n.startTime&&n.totalElapsedTime?(0,F.default)(n.startTime).add(n.totalElapsedTime,"second").valueOf():void 0,avgSpeed:n.avgSpeed,maxSpeed:n.maxSpeed,avgCadenceBpm:n.avgCadence,maxCadenceBpm:n.maxCadence,avgPower:n.avgPower,maxPower:n.maxPower,totalAscent:n.totalAscent,totalDescent:n.totalDescent,calories:n.totalCalories,__fit__lapMesgType:n})}return r}convertLap2Points(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];o.length&&(r=[...r,...o])}return r}},Ce=class extends I{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,o,s;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length){r.tracks=[];for(let a of t.Activities.Activity)r.tracks.push({name:a.Id,sport:a.Sport,trackseg:this.convertLap2Trackseg(a.Lap)})}if((s=(o=t.Courses)==null?void 0:o.Course)!=null&&s.length){r.routes=[];for(let a of t.Courses.Course){let c=a.Track||[];for(let d of c)r.routes.push({name:a.Name||"",points:this.convertTCXTrack(d)})}}return r}convertPoint(t){let{Position:r,Time:i,DistanceMeters:n,AltitudeMeters:o}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:i?(0,F.default)(i).valueOf():void 0,distance:n,ele:o}}convertLap2Trackseg(t){var i,n,o,s;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(f=>this.convertPoint(f)).filter(f=>f!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(i=d==null?void 0:d[0])==null?void 0:i.time,endTime:(n=d==null?void 0:d[d.length-1])==null?void 0:n.time,avgHeartRateBpm:a==null?void 0:a.AverageHeartRateBpm,maxHeartRateBpm:a==null?void 0:a.MaximumHeartRateBpm,maxSpeed:a.MaximumSpeed,calories:a.Calories,__tcx__Intensity:a==null?void 0:a.Intensity,__tcx__TriggerMethod:a==null?void 0:a.TriggerMethod,avgCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.Low,maxCadenceBpm:(s=a==null?void 0:a.Cadence)==null?void 0:s.High,points:d};r.push(l)}}return r}convertTCXTrack(t){return t.Trackpoint?t.Trackpoint.map(r=>this.convertPoint(r)).filter(r=>r!==void 0):[]}};function qe(p){return Math.round(p*(Math.pow(2,31)/180))}var Pe=class extends k{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var n,o,s,a;if(r.targetFormat!=="gpx")return;let i={version:"1.1",creator:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"};return(o=t.points)!=null&&o.length&&(i.wpt=this.convertPoints2Wpts(t.points)),(s=t.routes)!=null&&s.length&&(i.rte=t.routes.map(c=>this.convertRoute2GPXRoute(c))),(a=t.tracks)!=null&&a.length&&(i.trk=t.tracks.map(c=>this.convertTrack2GPXTrack(c))),i}convertPoints2Wpts(t){return t.map(r=>({lat:r.lat,lon:r.lon,ele:r.ele,time:r.time?this.convertTimeToDate(r.time):void 0,speed:r.speed,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t.name,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t.name,trkseg:((r=t.trackseg)==null?void 0:r.map(i=>({trkpt:i.points?this.convertPoints2Wpts(i.points):[]})))||[]}}extractGPXExtensions(t){let r={};return t.heart&&(r["gpxtpx:hr"]=t.heart),t.cadence&&(r["gpxtpx:cad"]=t.cadence),t.temperature&&(r["gpxtpx:atemp"]=t.temperature),Object.keys(r).length>0?r:void 0}},Ee=class extends k{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,o;if(r.targetFormat!=="fit")return;let i={};return(n=t.tracks)!=null&&n.length&&(i.sessionMesgs=t.tracks.map(s=>this.convertTrack2FITSession(s))),(o=t.routes)!=null&&o.length&&(i.courseMesgs=t.routes.map(s=>this.convertRoute2FITCourse(s))),i}convertTrack2FITSession(t){var i;return{event:t.name||"session",sport:t.sport||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2FITLap(n)))||[]}}convertSeg2FITLap(t){var i;return{startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalElapsedTime:t.duration,totalDistance:t.distance,avgSpeed:t.avgSpeed,maxSpeed:t.maxSpeed,avgCadence:t.avgCadenceBpm,maxCadence:t.maxCadenceBpm,avgPower:t.avgPower,maxPower:t.maxPower,totalAscent:t.totalAscent,totalDescent:t.totalDescent,totalCalories:t.calories,recordMesgs:((i=t.points)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:qe(t.lat),positionLong:qe(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heart,cadence:t.cadence,temperature:t.temperature,distance:t.distance,enhancedSpeed:t.enhancedSpeed,enhancedAltitude:t.enhancedAltitude,accumulatedPower:t.accumulatedPower}}convertRoute2FITCourse(t){return{event:t.name||"course",lapMesgs:t.points?[this.convertPoints2FITLap(t.points)]:[]}}convertPoints2FITLap(t){let r=t[0],i=t[t.length-1],n=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),o=r!=null&&r.time&&(i!=null&&i.time)?Math.round((i.time-r.time)/1e3):0,s=(i==null?void 0:i.distance)||0;return{startTime:n,totalElapsedTime:o,totalDistance:s,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},we=class extends k{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n,o,s;if(r.targetFormat!=="tcx")return;let i={Author:{Name:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"}};return(o=t.tracks)!=null&&o.length&&(i.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(s=t.routes)!=null&&s.length&&(i.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),i}convertTrack2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2TCXLap(n)))||[]}}convertSeg2TCXLap(t){let r={TotalTimeSeconds:t.duration,DistanceMeters:t.distance,MaximumSpeed:t.maxSpeed,Calories:t.calories,AverageHeartRateBpm:t.avgHeartRateBpm,MaximumHeartRateBpm:t.maxHeartRateBpm,Intensity:t.__tcx__Intensity||"Active",TriggerMethod:t.__tcx__TriggerMethod||"Manual",Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]};return(t.avgCadenceBpm!==void 0||t.maxCadenceBpm!==void 0)&&(r.Cadence={Low:t.avgCadenceBpm||0,High:t.maxCadenceBpm||0}),r}convertPoints2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){let r={Time:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),Position:{LatitudeDegrees:t.lat.toString(),LongitudeDegrees:t.lon.toString()},AltitudeMeters:t.ele,DistanceMeters:t.distance};return t.heart&&(r.HeartRateBpm=t.heart),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Se=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new ve),this.registerConverter(new xe),this.registerConverter(new Ce)}registerDefaultEncoders(){this.registerEncoder(new Pe),this.registerEncoder(new Ee),this.registerEncoder(new we)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),o=i.convert({},r);if(r.performance.convertTime=Date.now()-n,!o)throw new Error(`Converter "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),o=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!o)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var O=class{constructor(){this.gpxDecoder=new P,this.gpxEncoder=new E,this.fitDecoder=new w,this.fitEncoder=new S,this.tcxDecoder=new b,this.tcxEncoder=new L,this.sportProcessor=new Se}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToSport(e){return await this.sportProcessor.convertToSport(e,"gpx")}async convertFITToSport(e){return await this.sportProcessor.convertToSport(e,"fit")}async convertTCXToSport(e){return await this.sportProcessor.convertToSport(e,"tcx")}async convertSportToGPX(e){return await this.sportProcessor.encodeSport(e,"gpx")}async convertSportToFIT(e){return await this.sportProcessor.encodeSport(e,"fit")}async convertSportToTCX(e){return await this.sportProcessor.encodeSport(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let s=await this.parseGPX(e);if(!s)throw new Error("GPX file parsing failed");n=s;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let o;switch(i){case"gpx":o=await this.convertGPXToSport(n);break;case"fit":o=await this.convertFITToSport(n);break;case"tcx":o=await this.convertTCXToSport(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let s=await this.convertSportToGPX(o);return await this.encodeGPX(s);case"fit":let a=await this.convertSportToFIT(o);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(o);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToSport(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return this.convertGPXToSport(i);case"fit":let n=await this.parseFIT(e);return this.convertFITToSport(n);case"tcx":let o=await this.parseTCX(e);return this.convertTCXToSport(o);default:throw new Error(`Unsupported file format: ${r}`)}}getSportProcessor(){return this.sportProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.sportProcessor.destroy()}};var gt=O;0&&(module.exports={GPXManager,TrackSwap});
|
|
26
|
+
`)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:(0,Re.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\r/g," ").replace(/\n/g," ").replace(/\t/g,"	")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var I=class extends y{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(e){if(typeof e=="number")return e;if(e instanceof Date)return e.getTime();if(typeof e=="string"){let t=new Date(e);return isNaN(t.getTime())?void 0:t.getTime()}}}calculateDistance(e){if(e.length<2)return;let t=0;for(let r=1;r<e.length;r++){let i=e[r-1],n=e[r],o=6371e3,s=i.lat*Math.PI/180,a=n.lat*Math.PI/180,c=(n.lat-i.lat)*Math.PI/180,d=(n.lon-i.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(s)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),f=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=o*f}return t}calculateDuration(e){var i,n;if(e.length<2)return;let t=(i=e[0])==null?void 0:i.time,r=(n=e[e.length-1])==null?void 0:n.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},k=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}};var Ye={"gpxtpx:cad":"cadence","gpxtpx:hr":"heartRate","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Me=p=>p*(180/Math.pow(2,31));var F=h(require("dayjs"));function Ze(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ve=class extends I{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n!="string"&&typeof n!="number")r={...r,...this.convertGPXExtensions(n)};else if(typeof n<"u"&&n!=="undefined"){let o=Ye[i]||i;r[o]=n}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",creator:t.creator,fileType:"gpx"}};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.tracks=t.trk.map(i=>{var n;return{name:i.name,trackseg:((n=i.trkseg)==null?void 0:n.map(o=>({name:i.name,points:o.trkpt?this.convertWpts2Points(o.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(i=>({name:i.name,points:i.rtept?this.convertWpts2Points(i.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null||typeof t.lat!="number"||typeof t.lon!="number")return;let{extensions:r}=t,i=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,time:this.convertTime(t.time),...i}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null&&typeof n.lat=="number"&&typeof n.lon=="number"){let o=this.convertPoint(n);o&&r.push(o)}}return r}},xe=class extends I{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"}};if((i=t.sessionMesgs)!=null&&i.length){r.tracks=[];for(let o of t.sessionMesgs)r.tracks.push({name:o.event,startTime:o.startTime?(0,F.default)(o.startTime).valueOf():void 0,distance:o.totalDistance,duration:o.totalElapsedTime,sport:o.sport,trackseg:this.convertFITLap2Trackseg(o==null?void 0:o.lapMesgs),__fit__sessionMesgType:o})}else if((n=t.courseMesgs)!=null&&n.length){r.routes=[];for(let o of t.courseMesgs)r.routes.push({name:o.event,points:this.convertLap2Points(o==null?void 0:o.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:i,altitude:n,timestamp:o,...s}=t;if(!(r==null||i==null||typeof r!="number"||typeof i!="number"))return{lat:Ze(Me(Number(i)),6),lon:Ze(Me(Number(r)),6),ele:n,time:o?(0,F.default)(o).valueOf():void 0,...s}}convertFITLap2Trackseg(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let o of t){let s=((i=o==null?void 0:o.recordMesgs)==null?void 0:i.map(a=>this.convertPoint(a)).filter(a=>a!==void 0))||[];r.push({points:s,duration:o.totalElapsedTime,distance:o.totalDistance,startTime:o.startTime?(0,F.default)(o.startTime).valueOf():void 0,endTime:o.startTime&&o.totalElapsedTime?(0,F.default)(o.startTime).add(o.totalElapsedTime,"second").valueOf():void 0,avgSpeed:o.avgSpeed,maxSpeed:o.maxSpeed,avgCadenceBpm:o.avgCadence,maxCadenceBpm:o.maxCadence,avgPower:o.avgPower,maxPower:o.maxPower,totalAscent:o.totalAscent,totalDescent:o.totalDescent,calories:o.totalCalories,__fit__lapMesgType:o})}return r}convertLap2Points(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];o.length&&(r=[...r,...o])}return r}},Ce=class extends I{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,o,s;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length){r.tracks=[];for(let a of t.Activities.Activity)r.tracks.push({name:a.Id,sport:a.Sport,trackseg:this.convertLap2Trackseg(a.Lap)})}if((s=(o=t.Courses)==null?void 0:o.Course)!=null&&s.length){r.routes=[];for(let a of t.Courses.Course){let c=a.Track||[];for(let d of c)r.routes.push({name:a.Name||"",points:this.convertTCXTrack(d)})}}return r}convertPoint(t){let{Position:r,Time:i,DistanceMeters:n,AltitudeMeters:o}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:i?(0,F.default)(i).valueOf():void 0,distance:n,ele:o}}convertLap2Trackseg(t){var i,n,o,s;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(f=>this.convertPoint(f)).filter(f=>f!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(i=d==null?void 0:d[0])==null?void 0:i.time,endTime:(n=d==null?void 0:d[d.length-1])==null?void 0:n.time,avgHeartRateBpm:a==null?void 0:a.AverageHeartRateBpm,maxHeartRateBpm:a==null?void 0:a.MaximumHeartRateBpm,maxSpeed:a.MaximumSpeed,calories:a.Calories,__tcx__Intensity:a==null?void 0:a.Intensity,__tcx__TriggerMethod:a==null?void 0:a.TriggerMethod,avgCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.Low,maxCadenceBpm:(s=a==null?void 0:a.Cadence)==null?void 0:s.High,points:d};r.push(l)}}return r}convertTCXTrack(t){return t.Trackpoint?t.Trackpoint.map(r=>this.convertPoint(r)).filter(r=>r!==void 0):[]}};function qe(p){return Math.round(p*(Math.pow(2,31)/180))}var Pe=class extends k{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var n,o,s,a;if(r.targetFormat!=="gpx")return;let i={version:"1.1",creator:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"};return(o=t.points)!=null&&o.length&&(i.wpt=this.convertPoints2Wpts(t.points)),(s=t.routes)!=null&&s.length&&(i.rte=t.routes.map(c=>this.convertRoute2GPXRoute(c))),(a=t.tracks)!=null&&a.length&&(i.trk=t.tracks.map(c=>this.convertTrack2GPXTrack(c))),i}convertPoints2Wpts(t){return t.map(r=>({lat:r.lat,lon:r.lon,ele:r.ele,time:r.time?this.convertTimeToDate(r.time):void 0,speed:r.speed,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t.name,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t.name,trkseg:((r=t.trackseg)==null?void 0:r.map(i=>({trkpt:i.points?this.convertPoints2Wpts(i.points):[]})))||[]}}extractGPXExtensions(t){let r={};return t.heart&&(r["gpxtpx:hr"]=t.heart),t.cadence&&(r["gpxtpx:cad"]=t.cadence),t.temperature&&(r["gpxtpx:atemp"]=t.temperature),Object.keys(r).length>0?r:void 0}},Ee=class extends k{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,o;if(r.targetFormat!=="fit")return;let i={};return(n=t.tracks)!=null&&n.length&&(i.sessionMesgs=t.tracks.map(s=>this.convertTrack2FITSession(s))),(o=t.routes)!=null&&o.length&&(i.courseMesgs=t.routes.map(s=>this.convertRoute2FITCourse(s))),i}convertTrack2FITSession(t){var i;return{event:t.name||"session",sport:t.sport||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2FITLap(n)))||[]}}convertSeg2FITLap(t){var i;return{startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalElapsedTime:t.duration,totalDistance:t.distance,avgSpeed:t.avgSpeed,maxSpeed:t.maxSpeed,avgCadence:t.avgCadenceBpm,maxCadence:t.maxCadenceBpm,avgPower:t.avgPower,maxPower:t.maxPower,totalAscent:t.totalAscent,totalDescent:t.totalDescent,totalCalories:t.calories,recordMesgs:((i=t.points)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:qe(t.lat),positionLong:qe(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heart,cadence:t.cadence,temperature:t.temperature,distance:t.distance,enhancedSpeed:t.enhancedSpeed,enhancedAltitude:t.enhancedAltitude,accumulatedPower:t.accumulatedPower}}convertRoute2FITCourse(t){return{event:t.name||"course",lapMesgs:t.points?[this.convertPoints2FITLap(t.points)]:[]}}convertPoints2FITLap(t){let r=t[0],i=t[t.length-1],n=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),o=r!=null&&r.time&&(i!=null&&i.time)?Math.round((i.time-r.time)/1e3):0,s=(i==null?void 0:i.distance)||0;return{startTime:n,totalElapsedTime:o,totalDistance:s,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},we=class extends k{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n,o,s;if(r.targetFormat!=="tcx")return;let i={Author:{Name:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"}};return(o=t.tracks)!=null&&o.length&&(i.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(s=t.routes)!=null&&s.length&&(i.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),i}convertTrack2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2TCXLap(n)))||[]}}convertSeg2TCXLap(t){let r={TotalTimeSeconds:t.duration,DistanceMeters:t.distance,MaximumSpeed:t.maxSpeed,Calories:t.calories,AverageHeartRateBpm:t.avgHeartRateBpm,MaximumHeartRateBpm:t.maxHeartRateBpm,Intensity:t.__tcx__Intensity||"Active",TriggerMethod:t.__tcx__TriggerMethod||"Manual",Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]};return(t.avgCadenceBpm!==void 0||t.maxCadenceBpm!==void 0)&&(r.Cadence={Low:t.avgCadenceBpm||0,High:t.maxCadenceBpm||0}),r}convertPoints2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){let r={Time:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),Position:{LatitudeDegrees:t.lat.toString(),LongitudeDegrees:t.lon.toString()},AltitudeMeters:t.ele,DistanceMeters:t.distance};return t.heart&&(r.HeartRateBpm=t.heart),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Se=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new ve),this.registerConverter(new xe),this.registerConverter(new Ce)}registerDefaultEncoders(){this.registerEncoder(new Pe),this.registerEncoder(new Ee),this.registerEncoder(new we)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),o=i.convert({},r);if(r.performance.convertTime=Date.now()-n,!o)throw new Error(`Converter "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),o=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!o)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var O=class{constructor(){this.gpxDecoder=new P,this.gpxEncoder=new E,this.fitDecoder=new w,this.fitEncoder=new S,this.tcxDecoder=new b,this.tcxEncoder=new L,this.sportProcessor=new Se}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToSport(e){return await this.sportProcessor.convertToSport(e,"gpx")}async convertFITToSport(e){return await this.sportProcessor.convertToSport(e,"fit")}async convertTCXToSport(e){return await this.sportProcessor.convertToSport(e,"tcx")}async convertSportToGPX(e){return await this.sportProcessor.encodeSport(e,"gpx")}async convertSportToFIT(e){return await this.sportProcessor.encodeSport(e,"fit")}async convertSportToTCX(e){return await this.sportProcessor.encodeSport(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let s=await this.parseGPX(e);if(!s)throw new Error("GPX file parsing failed");n=s;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let o;switch(i){case"gpx":o=await this.convertGPXToSport(n);break;case"fit":o=await this.convertFITToSport(n);break;case"tcx":o=await this.convertTCXToSport(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let s=await this.convertSportToGPX(o);return await this.encodeGPX(s);case"fit":let a=await this.convertSportToFIT(o);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(o);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToSport(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return this.convertGPXToSport(i);case"fit":let n=await this.parseFIT(e);return this.convertFITToSport(n);case"tcx":let o=await this.parseTCX(e);return this.convertTCXToSport(o);default:throw new Error(`Unsupported file format: ${r}`)}}getSportProcessor(){return this.sportProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.sportProcessor.destroy()}};var gt=O;0&&(module.exports={GPXManager,TrackSwap});
|
package/dist/index.js
CHANGED
|
@@ -23,4 +23,4 @@ var h=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){ret
|
|
|
23
23
|
`)}buildPosition(e){let t=["<Position>"];return e.LatitudeDegrees&&t.push(`<LatitudeDegrees>${this.formatCoordinate(parseFloat(e.LatitudeDegrees))}</LatitudeDegrees>`),e.LongitudeDegrees&&t.push(`<LongitudeDegrees>${this.formatCoordinate(parseFloat(e.LongitudeDegrees))}</LongitudeDegrees>`),t.push("</Position>"),t.join("")}buildCadence(e){return`<Cadence><Low>${e.Low}</Low><High>${e.High}</High></Cadence>`}buildMultiSportSession(e){let t=["<MultiSportSession>"];return e.Id&&t.push(`<Id>${this.formatTime(e.Id)}</Id>`),e.FirstSport&&t.push(this.buildFirstSport(e.FirstSport)),e.NextSport&&e.NextSport.forEach(r=>{t.push(this.buildNextSport(r))}),this.addOptionalElement(t,"Notes",e.Notes),t.push("</MultiSportSession>"),t.join(`
|
|
24
24
|
`)}buildFirstSport(e){let t=["<FirstSport>"];return e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</FirstSport>"),t.join(`
|
|
25
25
|
`)}buildNextSport(e){let t=["<NextSport>"];return e.Transition&&t.push(`<Transition>${this.buildActivityLap(e.Transition)}</Transition>`),e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</NextSport>"),t.join(`
|
|
26
|
-
`)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:Ge(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\r/g," ").replace(/\n/g," ").replace(/\t/g,"	")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var b=class extends h{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(e){if(typeof e=="number")return e;if(e instanceof Date)return e.getTime();if(typeof e=="string"){let t=new Date(e);return isNaN(t.getTime())?void 0:t.getTime()}}}calculateDistance(e){if(e.length<2)return;let t=0;for(let r=1;r<e.length;r++){let i=e[r-1],n=e[r],o=6371e3,s=i.lat*Math.PI/180,a=n.lat*Math.PI/180,c=(n.lat-i.lat)*Math.PI/180,d=(n.lon-i.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(s)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),f=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=o*f}return t}calculateDuration(e){var i,n;if(e.length<2)return;let t=(i=e[0])==null?void 0:i.time,r=(n=e[e.length-1])==null?void 0:n.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},I=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}};var Be={"gpxtpx:cad":"cadence","gpxtpx:hr":"heartRate","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Ae=p=>p*(180/Math.pow(2,31));import M from"dayjs";function He(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ge=class extends b{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n!="string"&&typeof n!="number")r={...r,...this.convertGPXExtensions(n)};else if(typeof n<"u"&&n!=="undefined"){let o=Be[i]||i;r[o]=n}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",creator:t.creator,fileType:"gpx"}};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.tracks=t.trk.map(i=>{var n;return{name:i.name,trackseg:((n=i.trkseg)==null?void 0:n.map(o=>({name:i.name,points:o.trkpt?this.convertWpts2Points(o.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(i=>({name:i.name,points:i.rtept?this.convertWpts2Points(i.rtept):[]}))),r}convertPoint(t){if(!t.lat||!t.lon)return;let{extensions:r}=t,i=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,time:this.convertTime(t.time),...i}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat&&n.lon){let o=this.convertPoint(n);o&&r.push(o)}}return r}},he=class extends b{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"}};if((i=t.sessionMesgs)!=null&&i.length){r.tracks=[];for(let o of t.sessionMesgs)r.tracks.push({name:o.event,startTime:o.startTime?M(o.startTime).valueOf():void 0,distance:o.totalDistance,duration:o.totalElapsedTime,sport:o.sport,trackseg:this.convertFITLap2Trackseg(o==null?void 0:o.lapMesgs),__fit__sessionMesgType:o})}else if((n=t.courseMesgs)!=null&&n.length){r.routes=[];for(let o of t.courseMesgs)r.routes.push({name:o.event,points:this.convertLap2Points(o==null?void 0:o.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:i,altitude:n,timestamp:o,...s}=t;if(!(!r||!i))return{lat:He(Ae(Number(i)),6),lon:He(Ae(Number(r)),6),ele:n,time:o?M(o).valueOf():void 0,...s}}convertFITLap2Trackseg(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n==null?void 0:n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];r.push({points:o,duration:n.totalElapsedTime,distance:n.totalDistance,startTime:n.startTime?M(n.startTime).valueOf():void 0,endTime:n.startTime&&n.totalElapsedTime?M(n.startTime).add(n.totalElapsedTime,"second").valueOf():void 0,avgSpeed:n.avgSpeed,maxSpeed:n.maxSpeed,avgCadenceBpm:n.avgCadence,maxCadenceBpm:n.maxCadence,avgPower:n.avgPower,maxPower:n.maxPower,totalAscent:n.totalAscent,totalDescent:n.totalDescent,calories:n.totalCalories,__fit__lapMesgType:n})}return r}convertLap2Points(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];o.length&&(r=[...r,...o])}return r}},ye=class extends b{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,o,s;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length){r.tracks=[];for(let a of t.Activities.Activity)r.tracks.push({name:a.Id,sport:a.Sport,trackseg:this.convertLap2Trackseg(a.Lap)})}if((s=(o=t.Courses)==null?void 0:o.Course)!=null&&s.length){r.routes=[];for(let a of t.Courses.Course){let c=a.Track||[];for(let d of c)r.routes.push({name:a.Name||"",points:this.convertTCXTrack(d)})}}return r}convertPoint(t){let{Position:r,Time:i,DistanceMeters:n,AltitudeMeters:o}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:i?M(i).valueOf():void 0,distance:n,ele:o}}convertLap2Trackseg(t){var i,n,o,s;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(f=>this.convertPoint(f)).filter(f=>f!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(i=d==null?void 0:d[0])==null?void 0:i.time,endTime:(n=d==null?void 0:d[d.length-1])==null?void 0:n.time,avgHeartRateBpm:a==null?void 0:a.AverageHeartRateBpm,maxHeartRateBpm:a==null?void 0:a.MaximumHeartRateBpm,maxSpeed:a.MaximumSpeed,calories:a.Calories,__tcx__Intensity:a==null?void 0:a.Intensity,__tcx__TriggerMethod:a==null?void 0:a.TriggerMethod,avgCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.Low,maxCadenceBpm:(s=a==null?void 0:a.Cadence)==null?void 0:s.High,points:d};r.push(l)}}return r}convertTCXTrack(t){return t.Trackpoint?t.Trackpoint.map(r=>this.convertPoint(r)).filter(r=>r!==void 0):[]}};function ze(p){return Math.round(p*(Math.pow(2,31)/180))}var ve=class extends I{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var n,o,s,a;if(r.targetFormat!=="gpx")return;let i={version:"1.1",creator:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"};return(o=t.points)!=null&&o.length&&(i.wpt=this.convertPoints2Wpts(t.points)),(s=t.routes)!=null&&s.length&&(i.rte=t.routes.map(c=>this.convertRoute2GPXRoute(c))),(a=t.tracks)!=null&&a.length&&(i.trk=t.tracks.map(c=>this.convertTrack2GPXTrack(c))),i}convertPoints2Wpts(t){return t.map(r=>({lat:r.lat,lon:r.lon,ele:r.ele,time:r.time?this.convertTimeToDate(r.time):void 0,speed:r.speed,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t.name,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t.name,trkseg:((r=t.trackseg)==null?void 0:r.map(i=>({trkpt:i.points?this.convertPoints2Wpts(i.points):[]})))||[]}}extractGPXExtensions(t){let r={};return t.heart&&(r["gpxtpx:hr"]=t.heart),t.cadence&&(r["gpxtpx:cad"]=t.cadence),t.temperature&&(r["gpxtpx:atemp"]=t.temperature),Object.keys(r).length>0?r:void 0}},xe=class extends I{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,o;if(r.targetFormat!=="fit")return;let i={};return(n=t.tracks)!=null&&n.length&&(i.sessionMesgs=t.tracks.map(s=>this.convertTrack2FITSession(s))),(o=t.routes)!=null&&o.length&&(i.courseMesgs=t.routes.map(s=>this.convertRoute2FITCourse(s))),i}convertTrack2FITSession(t){var i;return{event:t.name||"session",sport:t.sport||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2FITLap(n)))||[]}}convertSeg2FITLap(t){var i;return{startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalElapsedTime:t.duration,totalDistance:t.distance,avgSpeed:t.avgSpeed,maxSpeed:t.maxSpeed,avgCadence:t.avgCadenceBpm,maxCadence:t.maxCadenceBpm,avgPower:t.avgPower,maxPower:t.maxPower,totalAscent:t.totalAscent,totalDescent:t.totalDescent,totalCalories:t.calories,recordMesgs:((i=t.points)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:ze(t.lat),positionLong:ze(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heart,cadence:t.cadence,temperature:t.temperature,distance:t.distance,enhancedSpeed:t.enhancedSpeed,enhancedAltitude:t.enhancedAltitude,accumulatedPower:t.accumulatedPower}}convertRoute2FITCourse(t){return{event:t.name||"course",lapMesgs:t.points?[this.convertPoints2FITLap(t.points)]:[]}}convertPoints2FITLap(t){let r=t[0],i=t[t.length-1],n=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),o=r!=null&&r.time&&(i!=null&&i.time)?Math.round((i.time-r.time)/1e3):0,s=(i==null?void 0:i.distance)||0;return{startTime:n,totalElapsedTime:o,totalDistance:s,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},Ce=class extends I{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n,o,s;if(r.targetFormat!=="tcx")return;let i={Author:{Name:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"}};return(o=t.tracks)!=null&&o.length&&(i.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(s=t.routes)!=null&&s.length&&(i.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),i}convertTrack2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2TCXLap(n)))||[]}}convertSeg2TCXLap(t){let r={TotalTimeSeconds:t.duration,DistanceMeters:t.distance,MaximumSpeed:t.maxSpeed,Calories:t.calories,AverageHeartRateBpm:t.avgHeartRateBpm,MaximumHeartRateBpm:t.maxHeartRateBpm,Intensity:t.__tcx__Intensity||"Active",TriggerMethod:t.__tcx__TriggerMethod||"Manual",Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]};return(t.avgCadenceBpm!==void 0||t.maxCadenceBpm!==void 0)&&(r.Cadence={Low:t.avgCadenceBpm||0,High:t.maxCadenceBpm||0}),r}convertPoints2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){let r={Time:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),Position:{LatitudeDegrees:t.lat.toString(),LongitudeDegrees:t.lon.toString()},AltitudeMeters:t.ele,DistanceMeters:t.distance};return t.heart&&(r.HeartRateBpm=t.heart),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Pe=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new ge),this.registerConverter(new he),this.registerConverter(new ye)}registerDefaultEncoders(){this.registerEncoder(new ve),this.registerEncoder(new xe),this.registerEncoder(new Ce)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),o=i.convert({},r);if(r.performance.convertTime=Date.now()-n,!o)throw new Error(`Converter "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),o=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!o)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var Ee=class{constructor(){this.gpxDecoder=new C,this.gpxEncoder=new P,this.fitDecoder=new E,this.fitEncoder=new w,this.tcxDecoder=new S,this.tcxEncoder=new R,this.sportProcessor=new Pe}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToSport(e){return await this.sportProcessor.convertToSport(e,"gpx")}async convertFITToSport(e){return await this.sportProcessor.convertToSport(e,"fit")}async convertTCXToSport(e){return await this.sportProcessor.convertToSport(e,"tcx")}async convertSportToGPX(e){return await this.sportProcessor.encodeSport(e,"gpx")}async convertSportToFIT(e){return await this.sportProcessor.encodeSport(e,"fit")}async convertSportToTCX(e){return await this.sportProcessor.encodeSport(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let s=await this.parseGPX(e);if(!s)throw new Error("GPX file parsing failed");n=s;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let o;switch(i){case"gpx":o=await this.convertGPXToSport(n);break;case"fit":o=await this.convertFITToSport(n);break;case"tcx":o=await this.convertTCXToSport(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let s=await this.convertSportToGPX(o);return await this.encodeGPX(s);case"fit":let a=await this.convertSportToFIT(o);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(o);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToSport(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return this.convertGPXToSport(i);case"fit":let n=await this.parseFIT(e);return this.convertFITToSport(n);case"tcx":let o=await this.parseTCX(e);return this.convertTCXToSport(o);default:throw new Error(`Unsupported file format: ${r}`)}}getSportProcessor(){return this.sportProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.sportProcessor.destroy()}};var gn=Ee;export{je as GPXManager,Ee as TrackSwap,gn as default};
|
|
26
|
+
`)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:Ge(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/\r/g," ").replace(/\n/g," ").replace(/\t/g,"	")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var b=class extends h{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(e){if(typeof e=="number")return e;if(e instanceof Date)return e.getTime();if(typeof e=="string"){let t=new Date(e);return isNaN(t.getTime())?void 0:t.getTime()}}}calculateDistance(e){if(e.length<2)return;let t=0;for(let r=1;r<e.length;r++){let i=e[r-1],n=e[r],o=6371e3,s=i.lat*Math.PI/180,a=n.lat*Math.PI/180,c=(n.lat-i.lat)*Math.PI/180,d=(n.lon-i.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(s)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),f=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=o*f}return t}calculateDuration(e){var i,n;if(e.length<2)return;let t=(i=e[0])==null?void 0:i.time,r=(n=e[e.length-1])==null?void 0:n.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},I=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}};var Be={"gpxtpx:cad":"cadence","gpxtpx:hr":"heartRate","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Ae=p=>p*(180/Math.pow(2,31));import M from"dayjs";function He(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ge=class extends b{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n!="string"&&typeof n!="number")r={...r,...this.convertGPXExtensions(n)};else if(typeof n<"u"&&n!=="undefined"){let o=Be[i]||i;r[o]=n}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",creator:t.creator,fileType:"gpx"}};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.tracks=t.trk.map(i=>{var n;return{name:i.name,trackseg:((n=i.trkseg)==null?void 0:n.map(o=>({name:i.name,points:o.trkpt?this.convertWpts2Points(o.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(i=>({name:i.name,points:i.rtept?this.convertWpts2Points(i.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null||typeof t.lat!="number"||typeof t.lon!="number")return;let{extensions:r}=t,i=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,time:this.convertTime(t.time),...i}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null&&typeof n.lat=="number"&&typeof n.lon=="number"){let o=this.convertPoint(n);o&&r.push(o)}}return r}},he=class extends b{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"}};if((i=t.sessionMesgs)!=null&&i.length){r.tracks=[];for(let o of t.sessionMesgs)r.tracks.push({name:o.event,startTime:o.startTime?M(o.startTime).valueOf():void 0,distance:o.totalDistance,duration:o.totalElapsedTime,sport:o.sport,trackseg:this.convertFITLap2Trackseg(o==null?void 0:o.lapMesgs),__fit__sessionMesgType:o})}else if((n=t.courseMesgs)!=null&&n.length){r.routes=[];for(let o of t.courseMesgs)r.routes.push({name:o.event,points:this.convertLap2Points(o==null?void 0:o.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:i,altitude:n,timestamp:o,...s}=t;if(!(r==null||i==null||typeof r!="number"||typeof i!="number"))return{lat:He(Ae(Number(i)),6),lon:He(Ae(Number(r)),6),ele:n,time:o?M(o).valueOf():void 0,...s}}convertFITLap2Trackseg(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let o of t){let s=((i=o==null?void 0:o.recordMesgs)==null?void 0:i.map(a=>this.convertPoint(a)).filter(a=>a!==void 0))||[];r.push({points:s,duration:o.totalElapsedTime,distance:o.totalDistance,startTime:o.startTime?M(o.startTime).valueOf():void 0,endTime:o.startTime&&o.totalElapsedTime?M(o.startTime).add(o.totalElapsedTime,"second").valueOf():void 0,avgSpeed:o.avgSpeed,maxSpeed:o.maxSpeed,avgCadenceBpm:o.avgCadence,maxCadenceBpm:o.maxCadence,avgPower:o.avgPower,maxPower:o.maxPower,totalAscent:o.totalAscent,totalDescent:o.totalDescent,calories:o.totalCalories,__fit__lapMesgType:o})}return r}convertLap2Points(t){var i;let r=[];if(!(t!=null&&t.length))return[];for(let n of t){let o=((i=n.recordMesgs)==null?void 0:i.map(s=>this.convertPoint(s)).filter(s=>s!==void 0))||[];o.length&&(r=[...r,...o])}return r}},ye=class extends b{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,o,s;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length){r.tracks=[];for(let a of t.Activities.Activity)r.tracks.push({name:a.Id,sport:a.Sport,trackseg:this.convertLap2Trackseg(a.Lap)})}if((s=(o=t.Courses)==null?void 0:o.Course)!=null&&s.length){r.routes=[];for(let a of t.Courses.Course){let c=a.Track||[];for(let d of c)r.routes.push({name:a.Name||"",points:this.convertTCXTrack(d)})}}return r}convertPoint(t){let{Position:r,Time:i,DistanceMeters:n,AltitudeMeters:o}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:i?M(i).valueOf():void 0,distance:n,ele:o}}convertLap2Trackseg(t){var i,n,o,s;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(f=>this.convertPoint(f)).filter(f=>f!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(i=d==null?void 0:d[0])==null?void 0:i.time,endTime:(n=d==null?void 0:d[d.length-1])==null?void 0:n.time,avgHeartRateBpm:a==null?void 0:a.AverageHeartRateBpm,maxHeartRateBpm:a==null?void 0:a.MaximumHeartRateBpm,maxSpeed:a.MaximumSpeed,calories:a.Calories,__tcx__Intensity:a==null?void 0:a.Intensity,__tcx__TriggerMethod:a==null?void 0:a.TriggerMethod,avgCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.Low,maxCadenceBpm:(s=a==null?void 0:a.Cadence)==null?void 0:s.High,points:d};r.push(l)}}return r}convertTCXTrack(t){return t.Trackpoint?t.Trackpoint.map(r=>this.convertPoint(r)).filter(r=>r!==void 0):[]}};function ze(p){return Math.round(p*(Math.pow(2,31)/180))}var ve=class extends I{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var n,o,s,a;if(r.targetFormat!=="gpx")return;let i={version:"1.1",creator:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"};return(o=t.points)!=null&&o.length&&(i.wpt=this.convertPoints2Wpts(t.points)),(s=t.routes)!=null&&s.length&&(i.rte=t.routes.map(c=>this.convertRoute2GPXRoute(c))),(a=t.tracks)!=null&&a.length&&(i.trk=t.tracks.map(c=>this.convertTrack2GPXTrack(c))),i}convertPoints2Wpts(t){return t.map(r=>({lat:r.lat,lon:r.lon,ele:r.ele,time:r.time?this.convertTimeToDate(r.time):void 0,speed:r.speed,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t.name,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t.name,trkseg:((r=t.trackseg)==null?void 0:r.map(i=>({trkpt:i.points?this.convertPoints2Wpts(i.points):[]})))||[]}}extractGPXExtensions(t){let r={};return t.heart&&(r["gpxtpx:hr"]=t.heart),t.cadence&&(r["gpxtpx:cad"]=t.cadence),t.temperature&&(r["gpxtpx:atemp"]=t.temperature),Object.keys(r).length>0?r:void 0}},xe=class extends I{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,o;if(r.targetFormat!=="fit")return;let i={};return(n=t.tracks)!=null&&n.length&&(i.sessionMesgs=t.tracks.map(s=>this.convertTrack2FITSession(s))),(o=t.routes)!=null&&o.length&&(i.courseMesgs=t.routes.map(s=>this.convertRoute2FITCourse(s))),i}convertTrack2FITSession(t){var i;return{event:t.name||"session",sport:t.sport||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2FITLap(n)))||[]}}convertSeg2FITLap(t){var i;return{startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalElapsedTime:t.duration,totalDistance:t.distance,avgSpeed:t.avgSpeed,maxSpeed:t.maxSpeed,avgCadence:t.avgCadenceBpm,maxCadence:t.maxCadenceBpm,avgPower:t.avgPower,maxPower:t.maxPower,totalAscent:t.totalAscent,totalDescent:t.totalDescent,totalCalories:t.calories,recordMesgs:((i=t.points)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:ze(t.lat),positionLong:ze(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heart,cadence:t.cadence,temperature:t.temperature,distance:t.distance,enhancedSpeed:t.enhancedSpeed,enhancedAltitude:t.enhancedAltitude,accumulatedPower:t.accumulatedPower}}convertRoute2FITCourse(t){return{event:t.name||"course",lapMesgs:t.points?[this.convertPoints2FITLap(t.points)]:[]}}convertPoints2FITLap(t){let r=t[0],i=t[t.length-1],n=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),o=r!=null&&r.time&&(i!=null&&i.time)?Math.round((i.time-r.time)/1e3):0,s=(i==null?void 0:i.distance)||0;return{startTime:n,totalElapsedTime:o,totalDistance:s,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},Ce=class extends I{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n,o,s;if(r.targetFormat!=="tcx")return;let i={Author:{Name:((n=t.metadata)==null?void 0:n.creator)||"TrackSwap"}};return(o=t.tracks)!=null&&o.length&&(i.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(s=t.routes)!=null&&s.length&&(i.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),i}convertTrack2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((i=t.trackseg)==null?void 0:i.map(n=>this.convertSeg2TCXLap(n)))||[]}}convertSeg2TCXLap(t){let r={TotalTimeSeconds:t.duration,DistanceMeters:t.distance,MaximumSpeed:t.maxSpeed,Calories:t.calories,AverageHeartRateBpm:t.avgHeartRateBpm,MaximumHeartRateBpm:t.maxHeartRateBpm,Intensity:t.__tcx__Intensity||"Active",TriggerMethod:t.__tcx__TriggerMethod||"Manual",Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]};return(t.avgCadenceBpm!==void 0||t.maxCadenceBpm!==void 0)&&(r.Cadence={Low:t.avgCadenceBpm||0,High:t.maxCadenceBpm||0}),r}convertPoints2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){let r={Time:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),Position:{LatitudeDegrees:t.lat.toString(),LongitudeDegrees:t.lon.toString()},AltitudeMeters:t.ele,DistanceMeters:t.distance};return t.heart&&(r.HeartRateBpm=t.heart),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Pe=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new ge),this.registerConverter(new he),this.registerConverter(new ye)}registerDefaultEncoders(){this.registerEncoder(new ve),this.registerEncoder(new xe),this.registerEncoder(new Ce)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),o=i.convert({},r);if(r.performance.convertTime=Date.now()-n,!o)throw new Error(`Converter "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeSport(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),o=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!o)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var Ee=class{constructor(){this.gpxDecoder=new C,this.gpxEncoder=new P,this.fitDecoder=new E,this.fitEncoder=new w,this.tcxDecoder=new S,this.tcxEncoder=new R,this.sportProcessor=new Pe}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToSport(e){return await this.sportProcessor.convertToSport(e,"gpx")}async convertFITToSport(e){return await this.sportProcessor.convertToSport(e,"fit")}async convertTCXToSport(e){return await this.sportProcessor.convertToSport(e,"tcx")}async convertSportToGPX(e){return await this.sportProcessor.encodeSport(e,"gpx")}async convertSportToFIT(e){return await this.sportProcessor.encodeSport(e,"fit")}async convertSportToTCX(e){return await this.sportProcessor.encodeSport(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let s=await this.parseGPX(e);if(!s)throw new Error("GPX file parsing failed");n=s;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let o;switch(i){case"gpx":o=await this.convertGPXToSport(n);break;case"fit":o=await this.convertFITToSport(n);break;case"tcx":o=await this.convertTCXToSport(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let s=await this.convertSportToGPX(o);return await this.encodeGPX(s);case"fit":let a=await this.convertSportToFIT(o);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(o);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToSport(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return this.convertGPXToSport(i);case"fit":let n=await this.parseFIT(e);return this.convertFITToSport(n);case"tcx":let o=await this.parseTCX(e);return this.convertTCXToSport(o);default:throw new Error(`Unsupported file format: ${r}`)}}getSportProcessor(){return this.sportProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.sportProcessor.destroy()}};var gn=Ee;export{je as GPXManager,Ee as TrackSwap,gn as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trackswap",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A powerful and flexible GPX parser and encoder library for Node.js and TypeScript. TrackSwap provides comprehensive support for GPX 1.1 format with advanced features like plugin system, middleware support, and optimized performance.",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|