vex-match-parser
v1.0.0
Published
A TypeScript library for parsing VEX Robotics match schedules from PDF files. Works in both Node.js and browser environments.
Maintainers
Readme
VEX Match Parser
A TypeScript library for parsing VEX Robotics match schedules from PDF files. Works in both Node.js and browser environments.
Features
- ✅ Universal: Works in Node.js and browsers
- ✅ Supports 3 VEX competition types: VEXIQ, V5, and VEXGO
- ✅ Parses both Qualification (Q) and Practice (P) matches
- ✅ Automatic competition type detection
- ✅ Full TypeScript support with type definitions
- ✅ Simple, clean API
Installation
npm install vex-match-parserUsage
Node.js (File Path)
import { parseVEXMatchSchedule } from 'vex-match-parser';
// Parse from file path
const schedule = await parseVEXMatchSchedule('./match-schedule.pdf');
console.log(schedule.type); // 'VEXIQ' | 'V5' | 'VEXGO'
console.log(schedule.matchType); // 'Qualification' | 'Practice'
console.log(schedule.event); // '南宁WRC-IQ初中'
console.log(schedule.matches); // Array of matchesBrowser (File Upload)
<!DOCTYPE html>
<html>
<head>
<title>VEX Match Parser Demo</title>
</head>
<body>
<input type="file" id="pdfInput" accept=".pdf" />
<div id="result"></div>
<script type="module">
import { parseVEXMatchScheduleFromFile } from 'vex-match-parser';
document.getElementById('pdfInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
try {
const schedule = await parseVEXMatchScheduleFromFile(file);
document.getElementById('result').innerHTML = `
<h2>${schedule.event}</h2>
<p>Competition: ${schedule.type}</p>
<p>Matches: ${schedule.matches.length}</p>
<pre>${JSON.stringify(schedule.matches[0], null, 2)}</pre>
`;
} catch (error) {
console.error('Error parsing PDF:', error);
}
});
</script>
</body>
</html>Browser (ArrayBuffer)
import { parseVEXMatchSchedule } from 'vex-match-parser';
// From fetch
const response = await fetch('/path/to/schedule.pdf');
const arrayBuffer = await response.arrayBuffer();
const schedule = await parseVEXMatchSchedule(arrayBuffer, 'schedule.pdf');
// From File
const file = document.querySelector('input[type="file"]').files[0];
const buffer = await file.arrayBuffer();
const schedule2 = await parseVEXMatchSchedule(buffer, file.name);React Example
import { parseVEXMatchScheduleFromFile } from 'vex-match-parser';
import { useState } from 'react';
function MatchScheduleUploader() {
const [schedule, setSchedule] = useState(null);
const [loading, setLoading] = useState(false);
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setLoading(true);
try {
const parsedSchedule = await parseVEXMatchScheduleFromFile(file);
setSchedule(parsedSchedule);
} catch (error) {
console.error('Error:', error);
} finally {
setLoading(false);
}
};
return (
<div>
<input type="file" onChange={handleFileUpload} accept=".pdf" />
{loading && <p>Loading...</p>}
{schedule && (
<div>
<h2>{schedule.event}</h2>
<p>Type: {schedule.type}</p>
<p>Total Matches: {schedule.matches.length}</p>
</div>
)}
</div>
);
}TypeScript Types
import { Match, MatchSchedule, CompetitionType } from 'vex-match-parser';
// Competition types
type CompetitionType = 'VEXIQ' | 'V5' | 'VEXGO';
type MatchType = 'Qualification' | 'Practice';
// Match schedule structure
interface MatchSchedule {
title: string; // "Qualification Match List"
matchType: MatchType; // "Qualification" or "Practice"
event: string; // Event name
division: string; // Division name
type: CompetitionType; // VEXIQ/V5/VEXGO
matches: Match[]; // Array of matches
filename: string; // Original PDF filename
}
// Match types (union type)
type Match = VEXIQMatch | V5Match | VEXGOMatch;
// VEXIQ/VEXGO Match (2 teams)
interface VEXIQMatch {
type: 'VEXIQ';
matchNumber: string; // "Q1", "P5", etc.
matchType: MatchType;
field: string; // "A", "B", etc.
time: string; // "周四 10:00 AM"
team1: string; // "7645B"
team2: string; // "7323W"
}
// V5 Match (4 teams, red vs blue alliance)
interface V5Match {
type: 'V5';
matchNumber: string;
matchType: MatchType;
field: string;
time: string;
red1: string; // "23456W"
red2: string; // "66666B"
blue1: string; // "1023K"
blue2: string; // "900K"
}API Reference
parseVEXMatchSchedule(data, filename?)
Main parsing function. Works in both Node.js and browser.
Parameters:
data:string | ArrayBuffer | Uint8Array- Node.js: File path as string
- Browser: ArrayBuffer or Uint8Array
filename?:string(optional) - Original filename for type detection
Returns: Promise<MatchSchedule>
parseVEXMatchScheduleFromFile(file)
Browser-specific helper for File objects.
Parameters:
file:File- File object from<input type="file">
Returns: Promise<MatchSchedule>
How It Works
The parser uses a three-layer detection system to automatically identify the competition type:
- Filename detection: Checks if filename contains "V5", "IQ", or "GO"
- Header detection: Checks the PDF title for competition type
- Team count detection: V5 has 4 teams per match, IQ/GO have 2 teams
Supported PDF Formats
The parser expects VEX match schedule PDFs with the following structure:
- Title:
Qualification Match ListorPractice Match List - Subtitle: Event name and division (e.g.,
南宁WRC-IQ初中 - Default Division) - Table columns:
- VEXIQ/VEXGO:
Match | Field | Time | Team 1 | Team 2 - V5:
Match | Field | Time | Red 1 | Red 2 | Blue 1 | Blue 2
- VEXIQ/VEXGO:
Development
# Install dependencies
npm install
# Build
npm run build
# Test
npm testBrowser Compatibility
- Modern browsers with ES modules support
- Requires support for:
ArrayBuffer,Uint8Array,FileAPI - Works with: Chrome 63+, Firefox 60+, Safari 11.1+, Edge 79+
License
MIT
