webamp/packages/skin-database/regionParser.ts
2022-10-03 19:32:27 -07:00

84 lines
2.6 KiB
TypeScript

/** Shamelessly copied from the Webamp package. We should probably pull this out into a separate package. */
interface IniData {
[section: string]: {
[key: string]: string;
};
}
export function pointPairs(arr: string[]): string[] {
const pairedValues = [];
for (let i = 0; i < arr.length; i += 2) {
// @ts-ignore
pairedValues.push(`${arr[i]},${arr[i + 1]}`);
}
return pairedValues;
}
type RegionData = { [section: string]: string[] };
export default function regionParser(regionStr: string): RegionData {
const iniData = parseIni(regionStr);
const data: RegionData = {};
Object.keys(iniData).forEach((section) => {
const { numpoints, pointlist } = iniData[section];
if (!numpoints || !pointlist) {
return;
}
const pointCounts = numpoints.split(/\s*,\s*/).filter((val) => val !== "");
const points = pointPairs(
// points can be separated by spaces, or by commas
pointlist.split(/\s*[, ]\s*/).filter((val) => val !== "")
);
let pointIndex = 0;
const polygons = pointCounts.map((numStr) => {
const num = Number(numStr);
if (num < 3) {
// What use is a polygon with less than three sides?
pointIndex += num;
return null;
}
const polygon = points.slice(pointIndex, pointIndex + num).join(" ");
if (!polygon.length) {
// It's possible that the skin author specified more polygons than provided points.
return null;
}
pointIndex += num;
return polygon;
});
const validPolygons = polygons.filter(
(polygon) => polygon != null
) as string[];
if (validPolygons.length) {
data[section] = validPolygons;
}
});
return data;
}
const SECTION_REGEX = /^\s*\[(.+?)\]\s*$/;
const PROPERTY_REGEX = /^\s*([^;][^=]*)\s*=\s*(.*)\s*$/;
const parseIni = (text: string): IniData => {
let section: string, match;
return text.split(/[\r\n]+/g).reduce((data: IniData, line) => {
if ((match = line.match(PROPERTY_REGEX)) && section != null) {
const key = match[1].trim().toLowerCase();
const value = match[2]
// Ignore anything after a second `=`
// TODO: What if this is inside quotes or escaped?
.replace(/=.*$/g, "")
.trim()
// Strip quotes
// TODO: What about escaped quotes?
// TODO: What about unbalanced quotes?
.replace(/(^")|("$)|(^')|('$)/g, "");
data[section][key] = value;
} else if ((match = line.match(SECTION_REGEX))) {
section = match[1].trim().toLowerCase();
data[section] = {};
}
return data;
}, {});
};