Add Zwift XML generation
This commit is contained in:
parent
cb8cb10a51
commit
5c34c7c167
|
|
@ -0,0 +1,71 @@
|
||||||
|
import * as xml from "xml";
|
||||||
|
import { Interval, Workout } from "./ast";
|
||||||
|
|
||||||
|
// Zwift Workout XML generator
|
||||||
|
|
||||||
|
const generateRangeInterval = (
|
||||||
|
tagName: "Warmup" | "Cooldown",
|
||||||
|
{ duration, intensity, cadence }: Interval
|
||||||
|
): xml.XmlObject => {
|
||||||
|
return {
|
||||||
|
[tagName]: [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
Duration: duration,
|
||||||
|
PowerLow: intensity.from,
|
||||||
|
PowerHigh: intensity.from,
|
||||||
|
...(cadence ? { Cadence: cadence } : {}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateSteadyStateInterval = ({
|
||||||
|
duration,
|
||||||
|
intensity,
|
||||||
|
cadence,
|
||||||
|
}: Interval): xml.XmlObject => {
|
||||||
|
return {
|
||||||
|
SteadyState: [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
Duration: duration,
|
||||||
|
Power: intensity.from,
|
||||||
|
...(cadence ? { Cadence: cadence } : {}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateInterval = (interval: Interval): xml.XmlObject => {
|
||||||
|
const { intensity } = interval;
|
||||||
|
if (intensity.from < intensity.to) {
|
||||||
|
return generateRangeInterval("Warmup", interval);
|
||||||
|
} else if (intensity.from > intensity.to) {
|
||||||
|
return generateRangeInterval("Cooldown", interval);
|
||||||
|
} else {
|
||||||
|
return generateSteadyStateInterval(interval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateZwo = ({
|
||||||
|
name,
|
||||||
|
author,
|
||||||
|
description,
|
||||||
|
intervals,
|
||||||
|
}: Workout): string => {
|
||||||
|
return xml(
|
||||||
|
{
|
||||||
|
workout_file: [
|
||||||
|
{ name: name },
|
||||||
|
{ author: author },
|
||||||
|
{ description: description },
|
||||||
|
{ sportType: "bike" },
|
||||||
|
...intervals.map(generateInterval),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ indent: " " }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { averageIntensity } from "./averageIntensity";
|
import { averageIntensity } from "./averageIntensity";
|
||||||
|
import { generateZwo } from "./generateZwo";
|
||||||
import { normalizedIntensity } from "./normalizedIntensity";
|
import { normalizedIntensity } from "./normalizedIntensity";
|
||||||
import { parse } from "./parser";
|
import { parse } from "./parser";
|
||||||
import { tokenize } from "./tokenizer";
|
import { tokenize } from "./tokenizer";
|
||||||
|
|
@ -13,7 +14,8 @@ console.log(`Parsing: ${filename}`);
|
||||||
|
|
||||||
const file = fs.readFileSync(filename, "utf8");
|
const file = fs.readFileSync(filename, "utf8");
|
||||||
|
|
||||||
const { intervals } = parse(tokenize(file));
|
const workout = parse(tokenize(file));
|
||||||
|
const { intervals } = workout;
|
||||||
|
|
||||||
const duration = totalDuration(intervals);
|
const duration = totalDuration(intervals);
|
||||||
const avgIntensity = averageIntensity(intervals);
|
const avgIntensity = averageIntensity(intervals);
|
||||||
|
|
@ -30,3 +32,5 @@ Normalized intensity: ${(normIntensity * 100).toFixed()}%
|
||||||
TSS #1: ${tss(intervals).toFixed()}
|
TSS #1: ${tss(intervals).toFixed()}
|
||||||
TSS #2: ${tss2(duration, normIntensity).toFixed()}
|
TSS #2: ${tss2(duration, normIntensity).toFixed()}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
console.log(generateZwo(workout));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue