feat: publish av-tools 0.1.0

This commit is contained in:
2026-07-24 14:58:03 +02:00
commit fcc537b024
254 changed files with 63270 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
import { describe, expect, it } from 'vitest';
import {
addDurations,
clampTime,
roundSeconds,
validateSourceRange,
} from '../../../src/media/duration';
import {
formatFrameTimecode,
formatTimecode,
parseTimecode,
parseTimecodeDetailed,
} from '../../../src/media/timecode';
describe('duration arithmetic', () => {
it('adds durations without exposing common binary drift', () => {
expect(addDurations([0.1, 0.2, 1.0000004])).toBe(1.3);
expect(roundSeconds(-0.0000001, 3)).toBe(0);
});
it('rejects invalid durations and clamps preview times', () => {
expect(() => addDurations([1, Number.NaN])).toThrow();
expect(() => addDurations([-1])).toThrow();
expect(clampTime(-2, 10)).toBe(0);
expect(clampTime(12, 10)).toBe(10);
});
it('validates source in/out ranges and source bounds', () => {
expect(validateSourceRange(1, 3, 5)).toEqual({
valid: true,
durationSeconds: 2,
issues: [],
});
expect(validateSourceRange(3, 1, 5).issues[0]?.code).toBe(
'source-out-before-in'
);
expect(validateSourceRange(1, 1, 5).issues[0]?.code).toBe('clip-too-short');
expect(
validateSourceRange(1, 6, 5).issues.some(
(issue) => issue.code === 'source-out-after-duration'
)
).toBe(true);
});
});
describe('timecode parsing and formatting', () => {
it.each([
['12.5', 12.5, undefined],
['01:02.500', 62.5, undefined],
['02:03:04.125', 7_384.125, undefined],
['00:00:10:12', 10.5, { frameRate: 24 }],
])('parses %s', (text, expected, options) => {
expect(parseTimecode(text, options)).toBe(expected);
});
it('reports malformed components', () => {
expect(parseTimecodeDetailed('01:60')).toEqual({
ok: false,
reason: 'seconds-out-of-range',
});
expect(parseTimecodeDetailed('00:00:01:10')).toEqual({
ok: false,
reason: 'frame-rate-required',
});
expect(parseTimecodeDetailed('-00:01', { allowNegative: false })).toEqual({
ok: false,
reason: 'negative-not-allowed',
});
expect(parseTimecode('anything')).toBeUndefined();
expect(parseTimecode('1.5:02:03')).toBeUndefined();
});
it('formats carry, precision, negative values and nominal frames', () => {
expect(formatTimecode(59.9996)).toBe('00:01:00.000');
expect(
formatTimecode(62.5, {
decimalPlaces: 2,
alwaysShowHours: false,
})
).toBe('01:02.50');
expect(formatTimecode(-1.25, { decimalPlaces: 2 })).toBe('-00:00:01.25');
expect(formatFrameTimecode(10.5, 24)).toBe('00:00:10:12');
expect(() => formatFrameTimecode(5, 0.5)).toThrow();
});
});