@sportloop/mrc
Version:
Workout file parser library, suitable for `.mrc` and `.erg` files, with first-class TypeScript support.
178 lines (174 loc) • 5.96 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var parseNumber = function (numberlike) {
var num = parseFloat(numberlike);
if (Number.isNaN(num)) {
throw new TypeError("could not parse value: " + numberlike + " as an integer");
}
return num;
};
// TODO(danielkov): [MODE DATA]?
var getSection = function (raw, sectionName, required) {
if (required === void 0) { required = false; }
var re = new RegExp("^\\[" + sectionName + "\\]((.|\\n)+)\\[END " + sectionName + "\\]$", "m");
var parsed = re.exec(raw);
if (!parsed) {
if (required) {
throw new TypeError("section: " + sectionName + " was not found");
}
return undefined;
}
var value = parsed[1];
if (!value) {
if (required) {
throw new TypeError("section: " + sectionName + " could not be read");
}
return undefined;
}
return value.trim();
};
var getField = function (raw, fieldName, required) {
if (required === void 0) { required = false; }
var re = new RegExp("^" + fieldName + "\\s?=\\s?((.)+)$", "m");
var parsed = re.exec(raw);
if (!parsed) {
if (required) {
throw new TypeError("field: " + fieldName + " was not specified");
}
return "";
}
var value = parsed[1];
if (!value) {
if (required) {
throw new TypeError("field: " + fieldName + " could not be read");
}
return "";
}
return value.trim();
};
var dataTypesRegexp = /^MINUTES\s(\w+)$/m;
var getDataTypes = function (raw) {
var parsed = dataTypesRegexp.exec(raw);
if (!parsed) {
throw new TypeError("data types should be in the format: `MINUTES <DATA TYPE, e.g.: PERCENT>`");
}
var value = parsed[1];
if (!value) {
throw new TypeError("data types should be in the format: `MINUTES <DATA TYPE, e.g.: PERCENT>`");
}
return ["MINUTES", value];
};
var getHeader = function (raw) {
var rawHeader = getSection(raw, "COURSE HEADER", true);
var version = parseNumber(getField(rawHeader, "VERSION", true));
var units = getField(rawHeader, "UNITS", true);
var description = getField(rawHeader, "DESCRIPTION");
var fileName = getField(rawHeader, "FILE NAME");
var dataTypes = getDataTypes(rawHeader);
var ftpString = getField(rawHeader, "FTP");
if (ftpString) {
var ftp = parseNumber(ftpString);
return {
version: version,
units: units,
description: description,
fileName: fileName,
ftp: ftp,
dataTypes: dataTypes,
};
}
return {
version: version,
units: units,
description: description,
fileName: fileName,
dataTypes: dataTypes,
};
};
var getCourseData = function (raw) {
var rawCourseData = getSection(raw, "COURSE DATA", true);
var lines = rawCourseData.split("\n");
return lines.map(function (line) {
var values = line.split("\t");
if (values.length !== 2) {
throw new TypeError("expected COURSE DATA to be in format number\tnumber, got: " + line);
}
var minutes = parseNumber(values[0]);
var value = parseNumber(values[1]);
return [minutes, value];
});
};
var getCourseText = function (raw) {
var rawCourseText = getSection(raw, "COURSE TEXT");
if (!rawCourseText) {
return undefined;
}
var lines = rawCourseText.split("\n");
return lines.map(function (line) {
var split = line.split("\t");
return [parseNumber(split[0]), split[1], parseNumber(split[2])];
});
};
var getIntervalData = function (raw) {
var rawIntervalData = getSection(raw, "INTERVAL DATA");
if (!rawIntervalData) {
return undefined;
}
var lines = rawIntervalData.split("\n");
return lines.map(function (line) {
var split = line.split("\t");
return [parseNumber(split[0]), parseNumber(split[1]), split[2]];
});
};
var parse = function (raw) {
var courseHeader = getHeader(raw);
var courseData = getCourseData(raw);
var result = { courseHeader: courseHeader, courseData: courseData };
var courseText = getCourseText(raw);
if (courseText) {
result.courseText = courseText;
}
var intervalData = getIntervalData(raw);
if (intervalData) {
result.intervalData = intervalData;
}
return result;
};
var writeNameRegexp = /[A-Z]/g;
var writeName = function (name) {
return name.replace(writeNameRegexp, function (match) { return " " + match; }).toUpperCase();
};
var writeValue = function (_a) {
var name = _a[0], value = _a[1];
if (Array.isArray(value)) {
return value.join(" ");
}
return writeName(name) + " = " + value;
};
var writePossibleNumber = function (value) {
return typeof value === "number" ? value.toFixed(2) : value;
};
var writeSection = function (_a) {
var name = _a[0], data = _a[1];
var formattedName = writeName(name);
var values = (Array.isArray(data)
? data.map(function (stringOrNumber) {
if (stringOrNumber.length > 2) {
return stringOrNumber.map(writePossibleNumber).join("\t");
}
return [stringOrNumber[0].toFixed(2), stringOrNumber[1]].join("\t");
})
: Object.entries(data).map(writeValue)).join("\n");
return "[" + formattedName + "]\n" + values + "\n[END " + formattedName + "]";
};
var stringify = function (parsed) {
return Object.entries(parsed)
.filter(function (_a) {
var value = _a[1];
return value;
})
.map(writeSection)
.join("\n") + "\n";
};
exports.parse = parse;
exports.stringify = stringify;