chore: refactored ClassCyclr to not extend arrays, with tests (#342)

## Overview

Small cleanup/refactor I've been meaning to do for a while. It's weird
that ClassCyclr adds aritrary properties to arrays. This switches the
internal representation of cycles a bit to use `TimeCycle` objects with
a `classes: ClassesList` property.

And, now `ClassCyclr` is unit tested! 🙌 

### PR Checklist

-   ~[ ] Fixes #~
-   [x] I have run this code to verify it works
-   [x] This PR includes unit tests for the code change
This commit is contained in:
Josh Goldberg
2022-10-17 10:03:51 -04:00
committed by GitHub
parent 5ae2f59099
commit 2d17b64723
8 changed files with 488 additions and 235 deletions
+1
View File
@@ -29,6 +29,7 @@
"Cyclr",
"devicelayr",
"dpad",
"dragonfruit",
"Drawr",
"Editr",
"eightbittr",
+373 -2
View File
@@ -1,5 +1,376 @@
import { expect } from "chai";
import { createClassCycler, createStubActor } from "./fakes.test";
const interval = 8;
describe("ClassCyclr", () => {
it("_", () => {
/* ... */
describe("addClassCycle", () => {
it("immediately runs a first class cycle when the actor does not have any cycles or class name", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
// Assert
expect(actor.className).to.be.equal("apple");
});
it("immediately runs a first class cycle when the actor does not have any cycles", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor({ className: "initial" });
// Act
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
// Assert
expect(actor.className).to.be.equal("initial apple");
});
it("immediately runs a first class cycle when the actor previously does have cycles", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor({ className: "initial" });
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle1", interval);
// Act
classCycler.addClassCycle(actor, ["cherry", "dragonfruit"], "myCycle2", interval);
// Assert
expect(actor.className).to.be.equal("initial apple cherry");
});
it("switches classes when the cycle time ticks", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor({ className: "initial" });
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
// Act
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("initial banana");
});
it("does not remove an existing, duplicate class name when the cycle time ticks", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = {
className: "initial apple",
placed: true,
};
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
// Act
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("initial apple banana");
});
it("switches classes again when the cycle time ticks twice", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor({ className: "initial" });
classCycler.addClassCycle(actor, ["apple", "banana", "cherry"], "myCycle", interval);
// Act
for (let i = 0; i < interval * 2; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("initial cherry");
});
it("restarts classes when the cycle time ticks through all classes after no initial class name", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana", "cherry"], "myCycle", interval);
// Act
for (let i = 0; i < interval * 3; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("apple");
});
it("restarts classes when the cycle time ticks through all classes after an initial class name", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor({ className: "initial" });
classCycler.addClassCycle(actor, ["apple", "banana", "cherry"], "myCycle", interval);
// Act
for (let i = 0; i < interval * 3; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("initial apple");
});
it("allows for multiple independent cycles", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle1", interval);
classCycler.addClassCycle(
actor,
["cherry", "dragonfruit"],
"myCycle2",
interval * 1.5
);
// Act
for (let i = 0; i < interval * 3; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("cherry banana");
});
});
describe("addClassCycleSynched", () => {
it("immediately runs a class cycle when the timeHandler", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycleSynched(actor, ["apple", "banana"], "myCycle", interval);
// Assert
expect(actor.className).to.be.equal("apple");
});
it("does not advance a class cycle when the timeHandler has not yet reached the tick interval", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycleSynched(actor, ["apple", "banana"], "myCycle", interval);
for (let i = 0; i < interval - 1; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("apple");
});
it("advances a class cycle when the timeHandler reaches the tick interval", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycleSynched(actor, ["apple", "banana"], "myCycle", interval);
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("banana");
});
it("adds a class when provided as a function that returns a string", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycle(
actor,
[() => "apple", () => "banana"],
"myCycle",
interval
);
// Assert
expect(actor.className).to.be.equal("apple");
});
it("adds a next class when provided as a function that returns a string", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycle(
actor,
[() => "apple", () => "banana"],
"myCycle",
interval
);
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("banana");
});
it("does not continue cycling when when provided a function that returns true", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycle(
actor,
[() => "apple", () => true, () => "cherry"],
"myCycle",
interval
);
for (let i = 0; i < interval * 2; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("");
});
it("continues cycling when when provided a function that returns false", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
// Act
classCycler.addClassCycle(
actor,
[() => "apple", () => false, () => "cherry"],
"myCycle",
interval
);
for (let i = 0; i < interval * 2; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("cherry");
});
});
describe("cancelAllCycles", () => {
it("does not crash when an actor does not yet have cycles", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
// Act
const act = () => classCycler.cancelAllCycles(actor);
// Assert
expect(act).not.to.throw();
});
it("cancels multiple cycles", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle1", interval);
classCycler.addClassCycle(actor, ["cherry", "dragonfruit"], "myCycle2", interval);
// Act
classCycler.cancelClassCycle(actor, "myCycle1");
classCycler.cancelClassCycle(actor, "myCycle2");
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Assert
expect(actor.className).to.be.equal("apple cherry");
});
});
describe("cancelClassCycle", () => {
it("does not crash when an actor does not yet have cycles", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
// Act
const act = () => classCycler.cancelClassCycle(actor, "myCycle");
// Assert
expect(act).not.to.throw();
});
it("cancels a cycle when the cycle has not reached its second iteration", () => {
// Arrange
const { classCycler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
// Act
classCycler.cancelClassCycle(actor, "myCycle");
// Assert
expect(actor.className).to.be.equal("apple");
});
it("cancels a cycle when the cycle has not yet looped", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
for (let i = 0; i < interval; i += 1) {
timeHandler.advance();
}
// Act
classCycler.cancelClassCycle(actor, "myCycle");
// Assert
expect(actor.className).to.be.equal("banana");
});
it("cancels a cycle when the cycle has looped", () => {
// Arrange
const { classCycler, timeHandler } = createClassCycler();
const actor = createStubActor();
classCycler.addClassCycle(actor, ["apple", "banana"], "myCycle", interval);
for (let i = 0; i < interval * 2; i += 1) {
timeHandler.advance();
}
// Act
classCycler.cancelClassCycle(actor, "myCycle");
// Assert
expect(actor.className).to.be.equal("apple");
});
});
});
+70 -140
View File
@@ -1,48 +1,11 @@
import { NumericCalculator, TimeEvent, TimeHandlr } from "timehandlr";
import { NumericCalculator, TimeHandlr } from "timehandlr";
import {
Actor,
ClassCalculator,
ClassChanger,
ClassCyclrSettings,
TimeCycle,
TimeCycleSettings,
} from "./types";
/**
* Default classAdd Function.
*
* @param actor The actor whose class is being modified.
* @param className The String to be added to the actor's class.
*/
const classAddGeneric = (actor: Actor, className: string): void => {
actor.className += ` ${className}`;
};
/**
* Default classRemove Function.
*
* @param actor The actor whose class is being modified.
* @param className The String to be removed from the actor's class.
*/
const classRemoveGeneric = (actor: Actor, className: string): void => {
actor.className = actor.className.replace(className, "");
};
import { Actor, ClassCyclrSettings, ClassesList, TimeCycle } from "./types";
/**
* Cycles through class names using TimeHandlr events.
*/
export class ClassCyclr {
/**
* Adds a class to an Actor.
*/
private readonly classAdd: ClassChanger;
/**
* Removes a class from an Actor.
*/
private readonly classRemove: ClassChanger;
/**
* Scheduling for dynamically repeating or synchronized events.
*/
@@ -54,9 +17,6 @@ export class ClassCyclr {
* @param settings Settings to be used for initialization.
*/
public constructor(settings: ClassCyclrSettings) {
this.classAdd = settings.classAdd === undefined ? classAddGeneric : settings.classAdd;
this.classRemove =
settings.classRemove === undefined ? classRemoveGeneric : settings.classRemove;
this.timeHandler = settings.timeHandler;
}
@@ -64,28 +24,24 @@ export class ClassCyclr {
* Adds a sprite cycle (settings) for an actor, to be referenced by the given
* name in the actor's cycles Object.
*
* @aram actor The object whose class is to be cycled.
* @param settings Container for repetition settings, particularly .length.
* @param actor The object whose class is to be cycled.
* @param classes Classes to cycle through.
* @param name Name of the cycle, to be referenced in the actor's cycles.
* @param timing How long to wait between classes.
*/
public addClassCycle(
actor: Actor,
settings: TimeCycleSettings,
classes: ClassesList,
name: string,
timing: number | NumericCalculator
): TimeCycle {
if (actor.cycles === undefined) {
actor.cycles = {};
}
) {
actor.cycles ??= {};
this.cancelClassCycle(actor, name);
// Immediately run the first class cycle, then return
settings = actor.cycles[name] = this.setClassCycle(actor, settings, timing);
this.cycleClass(actor, settings);
return settings;
// Immediately run the first class cycle
const cycle = (actor.cycles[name] = this.startClassCycle(actor, classes, timing));
this.cycleClass(actor, cycle);
}
/**
@@ -93,30 +49,24 @@ export class ClassCyclr {
* the given name in the actor's cycles Object, and in tune with all other
* cycles of the same period.
*
* @pram actor The object whose class is to be cycled.
* @param settings Container for repetition settings, particularly .length.
* @param actor The object whose class is to be cycled.
* @param classes Classes to cycle through.
* @param name Name of the cycle, to be referenced in the actor's cycles.
* @param timing How long to wait between classes.
*/
public addClassCycleSynched(
actor: Actor,
settings: TimeCycle,
classes: ClassesList,
name: string,
timing: number | NumericCalculator
): TimeCycle {
if (actor.cycles === undefined) {
actor.cycles = {};
}
) {
actor.cycles ??= {};
if (typeof name !== "undefined") {
this.cancelClassCycle(actor, name);
}
this.cancelClassCycle(actor, name);
// Immediately run the first class cycle, then return
settings = actor.cycles[name] = this.setClassCycle(actor, settings, timing, true);
this.cycleClass(actor, settings);
return settings;
// Immediately synch -and potentially run- the first class cycle
const cycle = (actor.cycles[name] = this.startClassCycle(actor, classes, timing, true));
this.cycleClass(actor, cycle);
}
/**
@@ -126,12 +76,12 @@ export class ClassCyclr {
* @param actor The actor whose cycle is to be cancelled.
* @param name Name of the cycle to be cancelled.
*/
public cancelClassCycle(actor: Actor, name: string): void {
public cancelClassCycle(actor: Actor, name: string) {
if (actor.cycles === undefined || !(name in actor.cycles)) {
return;
}
const cycle: TimeCycle = actor.cycles[name];
const cycle = actor.cycles[name];
if (cycle.event !== undefined) {
cycle.event.repeat = 0;
@@ -145,74 +95,63 @@ export class ClassCyclr {
*
* @param actor Actor whose cycles are to be cancelled.
*/
public cancelAllCycles(actor: Actor): void {
public cancelAllCycles(actor: Actor) {
if (actor.cycles === undefined) {
return;
}
for (const name in actor.cycles) {
if (!{}.hasOwnProperty.call(actor.cycles, name)) {
continue;
}
const cycle: TimeCycle = actor.cycles[name];
cycle.length = 1;
cycle[0] = false;
delete actor.cycles[name];
this.cancelClassCycle(actor, name);
}
}
/**
* Initialization utility for sprite cycles of actors. The settings are
* added t the right time (immediately if not synched, or on a delay if
* added to the right time (immediately if not synched, or on a delay if
* synched.
*
* @param ting The object whose class is to be cycled.
* @param settings Container for repetition settings, particularly .length.
* @param actor The object whose class is to be cycled.
* @param classes Classes to cycle through.
* @param timing How often to do the cycle.
* @param synched Whether the animations should be synched to their period.
* @returns The cycle containing settings and the new event.
*/
private setClassCycle(
private startClassCycle(
actor: Actor,
settings: TimeCycle,
classes: ClassesList,
timing: number | NumericCalculator,
synched?: boolean
): TimeCycle {
const timingNumber = TimeEvent.runCalculator(timing);
// Start off before the beginning of the cycle
settings.location = settings.oldClass = -1;
) {
const cycle: TimeCycle = {
classes,
location: -1,
};
// Let the object know to start the cycle when needed
if (synched) {
actor.onActorAdded = (): void => {
settings.event = this.timeHandler.addEventIntervalSynched(
this.cycleClass,
timingNumber,
Infinity,
actor,
settings
);
};
} else {
actor.onActorAdded = (): void => {
settings.event = this.timeHandler.addEventInterval(
this.cycleClass,
timingNumber,
Infinity,
actor,
settings
);
};
}
actor.onActorAdded = () => {
cycle.event = synched
? this.timeHandler.addEventIntervalSynched(
this.cycleClass,
timing,
Infinity,
actor,
cycle
)
: this.timeHandler.addEventInterval(
this.cycleClass,
timing,
Infinity,
actor,
cycle
);
};
// If it should already start, do that
if (actor.placed) {
actor.onActorAdded(actor);
}
return settings;
return cycle;
}
/**
@@ -220,52 +159,43 @@ export class ClassCyclr {
* If the next object is === false, or the repeat function returns false,
* stop by returning true.
*
* @param thing The object whose class is to be cycled.
* @param settings A container for repetition settings, particularly .length.
* @param actor The object whose class is to be cycled.
* @param cycle A currently cycling time cycle.
* @returns Whether the class cycle should stop (normally false).
*/
private readonly cycleClass = (
actor: Actor | undefined,
settings: TimeCycle | undefined
): boolean => {
private readonly cycleClass = (actor: Actor | undefined, cycle: TimeCycle) => {
// If anything has been invalidated, return true to stop
if (!actor || actor.removed || !settings?.length) {
if (!actor || actor.removed || !cycle.classes.length) {
return true;
}
// Get rid of the previous class from settings, if it's a String
if (
settings.oldClass !== undefined &&
settings.oldClass !== -1 &&
typeof settings[settings.oldClass] === "string"
) {
this.classRemove(actor, settings[settings.oldClass] as string);
// Get rid of the previous class from settings
if (cycle.previouslyAdded !== undefined) {
actor.className = actor.className.startsWith(cycle.previouslyAdded)
? actor.className.slice(cycle.previouslyAdded.length + 1)
: actor.className.replace(` ${cycle.previouslyAdded}`, "");
}
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
// Move to the next location in settings, as a circular list
settings.location = (settings.location = (settings.location ?? 0) + 1) % settings.length;
cycle.location = ((cycle.location ?? 0) + 1) % cycle.classes.length;
// Current is the class, bool, or Function currently added and/or run
const current: boolean | string | ClassCalculator = settings[settings.location];
// Current is the boolean, class, or Function currently added and/or run
const current = cycle.classes[cycle.location];
if (!current) {
return false;
}
const name =
current.constructor === Function
? (current as ClassCalculator)(actor, settings)
: current;
settings.oldClass = settings.location;
const nameNew = typeof current === "function" ? current(actor, cycle) : current;
// Strings are classes to be added directly
if (typeof name === "string") {
this.classAdd(actor, name);
if (typeof nameNew === "string") {
actor.className = actor.className === "" ? nameNew : `${actor.className} ${nameNew}`;
cycle.previouslyAdded = nameNew;
return false;
}
// Truthy non-String names imply a stop is required
return !!name;
// Truthy non-string names imply a stop is required
cycle.previouslyAdded = undefined;
return !!nameNew;
};
}
+17
View File
@@ -0,0 +1,17 @@
import { TimeHandlr } from "timehandlr";
import { ClassCyclr } from "./ClassCyclr";
import { Actor } from "./types";
export const createClassCycler = () => {
const timeHandler = new TimeHandlr();
const classCycler = new ClassCyclr({ timeHandler });
return { classCycler, timeHandler };
};
export const createStubActor = (overrides?: Partial<Actor>) => ({
className: "",
placed: true,
...overrides,
});
+10 -23
View File
@@ -1,9 +1,9 @@
import { TimeEvent, TimeHandlr } from "timehandlr";
/**
* Settings to create a class cycling event, commonly as a String[].
* Classes to cycle through, commonly as a string[].
*/
export interface TimeCycleSettings {
export interface ClassesList {
/**
* How many class phases should be cycled through.
*/
@@ -19,7 +19,12 @@ export interface TimeCycleSettings {
/**
* Information for a currently cycling time cycle.
*/
export interface TimeCycle extends TimeCycleSettings {
export interface TimeCycle {
/**
* Classes to cycle through.
*/
classes: ClassesList;
/**
* The container event using this cycle.
*/
@@ -31,9 +36,9 @@ export interface TimeCycle extends TimeCycleSettings {
location?: number;
/**
* The previous class' index.
* The class added by the previous cycle, if after a first cycle.
*/
oldClass?: number;
previouslyAdded?: string;
}
/**
@@ -49,14 +54,6 @@ export type TimeCycles = Record<string, TimeCycle>;
*/
export type ClassCalculator = (actor: Actor, settings: TimeCycle) => string | boolean;
/**
* General-purpose Function to add or remove a class on an Actor.
*
* @param actor An Actor whose class is to change.
* @param className The class to add or remove.
*/
export type ClassChanger = (actor: Actor, className: string) => void;
/**
* An object that may have classes added or removed, such as in a cycle.
*/
@@ -91,16 +88,6 @@ export interface Actor {
* Settings to initialize a new ClassCyclr.
*/
export interface ClassCyclrSettings {
/**
* Adds a class to an Actor (by default, string concatenation).
*/
classAdd?: ClassChanger;
/**
* Removes a class from an Actor (by default, string removal).
*/
classRemove?: ClassChanger;
/**
* Scheduling for dynamically repeating or synchronized events.
*/
+4 -4
View File
@@ -1,9 +1,9 @@
import { EventCallback, NumericCalculator, TimeEventLike } from "./types";
import { EventCallback, NumericCalculator } from "./types";
/**
* An event to be played, including a callback, repetition settings, and arguments.
*/
export class TimeEvent implements TimeEventLike {
export class TimeEvent {
/**
* The time at which to call this event.
*/
@@ -12,12 +12,12 @@ export class TimeEvent implements TimeEventLike {
/**
* Something to run when this event is triggered.
*/
public callback: () => void;
public callback: () => unknown;
/**
* Arguments to be passed to the callback.
*/
public args?: any[];
public args?: unknown[];
/**
* How many times this should repeat. If a Function, called for a return value.
+10 -23
View File
@@ -1,11 +1,5 @@
import { TimeEvent } from "./TimeEvent";
import {
CurrentEvents,
EventCallback,
NumericCalculator,
TimeEventLike,
TimeHandlrSettings,
} from "./types";
import { CurrentEvents, EventCallback, NumericCalculator, TimeHandlrSettings } from "./types";
/**
* Scheduling for dynamically repeating or synchronized events.
@@ -87,13 +81,10 @@ export class TimeHandlr {
*/
public addEventIntervalSynched<Args extends unknown[] = []>(
callback: EventCallback<Args>,
timeDelay?: number | NumericCalculator,
numRepeats?: number | EventCallback,
timeDelay: number | NumericCalculator = 1,
numRepeats: number | EventCallback = 1,
...args: Args
): TimeEvent {
timeDelay = timeDelay ?? 1;
numRepeats = numRepeats ?? 1;
) {
const calcTime = TimeEvent.runCalculator(timeDelay || this.timingDefault);
const entryTime = Math.ceil(this.time / calcTime) * calcTime;
@@ -112,7 +103,7 @@ export class TimeHandlr {
/**
* Increments time and handles all now-current events.
*/
public advance(): void {
public advance() {
this.time += 1;
const currentEvents = this.events[this.time];
@@ -136,13 +127,9 @@ export class TimeHandlr {
* @param event An event to be handled.
* @returns A new time the event is scheduled for (or undefined if it isn't).
*/
public handleEvent(event: TimeEventLike): number | undefined {
public handleEvent(event: TimeEvent): number | undefined {
// Events return truthy values to indicate a stop.
if (
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
event.repeat! <= 0 ||
event.callback.apply(this, event.args || [])
) {
if (event.repeat <= 0 || event.callback.apply(this, event.args || [])) {
return undefined;
}
@@ -172,14 +159,14 @@ export class TimeHandlr {
*
* @param event Event to cancel.
*/
public cancelEvent(event: TimeEvent): void {
public cancelEvent(event: TimeEvent) {
event.repeat = 0;
}
/**
* Cancels all events.
*/
public cancelAllEvents(): void {
public cancelAllEvents() {
this.events = {};
}
@@ -187,7 +174,7 @@ export class TimeHandlr {
* Quick handler to add an event to events at a particular time. If the time
* doesn't have any events listed, a new Array is made to hold this event.
*/
private insertEvent(event: TimeEventLike): void {
private insertEvent(event: TimeEvent) {
const atTime = this.events[event.time];
if (atTime) {
atTime.push(event);
+3 -43
View File
@@ -1,7 +1,9 @@
import type { TimeEvent } from "./TimeEvent";
/**
* Lookup of current events, mapping times to all associated events.
*/
export type CurrentEvents = Record<number, TimeEventLike[] | undefined>;
export type CurrentEvents = Record<number, TimeEvent[] | undefined>;
/**
* General-purpose Function for events.
@@ -27,48 +29,6 @@ export type NumericCalculator = () => number;
*/
export type RepeatCalculator = (...args: any[]) => boolean;
/**
* An event to be played, including a callback, repetition settings, and arguments.
*/
export interface TimeEventLike {
/**
* The time at which to call this event.
*/
time: number;
/**
* Something to run when this event is triggered.
*/
callback(): unknown;
/**
* Arguments to be passed to the callback.
*/
args?: any[];
/**
* How many times this should repeat. If a Function, called for whether to repeat.
*/
repeat?: number | RepeatCalculator;
/**
* How long to wait between calls, if repeat isn't 1.
*/
timeRepeat?: number | NumericCalculator;
/**
* How many times this has been called.
*/
count?: number;
/**
* Set the next call time using timeRepeat.
*
* @returns The new call time.
*/
scheduleNextRepeat(): number;
}
/**
* Settings to initialize a new TimeHandlr.
*/