Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
# Design — audio-shipped-file-size-cleanup
This change is a pure mechanical refactor across three packages. The design is the **split strategy** per file: every public symbol stays exported from its current module path; the splits happen *below* the public surface.
---
## 1. `@suaveplan/audio-timeline` — `engine/engine.ts` (548 → ≤300)
`TimelineEngine` is the single class in this file and currently owns:
- Construction + adapter wiring (`setAdapter`, `dispose`)
- Track CRUD (`addTrack`, `removeTrack`, `updateTrack`, `setTracks`)
- Clip CRUD (`addClip`, `removeClip`, `updateClip`, `splitClip`, `joinClip`)
- Mixer mutations (`setMasterVolume`, `setTrackVolume`, `setTrackMute`, `setTrackSolo`, `setTrackPan`)
- Transport (`play`, `pause`, `stop`, `seek`, `setLoop`, `setTempo`)
- Snapshot / restore + undo/redo dispatch
- Event emission
### Proposed split
Keep `TimelineEngine` in `engine.ts` as the public class, but extract helper modules called from its methods:
```text
src/engine/
engine.ts ← class shell + delegating methods (≤300)
engine-tracks.ts ← addTrack/removeTrack/updateTrack/setTracks helpers
engine-tracks.md
engine-clips.ts ← addClip/removeClip/updateClip/splitClip/joinClip helpers
engine-clips.md
engine-mixer.ts ← setMasterVolume/setTrackVolume/Mute/Solo/Pan helpers
engine-mixer.md
engine-transport.ts ← play/pause/stop/seek/setLoop/setTempo helpers
engine-transport.md
engine.test.ts ← class-level invariants only (≤500)
engine-tracks.test.ts ← extracted track tests
engine-clips.test.ts ← extracted clip tests
engine-mixer.test.ts ← extracted mixer tests
engine-transport.test.ts ← extracted transport tests
```
Each helper module exports pure functions of `(state, args) => newState` (where `state` is `TimelineEngine`'s internal record) plus any side-effect-free derived values. `TimelineEngine` methods become 1–3 liners that call the helper and forward the result. This pattern matches how `audio-core`'s `process/` directory is structured.
The original `engine.test.ts` splits along the same four axes; the residual `engine.test.ts` keeps construction, adapter wiring, snapshot/restore, undo/redo dispatch, and event emission tests — the cross-cutting concerns no single helper owns.
---
## 2. `@suaveplan/audio-transport` — `transport/transport.ts` (419 → ≤300)
`Transport` is the single class and owns:
- Construction + clock injection
- BPM + time-signature + PPQ state
- Tick advance + lookahead scheduling loop
- Schedule / cancel API
- Loop region + swing
- Tempo automation
### Proposed split
```text
src/transport/
transport.ts ← class shell (≤300)
transport-schedule.ts ← schedule/cancel/lookahead helpers
transport-schedule.md
transport-tempo.ts ← BPM + tempo automation + tick conversion helpers
transport-tempo.md
transport.test.ts ← stays as-is (already under cap)
```
No test splitting needed — `transport.test.ts` is already within the 500-line cap.
---
## 3. `@suaveplan/audio-metadata` — `parsers/id3v2/id3v2.ts` (536 → ≤300)
`id3v2.ts` is the most over-budget src file. It owns:
- Magic-byte detection
- Header + extended-header parsing
- Frame iteration
- Per-frame-type decoders (TXXX, T..., COMM, USLT, APIC, UFID, WCOM, WCOP, …)
- Text-encoding decoders (ISO-8859-1, UTF-16, UTF-16BE, UTF-8)
- Unsynchronisation reversal
### Proposed split
```text
src/parsers/id3v2/
id3v2.ts ← public parseId3v2() + frame dispatch (≤300)
id3v2-header.ts ← header + extended-header parsing
id3v2-header.md
id3v2-frames-text.ts ← T... / TXXX text frame decoders
id3v2-frames-text.md
id3v2-frames-binary.ts ← APIC / UFID / GEOB binary frame decoders
id3v2-frames-binary.md
id3v2-frames-url.ts ← W... URL frame decoders
id3v2-frames-url.md
id3v2-text-encoding.ts ← ISO-8859-1 / UTF-16 / UTF-16BE / UTF-8 decoders
id3v2-text-encoding.md
id3v2-unsync.ts ← unsynchronisation reversal
id3v2-unsync.md
id3v2.test.ts ← integration parses on real fixture files (≤500)
id3v2-header.test.ts ← header-specific
id3v2-frames-text.test.ts ← text-frame-specific
id3v2-frames-binary.test.ts ← binary-frame-specific
id3v2-frames-url.test.ts ← url-frame-specific
id3v2-text-encoding.test.ts ← encoding-specific
id3v2-unsync.test.ts ← unsync-specific
```
The split mirrors the spec sections of the ID3v2.4 standard, so the file boundaries match how future maintainers will reason about the format.
### `id3v2.test.ts` (1340 → 7 files of ≤500 each)
The current `id3v2.test.ts` mixes header tests, every frame type, encoding round-trips, and integration parses. Splitting by frame family (per the source split above) gives ~150–200 lines per file. The residual `id3v2.test.ts` keeps the end-to-end "parse a real fixture file" cases.
---
## 4. `@suaveplan/audio-metadata` — `parsers/mp4-atom/mp4-atom.ts` (351 → ≤300)
Lightest split. The file owns atom-walking + per-atom decoders (`ftyp`, `moov`, `mvhd`, `mdat`, `ilst` and the iTunes metadata sub-atoms). Extract the iTunes-specific decoders:
```text
src/parsers/mp4-atom/
mp4-atom.ts ← public parseMp4Atom() + container walker (≤300)
mp4-atom-itunes.ts ← iTunes/ilst metadata decoders
mp4-atom-itunes.md
mp4-atom.test.ts ← container + non-iTunes tests (≤500)
mp4-atom-itunes.test.ts ← iTunes-specific
```
---
## 5. `@suaveplan/audio-metadata` — `parsers/ogg-vorbis/ogg-vorbis.test.ts` (803 → ≤500)
Source file is already within cap. Only the test file needs splitting:
```text
src/parsers/ogg-vorbis/
ogg-vorbis.ts ← unchanged
ogg-vorbis.test.ts ← page parsing + comment header (≤500)
ogg-vorbis-frames.test.ts ← extracted frame-level tests
```
---
## 6. Cross-cutting rules for the split
- **Public surface is invariant.** Every existing `export` from `<pkg>/src/index.ts` must continue to resolve to the same symbol with the same signature. The split is *internal*.
- **Subpath exports unchanged.** The `package.json` `exports` map for each package keeps every existing entry. New internal helper modules are NOT added to `exports` — they are implementation details.
- **Barrels use explicit named re-exports** (§6a). No `export * from` in new feature barrels.
- **Sibling `.md` files** added for every new `.ts` per §4 (200-word minimum, six required sections).
- **Coverage stays 100/100/100/100** per `vitest.config.ts` thresholds.
- **No new behavior.** A diff of `dist/*.d.ts` must show only path changes — no type-shape changes.
## 7. Risk
Low. The packages have no published consumers; the refactor is mechanical; the tests are the contract and they all must continue to pass. The largest file (`id3v2.test.ts` at 1340 lines) is the highest-leverage win: shrinking it makes the format-spec correspondence explicit and gives future maintainers per-frame-family focus.
The one non-mechanical risk is in `audio-timeline/engine.ts` — extracting helper modules implies extracting a `TimelineEngineState` shape, which is currently inlined as private class fields. The helpers operate on that shape; if the extraction inadvertently widens the visibility of private state, the public surface widens. Mitigation: keep `TimelineEngineState` as a non-exported type in `engine-state.ts` (or inline in `engine.ts`) and pass it explicitly to helpers; do not export it.