trackswap 0.0.12 → 0.0.13

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 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 n=this.buildExtensionContent(r);return`<${t}>${n}</${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,ze.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,n){if(r!=null&&r!==""){let i=n?n(r):this.escapeXML(r);e.push(`<${t}>${i}</${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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}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 Ee=class extends S{constructor(){super(...arguments);this.name="tcx-performance-middleware";this.description="Monitor TCX parsing performance"}async onTokenize(t,r){return t}async onAstGenerate(t,r){let n=this.countNodes(t);return t}async onComplete(t,r){let n=r.metadata.get("performance");return t}countNodes(t){let r=1;if(t.children)for(let n of t.children)r+=this.countNodes(n);return r}},Se=class extends S{constructor(){super(...arguments);this.name="tcx-validation-middleware";this.description="Validate TCX data integrity"}async onComplete(t,r){let n=this.validateTCX(t);return n.length>0&&r.metadata.set("validation-errors",n),t}validateTCX(t){let r=[];if(t.version||r.push("Missing TCX version information"),t.creator||r.push("Missing TCX creator information"),t.Activities&&t.Activities.Activity){for(let n of t.Activities.Activity)if(n.Id||r.push("Activity missing ID information"),(!n.Lap||n.Lap.length===0)&&r.push("Activity must contain at least one Lap"),n.Lap){for(let i of n.Lap)if(i.Track){for(let s of i.Track)if(s.Trackpoint)for(let o of s.Trackpoint)o.Position&&(!o.Position.LatitudeDegrees||!o.Position.LongitudeDegrees)&&r.push("Invalid trackpoint coordinates")}}}return r}},be=class extends S{constructor(){super(...arguments);this.name="tcx-enhancement-middleware";this.description="Enhance TCX data with additional calculated fields"}async onComplete(t,r){if(t.Activities&&t.Activities.Activity)for(let n of t.Activities.Activity)n.totalDistance=this.calculateTotalDistance(n),n.totalDuration=this.calculateTotalDuration(n),n.totalDistance&&n.totalDuration&&(n.averageSpeed=n.totalDistance/n.totalDuration);return t}calculateTotalDistance(t){let r=0;if(t.Lap)for(let n of t.Lap)n.DistanceMeters&&(r+=n.DistanceMeters);return r}calculateTotalDuration(t){let r=0;if(t.Lap)for(let n of t.Lap)n.TotalTimeSeconds&&(r+=n.TotalTimeSeconds);return r}};async function St(p){let e=[new Ee,new Se,new be];for(let t of e)await p.registerMiddleware(t)}var X=class extends x{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 n=e[r-1],i=e[r],s=6371e3,o=n.lat*Math.PI/180,a=i.lat*Math.PI/180,c=(i.lat-n.lat)*Math.PI/180,d=(i.lon-n.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(o)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),u=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=s*u}return t}calculateDuration(e){var n,i;if(e.length<2)return;let t=(n=e[0])==null?void 0:n.time,r=(i=e[e.length-1])==null?void 0:i.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},R=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 rt={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Ue=p=>p*(180/Math.pow(2,31));var M=y(require("dayjs"));function nt(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var Ie=class extends X{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([n,i])=>{if(typeof i<"u"&&i!=="undefined"){let s=rt[n]||n;r[s]=this.autoNumber(i)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let n=r.sourceData;return this.convertGPX(n)}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(n=>{var i;return{name:n.name,trackseg:((i=n.trkseg)==null?void 0:i.map(s=>({name:n.name,points:s.trkpt?this.convertWpts2Points(s.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(n=>({name:n.name,points:n.rtept?this.convertWpts2Points(n.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null)return;let{extensions:r}=t,n=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,time:this.convertTime(t.time),...n}}convertWpts2Points(t){let r=[];for(let n=0;n<t.length;n++){let i=t[n];if(i.lat!=null&&i.lon!=null){let s=this.convertPoint(i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},Fe=class extends X{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let n=r.sourceData;return this.convertFIT(n)}convertFIT(t){var n,i;let r={metadata:{originType:"FIT",fileType:"fit"}};if((n=t.sessionMesgs)!=null&&n.length){r.tracks=[];for(let s of t.sessionMesgs)r.tracks.push({name:s.event,startTime:s.startTime?(0,M.default)(s.startTime).valueOf():void 0,distance:s.totalDistance,duration:s.totalElapsedTime,sport:s.sport,trackseg:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs),__fit__sessionMesgType:s})}else if((i=t.courseMesgs)!=null&&i.length){r.routes=[];for(let s of t.courseMesgs)r.routes.push({name:s.event,points:this.convertLap2Points(s==null?void 0:s.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:n,altitude:i,timestamp:s,heartRate:o,cadence:a,distance:c,power:d,enhancedAltitude:l,enhancedSpeed:u,temperature:f,...h}=t;if(!(r==null||n==null))return{lat:nt(Ue(Number(n)),6),lon:nt(Ue(Number(r)),6),ele:i,heartRate:o,power:d,cadence:a,temperature:f,time:s?(0,M.default)(s).valueOf():void 0,...h}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i==null?void 0:i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];r.push({points:s,duration:i.totalElapsedTime,distance:i.totalDistance,startTime:i.startTime?(0,M.default)(i.startTime).valueOf():void 0,endTime:i.startTime&&i.totalElapsedTime?(0,M.default)(i.startTime).add(i.totalElapsedTime,"second").valueOf():void 0,avgSpeed:i.avgSpeed,maxSpeed:i.maxSpeed,avgCadenceBpm:i.avgCadence,maxCadenceBpm:i.maxCadence,avgPower:i.avgPower,maxPower:i.maxPower,totalAscent:i.totalAscent,totalDescent:i.totalDescent,calories:i.totalCalories,__fit__lapMesgType:i})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];s.length&&(r=[...r,...s])}return r}},ke=class extends X{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let n=r.sourceData;return this.convertTCX(n)}convertTCX(t){var n,i,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((i=(n=t.Activities)==null?void 0:n.Activity)!=null&&i.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((o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.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:n,DistanceMeters:i,AltitudeMeters:s}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:n?(0,M.default)(n).valueOf():void 0,distance:i,ele:s}}convertLap2Trackseg(t){var n,i,s,o;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(u=>this.convertPoint(u)).filter(u=>u!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(n=d==null?void 0:d[0])==null?void 0:n.time,endTime:(i=d==null?void 0:d[d.length-1])==null?void 0:i.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:(s=a==null?void 0:a.Cadence)==null?void 0:s.Low,maxCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.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):[]}};var st=y(require("dayjs"));function it(p){return Math.round(p*(Math.pow(2,31)/180))}var Ae=class extends R{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var i,s,o,a,c,d,l;if(r.targetFormat!=="gpx")return;let n={version:"1.1",creator:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap",metadata:{name:(s=t==null?void 0:t.metadata)==null?void 0:s.fileName,time:(o=t==null?void 0:t.metadata)!=null&&o.date?(0,st.default)((a=t==null?void 0:t.metadata)==null?void 0:a.date).toDate():void 0}};return(c=t.points)!=null&&c.length&&(n.wpt=this.convertPoints2Wpts(t.points)),(d=t.routes)!=null&&d.length&&(n.rte=t.routes.map(u=>this.convertRoute2GPXRoute(u))),(l=t.tracks)!=null&&l.length&&(n.trk=t.tracks.map(u=>this.convertTrack2GPXTrack(u))),n}convertPoints2Wpts(t){return t==null?void 0:t.filter(r=>!!r.lat&&!!r.lon).map(r=>({lat:r.lat,lon:r.lon,ele:r==null?void 0:r.ele,time:r!=null&&r.time?this.convertTimeToDate(r.time):void 0,speed:r==null?void 0:r.speed,geoidheight:r==null?void 0:r.geoidheight,name:r==null?void 0:r.name,cmt:r==null?void 0:r.cmt,desc:r==null?void 0:r.desc,type:r==null?void 0:r.type,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,ageofdgpsdata:r==null?void 0:r.ageofdgpsdata,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,src:t==null?void 0:t.GPX_src,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,trkseg:((r=t.trackseg)==null?void 0:r.map(n=>{var i;return{trkpt:(i=n==null?void 0:n.points)!=null&&i.length?this.convertPoints2Wpts(n.points):[]}}))||[]}}extractGPXExtensions(t){let r={};return typeof(t==null?void 0:t.heartRate)<"u"&&(r["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(r["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(r["gpxtpx:atemp"]=t.temperature),typeof(t==null?void 0:t.power)<"u"&&(r.extractGPXExtensions=t.power),Object.keys(r).length>0?r:void 0}},_e=class extends R{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var i,s,o;if(r.targetFormat!=="fit")return;let n={};return(i=t.tracks)!=null&&i.length&&(n.sessionMesgs=(s=t==null?void 0:t.tracks)==null?void 0:s.map(a=>this.convertTrack2FITSession(a))),(o=t.routes)!=null&&o.length&&(n.courseMesgs=t.routes.map(a=>this.convertRoute2FITCourse(a))),n}convertTrack2FITSession(t){var n;return{event:(t==null?void 0:t.name)||"session",sport:(t==null?void 0:t.sport)||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2FITLap(i)))||[]}}convertSeg2FITLap(t){var n;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:((n=t.points)==null?void 0:n.map(i=>this.convertPoint2FITRecord(i)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:it(t.lat),positionLong:it(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heartRate,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],n=t[t.length-1],i=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),s=r!=null&&r.time&&(n!=null&&n.time)?Math.round((n.time-r.time)/1e3):0,o=(n==null?void 0:n.distance)||0;return{startTime:i,totalElapsedTime:s,totalDistance:o,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},De=class extends R{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var i,s,o;if(r.targetFormat!=="tcx")return;let n={Author:{Name:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap"}};return(s=t.tracks)!=null&&s.length&&(n.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(o=t.routes)!=null&&o.length&&(n.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),n}convertTrack2TCXActivity(t){var n;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2TCXLap(i)))||[]}}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.heartRate&&(r.HeartRateBpm=t.heartRate),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Xe=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new Ie),this.registerConverter(new Fe),this.registerConverter(new ke)}registerDefaultEncoders(){this.registerEncoder(new Ae),this.registerEncoder(new _e),this.registerEncoder(new De)}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 n=this.findConverter(t);if(!n)throw new Error(`No converter found for format "${t}"`);let i=Date.now(),s=n.convert({},r);if(r.performance.convertTime=Date.now()-i,!s)throw new Error(`Converter "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 n=this.findEncoder(t);if(!n)throw new Error(`No encoder found for format "${t}"`);let i=Date.now(),s=n.encode(e,r);if(r.performance.encodeTime=Date.now()-i,!s)throw new Error(`Encoder "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 L=class{constructor(){this.gpxDecoder=new k,this.gpxEncoder=new A,this.fitDecoder=new C,this.fitEncoder=new w,this.tcxDecoder=new _,this.tcxEncoder=new D,this.sportProcessor=new Xe}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 n=r||this.detectFormat(e);if(n==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(n===t)return e;let i;switch(n){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");i=o;break;case"fit":i=await this.parseFIT(e);break;case"tcx":i=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${n}`)}let s;switch(n){case"gpx":s=await this.convertGPXToSport(i);break;case"fit":s=await this.convertFITToSport(i);break;case"tcx":s=await this.convertTCXToSport(i);break;default:throw new Error(`Unsupported source file format conversion: ${n}`)}switch(t){case"gpx":let o=await this.convertSportToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertSportToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(n){let i=r||"auto-detect";throw new Error(`${i} to ${t.toUpperCase()} failed: ${n.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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return n;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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return this.convertGPXToSport(n);case"fit":let i=await this.parseFIT(e);return this.convertFITToSport(i);case"tcx":let s=await this.parseTCX(e);return this.convertTCXToSport(s);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 bt=L;0&&(module.exports={AbstractSourceConverter,ActivityConverter,ActivityLapConverter,ActivityListConverter,AstGenerateProcessor,BaseFITMessageConverter,BaseFITMiddleware,BaseFITStructurePlugin,BaseTCXConverter,BaseTCXMiddleware,CompleteProcessor,ConvertProcessor,CourseStructurePlugin,ExtensionsConverter,FITDecoder,FITEncoder,FileHeaderPlugin,GPXDecoder,GPXEncoder,MultiSportSessionConverter,PipelineStage,PositionConverter,SessionStructurePlugin,TCXDecoder,TCXEncoder,TCXEnhancementMiddleware,TCXPerformanceMiddleware,TCXPipelineStage,TCXValidationMiddleware,TokenizeProcessor,TrackConverter,TrackSwap,TrackpointConverter,registerDefaultMiddlewares,registerDefaultTCXMiddlewares});
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 n=this.buildExtensionContent(r);return`<${t}>${n}</${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,ze.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,n){if(r!=null&&r!==""){let i=n?n(r):this.escapeXML(r);e.push(`<${t}>${i}</${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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}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 Ee=class extends S{constructor(){super(...arguments);this.name="tcx-performance-middleware";this.description="Monitor TCX parsing performance"}async onTokenize(t,r){return t}async onAstGenerate(t,r){let n=this.countNodes(t);return t}async onComplete(t,r){let n=r.metadata.get("performance");return t}countNodes(t){let r=1;if(t.children)for(let n of t.children)r+=this.countNodes(n);return r}},Se=class extends S{constructor(){super(...arguments);this.name="tcx-validation-middleware";this.description="Validate TCX data integrity"}async onComplete(t,r){let n=this.validateTCX(t);return n.length>0&&r.metadata.set("validation-errors",n),t}validateTCX(t){let r=[];if(t.version||r.push("Missing TCX version information"),t.creator||r.push("Missing TCX creator information"),t.Activities&&t.Activities.Activity){for(let n of t.Activities.Activity)if(n.Id||r.push("Activity missing ID information"),(!n.Lap||n.Lap.length===0)&&r.push("Activity must contain at least one Lap"),n.Lap){for(let i of n.Lap)if(i.Track){for(let s of i.Track)if(s.Trackpoint)for(let o of s.Trackpoint)o.Position&&(!o.Position.LatitudeDegrees||!o.Position.LongitudeDegrees)&&r.push("Invalid trackpoint coordinates")}}}return r}},be=class extends S{constructor(){super(...arguments);this.name="tcx-enhancement-middleware";this.description="Enhance TCX data with additional calculated fields"}async onComplete(t,r){if(t.Activities&&t.Activities.Activity)for(let n of t.Activities.Activity)n.totalDistance=this.calculateTotalDistance(n),n.totalDuration=this.calculateTotalDuration(n),n.totalDistance&&n.totalDuration&&(n.averageSpeed=n.totalDistance/n.totalDuration);return t}calculateTotalDistance(t){let r=0;if(t.Lap)for(let n of t.Lap)n.DistanceMeters&&(r+=n.DistanceMeters);return r}calculateTotalDuration(t){let r=0;if(t.Lap)for(let n of t.Lap)n.TotalTimeSeconds&&(r+=n.TotalTimeSeconds);return r}};async function St(p){let e=[new Ee,new Se,new be];for(let t of e)await p.registerMiddleware(t)}var X=class extends x{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 n=e[r-1],i=e[r],s=6371e3,o=n.lat*Math.PI/180,a=i.lat*Math.PI/180,c=(i.lat-n.lat)*Math.PI/180,d=(i.lon-n.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(o)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),u=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=s*u}return t}calculateDuration(e){var n,i;if(e.length<2)return;let t=(n=e[0])==null?void 0:n.time,r=(i=e[e.length-1])==null?void 0:i.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},R=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 rt={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},Ue=p=>p*(180/Math.pow(2,31));var M=y(require("dayjs"));function nt(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var Ie=class extends X{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([n,i])=>{if(typeof i<"u"&&i!=="undefined"){let s=rt[n]||n;r[s]=this.autoNumber(i)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let n=r.sourceData;return this.convertGPX(n)}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(n=>{var i;return{name:n.name,trackseg:((i=n.trkseg)==null?void 0:i.map(s=>({name:n.name,points:s.trkpt?this.convertWpts2Points(s.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(n=>({name:n.name,points:n.rtept?this.convertWpts2Points(n.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null)return;let{extensions:r}=t,n=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,time:this.convertTime(t.time),...n}}convertWpts2Points(t){let r=[];for(let n=0;n<t.length;n++){let i=t[n];if(i.lat!=null&&i.lon!=null){let s=this.convertPoint(i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},Fe=class extends X{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let n=r.sourceData;return this.convertFIT(n)}convertFIT(t){var n,i;let r={metadata:{originType:"FIT",fileType:"fit"}};if((n=t.sessionMesgs)!=null&&n.length){r.tracks=[];for(let s of t.sessionMesgs)r.tracks.push({name:s.event,startTime:s.startTime?(0,M.default)(s.startTime).valueOf():void 0,distance:s.totalDistance,duration:s.totalElapsedTime,sport:s.sport,trackseg:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs),__fit__sessionMesgType:s})}else if((i=t.courseMesgs)!=null&&i.length){r.routes=[];for(let s of t.courseMesgs)r.routes.push({name:s.event,points:this.convertLap2Points(s==null?void 0:s.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:n,altitude:i,timestamp:s,heartRate:o,cadence:a,distance:c,power:d,enhancedAltitude:l,enhancedSpeed:u,temperature:f,...h}=t;if(!(r==null||n==null))return{lat:nt(Ue(Number(n)),6),lon:nt(Ue(Number(r)),6),ele:i,heartRate:o,power:d,cadence:a,temperature:f,time:s?(0,M.default)(s).valueOf():void 0,...h}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i==null?void 0:i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];r.push({points:s,duration:i.totalElapsedTime,distance:i.totalDistance,startTime:i.startTime?(0,M.default)(i.startTime).valueOf():void 0,endTime:i.startTime&&i.totalElapsedTime?(0,M.default)(i.startTime).add(i.totalElapsedTime,"second").valueOf():void 0,avgSpeed:i.avgSpeed,maxSpeed:i.maxSpeed,avgCadenceBpm:i.avgCadence,maxCadenceBpm:i.maxCadence,avgPower:i.avgPower,maxPower:i.maxPower,totalAscent:i.totalAscent,totalDescent:i.totalDescent,calories:i.totalCalories,__fit__lapMesgType:i})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];s.length&&(r=[...r,...s])}return r}},ke=class extends X{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let n=r.sourceData;return this.convertTCX(n)}convertTCX(t){var n,i,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((i=(n=t.Activities)==null?void 0:n.Activity)!=null&&i.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((o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.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:n,DistanceMeters:i,AltitudeMeters:s}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:n?(0,M.default)(n).valueOf():void 0,distance:i,ele:s}}convertLap2Trackseg(t){var n,i,s,o;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(u=>this.convertPoint(u)).filter(u=>u!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(n=d==null?void 0:d[0])==null?void 0:n.time,endTime:(i=d==null?void 0:d[d.length-1])==null?void 0:i.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:(s=a==null?void 0:a.Cadence)==null?void 0:s.Low,maxCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.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):[]}};var st=y(require("dayjs"));function it(p){return Math.round(p*(Math.pow(2,31)/180))}var Ae=class extends R{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var i,s,o,a,c,d,l;if(r.targetFormat!=="gpx")return;let n={version:"1.1",creator:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap",metadata:{name:(s=t==null?void 0:t.metadata)==null?void 0:s.fileName,time:(o=t==null?void 0:t.metadata)!=null&&o.date?(0,st.default)((a=t==null?void 0:t.metadata)==null?void 0:a.date).toDate():void 0}};return(c=t.points)!=null&&c.length&&(n.wpt=this.convertPoints2Wpts(t.points)),(d=t.routes)!=null&&d.length&&(n.rte=t.routes.map(u=>this.convertRoute2GPXRoute(u))),(l=t.tracks)!=null&&l.length&&(n.trk=t.tracks.map(u=>this.convertTrack2GPXTrack(u))),n}convertPoints2Wpts(t){return t==null?void 0:t.filter(r=>!!r.lat&&!!r.lon).map(r=>({lat:r.lat,lon:r.lon,ele:r==null?void 0:r.ele,time:r!=null&&r.time?this.convertTimeToDate(r.time):void 0,speed:r==null?void 0:r.speed,geoidheight:r==null?void 0:r.geoidheight,name:r==null?void 0:r.name,cmt:r==null?void 0:r.cmt,desc:r==null?void 0:r.desc,type:r==null?void 0:r.type,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,ageofdgpsdata:r==null?void 0:r.ageofdgpsdata,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,src:t==null?void 0:t.GPX_src,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,trkseg:((r=t.trackseg)==null?void 0:r.map(n=>{var i;return{trkpt:(i=n==null?void 0:n.points)!=null&&i.length?this.convertPoints2Wpts(n.points):[]}}))||[]}}extractGPXExtensions(t){let r={},n={};return typeof(t==null?void 0:t.heartRate)<"u"&&(n["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(n["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(n["gpxtpx:atemp"]=t.temperature),Object.keys(n).length>0&&(r["gpxtpx:TrackPointExtension"]=n),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},_e=class extends R{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var i,s,o;if(r.targetFormat!=="fit")return;let n={};return(i=t.tracks)!=null&&i.length&&(n.sessionMesgs=(s=t==null?void 0:t.tracks)==null?void 0:s.map(a=>this.convertTrack2FITSession(a))),(o=t.routes)!=null&&o.length&&(n.courseMesgs=t.routes.map(a=>this.convertRoute2FITCourse(a))),n}convertTrack2FITSession(t){var n;return{event:(t==null?void 0:t.name)||"session",sport:(t==null?void 0:t.sport)||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2FITLap(i)))||[]}}convertSeg2FITLap(t){var n;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:((n=t.points)==null?void 0:n.map(i=>this.convertPoint2FITRecord(i)))||[]}}convertPoint2FITRecord(t){return{timestamp:t.time?this.convertTimeToString(t.time):this.convertTimeToString(void 0),positionLat:it(t.lat),positionLong:it(t.lon),altitude:t.ele,speed:t.speed,power:t.power,heartRate:t.heartRate,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],n=t[t.length-1],i=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),s=r!=null&&r.time&&(n!=null&&n.time)?Math.round((n.time-r.time)/1e3):0,o=(n==null?void 0:n.distance)||0;return{startTime:i,totalElapsedTime:s,totalDistance:o,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},De=class extends R{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var i,s,o;if(r.targetFormat!=="tcx")return;let n={Author:{Name:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap"}};return(s=t.tracks)!=null&&s.length&&(n.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(o=t.routes)!=null&&o.length&&(n.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),n}convertTrack2TCXActivity(t){var n;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2TCXLap(i)))||[]}}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.heartRate&&(r.HeartRateBpm=t.heartRate),r}convertRoute2TCXCourse(t){return{Name:t.name||`Course_${Date.now()}`,Track:t.points?[this.convertPoints2TCXTrack(t.points)]:[]}}};var Xe=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new Ie),this.registerConverter(new Fe),this.registerConverter(new ke)}registerDefaultEncoders(){this.registerEncoder(new Ae),this.registerEncoder(new _e),this.registerEncoder(new De)}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 n=this.findConverter(t);if(!n)throw new Error(`No converter found for format "${t}"`);let i=Date.now(),s=n.convert({},r);if(r.performance.convertTime=Date.now()-i,!s)throw new Error(`Converter "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 n=this.findEncoder(t);if(!n)throw new Error(`No encoder found for format "${t}"`);let i=Date.now(),s=n.encode(e,r);if(r.performance.encodeTime=Date.now()-i,!s)throw new Error(`Encoder "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 L=class{constructor(){this.gpxDecoder=new k,this.gpxEncoder=new A,this.fitDecoder=new C,this.fitEncoder=new w,this.tcxDecoder=new _,this.tcxEncoder=new D,this.sportProcessor=new Xe}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 n=r||this.detectFormat(e);if(n==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(n===t)return e;let i;switch(n){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");i=o;break;case"fit":i=await this.parseFIT(e);break;case"tcx":i=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${n}`)}let s;switch(n){case"gpx":s=await this.convertGPXToSport(i);break;case"fit":s=await this.convertFITToSport(i);break;case"tcx":s=await this.convertTCXToSport(i);break;default:throw new Error(`Unsupported source file format conversion: ${n}`)}switch(t){case"gpx":let o=await this.convertSportToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertSportToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(n){let i=r||"auto-detect";throw new Error(`${i} to ${t.toUpperCase()} failed: ${n.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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return n;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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return this.convertGPXToSport(n);case"fit":let i=await this.parseFIT(e);return this.convertFITToSport(i);case"tcx":let s=await this.parseTCX(e);return this.convertTCXToSport(s);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 bt=L;0&&(module.exports={AbstractSourceConverter,ActivityConverter,ActivityLapConverter,ActivityListConverter,AstGenerateProcessor,BaseFITMessageConverter,BaseFITMiddleware,BaseFITStructurePlugin,BaseTCXConverter,BaseTCXMiddleware,CompleteProcessor,ConvertProcessor,CourseStructurePlugin,ExtensionsConverter,FITDecoder,FITEncoder,FileHeaderPlugin,GPXDecoder,GPXEncoder,MultiSportSessionConverter,PipelineStage,PositionConverter,SessionStructurePlugin,TCXDecoder,TCXEncoder,TCXEnhancementMiddleware,TCXPerformanceMiddleware,TCXPipelineStage,TCXValidationMiddleware,TokenizeProcessor,TrackConverter,TrackSwap,TrackpointConverter,registerDefaultMiddlewares,registerDefaultTCXMiddlewares});
package/dist/index.js CHANGED
@@ -23,4 +23,4 @@ var G=class{constructor(){this.stage="parse"}async process(e){let t=Date.now();i
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 n=this.buildExtensionContent(r);return`<${t}>${n}</${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:Ke(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,n){if(r!=null&&r!==""){let i=n?n(r):this.escapeXML(r);e.push(`<${t}>${i}</${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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}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 Me=class extends E{constructor(){super(...arguments);this.name="tcx-performance-middleware";this.description="Monitor TCX parsing performance"}async onTokenize(t,r){return t}async onAstGenerate(t,r){let n=this.countNodes(t);return t}async onComplete(t,r){let n=r.metadata.get("performance");return t}countNodes(t){let r=1;if(t.children)for(let n of t.children)r+=this.countNodes(n);return r}},Le=class extends E{constructor(){super(...arguments);this.name="tcx-validation-middleware";this.description="Validate TCX data integrity"}async onComplete(t,r){let n=this.validateTCX(t);return n.length>0&&r.metadata.set("validation-errors",n),t}validateTCX(t){let r=[];if(t.version||r.push("Missing TCX version information"),t.creator||r.push("Missing TCX creator information"),t.Activities&&t.Activities.Activity){for(let n of t.Activities.Activity)if(n.Id||r.push("Activity missing ID information"),(!n.Lap||n.Lap.length===0)&&r.push("Activity must contain at least one Lap"),n.Lap){for(let i of n.Lap)if(i.Track){for(let s of i.Track)if(s.Trackpoint)for(let o of s.Trackpoint)o.Position&&(!o.Position.LatitudeDegrees||!o.Position.LongitudeDegrees)&&r.push("Invalid trackpoint coordinates")}}}return r}},Oe=class extends E{constructor(){super(...arguments);this.name="tcx-enhancement-middleware";this.description="Enhance TCX data with additional calculated fields"}async onComplete(t,r){if(t.Activities&&t.Activities.Activity)for(let n of t.Activities.Activity)n.totalDistance=this.calculateTotalDistance(n),n.totalDuration=this.calculateTotalDuration(n),n.totalDistance&&n.totalDuration&&(n.averageSpeed=n.totalDistance/n.totalDuration);return t}calculateTotalDistance(t){let r=0;if(t.Lap)for(let n of t.Lap)n.DistanceMeters&&(r+=n.DistanceMeters);return r}calculateTotalDuration(t){let r=0;if(t.Lap)for(let n of t.Lap)n.TotalTimeSeconds&&(r+=n.TotalTimeSeconds);return r}};async function Br(p){let e=[new Me,new Le,new Oe];for(let t of e)await p.registerMiddleware(t)}var S=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 n=e[r-1],i=e[r],s=6371e3,o=n.lat*Math.PI/180,a=i.lat*Math.PI/180,c=(i.lat-n.lat)*Math.PI/180,d=(i.lon-n.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(o)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),u=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=s*u}return t}calculateDuration(e){var n,i;if(e.length<2)return;let t=(n=e[0])==null?void 0:n.time,r=(i=e[e.length-1])==null?void 0:i.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},b=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={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},$e=p=>p*(180/Math.pow(2,31));import L from"dayjs";function Ne(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ve=class extends S{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([n,i])=>{if(typeof i<"u"&&i!=="undefined"){let s=Ye[n]||n;r[s]=this.autoNumber(i)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let n=r.sourceData;return this.convertGPX(n)}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(n=>{var i;return{name:n.name,trackseg:((i=n.trkseg)==null?void 0:i.map(s=>({name:n.name,points:s.trkpt?this.convertWpts2Points(s.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(n=>({name:n.name,points:n.rtept?this.convertWpts2Points(n.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null)return;let{extensions:r}=t,n=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,time:this.convertTime(t.time),...n}}convertWpts2Points(t){let r=[];for(let n=0;n<t.length;n++){let i=t[n];if(i.lat!=null&&i.lon!=null){let s=this.convertPoint(i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},xe=class extends S{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let n=r.sourceData;return this.convertFIT(n)}convertFIT(t){var n,i;let r={metadata:{originType:"FIT",fileType:"fit"}};if((n=t.sessionMesgs)!=null&&n.length){r.tracks=[];for(let s of t.sessionMesgs)r.tracks.push({name:s.event,startTime:s.startTime?L(s.startTime).valueOf():void 0,distance:s.totalDistance,duration:s.totalElapsedTime,sport:s.sport,trackseg:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs),__fit__sessionMesgType:s})}else if((i=t.courseMesgs)!=null&&i.length){r.routes=[];for(let s of t.courseMesgs)r.routes.push({name:s.event,points:this.convertLap2Points(s==null?void 0:s.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:n,altitude:i,timestamp:s,heartRate:o,cadence:a,distance:c,power:d,enhancedAltitude:l,enhancedSpeed:u,temperature:T,...g}=t;if(!(r==null||n==null))return{lat:Ne($e(Number(n)),6),lon:Ne($e(Number(r)),6),ele:i,heartRate:o,power:d,cadence:a,temperature:T,time:s?L(s).valueOf():void 0,...g}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i==null?void 0:i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];r.push({points:s,duration:i.totalElapsedTime,distance:i.totalDistance,startTime:i.startTime?L(i.startTime).valueOf():void 0,endTime:i.startTime&&i.totalElapsedTime?L(i.startTime).add(i.totalElapsedTime,"second").valueOf():void 0,avgSpeed:i.avgSpeed,maxSpeed:i.maxSpeed,avgCadenceBpm:i.avgCadence,maxCadenceBpm:i.maxCadence,avgPower:i.avgPower,maxPower:i.maxPower,totalAscent:i.totalAscent,totalDescent:i.totalDescent,calories:i.totalCalories,__fit__lapMesgType:i})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];s.length&&(r=[...r,...s])}return r}},Ce=class extends S{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let n=r.sourceData;return this.convertTCX(n)}convertTCX(t){var n,i,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((i=(n=t.Activities)==null?void 0:n.Activity)!=null&&i.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((o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.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:n,DistanceMeters:i,AltitudeMeters:s}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:n?L(n).valueOf():void 0,distance:i,ele:s}}convertLap2Trackseg(t){var n,i,s,o;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(u=>this.convertPoint(u)).filter(u=>u!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(n=d==null?void 0:d[0])==null?void 0:n.time,endTime:(i=d==null?void 0:d[d.length-1])==null?void 0:i.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:(s=a==null?void 0:a.Cadence)==null?void 0:s.Low,maxCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.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):[]}};import Tt from"dayjs";function Ze(p){return Math.round(p*(Math.pow(2,31)/180))}var Pe=class extends b{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var i,s,o,a,c,d,l;if(r.targetFormat!=="gpx")return;let n={version:"1.1",creator:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap",metadata:{name:(s=t==null?void 0:t.metadata)==null?void 0:s.fileName,time:(o=t==null?void 0:t.metadata)!=null&&o.date?Tt((a=t==null?void 0:t.metadata)==null?void 0:a.date).toDate():void 0}};return(c=t.points)!=null&&c.length&&(n.wpt=this.convertPoints2Wpts(t.points)),(d=t.routes)!=null&&d.length&&(n.rte=t.routes.map(u=>this.convertRoute2GPXRoute(u))),(l=t.tracks)!=null&&l.length&&(n.trk=t.tracks.map(u=>this.convertTrack2GPXTrack(u))),n}convertPoints2Wpts(t){return t==null?void 0:t.filter(r=>!!r.lat&&!!r.lon).map(r=>({lat:r.lat,lon:r.lon,ele:r==null?void 0:r.ele,time:r!=null&&r.time?this.convertTimeToDate(r.time):void 0,speed:r==null?void 0:r.speed,geoidheight:r==null?void 0:r.geoidheight,name:r==null?void 0:r.name,cmt:r==null?void 0:r.cmt,desc:r==null?void 0:r.desc,type:r==null?void 0:r.type,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,ageofdgpsdata:r==null?void 0:r.ageofdgpsdata,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,src:t==null?void 0:t.GPX_src,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,trkseg:((r=t.trackseg)==null?void 0:r.map(n=>{var i;return{trkpt:(i=n==null?void 0:n.points)!=null&&i.length?this.convertPoints2Wpts(n.points):[]}}))||[]}}extractGPXExtensions(t){let r={};return typeof(t==null?void 0:t.heartRate)<"u"&&(r["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(r["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(r["gpxtpx:atemp"]=t.temperature),typeof(t==null?void 0:t.power)<"u"&&(r.extractGPXExtensions=t.power),Object.keys(r).length>0?r:void 0}},we=class extends b{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var i,s,o;if(r.targetFormat!=="fit")return;let n={};return(i=t.tracks)!=null&&i.length&&(n.sessionMesgs=(s=t==null?void 0:t.tracks)==null?void 0:s.map(a=>this.convertTrack2FITSession(a))),(o=t.routes)!=null&&o.length&&(n.courseMesgs=t.routes.map(a=>this.convertRoute2FITCourse(a))),n}convertTrack2FITSession(t){var n;return{event:(t==null?void 0:t.name)||"session",sport:(t==null?void 0:t.sport)||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2FITLap(i)))||[]}}convertSeg2FITLap(t){var n;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:((n=t.points)==null?void 0:n.map(i=>this.convertPoint2FITRecord(i)))||[]}}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.heartRate,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],n=t[t.length-1],i=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),s=r!=null&&r.time&&(n!=null&&n.time)?Math.round((n.time-r.time)/1e3):0,o=(n==null?void 0:n.distance)||0;return{startTime:i,totalElapsedTime:s,totalDistance:o,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},Ee=class extends b{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var i,s,o;if(r.targetFormat!=="tcx")return;let n={Author:{Name:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap"}};return(s=t.tracks)!=null&&s.length&&(n.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(o=t.routes)!=null&&o.length&&(n.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),n}convertTrack2TCXActivity(t){var n;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2TCXLap(i)))||[]}}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.heartRate&&(r.HeartRateBpm=t.heartRate),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 we),this.registerEncoder(new Ee)}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 n=this.findConverter(t);if(!n)throw new Error(`No converter found for format "${t}"`);let i=Date.now(),s=n.convert({},r);if(r.performance.convertTime=Date.now()-i,!s)throw new Error(`Converter "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 n=this.findEncoder(t);if(!n)throw new Error(`No encoder found for format "${t}"`);let i=Date.now(),s=n.encode(e,r);if(r.performance.encodeTime=Date.now()-i,!s)throw new Error(`Encoder "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 D,this.gpxEncoder=new X,this.fitDecoder=new P,this.fitEncoder=new w,this.tcxDecoder=new R,this.tcxEncoder=new M,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 n=r||this.detectFormat(e);if(n==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(n===t)return e;let i;switch(n){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");i=o;break;case"fit":i=await this.parseFIT(e);break;case"tcx":i=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${n}`)}let s;switch(n){case"gpx":s=await this.convertGPXToSport(i);break;case"fit":s=await this.convertFITToSport(i);break;case"tcx":s=await this.convertTCXToSport(i);break;default:throw new Error(`Unsupported source file format conversion: ${n}`)}switch(t){case"gpx":let o=await this.convertSportToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertSportToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(n){let i=r||"auto-detect";throw new Error(`${i} to ${t.toUpperCase()} failed: ${n.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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return n;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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return this.convertGPXToSport(n);case"fit":let i=await this.parseFIT(e);return this.convertFITToSport(i);case"tcx":let s=await this.parseTCX(e);return this.convertTCXToSport(s);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 Pn=O;export{ue as AbstractSourceConverter,ce as ActivityConverter,pe as ActivityLapConverter,de as ActivityListConverter,ge as AstGenerateProcessor,be as BaseFITMessageConverter,Ie as BaseFITMiddleware,v as BaseFITStructurePlugin,f as BaseTCXConverter,E as BaseTCXMiddleware,ye as CompleteProcessor,he as ConvertProcessor,k as CourseStructurePlugin,me as ExtensionsConverter,P as FITDecoder,w as FITEncoder,A as FileHeaderPlugin,D as GPXDecoder,X as GPXEncoder,le as MultiSportSessionConverter,Ae as PipelineStage,se as PositionConverter,F as SessionStructurePlugin,R as TCXDecoder,M as TCXEncoder,Oe as TCXEnhancementMiddleware,Me as TCXPerformanceMiddleware,je as TCXPipelineStage,Le as TCXValidationMiddleware,fe as TokenizeProcessor,ae as TrackConverter,O as TrackSwap,oe as TrackpointConverter,Pn as default,ut as registerDefaultMiddlewares,Br as registerDefaultTCXMiddlewares};
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 n=this.buildExtensionContent(r);return`<${t}>${n}</${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:Ke(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,n){if(r!=null&&r!==""){let i=n?n(r):this.escapeXML(r);e.push(`<${t}>${i}</${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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}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 Me=class extends E{constructor(){super(...arguments);this.name="tcx-performance-middleware";this.description="Monitor TCX parsing performance"}async onTokenize(t,r){return t}async onAstGenerate(t,r){let n=this.countNodes(t);return t}async onComplete(t,r){let n=r.metadata.get("performance");return t}countNodes(t){let r=1;if(t.children)for(let n of t.children)r+=this.countNodes(n);return r}},Le=class extends E{constructor(){super(...arguments);this.name="tcx-validation-middleware";this.description="Validate TCX data integrity"}async onComplete(t,r){let n=this.validateTCX(t);return n.length>0&&r.metadata.set("validation-errors",n),t}validateTCX(t){let r=[];if(t.version||r.push("Missing TCX version information"),t.creator||r.push("Missing TCX creator information"),t.Activities&&t.Activities.Activity){for(let n of t.Activities.Activity)if(n.Id||r.push("Activity missing ID information"),(!n.Lap||n.Lap.length===0)&&r.push("Activity must contain at least one Lap"),n.Lap){for(let i of n.Lap)if(i.Track){for(let s of i.Track)if(s.Trackpoint)for(let o of s.Trackpoint)o.Position&&(!o.Position.LatitudeDegrees||!o.Position.LongitudeDegrees)&&r.push("Invalid trackpoint coordinates")}}}return r}},Oe=class extends E{constructor(){super(...arguments);this.name="tcx-enhancement-middleware";this.description="Enhance TCX data with additional calculated fields"}async onComplete(t,r){if(t.Activities&&t.Activities.Activity)for(let n of t.Activities.Activity)n.totalDistance=this.calculateTotalDistance(n),n.totalDuration=this.calculateTotalDuration(n),n.totalDistance&&n.totalDuration&&(n.averageSpeed=n.totalDistance/n.totalDuration);return t}calculateTotalDistance(t){let r=0;if(t.Lap)for(let n of t.Lap)n.DistanceMeters&&(r+=n.DistanceMeters);return r}calculateTotalDuration(t){let r=0;if(t.Lap)for(let n of t.Lap)n.TotalTimeSeconds&&(r+=n.TotalTimeSeconds);return r}};async function Br(p){let e=[new Me,new Le,new Oe];for(let t of e)await p.registerMiddleware(t)}var S=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 n=e[r-1],i=e[r],s=6371e3,o=n.lat*Math.PI/180,a=i.lat*Math.PI/180,c=(i.lat-n.lat)*Math.PI/180,d=(i.lon-n.lon)*Math.PI/180,l=Math.sin(c/2)*Math.sin(c/2)+Math.cos(o)*Math.cos(a)*Math.sin(d/2)*Math.sin(d/2),u=2*Math.atan2(Math.sqrt(l),Math.sqrt(1-l));t+=s*u}return t}calculateDuration(e){var n,i;if(e.length<2)return;let t=(n=e[0])==null?void 0:n.time,r=(i=e[e.length-1])==null?void 0:i.time;if(!(!t||!r))return Math.round((r-t)/1e3)}},b=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={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},$e=p=>p*(180/Math.pow(2,31));import L from"dayjs";function Ne(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var ve=class extends S{constructor(){super(...arguments);this.name="gpx-to-sport-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([n,i])=>{if(typeof i<"u"&&i!=="undefined"){let s=Ye[n]||n;r[s]=this.autoNumber(i)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let n=r.sourceData;return this.convertGPX(n)}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(n=>{var i;return{name:n.name,trackseg:((i=n.trkseg)==null?void 0:i.map(s=>({name:n.name,points:s.trkpt?this.convertWpts2Points(s.trkpt):[]})))||[]}})),t.rte&&(r.routes=t.rte.map(n=>({name:n.name,points:n.rtept?this.convertWpts2Points(n.rtept):[]}))),r}convertPoint(t){if(t.lat==null||t.lon==null)return;let{extensions:r}=t,n=r?this.convertGPXExtensions(r):{};return{lat:t.lat,lon:t.lon,ele:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,time:this.convertTime(t.time),...n}}convertWpts2Points(t){let r=[];for(let n=0;n<t.length;n++){let i=t[n];if(i.lat!=null&&i.lon!=null){let s=this.convertPoint(i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},xe=class extends S{constructor(){super(...arguments);this.name="fit-to-sport-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let n=r.sourceData;return this.convertFIT(n)}convertFIT(t){var n,i;let r={metadata:{originType:"FIT",fileType:"fit"}};if((n=t.sessionMesgs)!=null&&n.length){r.tracks=[];for(let s of t.sessionMesgs)r.tracks.push({name:s.event,startTime:s.startTime?L(s.startTime).valueOf():void 0,distance:s.totalDistance,duration:s.totalElapsedTime,sport:s.sport,trackseg:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs),__fit__sessionMesgType:s})}else if((i=t.courseMesgs)!=null&&i.length){r.routes=[];for(let s of t.courseMesgs)r.routes.push({name:s.event,points:this.convertLap2Points(s==null?void 0:s.lapMesgs)})}return r}convertPoint(t){let{positionLong:r,positionLat:n,altitude:i,timestamp:s,heartRate:o,cadence:a,distance:c,power:d,enhancedAltitude:l,enhancedSpeed:u,temperature:T,...g}=t;if(!(r==null||n==null))return{lat:Ne($e(Number(n)),6),lon:Ne($e(Number(r)),6),ele:i,heartRate:o,power:d,cadence:a,temperature:T,time:s?L(s).valueOf():void 0,...g}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i==null?void 0:i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];r.push({points:s,duration:i.totalElapsedTime,distance:i.totalDistance,startTime:i.startTime?L(i.startTime).valueOf():void 0,endTime:i.startTime&&i.totalElapsedTime?L(i.startTime).add(i.totalElapsedTime,"second").valueOf():void 0,avgSpeed:i.avgSpeed,maxSpeed:i.maxSpeed,avgCadenceBpm:i.avgCadence,maxCadenceBpm:i.maxCadence,avgPower:i.avgPower,maxPower:i.maxPower,totalAscent:i.totalAscent,totalDescent:i.totalDescent,calories:i.totalCalories,__fit__lapMesgType:i})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let i of t){let s=((n=i.recordMesgs)==null?void 0:n.map(o=>this.convertPoint(o)).filter(o=>o!==void 0))||[];s.length&&(r=[...r,...s])}return r}},Ce=class extends S{constructor(){super(...arguments);this.name="tcx-to-sport-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let n=r.sourceData;return this.convertTCX(n)}convertTCX(t){var n,i,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"}};if((i=(n=t.Activities)==null?void 0:n.Activity)!=null&&i.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((o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.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:n,DistanceMeters:i,AltitudeMeters:s}=t;if(!(!(r!=null&&r.LatitudeDegrees)||!(r!=null&&r.LongitudeDegrees)||r.LatitudeDegrees===""||r.LongitudeDegrees===""))return{lat:Number(r.LatitudeDegrees),lon:Number(r.LongitudeDegrees),time:n?L(n).valueOf():void 0,distance:i,ele:s}}convertLap2Trackseg(t){var n,i,s,o;let r=[];for(let a of t)if(a.Track){for(let c of a.Track)if(c.Trackpoint){let d=c.Trackpoint.map(u=>this.convertPoint(u)).filter(u=>u!==void 0),l={duration:a.TotalTimeSeconds,distance:a.DistanceMeters,startTime:(n=d==null?void 0:d[0])==null?void 0:n.time,endTime:(i=d==null?void 0:d[d.length-1])==null?void 0:i.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:(s=a==null?void 0:a.Cadence)==null?void 0:s.Low,maxCadenceBpm:(o=a==null?void 0:a.Cadence)==null?void 0:o.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):[]}};import Tt from"dayjs";function Ze(p){return Math.round(p*(Math.pow(2,31)/180))}var Pe=class extends b{constructor(){super(...arguments);this.name="sport-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var i,s,o,a,c,d,l;if(r.targetFormat!=="gpx")return;let n={version:"1.1",creator:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap",metadata:{name:(s=t==null?void 0:t.metadata)==null?void 0:s.fileName,time:(o=t==null?void 0:t.metadata)!=null&&o.date?Tt((a=t==null?void 0:t.metadata)==null?void 0:a.date).toDate():void 0}};return(c=t.points)!=null&&c.length&&(n.wpt=this.convertPoints2Wpts(t.points)),(d=t.routes)!=null&&d.length&&(n.rte=t.routes.map(u=>this.convertRoute2GPXRoute(u))),(l=t.tracks)!=null&&l.length&&(n.trk=t.tracks.map(u=>this.convertTrack2GPXTrack(u))),n}convertPoints2Wpts(t){return t==null?void 0:t.filter(r=>!!r.lat&&!!r.lon).map(r=>({lat:r.lat,lon:r.lon,ele:r==null?void 0:r.ele,time:r!=null&&r.time?this.convertTimeToDate(r.time):void 0,speed:r==null?void 0:r.speed,geoidheight:r==null?void 0:r.geoidheight,name:r==null?void 0:r.name,cmt:r==null?void 0:r.cmt,desc:r==null?void 0:r.desc,type:r==null?void 0:r.type,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,ageofdgpsdata:r==null?void 0:r.ageofdgpsdata,magvar:r.magvar,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,rtept:t.points?this.convertPoints2Wpts(t.points):[]}}convertTrack2GPXTrack(t){var r;return{name:t==null?void 0:t.name,cmt:t==null?void 0:t.GPX_cmt,desc:t==null?void 0:t.GPX_desc,src:t==null?void 0:t.GPX_src,number:t==null?void 0:t.GPX_number,type:t==null?void 0:t.GPX_type,trkseg:((r=t.trackseg)==null?void 0:r.map(n=>{var i;return{trkpt:(i=n==null?void 0:n.points)!=null&&i.length?this.convertPoints2Wpts(n.points):[]}}))||[]}}extractGPXExtensions(t){let r={},n={};return typeof(t==null?void 0:t.heartRate)<"u"&&(n["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(n["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(n["gpxtpx:atemp"]=t.temperature),Object.keys(n).length>0&&(r["gpxtpx:TrackPointExtension"]=n),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},we=class extends b{constructor(){super(...arguments);this.name="sport-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var i,s,o;if(r.targetFormat!=="fit")return;let n={};return(i=t.tracks)!=null&&i.length&&(n.sessionMesgs=(s=t==null?void 0:t.tracks)==null?void 0:s.map(a=>this.convertTrack2FITSession(a))),(o=t.routes)!=null&&o.length&&(n.courseMesgs=t.routes.map(a=>this.convertRoute2FITCourse(a))),n}convertTrack2FITSession(t){var n;return{event:(t==null?void 0:t.name)||"session",sport:(t==null?void 0:t.sport)||"generic",startTime:t.startTime?this.convertTimeToString(t.startTime):this.convertTimeToString(void 0),totalDistance:t.distance,totalElapsedTime:t.duration,lapMesgs:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2FITLap(i)))||[]}}convertSeg2FITLap(t){var n;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:((n=t.points)==null?void 0:n.map(i=>this.convertPoint2FITRecord(i)))||[]}}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.heartRate,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],n=t[t.length-1],i=r!=null&&r.time?this.convertTimeToString(r.time):this.convertTimeToString(void 0),s=r!=null&&r.time&&(n!=null&&n.time)?Math.round((n.time-r.time)/1e3):0,o=(n==null?void 0:n.distance)||0;return{startTime:i,totalElapsedTime:s,totalDistance:o,recordMesgs:t.map(a=>this.convertPoint2FITRecord(a))}}},Ee=class extends b{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var i,s,o;if(r.targetFormat!=="tcx")return;let n={Author:{Name:((i=t.metadata)==null?void 0:i.creator)||"TrackSwap"}};return(s=t.tracks)!=null&&s.length&&(n.Activities={Activity:t.tracks.map(a=>this.convertTrack2TCXActivity(a))}),(o=t.routes)!=null&&o.length&&(n.Courses={Course:t.routes.map(a=>this.convertRoute2TCXCourse(a))}),n}convertTrack2TCXActivity(t){var n;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:t.name||`Activity_${Date.now()}`,Sport:r,Lap:((n=t.trackseg)==null?void 0:n.map(i=>this.convertSeg2TCXLap(i)))||[]}}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.heartRate&&(r.HeartRateBpm=t.heartRate),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 we),this.registerEncoder(new Ee)}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 n=this.findConverter(t);if(!n)throw new Error(`No converter found for format "${t}"`);let i=Date.now(),s=n.convert({},r);if(r.performance.convertTime=Date.now()-i,!s)throw new Error(`Converter "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 n=this.findEncoder(t);if(!n)throw new Error(`No encoder found for format "${t}"`);let i=Date.now(),s=n.encode(e,r);if(r.performance.encodeTime=Date.now()-i,!s)throw new Error(`Encoder "${n.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(n){throw r.errors.push(n),n}}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 D,this.gpxEncoder=new X,this.fitDecoder=new P,this.fitEncoder=new w,this.tcxDecoder=new R,this.tcxEncoder=new M,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 n=r||this.detectFormat(e);if(n==="unknown")throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(n===t)return e;let i;switch(n){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");i=o;break;case"fit":i=await this.parseFIT(e);break;case"tcx":i=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${n}`)}let s;switch(n){case"gpx":s=await this.convertGPXToSport(i);break;case"fit":s=await this.convertFITToSport(i);break;case"tcx":s=await this.convertTCXToSport(i);break;default:throw new Error(`Unsupported source file format conversion: ${n}`)}switch(t){case"gpx":let o=await this.convertSportToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertSportToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertSportToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(n){let i=r||"auto-detect";throw new Error(`${i} to ${t.toUpperCase()} failed: ${n.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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return n;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 n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");return this.convertGPXToSport(n);case"fit":let i=await this.parseFIT(e);return this.convertFITToSport(i);case"tcx":let s=await this.parseTCX(e);return this.convertTCXToSport(s);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 Pn=O;export{ue as AbstractSourceConverter,ce as ActivityConverter,pe as ActivityLapConverter,de as ActivityListConverter,ge as AstGenerateProcessor,be as BaseFITMessageConverter,Ie as BaseFITMiddleware,v as BaseFITStructurePlugin,f as BaseTCXConverter,E as BaseTCXMiddleware,ye as CompleteProcessor,he as ConvertProcessor,k as CourseStructurePlugin,me as ExtensionsConverter,P as FITDecoder,w as FITEncoder,A as FileHeaderPlugin,D as GPXDecoder,X as GPXEncoder,le as MultiSportSessionConverter,Ae as PipelineStage,se as PositionConverter,F as SessionStructurePlugin,R as TCXDecoder,M as TCXEncoder,Oe as TCXEnhancementMiddleware,Me as TCXPerformanceMiddleware,je as TCXPipelineStage,Le as TCXValidationMiddleware,fe as TokenizeProcessor,ae as TrackConverter,O as TrackSwap,oe as TrackpointConverter,Pn as default,ut as registerDefaultMiddlewares,Br as registerDefaultTCXMiddlewares};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trackswap",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
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",