@workingdevshero/olympia-ait-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/reader/parse-day-sheet.d.ts +10 -0
- package/dist/reader/parse-day-sheet.d.ts.map +1 -0
- package/dist/reader/parse-day-sheet.js +199 -0
- package/dist/reader/parse-day-sheet.js.map +1 -0
- package/dist/reader/parse-workbook.d.ts +3 -0
- package/dist/reader/parse-workbook.d.ts.map +1 -0
- package/dist/reader/parse-workbook.js +55 -0
- package/dist/reader/parse-workbook.js.map +1 -0
- package/dist/schema/program.d.ts +692 -0
- package/dist/schema/program.d.ts.map +1 -0
- package/dist/schema/program.js +125 -0
- package/dist/schema/program.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +58 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/json-to-xlsx.d.ts +3 -0
- package/dist/tools/json-to-xlsx.d.ts.map +1 -0
- package/dist/tools/json-to-xlsx.js +5 -0
- package/dist/tools/json-to-xlsx.js.map +1 -0
- package/dist/tools/xlsx-to-json.d.ts +3 -0
- package/dist/tools/xlsx-to-json.d.ts.map +1 -0
- package/dist/tools/xlsx-to-json.js +5 -0
- package/dist/tools/xlsx-to-json.js.map +1 -0
- package/dist/writer/build-workbook.d.ts +3 -0
- package/dist/writer/build-workbook.d.ts.map +1 -0
- package/dist/writer/build-workbook.js +166 -0
- package/dist/writer/build-workbook.js.map +1 -0
- package/dist/writer/layout.d.ts +21 -0
- package/dist/writer/layout.d.ts.map +1 -0
- package/dist/writer/layout.js +40 -0
- package/dist/writer/layout.js.map +1 -0
- package/dist/writer/stamp-exercise.d.ts +31 -0
- package/dist/writer/stamp-exercise.d.ts.map +1 -0
- package/dist/writer/stamp-exercise.js +80 -0
- package/dist/writer/stamp-exercise.js.map +1 -0
- package/dist/writer/styles.d.ts +59 -0
- package/dist/writer/styles.d.ts.map +1 -0
- package/dist/writer/styles.js +266 -0
- package/dist/writer/styles.js.map +1 -0
- package/dist/writer/supplemental-template.d.ts +23 -0
- package/dist/writer/supplemental-template.d.ts.map +1 -0
- package/dist/writer/supplemental-template.js +112 -0
- package/dist/writer/supplemental-template.js.map +1 -0
- package/package.json +42 -0
- package/src/assets/olympia-logo.png +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="src/assets/olympia-logo.png" alt="Olympia Fitness & Performance RI" width="400">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# olympia-ait-adapter
|
|
6
|
+
|
|
7
|
+
MCP adapter that converts Olympia Fitness & Performance program XLSX workbooks
|
|
8
|
+
to and from a strict JSON schema. Built for the
|
|
9
|
+
[Automate It](https://automate.it.com) framework so AI agents can author new
|
|
10
|
+
strength-and-conditioning programs from prior client data without ever
|
|
11
|
+
touching XLSX directly.
|
|
12
|
+
|
|
13
|
+
## Why this exists
|
|
14
|
+
|
|
15
|
+
Olympia's coaches build client programs in XLSX workbooks — one client per
|
|
16
|
+
file, one sheet per training day, with merged cells, custom borders, an
|
|
17
|
+
embedded logo, and a domain-specific notation (`12E`, `:20E`, `12EL`,
|
|
18
|
+
`x3 Rest :60`, etc.). Asking an LLM to edit XLSX directly is fragile: it
|
|
19
|
+
corrupts merges, loses the logo, and can't reason about the implicit
|
|
20
|
+
6-week / 1A-1B / set-by-set structure encoded in the visual layout.
|
|
21
|
+
|
|
22
|
+
This package gives the agent a clean structured view of an Olympia program
|
|
23
|
+
and guarantees well-formed output: the LLM reads JSON, reasons about it,
|
|
24
|
+
writes JSON, and the adapter handles all the visual fidelity on the way
|
|
25
|
+
back to XLSX.
|
|
26
|
+
|
|
27
|
+
## What it does
|
|
28
|
+
|
|
29
|
+
Two MCP tools, exposed over stdio:
|
|
30
|
+
|
|
31
|
+
| Tool | Direction | Purpose |
|
|
32
|
+
| ------------------------ | --------------- | ------------------------------------------------------------------ |
|
|
33
|
+
| `olympia_xlsx_to_json` | XLSX → JSON | Parse an Olympia workbook into a typed `Program` document. |
|
|
34
|
+
| `olympia_json_to_xlsx` | JSON → XLSX | Render a `Program` document back to a styled .xlsx on disk. |
|
|
35
|
+
|
|
36
|
+
The JSON schema is defined once in `src/schema/program.ts` using Zod and
|
|
37
|
+
surfaces as:
|
|
38
|
+
|
|
39
|
+
1. The TypeScript type used internally
|
|
40
|
+
2. The runtime validator at each tool boundary
|
|
41
|
+
3. The JSON Schema published as each tool's `inputSchema` so the LLM sees
|
|
42
|
+
the full typed contract at discovery time
|
|
43
|
+
|
|
44
|
+
## JSON shape
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
type Program = {
|
|
48
|
+
client: string; // "Bobby Galli"
|
|
49
|
+
programDate: string; // "4.26"
|
|
50
|
+
weekDates?: (string | null)[]; // optional, length 6
|
|
51
|
+
days: Day[];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type Day = {
|
|
55
|
+
name: string; // "Day 1"
|
|
56
|
+
sections: Section[];
|
|
57
|
+
supplementalNotes?: SupplementalNote[];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type Section = {
|
|
61
|
+
kind: "warmup" | "main" | "sportSpecific" | "supplemental" | "conditioning";
|
|
62
|
+
exercises: Exercise[];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type Exercise = {
|
|
66
|
+
name: string; // "2DB Alternating Bench Press"
|
|
67
|
+
groupLabel?: string; // "1A", "1B", "2A"… matches /^\d+[A-Z]$/
|
|
68
|
+
notes?: string;
|
|
69
|
+
sets: (string | null)[][]; // [setIdx][weekIdx]; inner length 6
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type SupplementalNote = {
|
|
73
|
+
row: number; // offset from "Sport Specific/" label row
|
|
74
|
+
col: string; // "C" | "D" | … | "P"
|
|
75
|
+
value: string;
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Prescription cell grammar
|
|
80
|
+
|
|
81
|
+
Olympia does **not** prescribe weights. Each `sets[setIdx][weekIdx]` is a
|
|
82
|
+
single opaque string encoding **reps**, **time**, or **breaths**:
|
|
83
|
+
|
|
84
|
+
| Format | Meaning |
|
|
85
|
+
| --------------------- | ------------------------------------ |
|
|
86
|
+
| `"12"` / `"10E"` | reps (`E` = each side) |
|
|
87
|
+
| `":20"` / `":20E"` | seconds (`E` = each side) |
|
|
88
|
+
| `"5 breaths"` | breath count |
|
|
89
|
+
| `"12EL"` / `"10ER"` | reps each side, left or right lead |
|
|
90
|
+
| free-form strings | circuit-style instructions, OK too |
|
|
91
|
+
| `null` | empty cell |
|
|
92
|
+
|
|
93
|
+
The schema enforces shape (6 weeks per set, group label regex, allowed
|
|
94
|
+
section kinds) but does **not** validate the grammar of each prescription
|
|
95
|
+
string — Olympia's own files include free-form entries in some spots.
|
|
96
|
+
|
|
97
|
+
### Supplemental area
|
|
98
|
+
|
|
99
|
+
The bottom of every day sheet is a trainer-managed "Sport Specific /
|
|
100
|
+
Supplemental" area where coaches write athlete-specific instructions that
|
|
101
|
+
don't fit the structured exercise table (conditioning circuits, sport
|
|
102
|
+
drills, recovery work). The adapter:
|
|
103
|
+
|
|
104
|
+
- **Reads** that area as a sparse list of `{ row, col, value }` entries
|
|
105
|
+
(master cells only) so the signal is preserved for downstream agents.
|
|
106
|
+
- **Writes** the fixed 10-row template (with "Sport Specific/" and
|
|
107
|
+
"Supplemental" labels) at the bottom of every day, then layers any
|
|
108
|
+
supplied `supplementalNotes` on top.
|
|
109
|
+
|
|
110
|
+
## Installation
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm install
|
|
114
|
+
npm run build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The built CLI lives at `dist/server.js`; the `bin` entry registers it as
|
|
118
|
+
`olympia-ait-adapter`.
|
|
119
|
+
|
|
120
|
+
## Running the MCP server
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Dev (TypeScript via tsx)
|
|
124
|
+
npm run dev
|
|
125
|
+
|
|
126
|
+
# Built (after `npm run build`)
|
|
127
|
+
npm start
|
|
128
|
+
# or
|
|
129
|
+
npx olympia-ait-adapter
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The server speaks the Model Context Protocol over stdio. To wire it into
|
|
133
|
+
Claude or another MCP client, add an entry like:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"olympia-ait-adapter": {
|
|
139
|
+
"command": "npx",
|
|
140
|
+
"args": ["olympia-ait-adapter"]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Both tools take absolute paths to .xlsx files on the local filesystem.
|
|
147
|
+
|
|
148
|
+
## Repo layout
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
src/
|
|
152
|
+
schema/program.ts # Zod schema — single source of truth
|
|
153
|
+
reader/
|
|
154
|
+
parse-workbook.ts # Workbook → Program JSON
|
|
155
|
+
parse-day-sheet.ts # One sheet, section detection, supplemental capture
|
|
156
|
+
writer/
|
|
157
|
+
build-workbook.ts # Program → ExcelJS workbook
|
|
158
|
+
layout.ts # Column widths, row positions, logo anchor
|
|
159
|
+
styles.ts # All borders/fonts/fills as constants
|
|
160
|
+
stamp-exercise.ts # One exercise block (variable sets, group borders)
|
|
161
|
+
supplemental-template.ts # Fixed bottom template + supplementalNotes overlay
|
|
162
|
+
tools/
|
|
163
|
+
xlsx-to-json.ts # MCP handler
|
|
164
|
+
json-to-xlsx.ts # MCP handler
|
|
165
|
+
server.ts # Bootstrap, registers both tools
|
|
166
|
+
assets/
|
|
167
|
+
olympia-logo.png # Extracted from sample workbooks; embedded in output
|
|
168
|
+
|
|
169
|
+
samples/ # Real Olympia .xlsx files used as round-trip fixtures
|
|
170
|
+
scripts/ # Inspection helpers used during development
|
|
171
|
+
tests/ # vitest — schema, reader, round-trip, MCP smoke
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Tests
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm test # one-shot
|
|
178
|
+
npm run test:watch # vitest watch mode
|
|
179
|
+
npm run typecheck # tsc --noEmit
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Coverage:
|
|
183
|
+
|
|
184
|
+
- **`schema.test.ts`** — Zod rejects malformed input (week count, group
|
|
185
|
+
label regex, section kinds, missing fields).
|
|
186
|
+
- **`reader.test.ts`** — All three sample workbooks parse into
|
|
187
|
+
schema-valid `Program` documents; spot checks on Bobby's first exercise,
|
|
188
|
+
Giulianna's variable set counts, exercise notes, supplemental notes.
|
|
189
|
+
- **`round-trip.test.ts`** — The primary determinism guarantee: for each
|
|
190
|
+
sample, `parse → write → parse` produces JSON equal to the original.
|
|
191
|
+
- **`mcp-smoke.test.ts`** — End-to-end MCP server check via the in-memory
|
|
192
|
+
transport: tool discovery, round-trip via `client.callTool`, schema
|
|
193
|
+
rejection of malformed input at the SDK boundary.
|
|
194
|
+
|
|
195
|
+
## Determinism
|
|
196
|
+
|
|
197
|
+
The writer is fully programmatic — no template `.xlsx` file. Every byte of
|
|
198
|
+
the output is determined by code plus the input JSON, so the same JSON
|
|
199
|
+
produces the same workbook. The Olympia logo is the only binary asset
|
|
200
|
+
(`src/assets/olympia-logo.png`).
|
|
201
|
+
|
|
202
|
+
This trade-off is intentional: templates introduce hidden state that
|
|
203
|
+
ExcelJS occasionally drops (drawings, theme colors), whereas pure code →
|
|
204
|
+
output gives byte-stable, snapshot-testable results.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
Internal — Automate It / Olympia Fitness & Performance RI.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, SupplementalNote, XlsxToJsonInput, XlsxToJsonOutput, JsonToXlsxInput, JsonToXlsxOutput, } from "./schema/program.js";
|
|
2
|
+
export { createServer } from "./server.js";
|
|
3
|
+
export { parseWorkbook } from "./reader/parse-workbook.js";
|
|
4
|
+
export { buildWorkbook } from "./writer/build-workbook.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,OAAO,EACP,GAAG,EACH,OAAO,EACP,WAAW,EACX,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Programmatic entry point. The package's primary use is the MCP CLI
|
|
2
|
+
// (registered under the `bin` field), but the schema and server factory
|
|
3
|
+
// are also exported for callers that want to embed or compose the adapter.
|
|
4
|
+
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, SupplementalNote, XlsxToJsonInput, XlsxToJsonOutput, JsonToXlsxInput, JsonToXlsxOutput, } from "./schema/program.js";
|
|
5
|
+
export { createServer } from "./server.js";
|
|
6
|
+
export { parseWorkbook } from "./reader/parse-workbook.js";
|
|
7
|
+
export { buildWorkbook } from "./writer/build-workbook.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,wEAAwE;AACxE,2EAA2E;AAE3E,OAAO,EACL,OAAO,EACP,GAAG,EACH,OAAO,EACP,WAAW,EACX,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ExcelJS from "exceljs";
|
|
2
|
+
import type { SupplementalNote, Day } from "../schema/program.js";
|
|
3
|
+
export interface ParsedDay {
|
|
4
|
+
sections: Day["sections"];
|
|
5
|
+
weekDates?: (string | null)[];
|
|
6
|
+
supplementalNotes?: SupplementalNote[];
|
|
7
|
+
warnings: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function parseDaySheet(ws: ExcelJS.Worksheet): ParsedDay;
|
|
10
|
+
//# sourceMappingURL=parse-day-sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-day-sheet.d.ts","sourceRoot":"","sources":["../../src/reader/parse-day-sheet.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EACV,gBAAgB,EAEhB,GAAG,EAIJ,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC1B,SAAS,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmFD,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAsG9D"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
const FIRST_BODY_ROW = 7;
|
|
2
|
+
const WEEK_COLS = ["D", "F", "H", "J", "L", "N"];
|
|
3
|
+
const SECTION_LABELS = new Map([
|
|
4
|
+
["warmup", "warmup"],
|
|
5
|
+
["sport specific", "sportSpecific"],
|
|
6
|
+
["sport specific/", "sportSpecific"],
|
|
7
|
+
["supplemental", "supplemental"],
|
|
8
|
+
["conditioning", "conditioning"],
|
|
9
|
+
]);
|
|
10
|
+
const SUPPLEMENTAL_TRIGGER_LABELS = new Set([
|
|
11
|
+
"sport specific",
|
|
12
|
+
"sport specific/",
|
|
13
|
+
"supplemental",
|
|
14
|
+
"conditioning",
|
|
15
|
+
"circuit",
|
|
16
|
+
]);
|
|
17
|
+
// Columns scanned for supplementalNotes. Excludes A/B (cosmetic narrow margins)
|
|
18
|
+
// and Q (rarely used).
|
|
19
|
+
const SUPPLEMENTAL_COLS = ["C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"];
|
|
20
|
+
function isGroupLabel(s) {
|
|
21
|
+
return /^\d+[A-Z]$/.test(s);
|
|
22
|
+
}
|
|
23
|
+
function cellText(value) {
|
|
24
|
+
if (value === null || value === undefined)
|
|
25
|
+
return "";
|
|
26
|
+
if (typeof value === "string")
|
|
27
|
+
return value;
|
|
28
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
29
|
+
return String(value);
|
|
30
|
+
if (value instanceof Date)
|
|
31
|
+
return value.toISOString();
|
|
32
|
+
if (typeof value === "object") {
|
|
33
|
+
if ("richText" in value && Array.isArray(value.richText)) {
|
|
34
|
+
return value.richText
|
|
35
|
+
.map((r) => r.text)
|
|
36
|
+
.join("");
|
|
37
|
+
}
|
|
38
|
+
if ("text" in value && typeof value.text === "string") {
|
|
39
|
+
return value.text;
|
|
40
|
+
}
|
|
41
|
+
if ("result" in value) {
|
|
42
|
+
return cellText(value.result);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
function cellOrNull(value) {
|
|
48
|
+
const t = cellText(value).trim();
|
|
49
|
+
return t === "" ? null : t;
|
|
50
|
+
}
|
|
51
|
+
function isMergeContinuation(cell) {
|
|
52
|
+
if (!cell.isMerged)
|
|
53
|
+
return false;
|
|
54
|
+
const master = cell.master;
|
|
55
|
+
return master !== undefined && master.address !== cell.address;
|
|
56
|
+
}
|
|
57
|
+
function readWeekRow(row) {
|
|
58
|
+
return WEEK_COLS.map((col) => cellOrNull(row.getCell(col).value));
|
|
59
|
+
}
|
|
60
|
+
function readWeekDates(row) {
|
|
61
|
+
return WEEK_COLS.map((col) => {
|
|
62
|
+
const t = cellText(row.getCell(col).value).trim();
|
|
63
|
+
if (t === "" || t.toLowerCase() === "date:")
|
|
64
|
+
return null;
|
|
65
|
+
return t;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
export function parseDaySheet(ws) {
|
|
69
|
+
const warnings = [];
|
|
70
|
+
const sections = [];
|
|
71
|
+
let current = { kind: "main", exercises: [] };
|
|
72
|
+
let exercise = null;
|
|
73
|
+
let weekDates;
|
|
74
|
+
const dateRow = ws.getRow(2);
|
|
75
|
+
if (dateRow) {
|
|
76
|
+
const dates = readWeekDates(dateRow);
|
|
77
|
+
if (dates.some((d) => d !== null))
|
|
78
|
+
weekDates = dates;
|
|
79
|
+
}
|
|
80
|
+
const flushExercise = (groupLabel) => {
|
|
81
|
+
if (!exercise)
|
|
82
|
+
return;
|
|
83
|
+
const ex = {
|
|
84
|
+
name: exercise.name.trim(),
|
|
85
|
+
sets: exercise.sets,
|
|
86
|
+
};
|
|
87
|
+
if (groupLabel)
|
|
88
|
+
ex.groupLabel = groupLabel;
|
|
89
|
+
if (exercise.notes)
|
|
90
|
+
ex.notes = exercise.notes;
|
|
91
|
+
current.exercises.push(ex);
|
|
92
|
+
exercise = null;
|
|
93
|
+
};
|
|
94
|
+
const flushSection = () => {
|
|
95
|
+
flushExercise();
|
|
96
|
+
sections.push({ kind: current.kind, exercises: current.exercises });
|
|
97
|
+
};
|
|
98
|
+
const lastRow = ws.actualRowCount > 0 ? ws.rowCount : 0;
|
|
99
|
+
let supplementalStartRow;
|
|
100
|
+
let supplementalNotes;
|
|
101
|
+
for (let r = FIRST_BODY_ROW; r <= lastRow; r++) {
|
|
102
|
+
const row = ws.getRow(r);
|
|
103
|
+
const cCell = row.getCell("C");
|
|
104
|
+
const cText = cellText(cCell.value).trim();
|
|
105
|
+
const cLower = cText.toLowerCase();
|
|
106
|
+
// Trigger label → switch from exercise parsing to supplemental capture.
|
|
107
|
+
if (SUPPLEMENTAL_TRIGGER_LABELS.has(cLower)) {
|
|
108
|
+
flushSection();
|
|
109
|
+
supplementalStartRow = r;
|
|
110
|
+
supplementalNotes = captureSupplementalNotes(ws, r, lastRow);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
// Group label terminates an exercise block.
|
|
114
|
+
if (cText !== "" && isGroupLabel(cText) && !isMergeContinuation(cCell)) {
|
|
115
|
+
if (!exercise) {
|
|
116
|
+
warnings.push(`row ${r}: group label "${cText}" without a preceding exercise name`);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
exercise.sets.push(readWeekRow(row));
|
|
120
|
+
const pNote = cellText(row.getCell("P").value).trim();
|
|
121
|
+
if (pNote && !exercise.notes)
|
|
122
|
+
exercise.notes = pNote;
|
|
123
|
+
flushExercise(cText);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
// Continuation of a merged exercise name?
|
|
127
|
+
if (isMergeContinuation(cCell) && exercise) {
|
|
128
|
+
exercise.sets.push(readWeekRow(row));
|
|
129
|
+
const pNote = cellText(row.getCell("P").value).trim();
|
|
130
|
+
if (pNote && !exercise.notes)
|
|
131
|
+
exercise.notes = pNote;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
// New exercise block: non-empty C, not a section/group label, master cell.
|
|
135
|
+
if (cText !== "") {
|
|
136
|
+
flushExercise();
|
|
137
|
+
exercise = {
|
|
138
|
+
name: cText,
|
|
139
|
+
sets: [readWeekRow(row)],
|
|
140
|
+
};
|
|
141
|
+
const pNote = cellText(row.getCell("P").value).trim();
|
|
142
|
+
if (pNote)
|
|
143
|
+
exercise.notes = pNote;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (supplementalStartRow === undefined) {
|
|
148
|
+
flushSection();
|
|
149
|
+
}
|
|
150
|
+
const nonEmpty = sections.filter((s) => s.exercises.length > 0);
|
|
151
|
+
if (nonEmpty.length === 0) {
|
|
152
|
+
nonEmpty.push({ kind: "main", exercises: [] });
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
sections: nonEmpty,
|
|
156
|
+
...(weekDates ? { weekDates } : {}),
|
|
157
|
+
...(supplementalNotes && supplementalNotes.length > 0
|
|
158
|
+
? { supplementalNotes }
|
|
159
|
+
: {}),
|
|
160
|
+
warnings,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Capture freeform cells in the supplemental area of a day sheet — the
|
|
165
|
+
* trainer-managed Sport Specific / Supplemental block below the main
|
|
166
|
+
* programming. Returns an array of `{ row, col, value }` entries where `row`
|
|
167
|
+
* is the offset from `supplementalStartRow` (so row 0 = the row containing
|
|
168
|
+
* the first trigger label).
|
|
169
|
+
*
|
|
170
|
+
* Only MASTER cells of merge ranges are captured (so a value that spans
|
|
171
|
+
* multiple cells appears once). The trigger labels themselves are skipped
|
|
172
|
+
* since they're added back by the writer's fixed template.
|
|
173
|
+
*/
|
|
174
|
+
function captureSupplementalNotes(ws, supplementalStartRow, lastRow) {
|
|
175
|
+
const out = [];
|
|
176
|
+
for (let r = supplementalStartRow; r <= lastRow; r++) {
|
|
177
|
+
const row = ws.getRow(r);
|
|
178
|
+
for (const col of SUPPLEMENTAL_COLS) {
|
|
179
|
+
const cell = row.getCell(col);
|
|
180
|
+
if (isMergeContinuation(cell))
|
|
181
|
+
continue;
|
|
182
|
+
const value = cellText(cell.value).trim();
|
|
183
|
+
if (value === "")
|
|
184
|
+
continue;
|
|
185
|
+
// Skip the static template labels — the writer adds them back.
|
|
186
|
+
if (col === "C" &&
|
|
187
|
+
SUPPLEMENTAL_TRIGGER_LABELS.has(value.toLowerCase())) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
out.push({
|
|
191
|
+
row: r - supplementalStartRow,
|
|
192
|
+
col,
|
|
193
|
+
value,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=parse-day-sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-day-sheet.js","sourceRoot":"","sources":["../../src/reader/parse-day-sheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-workbook.d.ts","sourceRoot":"","sources":["../../src/reader/parse-workbook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAyD3B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import ExcelJS from "exceljs";
|
|
2
|
+
import { parseDaySheet } from "./parse-day-sheet.js";
|
|
3
|
+
export async function parseWorkbook(xlsxPath) {
|
|
4
|
+
const workbook = new ExcelJS.Workbook();
|
|
5
|
+
await workbook.xlsx.readFile(xlsxPath);
|
|
6
|
+
const warnings = [];
|
|
7
|
+
const days = [];
|
|
8
|
+
let weekDates;
|
|
9
|
+
for (const ws of workbook.worksheets) {
|
|
10
|
+
const parsed = parseDaySheet(ws);
|
|
11
|
+
parsed.warnings.forEach((w) => warnings.push(`[${ws.name}] ${w}`));
|
|
12
|
+
if (weekDates === undefined && parsed.weekDates !== undefined) {
|
|
13
|
+
weekDates = parsed.weekDates;
|
|
14
|
+
}
|
|
15
|
+
days.push({
|
|
16
|
+
name: ws.name,
|
|
17
|
+
sections: parsed.sections,
|
|
18
|
+
...(parsed.supplementalNotes
|
|
19
|
+
? { supplementalNotes: parsed.supplementalNotes }
|
|
20
|
+
: {}),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// Prefer workbook custom properties (set by our own writer); fall back to
|
|
24
|
+
// filename parsing for source files coming straight from Olympia.
|
|
25
|
+
let clientName;
|
|
26
|
+
let programDate;
|
|
27
|
+
const subject = typeof workbook.subject === "string" ? workbook.subject.trim() : "";
|
|
28
|
+
const keywords = typeof workbook.keywords === "string" ? workbook.keywords.trim() : "";
|
|
29
|
+
if (subject && keywords) {
|
|
30
|
+
clientName = subject;
|
|
31
|
+
programDate = keywords;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const match = xlsxPath.match(/([^/\\]+?)\s+Programs?\s+([\d.]+)\.xlsx$/i);
|
|
35
|
+
if (match && match[1] !== undefined && match[2] !== undefined) {
|
|
36
|
+
clientName = match[1];
|
|
37
|
+
programDate = match[2];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
clientName = "Unknown";
|
|
41
|
+
programDate = "";
|
|
42
|
+
warnings.push(`Could not derive client name or program date from filename or workbook properties: ${xlsxPath}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
program: {
|
|
47
|
+
client: clientName,
|
|
48
|
+
programDate,
|
|
49
|
+
...(weekDates ? { weekDates } : {}),
|
|
50
|
+
days,
|
|
51
|
+
},
|
|
52
|
+
warnings,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=parse-workbook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-workbook.js","sourceRoot":"","sources":["../../src/reader/parse-workbook.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB;IAEhB,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IACxC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEvC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAwC,EAAE,CAAC;IACrD,IAAI,SAAwC,CAAC;IAE7C,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QACjC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACnE,IAAI,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAC9D,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,CAAC,MAAM,CAAC,iBAAiB;gBAC1B,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE;gBACjD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,kEAAkE;IAClE,IAAI,UAA8B,CAAC;IACnC,IAAI,WAA+B,CAAC;IACpC,MAAM,OAAO,GACX,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,QAAQ,GACZ,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;QACxB,UAAU,GAAG,OAAO,CAAC;QACrB,WAAW,GAAG,QAAQ,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC1E,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9D,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,SAAS,CAAC;YACvB,WAAW,GAAG,EAAE,CAAC;YACjB,QAAQ,CAAC,IAAI,CACX,sFAAsF,QAAQ,EAAE,CACjG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP,MAAM,EAAE,UAAU;YAClB,WAAW;YACX,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,IAAI;SACL;QACD,QAAQ;KACT,CAAC;AACJ,CAAC"}
|