Parsing of interval parameters
This commit is contained in:
parent
2a362e6362
commit
04467b944f
|
|
@ -1,3 +1,5 @@
|
|||
import { IntervalLabelTokenValue } from "./tokenizer";
|
||||
|
||||
export type Workout = {
|
||||
name: string;
|
||||
author: string;
|
||||
|
|
@ -5,9 +7,12 @@ export type Workout = {
|
|||
intervals: Interval[];
|
||||
};
|
||||
|
||||
export type Interval = {
|
||||
type: "Warmup" | "Cooldown" | "Interval" | "Rest";
|
||||
export type IntervalData = {
|
||||
duration: number;
|
||||
power: { from: number; to: number };
|
||||
cadence?: number;
|
||||
};
|
||||
|
||||
export type Interval = IntervalData & {
|
||||
type: IntervalLabelTokenValue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Interval, Workout } from "./ast";
|
||||
import { LabelTokenValue, Token } from "./tokenizer";
|
||||
import { Interval, IntervalData, Workout } from "./ast";
|
||||
import { isIntervalLabelTokenValue, Token } from "./tokenizer";
|
||||
|
||||
type Header = {
|
||||
name?: string;
|
||||
|
|
@ -25,23 +25,17 @@ const parseHeader = (tokens: Token[]): [Header, Token[]] => {
|
|||
|
||||
while (tokens[0]) {
|
||||
const token = tokens[0];
|
||||
if (token.type === "label" && token.value === LabelTokenValue.Name) {
|
||||
if (token.type === "label" && token.value === "Name") {
|
||||
tokens.shift();
|
||||
const [name, rest] = extractText(tokens);
|
||||
header.name = name;
|
||||
tokens = rest;
|
||||
} else if (
|
||||
token.type === "label" &&
|
||||
token.value === LabelTokenValue.Author
|
||||
) {
|
||||
} else if (token.type === "label" && token.value === "Author") {
|
||||
tokens.shift();
|
||||
const [author, rest] = extractText(tokens);
|
||||
header.author = author;
|
||||
tokens = rest;
|
||||
} else if (
|
||||
token.type === "label" &&
|
||||
token.value === LabelTokenValue.Description
|
||||
) {
|
||||
} else if (token.type === "label" && token.value === "Description") {
|
||||
tokens.shift();
|
||||
const [description, rest] = extractText(tokens);
|
||||
header.description = description;
|
||||
|
|
@ -55,8 +49,60 @@ const parseHeader = (tokens: Token[]): [Header, Token[]] => {
|
|||
return [header, tokens];
|
||||
};
|
||||
|
||||
const parseIntervalParams = (tokens: Token[]): [IntervalData, Token[]] => {
|
||||
const data: Partial<IntervalData> = {};
|
||||
|
||||
while (tokens[0]) {
|
||||
const token = tokens[0];
|
||||
if (token.type === "duration") {
|
||||
data.duration = token.value;
|
||||
tokens.shift();
|
||||
} else if (token.type === "cadence") {
|
||||
data.cadence = token.value;
|
||||
tokens.shift();
|
||||
} else if (token.type === "power") {
|
||||
data.power = { from: token.value, to: token.value };
|
||||
tokens.shift();
|
||||
} else if (token.type === "power-range") {
|
||||
data.power = { from: token.value[0], to: token.value[1] };
|
||||
tokens.shift();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!("duration" in data)) {
|
||||
throw new Error("Duration not specified");
|
||||
}
|
||||
if (!("power" in data)) {
|
||||
throw new Error("Power not specified");
|
||||
}
|
||||
|
||||
return [data as IntervalData, tokens];
|
||||
};
|
||||
|
||||
const parseIntervals = (tokens: Token[]): Interval[] => {
|
||||
return [];
|
||||
const intervals: Interval[] = [];
|
||||
|
||||
while (tokens[0]) {
|
||||
const token = tokens.shift() as Token;
|
||||
if (token.type === "label" && isIntervalLabelTokenValue(token.value)) {
|
||||
const [{ duration, power, cadence }, rest] = parseIntervalParams(tokens);
|
||||
intervals.push({
|
||||
type: token.value,
|
||||
duration,
|
||||
power,
|
||||
cadence,
|
||||
});
|
||||
tokens = rest;
|
||||
} else if (token.type === "text" && token.value === "") {
|
||||
// Ignore empty lines
|
||||
} else {
|
||||
throw new Error(`Unexpected token [${token.type} ${token.value}]`);
|
||||
}
|
||||
}
|
||||
|
||||
return intervals;
|
||||
};
|
||||
|
||||
export const parse = (tokens: Token[]): Workout => {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,25 @@
|
|||
export enum LabelTokenValue {
|
||||
Name = "Name",
|
||||
Author = "Author",
|
||||
Description = "Description",
|
||||
Warmup = "Warmup",
|
||||
Rest = "Rest",
|
||||
Interval = "Interval",
|
||||
Cooldown = "Cooldown",
|
||||
}
|
||||
export type HeaderLabelTokenValue = "Name" | "Author" | "Description";
|
||||
export type IntervalLabelTokenValue =
|
||||
| "Warmup"
|
||||
| "Rest"
|
||||
| "Interval"
|
||||
| "Cooldown";
|
||||
export type LabelTokenValue = HeaderLabelTokenValue | IntervalLabelTokenValue;
|
||||
|
||||
export const isHeaderLabelTokenValue = (
|
||||
value: string
|
||||
): value is HeaderLabelTokenValue => {
|
||||
return ["Name", "Author", "Description"].includes(value);
|
||||
};
|
||||
export const isIntervalLabelTokenValue = (
|
||||
value: string
|
||||
): value is IntervalLabelTokenValue => {
|
||||
return ["Warmup", "Rest", "Interval", "Cooldown"].includes(value);
|
||||
};
|
||||
export const isLabelTokenValue = (value: string): value is LabelTokenValue => {
|
||||
return isHeaderLabelTokenValue(value) || isIntervalLabelTokenValue(value);
|
||||
};
|
||||
|
||||
export type LabelToken = {
|
||||
type: "label";
|
||||
value: LabelTokenValue;
|
||||
|
|
@ -53,15 +66,15 @@ const tokenizeValueParam = (text: string): Token => {
|
|||
|
||||
const tokenizeParams = (type: LabelTokenValue, text: string): Token[] => {
|
||||
switch (type) {
|
||||
case LabelTokenValue.Name:
|
||||
case LabelTokenValue.Author:
|
||||
case LabelTokenValue.Description: {
|
||||
case "Name":
|
||||
case "Author":
|
||||
case "Description": {
|
||||
return [{ type: "text", value: text }];
|
||||
}
|
||||
case LabelTokenValue.Warmup:
|
||||
case LabelTokenValue.Rest:
|
||||
case LabelTokenValue.Interval:
|
||||
case LabelTokenValue.Cooldown:
|
||||
case "Warmup":
|
||||
case "Rest":
|
||||
case "Interval":
|
||||
case "Cooldown":
|
||||
return text.split(" ").map(tokenizeValueParam);
|
||||
}
|
||||
};
|
||||
|
|
@ -71,7 +84,7 @@ const tokenizeRule = (line: string): Token[] => {
|
|||
if (!matches) {
|
||||
return [{ type: "text", value: line.trim() }];
|
||||
}
|
||||
if (!Object.keys(LabelTokenValue).includes(matches[1])) {
|
||||
if (!isLabelTokenValue(matches[1])) {
|
||||
return [{ type: "text", value: line.trim() }];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue