UNPKG

klog.js

Version:

A JavaScript implementation of the Klog time tracking file format

120 lines (119 loc) 3.77 kB
// Define `util.inspect.custom` manually so that we should be portable into the // browser. const customInspect = Symbol.for("nodejs.util.inspect.custom"); const bumpNegativeZero = (value) => (value === -0 ? 0 : value); /** * Represents a duration of time in hours and minutes. */ export class Duration { /** @internal */ #value; /** Whether to explicitly show a positive sign. */ explicitPositive; /** The sign to use for zero values. */ zeroSign; /** * Create a new duration. * @param hours - The number of hours. * @param minutes - The number of minutes. * @param options - Formatting options for the duration. */ constructor(hours, minutes, { explicitPositive = false, zeroSign = "" } = {}) { this.#value = hours * 60 + minutes; this.explicitPositive = explicitPositive; this.zeroSign = zeroSign; } /** @internal */ static fromAST(node) { return this.fromMinutes(node.value, { explicitPositive: node.sign === "+", zeroSign: node.value === 0 ? node.sign : "", }); } /** * Create a new duration from a total number of minutes. * @param value - The total number of minutes. * @param options - Formatting options for the duration. */ static fromMinutes = (value, options = {}) => { const hours = Math.trunc(value / 60); const minutes = value % 60; return new this(hours, minutes, options); }; /** * The number of minutes in the duration. */ get minutes() { return bumpNegativeZero(this.#value % 60); } /** * The number of hours in the duration. */ get hours() { return bumpNegativeZero(Math.trunc(this.#value / 60)); } /** @internal */ get #options() { return { explicitPositive: this.explicitPositive, zeroSign: this.zeroSign }; } /** * The sign of the duration. Takes the `zeroSign` option into account. */ get sign() { if (this.#value === 0) return this.zeroSign; else if (this.#value < 0) return "-"; else return this.explicitPositive ? "+" : ""; } /** * Add another duration to this duration. * @param other - The other duration to add. * @returns A new Duration instance representing the sum. */ add(other) { return Duration.fromMinutes(this.#value + other.#value, this.#options); } /** * Subtract another duration from this duration. * @param other - The other duration to subtract. * @returns A new Duration instance representing the difference. */ subtract(other) { return Duration.fromMinutes(this.#value - other.#value, this.#options); } /** * Check if this duration is equal to another duration. * @param other - The other duration to compare against. */ equals(other) { return this.toMinutes() === other.toMinutes(); } /** * Render the duration as a Klog string. */ toString() { if (this.#value === 0) return `${this.sign}0m`; const h = this.hours !== 0 ? `${Math.abs(this.hours)}h` : ""; const m = this.minutes !== 0 ? `${Math.abs(this.minutes)}m` : ""; return `${this.sign}${h}${m}`; } /** * Convert the duration to a JSON object. */ toJSON() { const { hours, minutes, zeroSign, explicitPositive } = this; return { hours, minutes, zeroSign, explicitPositive }; } /** * Converts the duration to minutes. */ toMinutes() { return this.#value; } [customInspect]() { return `Duration { hours: ${this.hours}, minutes: ${this.minutes} }`; } }