@workingdevshero/olympia-ait-adapter 1.0.0 → 1.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 +35 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/reader/parse-day-sheet.d.ts.map +1 -1
- package/dist/reader/parse-day-sheet.js +98 -29
- package/dist/reader/parse-day-sheet.js.map +1 -1
- package/dist/schema/program.d.ts +363 -19
- package/dist/schema/program.d.ts.map +1 -1
- package/dist/schema/program.js +110 -14
- package/dist/schema/program.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/writer/build-workbook.d.ts +1 -1
- package/dist/writer/build-workbook.d.ts.map +1 -1
- package/dist/writer/build-workbook.js +18 -12
- package/dist/writer/build-workbook.js.map +1 -1
- package/dist/writer/layout.d.ts +19 -7
- package/dist/writer/layout.d.ts.map +1 -1
- package/dist/writer/layout.js +40 -21
- package/dist/writer/layout.js.map +1 -1
- package/dist/writer/stamp-exercise.d.ts +13 -5
- package/dist/writer/stamp-exercise.d.ts.map +1 -1
- package/dist/writer/stamp-exercise.js +25 -18
- package/dist/writer/stamp-exercise.js.map +1 -1
- package/dist/writer/supplemental-template.d.ts +3 -2
- package/dist/writer/supplemental-template.d.ts.map +1 -1
- package/dist/writer/supplemental-template.js +15 -15
- package/dist/writer/supplemental-template.js.map +1 -1
- package/package.json +1 -1
- package/skills/olympia-authoring/SKILL.md +25 -9
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ file, one sheet per training day, with merged cells, custom borders, an
|
|
|
17
17
|
embedded logo, and a domain-specific notation (`12E`, `:20E`, `12EL`,
|
|
18
18
|
`x3 Rest :60`, etc.). Asking an LLM to edit XLSX directly is fragile: it
|
|
19
19
|
corrupts merges, loses the logo, and can't reason about the implicit
|
|
20
|
-
|
|
20
|
+
multi-week / 1A-1B / set-by-set structure encoded in the visual layout.
|
|
21
21
|
|
|
22
22
|
Each program also ships with a **companion warm-up workbook** — same client,
|
|
23
23
|
same date, paired day-for-day (the "Day 4" warm-up column is performed
|
|
@@ -77,20 +77,21 @@ type Exercise = {
|
|
|
77
77
|
name: string; // "2DB Alternating Bench Press"
|
|
78
78
|
groupLabel?: string; // "1A", "1B", "2A"… matches /^\d+[A-Z]$/
|
|
79
79
|
notes?: string;
|
|
80
|
-
sets: (string | null)[][]; // [setIdx][weekIdx];
|
|
80
|
+
sets: (string | null)[][]; // [setIdx][weekIdx]; one entry per week (4 or 6)
|
|
81
|
+
weights?: (string | null)[][]; // Weight column, same shape as sets
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
type SupplementalNote = {
|
|
84
85
|
row: number; // offset from "Sport Specific/" label row
|
|
85
|
-
col: string; // "
|
|
86
|
+
col: string; // a week's Reps column: "D" | "F" | … (one per week)
|
|
86
87
|
value: string;
|
|
87
88
|
};
|
|
88
89
|
```
|
|
89
90
|
|
|
90
91
|
### Prescription cell grammar
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
Each `sets[setIdx][weekIdx]` is a single opaque string encoding **reps**,
|
|
94
|
+
**time**, or **breaths**:
|
|
94
95
|
|
|
95
96
|
| Format | Meaning |
|
|
96
97
|
| --------------------- | ------------------------------------ |
|
|
@@ -101,14 +102,36 @@ single opaque string encoding **reps**, **time**, or **breaths**:
|
|
|
101
102
|
| free-form strings | circuit-style instructions, OK too |
|
|
102
103
|
| `null` | empty cell |
|
|
103
104
|
|
|
104
|
-
The schema enforces shape (6 weeks per set
|
|
105
|
-
section kinds) but does **not** validate the grammar of each prescription
|
|
105
|
+
The schema enforces shape (1-6 weeks per set and the same count for every
|
|
106
|
+
set in a program, group label regex, allowed section kinds) but does **not** validate the grammar of each prescription
|
|
106
107
|
string — Olympia's own files include free-form entries in some spots.
|
|
107
108
|
|
|
108
109
|
The `Date:` cells in each sheet's header row are **intentionally left
|
|
109
110
|
blank** — clients hand-write the week dates on the printed sheet, so the
|
|
110
111
|
schema has no field for them and the writer never fills them.
|
|
111
112
|
|
|
113
|
+
### Weight column
|
|
114
|
+
|
|
115
|
+
Each week has a Weight cell beside its reps cell. Most are left empty for
|
|
116
|
+
the client to fill in by hand, but coaches type starting loads (`25`) and
|
|
117
|
+
equipment settings there too: a band colour (`Yel`), a box height
|
|
118
|
+
(`12" + 2 Pads`), a rack position (`#10`). `weights` carries those cells
|
|
119
|
+
as free text, in the same shape as `sets`, and is omitted when every cell
|
|
120
|
+
is empty.
|
|
121
|
+
|
|
122
|
+
### Week count and sheet layout
|
|
123
|
+
|
|
124
|
+
Olympia programs run 4 or 6 weeks. The week count is the length of each
|
|
125
|
+
set row; the writer lays the sheet out with exactly that many week pairs
|
|
126
|
+
and puts the Notes column right after the last one (L for 4 weeks, P for
|
|
127
|
+
6). The reader finds the table from its `Exercise | Reps | Weight …`
|
|
128
|
+
header row, so it handles both lengths and the two header positions seen
|
|
129
|
+
in coach-built files (row 4 or row 5).
|
|
130
|
+
|
|
131
|
+
Warm-up exercises listed inside a day sheet are closed by a `Warmup N`
|
|
132
|
+
label row; they decode into a `warmup` section and are written back the
|
|
133
|
+
same way.
|
|
134
|
+
|
|
112
135
|
### Supplemental area
|
|
113
136
|
|
|
114
137
|
The bottom of every day sheet is a trainer-managed "Sport Specific /
|
|
@@ -250,6 +273,11 @@ Coverage:
|
|
|
250
273
|
- **`reader.test.ts`** — All three program samples parse into schema-valid
|
|
251
274
|
`Program` documents; spot checks on Bobby's first exercise, Giulianna's
|
|
252
275
|
variable set counts, exercise notes, supplemental notes.
|
|
276
|
+
- **`week-count.test.ts`** — A 4-week program is laid out with four week
|
|
277
|
+
pairs and round-trips; a hand-built 4-week sheet (header on row 4,
|
|
278
|
+
`Warmup N` labels, Notes in column L) decodes correctly.
|
|
279
|
+
- **`weights.test.ts`** — Weight-column cells are written beside their
|
|
280
|
+
reps, round-trip, and must match the shape of `sets`.
|
|
253
281
|
- **`round-trip.test.ts`** — The primary determinism guarantee: for each
|
|
254
282
|
program sample, `parse → write → parse` produces JSON equal to the
|
|
255
283
|
original.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, SupplementalNote, ProgramXlsxToJsonInput, ProgramXlsxToJsonOutput, ProgramJsonToXlsxInput, ProgramJsonToXlsxOutput, } from "./schema/program.js";
|
|
1
|
+
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, WeightCell, SupplementalNote, ProgramXlsxToJsonInput, ProgramXlsxToJsonOutput, ProgramJsonToXlsxInput, ProgramJsonToXlsxOutput, } from "./schema/program.js";
|
|
2
2
|
export { WarmUpDocument, WarmUpDay, WarmUpSection, WarmUpItem, WarmUpXlsxToJsonInput, WarmUpXlsxToJsonOutput, WarmUpJsonToXlsxInput, WarmUpJsonToXlsxOutput, } from "./schema/warmup.js";
|
|
3
3
|
export { createServer } from "./server.js";
|
|
4
4
|
export { parseProgramWorkbook } from "./reader/parse-workbook.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC"}
|
|
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,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Programmatic entry point. The package's primary use is the MCP CLI
|
|
2
2
|
// (registered under the `bin` field), but the schema and server factory
|
|
3
3
|
// are also exported for callers that want to embed or compose the adapter.
|
|
4
|
-
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, SupplementalNote, ProgramXlsxToJsonInput, ProgramXlsxToJsonOutput, ProgramJsonToXlsxInput, ProgramJsonToXlsxOutput, } from "./schema/program.js";
|
|
4
|
+
export { Program, Day, Section, SectionKind, Exercise, SetRow, Cell, WeightCell, SupplementalNote, ProgramXlsxToJsonInput, ProgramXlsxToJsonOutput, ProgramJsonToXlsxInput, ProgramJsonToXlsxOutput, } from "./schema/program.js";
|
|
5
5
|
export { WarmUpDocument, WarmUpDay, WarmUpSection, WarmUpItem, WarmUpXlsxToJsonInput, WarmUpXlsxToJsonOutput, WarmUpJsonToXlsxInput, WarmUpJsonToXlsxOutput, } from "./schema/warmup.js";
|
|
6
6
|
export { createServer } from "./server.js";
|
|
7
7
|
export { parseProgramWorkbook } from "./reader/parse-workbook.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC"}
|
|
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,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC"}
|
|
@@ -1 +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;AAG9B,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC1B,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;
|
|
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;AAG9B,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC1B,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAyFD,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CA6H9D"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { cellText, cellOrNull, isMergeContinuation } from "./cell-utils.js";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
["supplemental", "supplemental"],
|
|
9
|
-
["conditioning", "conditioning"],
|
|
10
|
-
]);
|
|
2
|
+
const MAX_WEEK_COUNT = 6;
|
|
3
|
+
const FIRST_WEEK_COL_INDEX = 4; // column D
|
|
4
|
+
const HEADER_SEARCH_ROWS = 12;
|
|
5
|
+
// Layout of sheets written by this package, used when a sheet has no
|
|
6
|
+
// recognizable "Exercise | Reps | Weight …" header row.
|
|
7
|
+
const DEFAULT_HEADER_ROW = 5;
|
|
11
8
|
const SUPPLEMENTAL_TRIGGER_LABELS = new Set([
|
|
12
9
|
"sport specific",
|
|
13
10
|
"sport specific/",
|
|
@@ -15,21 +12,62 @@ const SUPPLEMENTAL_TRIGGER_LABELS = new Set([
|
|
|
15
12
|
"conditioning",
|
|
16
13
|
"circuit",
|
|
17
14
|
]);
|
|
18
|
-
// Columns scanned for supplementalNotes. Excludes A/B (cosmetic narrow margins)
|
|
19
|
-
// and Q (rarely used).
|
|
20
|
-
const SUPPLEMENTAL_COLS = ["C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"];
|
|
21
15
|
function isGroupLabel(s) {
|
|
22
16
|
return /^\d+[A-Z]$/.test(s);
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
/** "Warmup 1", "Warm Up 2", "Warm-up 3": the label row closing an in-sheet warm-up exercise. */
|
|
19
|
+
function isWarmupLabel(s) {
|
|
20
|
+
return /^warm[\s-]?up\s*#?\d+$/i.test(s);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Locate the exercise table from its header row ("Exercise | Reps | Weight |
|
|
24
|
+
* Reps | Weight | …"). Olympia's sheets vary: the header sits on row 4 or 5
|
|
25
|
+
* and a program runs 4 or 6 weeks, with the Notes column immediately right
|
|
26
|
+
* of the last week pair. The body starts two rows below the header.
|
|
27
|
+
*/
|
|
28
|
+
function detectLayout(ws) {
|
|
29
|
+
let headerRow = DEFAULT_HEADER_ROW;
|
|
30
|
+
let weekCount = MAX_WEEK_COUNT;
|
|
31
|
+
for (let r = 1; r <= HEADER_SEARCH_ROWS; r++) {
|
|
32
|
+
const row = ws.getRow(r);
|
|
33
|
+
if (cellText(row.getCell("C").value).trim().toLowerCase() !== "exercise")
|
|
34
|
+
continue;
|
|
35
|
+
let found = 0;
|
|
36
|
+
while (found < MAX_WEEK_COUNT &&
|
|
37
|
+
cellText(row.getCell(FIRST_WEEK_COL_INDEX + 2 * found).value).trim().toLowerCase() === "reps") {
|
|
38
|
+
found++;
|
|
39
|
+
}
|
|
40
|
+
// An "Exercise" cell without Reps headers beside it (a title, a note)
|
|
41
|
+
// is not the header row; keep looking.
|
|
42
|
+
if (found === 0)
|
|
43
|
+
continue;
|
|
44
|
+
headerRow = r;
|
|
45
|
+
weekCount = found;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
const weekCols = Array.from({ length: weekCount }, (_, i) => FIRST_WEEK_COL_INDEX + 2 * i);
|
|
49
|
+
return {
|
|
50
|
+
firstBodyRow: headerRow + 2,
|
|
51
|
+
weekCols,
|
|
52
|
+
notesCol: FIRST_WEEK_COL_INDEX + 2 * weekCount,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function readWeekRow(row, layout) {
|
|
56
|
+
return layout.weekCols.map((col) => cellOrNull(row.getCell(col).value));
|
|
57
|
+
}
|
|
58
|
+
/** The Weight cell sits immediately right of each week's Reps cell. */
|
|
59
|
+
function readWeightRow(row, layout) {
|
|
60
|
+
return layout.weekCols.map((col) => cellOrNull(row.getCell(col + 1).value));
|
|
26
61
|
}
|
|
27
62
|
export function parseDaySheet(ws) {
|
|
28
63
|
const warnings = [];
|
|
29
64
|
const sections = [];
|
|
65
|
+
const layout = detectLayout(ws);
|
|
30
66
|
let current = { kind: "main", exercises: [] };
|
|
31
67
|
let exercise = null;
|
|
32
|
-
|
|
68
|
+
// An exercise closed by a "Warmup N" label belongs to the warmup section;
|
|
69
|
+
// every other exercise belongs to main. A change of kind starts a new section.
|
|
70
|
+
const flushExercise = (groupLabel, kind = "main") => {
|
|
33
71
|
if (!exercise)
|
|
34
72
|
return;
|
|
35
73
|
const ex = {
|
|
@@ -40,9 +78,19 @@ export function parseDaySheet(ws) {
|
|
|
40
78
|
ex.groupLabel = groupLabel;
|
|
41
79
|
if (exercise.notes)
|
|
42
80
|
ex.notes = exercise.notes;
|
|
81
|
+
if (exercise.weights.some((row) => row.some((cell) => cell !== null))) {
|
|
82
|
+
ex.weights = exercise.weights;
|
|
83
|
+
}
|
|
84
|
+
if (current.kind !== kind) {
|
|
85
|
+
if (current.exercises.length > 0) {
|
|
86
|
+
sections.push({ kind: current.kind, exercises: current.exercises });
|
|
87
|
+
}
|
|
88
|
+
current = { kind, exercises: [] };
|
|
89
|
+
}
|
|
43
90
|
current.exercises.push(ex);
|
|
44
91
|
exercise = null;
|
|
45
92
|
};
|
|
93
|
+
const noteOf = (row) => cellText(row.getCell(layout.notesCol).value).trim();
|
|
46
94
|
const flushSection = () => {
|
|
47
95
|
flushExercise();
|
|
48
96
|
sections.push({ kind: current.kind, exercises: current.exercises });
|
|
@@ -50,7 +98,7 @@ export function parseDaySheet(ws) {
|
|
|
50
98
|
const lastRow = ws.actualRowCount > 0 ? ws.rowCount : 0;
|
|
51
99
|
let supplementalStartRow;
|
|
52
100
|
let supplementalNotes;
|
|
53
|
-
for (let r =
|
|
101
|
+
for (let r = layout.firstBodyRow; r <= lastRow; r++) {
|
|
54
102
|
const row = ws.getRow(r);
|
|
55
103
|
const cCell = row.getCell("C");
|
|
56
104
|
const cText = cellText(cCell.value).trim();
|
|
@@ -59,26 +107,41 @@ export function parseDaySheet(ws) {
|
|
|
59
107
|
if (SUPPLEMENTAL_TRIGGER_LABELS.has(cLower)) {
|
|
60
108
|
flushSection();
|
|
61
109
|
supplementalStartRow = r;
|
|
62
|
-
supplementalNotes = captureSupplementalNotes(ws, r, lastRow);
|
|
110
|
+
supplementalNotes = captureSupplementalNotes(ws, r, lastRow, layout);
|
|
63
111
|
break;
|
|
64
112
|
}
|
|
65
|
-
//
|
|
66
|
-
|
|
113
|
+
// A group label ("1A") or warm-up label ("Warmup 1") terminates an exercise block.
|
|
114
|
+
const warmupLabel = isWarmupLabel(cText);
|
|
115
|
+
if (cText !== "" && (isGroupLabel(cText) || warmupLabel) && !isMergeContinuation(cCell)) {
|
|
67
116
|
if (!exercise) {
|
|
68
|
-
warnings.push(`row ${r}:
|
|
117
|
+
warnings.push(`row ${r}: label "${cText}" without a preceding exercise name`);
|
|
69
118
|
continue;
|
|
70
119
|
}
|
|
71
|
-
|
|
72
|
-
|
|
120
|
+
// A label row with nothing in it, under rows that do hold a
|
|
121
|
+
// prescription, is only there to carry the label of a one-set
|
|
122
|
+
// exercise — it is not a set.
|
|
123
|
+
const labelSets = readWeekRow(row, layout);
|
|
124
|
+
const labelWeights = readWeightRow(row, layout);
|
|
125
|
+
const labelRowEmpty = [...labelSets, ...labelWeights].every((cell) => cell === null);
|
|
126
|
+
const blockHasContent = [...exercise.sets, ...exercise.weights].some((cells) => cells.some((cell) => cell !== null));
|
|
127
|
+
if (!(labelRowEmpty && blockHasContent)) {
|
|
128
|
+
exercise.sets.push(labelSets);
|
|
129
|
+
exercise.weights.push(labelWeights);
|
|
130
|
+
}
|
|
131
|
+
const pNote = noteOf(row);
|
|
73
132
|
if (pNote && !exercise.notes)
|
|
74
133
|
exercise.notes = pNote;
|
|
75
|
-
|
|
134
|
+
if (warmupLabel)
|
|
135
|
+
flushExercise(undefined, "warmup");
|
|
136
|
+
else
|
|
137
|
+
flushExercise(cText);
|
|
76
138
|
continue;
|
|
77
139
|
}
|
|
78
140
|
// Continuation of a merged exercise name?
|
|
79
141
|
if (isMergeContinuation(cCell) && exercise) {
|
|
80
|
-
exercise.sets.push(readWeekRow(row));
|
|
81
|
-
|
|
142
|
+
exercise.sets.push(readWeekRow(row, layout));
|
|
143
|
+
exercise.weights.push(readWeightRow(row, layout));
|
|
144
|
+
const pNote = noteOf(row);
|
|
82
145
|
if (pNote && !exercise.notes)
|
|
83
146
|
exercise.notes = pNote;
|
|
84
147
|
continue;
|
|
@@ -88,9 +151,10 @@ export function parseDaySheet(ws) {
|
|
|
88
151
|
flushExercise();
|
|
89
152
|
exercise = {
|
|
90
153
|
name: cText,
|
|
91
|
-
sets: [readWeekRow(row)],
|
|
154
|
+
sets: [readWeekRow(row, layout)],
|
|
155
|
+
weights: [readWeightRow(row, layout)],
|
|
92
156
|
};
|
|
93
|
-
const pNote =
|
|
157
|
+
const pNote = noteOf(row);
|
|
94
158
|
if (pNote)
|
|
95
159
|
exercise.notes = pNote;
|
|
96
160
|
continue;
|
|
@@ -122,11 +186,16 @@ export function parseDaySheet(ws) {
|
|
|
122
186
|
* multiple cells appears once). The trigger labels themselves are skipped
|
|
123
187
|
* since they're added back by the writer's fixed template.
|
|
124
188
|
*/
|
|
125
|
-
function captureSupplementalNotes(ws, supplementalStartRow, lastRow) {
|
|
189
|
+
function captureSupplementalNotes(ws, supplementalStartRow, lastRow, layout) {
|
|
126
190
|
const out = [];
|
|
191
|
+
// Scan from column C through the Notes column. Excludes A/B (cosmetic
|
|
192
|
+
// narrow margins) and anything right of Notes.
|
|
193
|
+
const cols = [];
|
|
194
|
+
for (let i = 3; i <= layout.notesCol; i++)
|
|
195
|
+
cols.push(String.fromCharCode(64 + i));
|
|
127
196
|
for (let r = supplementalStartRow; r <= lastRow; r++) {
|
|
128
197
|
const row = ws.getRow(r);
|
|
129
|
-
for (const col of
|
|
198
|
+
for (const col of cols) {
|
|
130
199
|
const cell = row.getCell(col);
|
|
131
200
|
if (isMergeContinuation(cell))
|
|
132
201
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-day-sheet.js","sourceRoot":"","sources":["../../src/reader/parse-day-sheet.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAQ5E,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,
|
|
1
|
+
{"version":3,"file":"parse-day-sheet.js","sourceRoot":"","sources":["../../src/reader/parse-day-sheet.ts"],"names":[],"mappings":"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"}
|