@enagonathletics/flipturn

中文文档
0.4.0发布于 2026/10/05MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 2496

Read and write swim meet files (SDIF, Hy-Tek .hy3/.ev3/.hyv) in TypeScript.

原始使用文档
文档目录7 节
  1. Install
  2. Status
  3. Formats
  4. Entry limits and fees
  5. Usage
  6. Docs
  7. License

flipturn

Read and write swim meet files (SDIF, Hy-Tek .hy3/.ev3/.hyv) in TypeScript.

MIT-licensed, zero-runtime-dependency, ESM. Runs on Node >=22, Bun, and browsers. Library code never touches the file system: pass it text or bytes.

Install

npm install @enagonathletics/flipturn

Status

Pre-1.0. The API is unstable and will change without a major version bump (see bump-minor-pre-major in release-please-config.json).

Formats

FormatExtensionsReadWrite
SDIF v3.sd3, .cl2Yes: meet, teams, swimmers, entries, results, splitsYes: entries (standard SDIF)
Hy-Tek meet results.hy3Yes: entries, results per round, relays, DQ reasonsNo
Hy-Tek event files.ev3, .hyvYes: events, sessions, fees, qualifying timesNo
Zip containers.zipYes: detects and reads each meet file insideNo
Lenex.lef, .lxfNoNo

Every reader returns the same format-neutral Meet model plus the file's raw records and any warnings. Known gaps: HY3 split records (G1) are not read, and Team Unify's "Extended" SD3 variant is not written until a real sample has been compared.

Entry limits and fees

Meet.entryLimits and Meet.fees are meet-wide; MeetEvent.entryFee is per event and IndividualEntry/RelayEntry.entryFee is per entry. A format only gets a field here when a byte position for it was confirmed against a documented field table or a real exported file — see porting policy for the sources.

FormatentryLimitsFee types
EV3maxTotalEntries, maxIndividualEntries, maxRelayEntries — meet-wide, per swimmer except the total (header fields 19–21, 1-based)MeetEvent.entryFee per event/relay (field 15), plus meet-wide teamSurcharge, athleteSurcharge, facilitySurcharge (header fields 7–9)
HYVNone — confirmed absent. Team Manager's 11-field header and ~18-field event row have no unclaimed columns for one; cross-checked against swimparse and hytek-parser's independent HYV readers, neither of which decodes anything beyond the existing per-event entryFeeMeetEvent.entryFee per event/relay only
HY3None — confirmed absent. A results/entries format has no reason to carry them and none of swimparse, swimlib or hytek-parser decode anyIndividualEntry.entryFee (E1, 1-based cols 33–38) and RelayEntry.entryFee (F1, same columns) only — no meet-wide fee field
SDIFNone — confirmed absent from the spec text itself (no field in B1/B2/D0/D1)None — confirmed absent, same basis

Two candidates were investigated and deliberately not modeled:

  • EV3 event-row columns 27–29 (max_entries, max_individual_entries, max_relay_entries per swimlib's field table) sit right after the per-event session columns, which would fit a per-day/session limit — but the one EV3 sample available repeats the same three values on every event regardless of day, which is equally consistent with "an event-level cap" as with "a per-day limit stated redundantly." Absent a real file where they vary by day, this is not asserted as the per-day limit the task asked for.
  • HY3 B2's meetFee (swimlib's claimed 1-based cols 100–106) does not survive a cross-check: swimlib's own B1 date fields, in the same record family, land on garbage when checked against real Meet Manager results exports, while swimparse and hytek-parser — the two libraries whose B-record offsets do reproduce the real dates in those files — neither decode a B2 fee at all. Treated as unconfirmed, not modeled.

Usage

Read any meet file:

import { readSdif } from '@enagonathletics/flipturn/sdif';

const { meet, warnings } = readSdif(bytes); // Uint8Array (Windows-1252) or string
meet.swimmers; // name, birth date, gender, external ids
meet.entries; // seed times and, for results files, one result per round

Read every meet file in a Meet Manager zip:

import { readMeetArchive } from '@enagonathletics/flipturn/zip';

for (const file of await readMeetArchive(zipBytes)) {
    if (file.result) console.log(file.name, file.format, file.result.meet.events.length);
    else if (file.error) console.warn(file.name, file.error);
}

Event files keep the sex code as written (G/B age-group, W/M senior) next to the canonical gender:

import { readEv3 } from '@enagonathletics/flipturn/ev3';

const [event] = readEv3(text).meet.events;
event.sexCode; // 'G'
event.gender; // 'F'

Write an SDIF entries file. canadian mode makes the USA Swimming ID optional:

import { encodeWindows1252 } from '@enagonathletics/flipturn/core';
import { writeSdifEntries } from '@enagonathletics/flipturn/sdif';

const { text, warnings } = writeSdifEntries(meet, {
    mode: 'canadian',
    contact: { name: 'Registrar, Lee', phone: '2505550199' }
});
const bytes = encodeWindows1252(text); // 160-byte records, CRLF line endings

Meet.altitude (whole feet, 0-9999) goes in B1. Pass profile: 'team-unify' to write the layout of Team Unify's Standard SD3 export instead of the spec's where they differ: event numbers right-justified in columns 73-75 with an uppercase suffix letter in 76, TIME codes such as NT right-justified, no C2 for a team without a coach, an A0 description (description, default Meet Entries), B1 altitude 0 when unset, the team code's LSC in D0 columns 4-11, D3 participation flags F, Swimmer.middleName and N in column 147, and Z0 batch 1 with zero membership counts.

Swim times are integers in hundredths:

import { formatSwimTime, parseSwimTime } from '@enagonathletics/flipturn/core';

parseSwimTime('1:02.34'); // { kind: 'time', hundredths: 6234 }
formatSwimTime({ kind: 'nt' }); // 'NT'

Docs

License

MIT © Enagon Athletics

版本与发布记录

@enagonathletics/flipturn 共发布 4 个版本,首次发布于 2026/09/27;过去 12 个月发布了 4 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.0latest2026/10/051 个月前
0.3.02026/09/271 个月前
0.2.02026/09/271 个月前
0.1.02026/09/271 个月前

关于 @enagonathletics/flipturn 的常见问题

@enagonathletics/flipturn 是什么?

Read and write swim meet files (SDIF, Hy-Tek .hy3/.ev3/.hyv) in TypeScript.

如何安装 @enagonathletics/flipturn?

在项目目录运行 npm install @enagonathletics/flipturn,或使用 pnpm add / yarn add / bun add。

@enagonathletics/flipturn 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@enagonathletics/flipturn 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@enagonathletics/flipturn 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@enagonathletics/flipturn 可以商用吗?

@enagonathletics/flipturn 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@enagonathletics/flipturn 的下载量有多少?

根据 npm 官方下载统计,@enagonathletics/flipturn 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,496 次,日均约 83 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@enagonathletics/flipturn 还在维护吗?

最新版本 0.4.0 发布于 2026/10/05(1 个月前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/09/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。