From 30a739dada30471df2be624c5e21c095c13f9704 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:11:09 +0200 Subject: [PATCH 1/8] fix: use typed domain errors instead of generic Error Four throw sites used plain `Error`, so callers couldn't discriminate them from the library's typed error hierarchy the way they can for DateAlignmentError, NoWeightsError, etc. Add InvalidArgumentError (bad argument values) and CaptorApiError (Captor API fetch failures), reuse the existing but previously unthrown IncorrectArgumentComboError for the report generator's constituent-count check, and update tests to assert on error type in addition to message. Co-Authored-By: Claude Sonnet 5 --- src/captor.ts | 6 +++++- src/datefixer.ts | 4 +++- src/index.ts | 2 ++ src/report.ts | 5 +++-- src/series.ts | 3 ++- src/types.ts | 14 ++++++++++++++ tests/captor.test.ts | 13 +++++++++++-- tests/datefixer.test.ts | 2 ++ tests/errors.test.ts | 16 ++++++++++++++++ tests/report.test.ts | 2 ++ tests/series.test.ts | 4 ++++ 11 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/captor.ts b/src/captor.ts index daaf727..3b8128c 100644 --- a/src/captor.ts +++ b/src/captor.ts @@ -4,6 +4,8 @@ * API: https://api.captor.se/public/api/opentimeseries/{id} */ +import { CaptorApiError } from "./types"; + const API_BASE = "https://api.captor.se/public/api/opentimeseries"; export type CaptorSeriesResponse = { @@ -27,7 +29,9 @@ export async function fetchCaptorSeries( const url = `${API_BASE}/${id}`; const res = await fetch(url); if (!res.ok) { - throw new Error(`Failed to fetch ${id}: ${res.status} ${res.statusText}`); + throw new CaptorApiError( + `Failed to fetch ${id}: ${res.status} ${res.statusText}`, + ); } return res.json() as Promise; } diff --git a/src/datefixer.ts b/src/datefixer.ts index 2563650..b6f0fca 100644 --- a/src/datefixer.ts +++ b/src/datefixer.ts @@ -1,3 +1,5 @@ +import { InvalidArgumentError } from "./types"; + /** Normalizes string or Date input to a Date. */ export function dateFix(input: string | Date): Date { if (typeof input === "string") { @@ -17,7 +19,7 @@ export function generateCalendarDateRange( options?: { start?: string; end?: string }, ): string[] { if (tradingDays < 1) { - throw new Error("trading_days must be greater than zero"); + throw new InvalidArgumentError("trading_days must be greater than zero"); } const result: string[] = []; if (options?.end) { diff --git a/src/index.ts b/src/index.ts index aa321d0..152e81b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -50,6 +50,8 @@ export { NoWeightsError, IncorrectArgumentComboError, ResampleDataLossError, + InvalidArgumentError, + CaptorApiError, } from "./types"; export { mean, std, quantile, pctChange } from "./utils"; export type { LagSeries, LjungBoxResult } from "./autocorr"; diff --git a/src/report.ts b/src/report.ts index 420c765..02b0e8d 100644 --- a/src/report.ts +++ b/src/report.ts @@ -8,6 +8,7 @@ import { OpenFrame } from "./frame"; import { OpenTimeSeries } from "./series"; import { ffill, pctChange } from "./utils"; import { lastBusinessDayOfMonth, lastBusinessDayOfYear } from "./bizcalendar"; +import { IncorrectArgumentComboError } from "./types"; export interface ReportOptions { title?: string; @@ -88,14 +89,14 @@ export function computeCaptureRatioCagr( * @param frame - OpenFrame with aligned series (mergeSeries("inner")) * @param options - Report options (title, logo). Countries come from frame.countries. * @returns HTML string - * @throws Error when frame has fewer than 2 constituents + * @throws {IncorrectArgumentComboError} when frame has fewer than 2 constituents */ export function reportHtml( frame: OpenFrame, options: ReportOptions = {}, ): string { if (frame.itemCount < 2) { - throw new Error( + throw new IncorrectArgumentComboError( "OpenFrame must have at least 2 constituents to generate a report", ); } diff --git a/src/series.ts b/src/series.ts index 937dd4a..2a08251 100644 --- a/src/series.ts +++ b/src/series.ts @@ -1,6 +1,7 @@ import { DateAlignmentError, InitialValueZeroError, + InvalidArgumentError, ResampleDataLossError, ValueType, } from "./types"; @@ -156,7 +157,7 @@ export class OpenTimeSeries { ): OpenTimeSeries { const idx = options?.columnIndex ?? 0; const col = dateColumns.columns[idx]; - if (!col) throw new Error("Column index out of range"); + if (!col) throw new InvalidArgumentError("Column index out of range"); return OpenTimeSeries.fromArrays(col.name, dateColumns.dates, col.values, { valuetype: options?.valuetype, countries: options?.countries, diff --git a/src/types.ts b/src/types.ts index e3f3ab2..3225b51 100644 --- a/src/types.ts +++ b/src/types.ts @@ -77,3 +77,17 @@ export class ResampleDataLossError extends Error { this.name = "ResampleDataLossError"; } } + +export class InvalidArgumentError extends Error { + constructor(message: string) { + super(message); + this.name = "InvalidArgumentError"; + } +} + +export class CaptorApiError extends Error { + constructor(message: string) { + super(message); + this.name = "CaptorApiError"; + } +} diff --git a/tests/captor.test.ts b/tests/captor.test.ts index 342dcf2..0dfaaf6 100644 --- a/tests/captor.test.ts +++ b/tests/captor.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { fetchCaptorSeries, fetchCaptorSeriesBatch } from "../src/captor"; +import { CaptorApiError } from "../src/types"; describe("fetchCaptorSeries", () => { const mockResponse = { @@ -53,7 +54,11 @@ describe("fetchCaptorSeries", () => { statusText: "Not Found", } as Response); - await expect(fetchCaptorSeries("nonexistent-id")).rejects.toThrow( + const error: unknown = await fetchCaptorSeries("nonexistent-id").catch( + (e: unknown) => e, + ); + expect(error).toBeInstanceOf(CaptorApiError); + expect((error as Error).message).toBe( "Failed to fetch nonexistent-id: 404 Not Found", ); }); @@ -135,7 +140,11 @@ describe("fetchCaptorSeriesBatch", () => { statusText: "Internal Server Error", } as Response); - await expect(fetchCaptorSeriesBatch(["id-1", "id-2"])).rejects.toThrow( + const error: unknown = await fetchCaptorSeriesBatch(["id-1", "id-2"]).catch( + (e: unknown) => e, + ); + expect(error).toBeInstanceOf(CaptorApiError); + expect((error as Error).message).toBe( "Failed to fetch id-2: 500 Internal Server Error", ); }); diff --git a/tests/datefixer.test.ts b/tests/datefixer.test.ts index f9a9ff6..a4a2220 100644 --- a/tests/datefixer.test.ts +++ b/tests/datefixer.test.ts @@ -5,6 +5,7 @@ import { dateFix, dateToStr, } from "../src/datefixer"; +import { InvalidArgumentError } from "../src/types"; describe("dateFix", () => { it("returns Date when given string", () => { @@ -32,6 +33,7 @@ describe("generateCalendarDateRange", () => { expect(() => generateCalendarDateRange(-1)).toThrow( "trading_days must be greater than zero", ); + expect(() => generateCalendarDateRange(0)).toThrow(InvalidArgumentError); }); it("with end option returns expected dates (5 days ending 2020-01-10)", () => { diff --git a/tests/errors.test.ts b/tests/errors.test.ts index ded4944..25205e3 100644 --- a/tests/errors.test.ts +++ b/tests/errors.test.ts @@ -7,6 +7,8 @@ import { LabelsNotUniqueError, IncorrectArgumentComboError, ResampleDataLossError, + InvalidArgumentError, + CaptorApiError, } from "../src/types"; describe("Error classes", () => { @@ -58,4 +60,18 @@ describe("Error classes", () => { expect(err.message).toBe("test message"); expect(err).toBeInstanceOf(Error); }); + + it("InvalidArgumentError has correct name and message", () => { + const err = new InvalidArgumentError("test message"); + expect(err.name).toBe("InvalidArgumentError"); + expect(err.message).toBe("test message"); + expect(err).toBeInstanceOf(Error); + }); + + it("CaptorApiError has correct name and message", () => { + const err = new CaptorApiError("test message"); + expect(err.name).toBe("CaptorApiError"); + expect(err.message).toBe("test message"); + expect(err).toBeInstanceOf(Error); + }); }); diff --git a/tests/report.test.ts b/tests/report.test.ts index 4aa11e3..5dd2809 100644 --- a/tests/report.test.ts +++ b/tests/report.test.ts @@ -6,6 +6,7 @@ import { } from "../src/report"; import { OpenFrame } from "../src/frame"; import { OpenTimeSeries } from "../src/series"; +import { IncorrectArgumentComboError } from "../src/types"; /** Creates a minimal frame with positive price-like values for report tests. */ function frameForReport(numSeries = 2): OpenFrame { @@ -106,6 +107,7 @@ describe("reportHtml", () => { expect(() => reportHtml(frame)).toThrow( "OpenFrame must have at least 2 constituents to generate a report", ); + expect(() => reportHtml(frame)).toThrow(IncorrectArgumentComboError); }); it("throws when frame has 1 constituent", () => { diff --git a/tests/series.test.ts b/tests/series.test.ts index 46c0e11..1a39043 100644 --- a/tests/series.test.ts +++ b/tests/series.test.ts @@ -4,6 +4,7 @@ import { ValueType } from "../src/types"; import { DateAlignmentError, InitialValueZeroError, + InvalidArgumentError, ResampleDataLossError, } from "../src/types"; import { simulatedSeries } from "./fixtures"; @@ -48,6 +49,9 @@ describe("OpenTimeSeries", () => { dates: ["2020-01-01"], columns: [{ name: "A", values: [100] }], }; + expect(() => + OpenTimeSeries.fromDateColumns(dateColumns, { columnIndex: 5 }), + ).toThrow(InvalidArgumentError); expect(() => OpenTimeSeries.fromDateColumns(dateColumns, { columnIndex: 5 }), ).toThrow("Column index out of range"); From 0f7f8a9577546a3867a59d374840e2bf49f6076a Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:15:21 +0200 Subject: [PATCH 2/8] docs: fill in JSDoc gaps on public API types.ts had zero doc comments across its 14 exports, utils.ts left 6 of 10 functions undocumented, and roughly half of OpenTimeSeries's methods/getters in series.ts had no JSDoc. Since typedoc publishes this as the library's docs site, these gaps showed up directly in the generated reference. Document the remaining exports and add @throws tags where a typed error can be raised. Co-Authored-By: Claude Sonnet 5 --- src/series.ts | 48 +++++++++++++++++++++++++++++++++++++++++++++++- src/types.ts | 20 ++++++++++++++++++++ src/utils.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/series.ts b/src/series.ts index 2a08251..2ff6dcf 100644 --- a/src/series.ts +++ b/src/series.ts @@ -164,6 +164,7 @@ export class OpenTimeSeries { }); } + /** Returns an independent copy of this series (dates/values arrays are cloned). */ fromDeepcopy(): OpenTimeSeries { return new OpenTimeSeries({ timeseriesId: this.timeseriesId, @@ -180,10 +181,12 @@ export class OpenTimeSeries { }); } + /** Returns the current values from `tsdf`, in date order. */ getTsdfValues(): number[] { return this.tsdf.map((r) => r.value); } + /** Returns the current dates from `tsdf`, in date order. */ getTsdfDates(): string[] { return this.tsdf.map((r) => r.date); } @@ -231,30 +234,37 @@ export class OpenTimeSeries { return values.length / fraction; } + /** Number of observations in `tsdf`. */ get length(): number { return this.tsdf.length; } + /** The earliest date in `tsdf`. */ get firstIdx(): string { return this.tsdf[0].date; } + /** The latest date in `tsdf`. */ get lastIdx(): string { return this.tsdf[this.tsdf.length - 1].date; } + /** Number of calendar days between `firstIdx` and `lastIdx`. */ get spanOfDays(): number { return daysBetween(this.firstIdx, this.lastIdx); } + /** `spanOfDays` expressed in years (365.25-day year). */ get yearfrac(): number { return this.spanOfDays / 365.25; } + /** Average number of observations per year, based on `length` and `yearfrac`. */ get periodsInAYear(): number { return this.length / this.yearfrac; } + /** Converts a price series to period-over-period returns in place. */ valueToRet(): this { const vals = ffill(this.getTsdfValues()); const rets = pctChange(vals); @@ -267,6 +277,7 @@ export class OpenTimeSeries { return this; } + /** Converts to a cumulative-return price series (rebased to 1 at the first date), in place. */ toCumret(): this { let rets: number[]; if (this.valuetype === ValueType.PRICE) { @@ -291,6 +302,10 @@ export class OpenTimeSeries { return this; } + /** + * Annualized geometric (compound) return over the sliced date range. + * @throws {InitialValueZeroError} when the first or last value is zero or negative + */ geoRet(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -304,6 +319,7 @@ export class OpenTimeSeries { return (last / first) ** (1 / fraction) - 1; } + /** Annualized arithmetic mean return over the sliced date range. */ arithmeticRet(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -314,6 +330,10 @@ export class OpenTimeSeries { return mean(vals) * tf; } + /** + * Simple (non-annualized) return between the first and last value in the sliced range. + * @throws {InitialValueZeroError} when the first value is zero + */ valueRet(opts: DateRangeOptions = {}): number { const { values } = this.sliceByRange(opts); if (values.length < 2) return NaN; @@ -326,6 +346,7 @@ export class OpenTimeSeries { return last / first - 1; } + /** Annualized volatility (sample standard deviation of returns) over the sliced date range. */ vol(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -337,6 +358,7 @@ export class OpenTimeSeries { return std(rets, 1) * Math.sqrt(tf); } + /** Largest peak-to-trough decline over the sliced date range, expressed as a negative fraction. */ maxDrawdown(opts: DateRangeOptions = {}): number { const { values } = this.sliceByRange(opts); if (values.length < 2) return 0; @@ -371,6 +393,7 @@ export class OpenTimeSeries { return bottomIdx >= 0 ? dates[bottomIdx] : undefined; } + /** Historical Value at Risk at the given confidence `level` over the sliced date range. */ varDown(level = 0.95, opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -381,6 +404,7 @@ export class OpenTimeSeries { return quantile(rets, 1 - level); } + /** Historical Conditional Value at Risk (expected shortfall) at the given confidence `level`. */ cvarDown(level = 0.95, opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -396,6 +420,10 @@ export class OpenTimeSeries { return mean(rets.slice(0, n)); } + /** + * Annualized downside deviation: volatility of returns falling short of a + * minimum acceptable return (`mar`, annualized). + */ downsideDeviation(opts: DateRangeOptions = {}, mar = 0): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -409,12 +437,14 @@ export class OpenTimeSeries { return Math.sqrt(lpm2) * Math.sqrt(tf); } + /** Sharpe ratio: annualized excess return over `riskfreeRate`, divided by volatility. */ retVolRatio(riskfreeRate = 0, opts: DateRangeOptions = {}): number { const ret = this.arithmeticRet(opts) - riskfreeRate; const v = this.vol(opts); return v === 0 ? NaN : ret / v; } + /** Sortino ratio: annualized excess return over `riskfreeRate`, divided by downside deviation. */ sortinoRatio( riskfreeRate = 0, minAcceptedReturn = 0, @@ -425,6 +455,7 @@ export class OpenTimeSeries { return dd === 0 ? NaN : ret / dd; } + /** Fraction of periods with a positive return over the sliced date range. */ positiveShare(opts: DateRangeOptions = {}): number { const { values } = this.sliceByRange(opts); if (values.length < 2) return NaN; @@ -436,6 +467,7 @@ export class OpenTimeSeries { return rets.length === 0 ? NaN : pos / rets.length; } + /** Worst rolling sum of `observations` consecutive returns over the sliced date range. */ worst(observations = 1, opts: DateRangeOptions = {}): number { const { values } = this.sliceByRange(opts); if (values.length < observations + 1) return NaN; @@ -451,6 +483,7 @@ export class OpenTimeSeries { return minVal; } + /** Sample skewness of returns over the sliced date range. */ skew(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 3) return NaN; @@ -461,6 +494,7 @@ export class OpenTimeSeries { return skewness(rets); } + /** Sample excess kurtosis of returns over the sliced date range. */ kurtosis(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 4) return NaN; @@ -471,6 +505,7 @@ export class OpenTimeSeries { return kurtosis(rets); } + /** Z-score of the most recent return relative to the mean and standard deviation of the range. */ zScore(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -544,6 +579,7 @@ export class OpenTimeSeries { return ljungBoxFromReturns(rets, lags); } + /** Annualized volatility implied by the historical VaR at the given confidence `level`. */ volFromVar(level = 0.95, opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); if (dates.length < 2) return NaN; @@ -556,6 +592,10 @@ export class OpenTimeSeries { return (-Math.sqrt(tf) * q) / normPpf(level); } + /** + * Annualized EWMA (exponentially weighted moving average) volatility series. + * The first `dayChunk` log-returns seed the initial volatility estimate. + */ ewmaVolFunc( lmbda = 0.94, dayChunk = 11, @@ -576,6 +616,7 @@ export class OpenTimeSeries { return result; } + /** EWMA Value at Risk series at the given confidence `level`, derived from `ewmaVolFunc`. */ ewmaVarFunc( lmbda = 0.94, dayChunk = 11, @@ -586,6 +627,7 @@ export class OpenTimeSeries { return vols.map((v) => v * normPpf(1 - level)); } + /** Sets `label` and/or `valuetype` in place. Either argument may be omitted to leave it unchanged. */ setNewLabel(lvlZero?: string, lvlOne?: ValueType): this { if (lvlZero != null) this.label = lvlZero; if (lvlOne != null) this.valuetype = lvlOne; @@ -607,7 +649,8 @@ export class OpenTimeSeries { /** * Resamples to business period-end frequency (week, month, quarter, year). - * Mutates tsdf. Throws on return series (use price series). + * Mutates tsdf. + * @throws {ResampleDataLossError} on return series (convert to a price series first) */ resampleToPeriodEnd(freq: ResampleFreq = "ME"): this { if (this.valuetype === ValueType.RTRN) @@ -629,6 +672,7 @@ export class OpenTimeSeries { /** * Worst single calendar month return (business-month-end based). * Uses filterToBusinessDays + resampleToPeriodEnd(ME) + min of monthly returns. + * @throws {ResampleDataLossError} on return series (convert to a price series first) */ worstMonth(opts: DateRangeOptions = {}): number { const { dates, values } = this.sliceByRange(opts); @@ -653,6 +697,7 @@ export class OpenTimeSeries { return monthlyRets.length === 0 ? NaN : Math.min(...monthlyRets); } + /** Converts to a drawdown series (fraction below the running peak, always <= 0), in place. */ toDrawdownSeries(): this { const vals = this.getTsdfValues().map((v) => Number.isNaN(v) ? -Infinity : v, @@ -672,6 +717,7 @@ export class OpenTimeSeries { /** * Chains two timeseries at their overlap. Scales back by front's level at the overlap date. + * @throws {DateAlignmentError} when the two series' dates do not overlap */ export function timeseriesChain( front: OpenTimeSeries, diff --git a/src/types.ts b/src/types.ts index 3225b51..24218e7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ +/** Identifies what kind of quantity a timeseries or column holds. */ export enum ValueType { EWMA_VOL = "EWMA volatility", EWMA_VAR = "EWMA VaR", @@ -13,22 +14,33 @@ export enum ValueType { ROLLVOL = "Rolling volatility", } +/** A calendar date formatted as `YYYY-MM-DD`. */ export type DateString = string; +/** An array of {@link DateString}, typically aligned index-for-index with a {@link ValueList}. */ export type DateList = DateString[]; +/** An array of numeric observations, typically aligned index-for-index with a {@link DateList}. */ export type ValueList = number[]; +/** A single date/value observation, as used when building a timeseries row by row. */ export interface TsdfRow { date: DateString; value: number; } +/** + * Business-day resampling frequency, matching pandas' offset aliases: + * `"B"` business day, `"BME"` business month end, `"BQE"` business quarter + * end, `"BYE"` business year end. + */ export type LiteralBizDayFreq = "B" | "BME" | "BQE" | "BYE"; +/** Strategy used by `OpenFrame.makePortfolio` to derive constituent weights. */ export type LiteralPortfolioWeightings = | "eq_weights" | "inv_vol" | "max_div" | "min_vol_overweight"; +/** Thrown when a date range or lookup falls outside a series' date index. */ export class DateAlignmentError extends Error { constructor(message: string) { super(message); @@ -36,6 +48,7 @@ export class DateAlignmentError extends Error { } } +/** Thrown when a return-style calculation needs a non-zero starting value. */ export class InitialValueZeroError extends Error { constructor(message: string) { super(message); @@ -43,6 +56,7 @@ export class InitialValueZeroError extends Error { } } +/** Thrown when an operation requires constituents to share a single {@link ValueType}. */ export class MixedValuetypesError extends Error { constructor(message: string) { super(message); @@ -50,6 +64,7 @@ export class MixedValuetypesError extends Error { } } +/** Thrown when portfolio weights are required but none were provided or derivable. */ export class NoWeightsError extends Error { constructor(message: string) { super(message); @@ -57,6 +72,7 @@ export class NoWeightsError extends Error { } } +/** Thrown when the combination of arguments passed to a function is invalid. */ export class IncorrectArgumentComboError extends Error { constructor(message: string) { super(message); @@ -64,6 +80,7 @@ export class IncorrectArgumentComboError extends Error { } } +/** Thrown when timeseries labels that are required to be unique collide. */ export class LabelsNotUniqueError extends Error { constructor(message: string) { super(message); @@ -71,6 +88,7 @@ export class LabelsNotUniqueError extends Error { } } +/** Thrown when resampling would silently discard information (e.g. resampling a return series). */ export class ResampleDataLossError extends Error { constructor(message: string) { super(message); @@ -78,6 +96,7 @@ export class ResampleDataLossError extends Error { } } +/** Thrown when a single argument's value is outside its valid range. */ export class InvalidArgumentError extends Error { constructor(message: string) { super(message); @@ -85,6 +104,7 @@ export class InvalidArgumentError extends Error { } } +/** Thrown when a request to the Captor Open API fails. */ export class CaptorApiError extends Error { constructor(message: string) { super(message); diff --git a/src/utils.ts b/src/utils.ts index 9cdbe44..78bb1d9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -34,6 +34,13 @@ export function pctChange(values: number[]): number[] { return result; } +/** + * Returns the running (cumulative) product of an array. + * + * @param values - Factors to multiply, e.g. `1 + return` for each period + * @param start - Initial accumulator value + * @returns Cumulative product after each element + */ export function cumProd(values: number[], start = 1): number[] { const result: number[] = []; let acc = start; @@ -44,6 +51,10 @@ export function cumProd(values: number[], start = 1): number[] { return result; } +/** + * Forward-fills NaN values with the last preceding non-NaN value. + * Leading NaNs before the first non-NaN value are left unchanged. + */ export function ffill(values: number[]): number[] { const result: number[] = []; let last = values[0]; @@ -54,6 +65,9 @@ export function ffill(values: number[]): number[] { return result; } +/** + * Returns period-over-period logarithmic returns. First element is 0. + */ export function logReturns(values: number[]): number[] { const result: number[] = [0]; for (let i = 1; i < values.length; i++) { @@ -62,6 +76,13 @@ export function logReturns(values: number[]): number[] { return result; } +/** + * Returns the inverse of the standard normal CDF (the probit function) via + * the Acklam rational approximation. + * + * @param p - Probability in the open interval (0, 1) + * @returns The z-score such that `Phi(z) === p`, or NaN when p is outside (0, 1) + */ export function normPpf(p: number): number { if (p <= 0 || p >= 1) return NaN; const a = [ @@ -106,6 +127,11 @@ export function normPpf(p: number): number { return x; } +/** + * Returns the sample skewness (third standardized moment). + * Returns NaN when there are fewer than 3 values, and 0 when the + * standard deviation is 0. + */ export function skewness(arr: number[]): number { const n = arr.length; if (n < 3) return NaN; @@ -116,6 +142,11 @@ export function skewness(arr: number[]): number { return m3 / s ** 3; } +/** + * Returns the sample excess kurtosis (fourth standardized moment minus 3). + * Returns NaN when there are fewer than 4 values, and 0 when the + * standard deviation is 0. + */ export function kurtosis(arr: number[]): number { const n = arr.length; if (n < 4) return NaN; From 15b0a9573557b811942489ba9ab3aec52899d179 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:18:52 +0200 Subject: [PATCH 3/8] build: enable type-aware ESLint rules parserOptions.project was already set (full type info was being computed on every lint run) but the config only extended tseslint.configs.recommended, so none of the type-aware rules (no-unsafe-*, no-floating-promises, etc.) were actually enabled. Switch to recommendedTypeChecked. Fixes surfaced by the switch: new Array(n).fill(x) resolves to any[], not number[], causing unsafe-return/unsafe-argument in frame.ts's and portfoliotools.ts's weight calculations - type the Array constructor calls explicitly. In scripts/compare-metrics.ts, narrow JSON.parse's result to `unknown` before use instead of implicitly typing it `any`. The remaining ~90 violations were non-null assertions and type assertions that were already redundant under the current tsconfig and are removed by --fix. Co-Authored-By: Claude Sonnet 5 --- eslint.config.js | 2 +- scripts/compare-metrics.ts | 23 +++++++++++++++-------- scripts/efficient-frontier.ts | 11 ++++++----- scripts/plot.ts | 11 ++++++----- scripts/report.ts | 11 ++++++----- src/autocorr.ts | 16 ++++++++-------- src/bizcalendar.ts | 17 ++++++++--------- src/frame.ts | 18 ++++++++++-------- src/plot.ts | 4 ++-- src/portfoliotools.ts | 24 +++++++++++------------- src/report.ts | 19 ++++++++----------- src/series.ts | 2 +- tests/autocorr.test.ts | 4 ++-- tests/frame.test.ts | 8 ++++---- tests/portfoliotools.test.ts | 10 +++++----- tests/series.test.ts | 16 ++++++++-------- 16 files changed, 101 insertions(+), 95 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index fe25e4e..e721564 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,7 +4,7 @@ import eslintConfigPrettier from "eslint-config-prettier"; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, eslintConfigPrettier, { files: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts"], diff --git a/scripts/compare-metrics.ts b/scripts/compare-metrics.ts index f978b4b..afb6eaf 100644 --- a/scripts/compare-metrics.ts +++ b/scripts/compare-metrics.ts @@ -77,8 +77,8 @@ function loadFrameFromJson(path: string): { irisSeries: OpenTimeSeries; frame: OpenFrame; } { - const raw = JSON.parse(readFileSync(path, "utf-8")); - const items: FrameJsonItem[] = Array.isArray(raw) ? raw : [raw]; + const raw: unknown = JSON.parse(readFileSync(path, "utf-8")); + const items = (Array.isArray(raw) ? raw : [raw]) as FrameJsonItem[]; if (items.length < 1) { throw new Error("frame.json must contain at least one series"); } @@ -98,14 +98,21 @@ function loadFrameFromJson(path: string): { } function loadPythonMetrics(path: string): Record { - const raw = JSON.parse(readFileSync(path, "utf-8")); + const raw: unknown = JSON.parse(readFileSync(path, "utf-8")); + const asRecord = + typeof raw === "object" && raw !== null + ? (raw as Record) + : {}; const col = - typeof raw === "object" && raw !== null && IRIS_LABEL in raw - ? raw[IRIS_LABEL] - : Object.values(raw)[0]; + IRIS_LABEL in asRecord ? asRecord[IRIS_LABEL] : Object.values(asRecord)[0]; return (col as Record) ?? {}; } +/** Stringifies a JSON-decoded value without falling back to `[object Object]`. */ +function safeString(v: unknown): string { + return typeof v === "object" && v !== null ? JSON.stringify(v) : String(v); +} + function tsDateStr(v: unknown): string { if (typeof v === "string") return v.slice(0, 10); return String(v); @@ -136,7 +143,7 @@ function parseDecimals(args: string[]): number { // --decimals N const idx = args.indexOf("--decimals"); if (idx >= 0 && args[idx + 1] != null) { - const n = parseInt(args[idx + 1]!, 10); + const n = parseInt(args[idx + 1], 10); if (Number.isInteger(n) && n >= 0) return n; } // env COMPARE_DECIMALS (works with npm run even without --) @@ -242,7 +249,7 @@ function main(): void { // Build comparison table using mapping: Python key -> tsMetrics key const pyKeys = Object.keys(pythonMetrics).filter( - (k) => pythonMetrics[k] != null && String(pythonMetrics[k]) !== "null", + (k) => pythonMetrics[k] != null && safeString(pythonMetrics[k]) !== "null", ); const tsOnlyKeys = Object.keys(tsMetrics).filter( (tk) => !Object.values(PY_TO_TS).includes(tk) && !pyKeys.includes(tk), diff --git a/scripts/efficient-frontier.ts b/scripts/efficient-frontier.ts index 51d8644..8c49dc1 100644 --- a/scripts/efficient-frontier.ts +++ b/scripts/efficient-frontier.ts @@ -69,17 +69,18 @@ function parseArgs(args: string[]): { title = args[i + 1]!; i++; } else if (a === "--simulations" && args[i + 1]) { - simulations = parseInt(args[i + 1]!, 10); + simulations = parseInt(args[i + 1], 10); i++; } else if (a === "--points" && args[i + 1]) { - points = parseInt(args[i + 1]!, 10); + points = parseInt(args[i + 1], 10); i++; } else if (a === "--seed" && args[i + 1]) { - seed = parseInt(args[i + 1]!, 10); + seed = parseInt(args[i + 1], 10); i++; } else if (a === "--countries" && args[i + 1]) { - countries = args[i + 1]!.split(",") - .map((c) => c.trim().toUpperCase() as CountryCode) + countries = args[i + 1] + .split(",") + .map((c) => c.trim().toUpperCase()) .filter(Boolean); i++; } else if (a === "--filename" && args[i + 1]) { diff --git a/scripts/plot.ts b/scripts/plot.ts index 85dccc4..8331598 100644 --- a/scripts/plot.ts +++ b/scripts/plot.ts @@ -82,8 +82,9 @@ function parseArgs(args: string[]): { toDate = args[i + 1]!; i++; } else if (a === "--countries" && args[i + 1]) { - countries = args[i + 1]!.split(",") - .map((c) => c.trim().toUpperCase() as CountryCode) + countries = args[i + 1] + .split(",") + .map((c) => c.trim().toUpperCase()) .filter(Boolean); i++; } else if (a === "--filename" && args[i + 1]) { @@ -99,8 +100,8 @@ function parseArgs(args: string[]): { useDrawdown = true; } else if (a === "--ids") { i++; - while (i < args.length && !args[i]!.startsWith("--")) { - ids.push(args[i]!); + while (i < args.length && !args[i].startsWith("--")) { + ids.push(args[i]); i++; } i--; @@ -121,7 +122,7 @@ function parseArgs(args: string[]): { const finalTitle = useDrawdown ? "Drawdown Series" : useIris - ? IRIS_SERIES[0]!.name + ? IRIS_SERIES[0].name : title; return { diff --git a/scripts/report.ts b/scripts/report.ts index 855aaba..fa42020 100644 --- a/scripts/report.ts +++ b/scripts/report.ts @@ -90,8 +90,9 @@ function parseArgs(args: string[]): { toDate = args[i + 1]!; i++; } else if (a === "--countries" && args[i + 1]) { - countries = args[i + 1]!.split(",") - .map((c) => c.trim().toUpperCase() as CountryCode) + countries = args[i + 1] + .split(",") + .map((c) => c.trim().toUpperCase()) .filter(Boolean); i++; } else if (a === "--filename" && args[i + 1]) { @@ -107,8 +108,8 @@ function parseArgs(args: string[]): { useCaptor = true; } else if (a === "--ids") { i++; - while (i < args.length && !args[i]!.startsWith("--")) { - ids.push(args[i]!); + while (i < args.length && !args[i].startsWith("--")) { + ids.push(args[i]); i++; } i--; @@ -127,7 +128,7 @@ function parseArgs(args: string[]): { const finalIds = preset ? preset.map((s) => s.id) : ids; const presetNames = preset ? preset.map((s) => s.name) : undefined; const effectiveUseIris = preset === IRIS_SERIES; - const finalTitle = effectiveUseIris ? IRIS_SERIES[0]!.name : title; + const finalTitle = effectiveUseIris ? IRIS_SERIES[0].name : title; return { ids: finalIds, diff --git a/src/autocorr.ts b/src/autocorr.ts index 104cd94..a4bf161 100644 --- a/src/autocorr.ts +++ b/src/autocorr.ts @@ -59,8 +59,8 @@ export function pearsonAutocorrAtLag(rets: number[], lag: number): number { let dx = 0; let dy = 0; for (let i = 0; i < x.length; i++) { - const a = x[i]! - mx; - const b = y[i]! - my; + const a = x[i] - mx; + const b = y[i] - my; num += a * b; dx += a * a; dy += b * b; @@ -102,17 +102,17 @@ export function pacfFromReturns( if (k === 1) { phiKk = acfArr[1]!; } else { - let numer = acfArr[k]!; + let numer = acfArr[k]; let denom = 1.0; for (let j = 0; j < k - 1; j++) { - numer -= phi[k - 2]![j]! * acfArr[k - 1 - j]!; - denom -= phi[k - 2]![j]! * acfArr[j + 1]!; + numer -= phi[k - 2][j] * acfArr[k - 1 - j]; + denom -= phi[k - 2][j] * acfArr[j + 1]; } phiKk = numer / denom; } const phiRow = new Array(k).fill(0); for (let j = 0; j < k - 1; j++) { - phiRow[j] = phi[k - 2]![j]! - phiKk * phi[k - 2]![k - 2 - j]!; + phiRow[j] = phi[k - 2][j] - phiKk * phi[k - 2][k - 2 - j]; } phiRow[k - 1] = phiKk; phi.push(phiRow); @@ -202,8 +202,8 @@ function logGamma(z: number): number { return Math.log(Math.PI / Math.sin(Math.PI * z)) - logGamma(1 - z); } z -= 1; - let x = c[0]!; - for (let i = 1; i < g + 2; i++) x += c[i]! / (z + i); + let x = c[0]; + for (let i = 1; i < g + 2; i++) x += c[i] / (z + i); const t = z + g + 0.5; return ( 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(t) - t + Math.log(x) diff --git a/src/bizcalendar.ts b/src/bizcalendar.ts index 53a77d3..8693207 100644 --- a/src/bizcalendar.ts +++ b/src/bizcalendar.ts @@ -161,17 +161,17 @@ export function resampleToPeriodEnd( let i = 0; while (i < dates.length) { - const periodKey = getPeriodKey(dates[i]!); + const periodKey = getPeriodKey(dates[i]); let lastBizIdx = -1; let j = i; - while (j < dates.length && getPeriodKey(dates[j]!) === periodKey) { - if (isBiz(dates[j]!)) lastBizIdx = j; + while (j < dates.length && getPeriodKey(dates[j]) === periodKey) { + if (isBiz(dates[j])) lastBizIdx = j; j++; } if (lastBizIdx >= 0) { - outDates.push(dates[lastBizIdx]!); + outDates.push(dates[lastBizIdx]); for (let c = 0; c < columns.length; c++) { - outCols[c].push(columns[c][lastBizIdx]!); + outCols[c].push(columns[c][lastBizIdx]); } } i = j; @@ -191,11 +191,10 @@ export function filterToBusinessDays( const checkers = createHolidayCheckers(countries); const indices: number[] = []; for (let i = 0; i < dates.length; i++) { - if (!isWeekend(dates[i]!) && !isHoliday(dates[i]!, checkers)) - indices.push(i); + if (!isWeekend(dates[i]) && !isHoliday(dates[i], checkers)) indices.push(i); } return { - dates: indices.map((i) => dates[i]!), - columns: columns.map((col) => indices.map((i) => col[i]!)), + dates: indices.map((i) => dates[i]), + columns: columns.map((col) => indices.map((i) => col[i])), }; } diff --git a/src/frame.ts b/src/frame.ts index bbea2ba..40fcea0 100644 --- a/src/frame.ts +++ b/src/frame.ts @@ -64,14 +64,14 @@ function alignSeriesToCommonDates( let hi = seriesDates.length - 1; while (lo < hi) { const mid = Math.ceil((lo + hi) / 2); - if (seriesDates[mid]! <= d) lo = mid; + if (seriesDates[mid] <= d) lo = mid; else hi = mid - 1; } - return dateToVal.get(seriesDates[lo]!) ?? null; + return dateToVal.get(seriesDates[lo]) ?? null; }; const valuesBySeries = series.map((s, i) => - dates.map((d) => getVal(seriesMaps[i]!, d) ?? NaN), + dates.map((d) => getVal(seriesMaps[i], d) ?? NaN), ); const ffilled = valuesBySeries.map((vals) => { @@ -175,8 +175,8 @@ export class OpenFrame { i < this.constituents.length && i < newColumns.length; i++ ) { - const col = newColumns[i]!; - this.constituents[i]!.tsdf = this.tsdf.dates.map((d, j) => ({ + const col = newColumns[i]; + this.constituents[i].tsdf = this.tsdf.dates.map((d, j) => ({ date: d, value: col[j] ?? NaN, })); @@ -278,7 +278,7 @@ export class OpenFrame { rets: number[][], ): number[] { if (strat === "eq_weights") { - return new Array(this.itemCount).fill(1 / this.itemCount); + return new Array(this.itemCount).fill(1 / this.itemCount); } if (strat === "inv_vol") { const vols = rets.map((col) => { @@ -292,7 +292,9 @@ export class OpenFrame { if (strat === "min_vol_overweight") { const vols = rets.map((col) => std(col.slice(1), 1)); const minIdx = vols.indexOf(Math.min(...vols)); - const w = new Array(this.itemCount).fill(0.4 / (this.itemCount - 1)); + const w = new Array(this.itemCount).fill( + 0.4 / (this.itemCount - 1), + ); w[minIdx] = 0.6; return w; } @@ -318,7 +320,7 @@ export class OpenFrame { const total = sum.reduce((a, b) => a + b, 0); return sum.map((s) => s / total); } - return new Array(this.itemCount).fill(1 / this.itemCount); + return new Array(this.itemCount).fill(1 / this.itemCount); } private invertMatrix(m: number[][]): number[][] { diff --git a/src/plot.ts b/src/plot.ts index f68c5e7..9423561 100644 --- a/src/plot.ts +++ b/src/plot.ts @@ -47,7 +47,7 @@ function seriesToPlotData( }, ]; } - const frame = series as OpenFrame; + const frame = series; const { dates, columns } = frame.tsdf; const colsFfilled = columns.map((col) => ffill(col)); return frame.columnLabels.map((name, i) => ({ @@ -66,7 +66,7 @@ function toCumulativeReturns( rets[0] = 0; const cum = [1]; for (let i = 1; i < rets.length; i++) { - cum.push((cum[i - 1] ?? 0) * (1 + rets[i]!)); + cum.push((cum[i - 1] ?? 0) * (1 + rets[i])); } return { name: s.name, dates: s.dates, values: cum }; }); diff --git a/src/portfoliotools.ts b/src/portfoliotools.ts index f67e690..0dd6a90 100644 --- a/src/portfoliotools.ts +++ b/src/portfoliotools.ts @@ -126,7 +126,7 @@ export function efficientFrontier( } const invCov = invertMatrix(cov); - const ones = new Array(frame.itemCount).fill(1); + const ones = new Array(frame.itemCount).fill(1); const invCovOnes = matVec(invCov, ones); const sumInv = invCovOnes.reduce((a, b) => a + b, 0); const wGmv = sumInv !== 0 ? invCovOnes.map((x) => x / sumInv) : null; @@ -163,11 +163,11 @@ export function efficientFrontier( ); if (w) { let ret = 0; - for (let i = 0; i < frame.itemCount; i++) ret += w[i]! * meanRets[i]!; + for (let i = 0; i < frame.itemCount; i++) ret += w[i] * meanRets[i]; let varP = 0; for (let i = 0; i < frame.itemCount; i++) { for (let j = 0; j < frame.itemCount; j++) { - varP += w[i]! * w[j]! * cov[i]![j]!; + varP += w[i] * w[j] * cov[i][j]; } } const vol = Math.sqrt(varP); @@ -221,22 +221,22 @@ function invertMatrix(m: number[][]): number[][] { for (let col = 0; col < n; col++) { let maxRow = col; for (let row = col + 1; row < n; row++) { - if (Math.abs(a[row][col]!) > Math.abs(a[maxRow][col]!)) maxRow = row; + if (Math.abs(a[row][col]) > Math.abs(a[maxRow][col])) maxRow = row; } [a[col], a[maxRow]] = [a[maxRow], a[col]]; [inv[col], inv[maxRow]] = [inv[maxRow], inv[col]]; const pivot = a[col][col]; if (pivot === undefined || Math.abs(pivot) < 1e-12) return m; for (let j = 0; j < n; j++) { - a[col][j]! /= pivot; - inv[col][j]! /= pivot; + a[col][j] /= pivot; + inv[col][j] /= pivot; } for (let row = 0; row < n; row++) { if (row !== col) { - const factor = a[row][col]!; + const factor = a[row][col]; for (let j = 0; j < n; j++) { - a[row][j]! -= factor * a[col][j]!; - inv[row][j]! -= factor * inv[col][j]!; + a[row][j] -= factor * a[col][j]; + inv[row][j] -= factor * inv[col][j]; } } } @@ -264,10 +264,8 @@ function solveEfficientWeights( if (Math.abs(det) < 1e-14) return null; const lambda1 = (C * targetRet - A) / det; const lambda2 = (B - A * targetRet) / det; - const ones = new Array(n).fill(1); - const linearCombo = meanRets.map( - (mu, i) => lambda1 * mu + lambda2 * ones[i]!, - ); + const ones = new Array(n).fill(1); + const linearCombo = meanRets.map((mu, i) => lambda1 * mu + lambda2 * ones[i]); const w = matVec(invCov, linearCombo); const sum = w.reduce((a, b) => a + b, 0); if (Math.abs(sum) < 1e-12) return null; diff --git a/src/report.ts b/src/report.ts index 02b0e8d..c2d5bb4 100644 --- a/src/report.ts +++ b/src/report.ts @@ -37,12 +37,12 @@ export function computeAnnualReturns( const byYear: Record = {}; for (let i = 0; i < dates.length; i++) { const year = dates[i].slice(0, 4); - if (!byYear[year]) byYear[year] = { first: values[i]!, last: values[i]! }; - else byYear[year]!.last = values[i]!; + if (!byYear[year]) byYear[year] = { first: values[i], last: values[i] }; + else byYear[year].last = values[i]!; } const result: Record = {}; for (const year of Object.keys(byYear).sort()) { - const { first, last } = byYear[year]!; + const { first, last } = byYear[year]; result[year] = first <= 0 ? NaN : last / first - 1; } return result; @@ -113,16 +113,13 @@ export function reportHtml( const seriesData = frame.columnLabels.map((name, i) => ({ name, dates: rawDates, - values: colsFfilled[i]!, + values: colsFfilled[i], })); const series = frame.columnLabels.map((_, i) => - OpenTimeSeries.fromArrays( - frame.columnLabels[i]!, - rawDates, - colsFfilled[i]!, - { countries }, - ), + OpenTimeSeries.fromArrays(frame.columnLabels[i], rawDates, colsFfilled[i], { + countries, + }), ); const stats: { metric: string; values: (string | number)[] }[] = []; @@ -243,7 +240,7 @@ function generateHtml( rets[0] = 0; const cum = [1]; for (let i = 1; i < rets.length; i++) { - cum.push((cum[i - 1] ?? 0) * (1 + rets[i]!)); + cum.push((cum[i - 1] ?? 0) * (1 + rets[i])); } return { name: s.name, dates: s.dates, values: cum }; }); diff --git a/src/series.ts b/src/series.ts index 2ff6dcf..a710e04 100644 --- a/src/series.ts +++ b/src/series.ts @@ -565,7 +565,7 @@ export class OpenTimeSeries { ): number { const result = this.pacf(lag, opts, squared); const idx = result.lags.indexOf(lag); - return idx >= 0 ? result.values[idx]! : NaN; + return idx >= 0 ? result.values[idx] : NaN; } /** Ljung-Box test for autocorrelation at the given lags. */ diff --git a/tests/autocorr.test.ts b/tests/autocorr.test.ts index ddec7d8..c0e4f55 100644 --- a/tests/autocorr.test.ts +++ b/tests/autocorr.test.ts @@ -87,9 +87,9 @@ describe("OpenTimeSeries autocorr extensions", () => { const s = simulatedSeries("Test"); const acf = s.acf(3, {}, true); expect(acf.lags).toEqual([0, 1, 2, 3]); - expect(to9(acf.values[1]!)).toBe("-0.051726453"); + expect(to9(acf.values[1])).toBe("-0.051726453"); const pacf = s.pacf(2, {}, true); - expect(to9(pacf.values[2]!)).toBe("-0.005466009"); + expect(to9(pacf.values[2])).toBe("-0.005466009"); }); it("ljungBox with custom lags and squared=true match Python", () => { diff --git a/tests/frame.test.ts b/tests/frame.test.ts index 378c458..8b402b1 100644 --- a/tests/frame.test.ts +++ b/tests/frame.test.ts @@ -128,7 +128,7 @@ describe("OpenFrame", () => { const bottoms = frame.maxDrawdownBottomDate(); expect(bottoms.length).toBe(3); expect( - bottoms.every((d) => d === undefined || /^\d{4}-\d{2}-\d{2}$/.test(d!)), + bottoms.every((d) => d === undefined || /^\d{4}-\d{2}-\d{2}$/.test(d)), ).toBe(true); }); @@ -273,7 +273,7 @@ describe("OpenFrame", () => { frame.tsdf.columns[0][1] = Number.NaN; frame.toDrawdownSeries(); expect(frame.tsdf.columns[0][0]).toBe(0); - expect(Number.isFinite(frame.tsdf.columns[0][1]!)).toBe(false); + expect(Number.isFinite(frame.tsdf.columns[0][1])).toBe(false); expect(frame.tsdf.columns[0][2]).toBeCloseTo(-0.05); }); @@ -294,8 +294,8 @@ describe("OpenFrame", () => { const frame = new OpenFrame([s1]); frame.mergeSeries("inner"); frame.toDrawdownSeries(); - expect(frame.constituents[0]!.getTsdfValues()[0]).toBe(0); - expect(frame.constituents[0]!.getTsdfValues()[1]).toBeCloseTo(-0.1); + expect(frame.constituents[0].getTsdfValues()[0]).toBe(0); + expect(frame.constituents[0].getTsdfValues()[1]).toBeCloseTo(-0.1); }); }); diff --git a/tests/portfoliotools.test.ts b/tests/portfoliotools.test.ts index 2365d70..aa8afc9 100644 --- a/tests/portfoliotools.test.ts +++ b/tests/portfoliotools.test.ts @@ -105,11 +105,11 @@ describe("efficientFrontier", () => { }); const ef = efficientFrontier(frame, 500, 71, 25); for (let i = 1; i < ef.frontier.length; i++) { - expect(ef.frontier[i]!.stdev).toBeGreaterThanOrEqual( - ef.frontier[i - 1]!.stdev - 1e-9, + expect(ef.frontier[i].stdev).toBeGreaterThanOrEqual( + ef.frontier[i - 1].stdev - 1e-9, ); - expect(ef.frontier[i]!.ret).toBeGreaterThanOrEqual( - ef.frontier[i - 1]!.ret - 1e-9, + expect(ef.frontier[i].ret).toBeGreaterThanOrEqual( + ef.frontier[i - 1].ret - 1e-9, ); } }); @@ -152,7 +152,7 @@ describe("efficientFrontier", () => { const toPrice = (rets: number[]) => { const out = [100]; for (let i = 1; i < rets.length; i++) { - out.push(out[i - 1]! * (1 + rets[i]!)); + out.push(out[i - 1] * (1 + rets[i])); } return out; }; diff --git a/tests/series.test.ts b/tests/series.test.ts index 1a39043..f956d01 100644 --- a/tests/series.test.ts +++ b/tests/series.test.ts @@ -334,9 +334,9 @@ describe("OpenTimeSeries", () => { const acf = s.acf(5); expect(acf.lags).toEqual([0, 1, 2, 3, 4, 5]); expect(acf.values[0]).toBe(1); - expect(to9(acf.values[1]!)).toBe("0.006631759"); - expect(to9(acf.values[2]!)).toBe("-0.091794828"); - expect(to9(acf.values[5]!)).toBe("0.011634972"); + expect(to9(acf.values[1])).toBe("0.006631759"); + expect(to9(acf.values[2])).toBe("-0.091794828"); + expect(to9(acf.values[5])).toBe("0.011634972"); }); it("acf(lags=[0,1,3,5]) matches expected", () => { @@ -344,8 +344,8 @@ describe("OpenTimeSeries", () => { const acf = s.acf([0, 1, 3, 5]); expect(acf.lags).toEqual([0, 1, 3, 5]); expect(acf.values[0]).toBe(1); - expect(to9(acf.values[1]!)).toBe("0.006631759"); - expect(to9(acf.values[3]!)).toBe("0.011634972"); + expect(to9(acf.values[1])).toBe("0.006631759"); + expect(to9(acf.values[3])).toBe("0.011634972"); }); it("pacf(lags=5) matches expected", () => { @@ -353,9 +353,9 @@ describe("OpenTimeSeries", () => { const pacf = s.pacf(5); expect(pacf.lags).toEqual([0, 1, 2, 3, 4, 5]); expect(pacf.values[0]).toBe(1); - expect(to9(pacf.values[1]!)).toBe("0.006631759"); - expect(to9(pacf.values[2]!)).toBe("-0.091842847"); - expect(to9(pacf.values[5]!)).toBe("0.026246036"); + expect(to9(pacf.values[1])).toBe("0.006631759"); + expect(to9(pacf.values[2])).toBe("-0.091842847"); + expect(to9(pacf.values[5])).toBe("0.026246036"); }); it("partialAutocorr matches expected", () => { From 8f97ceee93243d979b7c3c9f4d9a428963115740 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:19:15 +0200 Subject: [PATCH 4/8] ci: check formatting in CI npm run format:check existed as a script but nothing ran it, so a PR with unformatted code could merge and only get caught locally if someone happened to run prettier by hand. Run it alongside the existing lint/typecheck step. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9ed26a4..78d365d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,6 +41,9 @@ jobs: - name: Lint and typecheck run: npm run check + - name: Check formatting + run: npm run format:check + - name: Run tests with coverage run: npm run test:coverage From c8ed9a47ad03118f834f4a198d2df0bc3c60a291 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:23:33 +0200 Subject: [PATCH 5/8] ci: automate docs build/deploy, stop committing generated docs docs/ (typedoc output) was manually rebuilt and committed to master, so it could drift from source between rebuilds and every regeneration produced a large, low-signal diff. Add a workflow that builds and deploys the docs to GitHub Pages via GitHub Actions on every push to master, and stop tracking the generated output. Manual follow-up needed: this repo's GitHub Pages source (Settings > Pages) is presumably still set to "Deploy from a branch" against /docs on master. It needs to be switched to "GitHub Actions" for this workflow to actually publish the site - that's a repo setting this commit can't change. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/docs.yml | 57 + .gitignore | 1 + docs/.nojekyll | 0 docs/assets/hierarchy.js | 1 - docs/assets/highlight.css | 85 - docs/assets/icons.js | 18 - docs/assets/icons.svg | 1 - docs/assets/main.js | 60 - docs/assets/navigation.js | 1 - docs/assets/search.js | 1 - docs/assets/style.css | 1633 ----------------- docs/classes/DateAlignmentError.html | 32 - docs/classes/IncorrectArgumentComboError.html | 32 - docs/classes/InitialValueZeroError.html | 32 - docs/classes/MixedValuetypesError.html | 32 - docs/classes/NoWeightsError.html | 32 - docs/classes/OpenFrame.html | 62 - docs/classes/OpenTimeSeries.html | 78 - docs/classes/ResampleDataLossError.html | 32 - docs/classes/ReturnSimulation.html | 21 - docs/enums/ValueType.html | 13 - docs/functions/dateFix.html | 2 - docs/functions/dateToStr.html | 2 - docs/functions/efficientFrontier.html | 2 - docs/functions/fetchCaptorSeries.html | 4 - docs/functions/fetchCaptorSeriesBatch.html | 4 - docs/functions/filterBusinessDays.html | 6 - docs/functions/filterToBusinessDays.html | 3 - docs/functions/generateCalendarDateRange.html | 2 - .../getPreviousBusinessDayBeforeToday.html | 3 - docs/functions/isBusinessDay.html | 2 - docs/functions/lastBusinessDayOfMonth.html | 2 - docs/functions/lastBusinessDayOfYear.html | 2 - docs/functions/mean.html | 2 - docs/functions/offsetBusinessDays.html | 2 - docs/functions/pctChange.html | 2 - docs/functions/plotSeries.html | 6 - docs/functions/plotSeriesHtml.html | 7 - docs/functions/preparePlotData.html | 3 - docs/functions/prevBusinessDay.html | 2 - docs/functions/quantile.html | 2 - docs/functions/randomGenerator.html | 2 - docs/functions/reportHtml.html | 11 - docs/functions/resampleToPeriodEnd.html | 7 - docs/functions/sharpeplot.html | 2 - docs/functions/sharpeplotHtml.html | 3 - docs/functions/simulatePortfolios.html | 2 - docs/functions/std.html | 2 - docs/functions/timeseriesChain.html | 2 - docs/hierarchy.html | 1 - docs/index.html | 292 --- docs/interfaces/EfficientFrontierPoint.html | 5 - docs/interfaces/LagSeries.html | 4 - docs/interfaces/OrdLeastSquaresResult.html | 5 - docs/interfaces/PlotSeriesOptions.html | 13 - docs/interfaces/ReportOptions.html | 4 - docs/interfaces/SharpePlotOptions.html | 8 - docs/interfaces/SharpePlotPoint.html | 7 - docs/interfaces/SimulatedPortfolio.html | 5 - docs/modules.html | 1 - docs/types/CaptorSeriesResponse.html | 6 - docs/types/CountryCode.html | 1 - docs/types/DateRangeOptions.html | 6 - docs/types/LiteralBizDayFreq.html | 1 - docs/types/LiteralPortfolioWeightings.html | 1 - docs/types/LjungBoxResult.html | 2 - docs/types/RandomGenerator.html | 1 - docs/types/ResampleFreq.html | 1 - 68 files changed, 58 insertions(+), 2621 deletions(-) create mode 100644 .github/workflows/docs.yml delete mode 100644 docs/.nojekyll delete mode 100644 docs/assets/hierarchy.js delete mode 100644 docs/assets/highlight.css delete mode 100644 docs/assets/icons.js delete mode 100644 docs/assets/icons.svg delete mode 100644 docs/assets/main.js delete mode 100644 docs/assets/navigation.js delete mode 100644 docs/assets/search.js delete mode 100644 docs/assets/style.css delete mode 100644 docs/classes/DateAlignmentError.html delete mode 100644 docs/classes/IncorrectArgumentComboError.html delete mode 100644 docs/classes/InitialValueZeroError.html delete mode 100644 docs/classes/MixedValuetypesError.html delete mode 100644 docs/classes/NoWeightsError.html delete mode 100644 docs/classes/OpenFrame.html delete mode 100644 docs/classes/OpenTimeSeries.html delete mode 100644 docs/classes/ResampleDataLossError.html delete mode 100644 docs/classes/ReturnSimulation.html delete mode 100644 docs/enums/ValueType.html delete mode 100644 docs/functions/dateFix.html delete mode 100644 docs/functions/dateToStr.html delete mode 100644 docs/functions/efficientFrontier.html delete mode 100644 docs/functions/fetchCaptorSeries.html delete mode 100644 docs/functions/fetchCaptorSeriesBatch.html delete mode 100644 docs/functions/filterBusinessDays.html delete mode 100644 docs/functions/filterToBusinessDays.html delete mode 100644 docs/functions/generateCalendarDateRange.html delete mode 100644 docs/functions/getPreviousBusinessDayBeforeToday.html delete mode 100644 docs/functions/isBusinessDay.html delete mode 100644 docs/functions/lastBusinessDayOfMonth.html delete mode 100644 docs/functions/lastBusinessDayOfYear.html delete mode 100644 docs/functions/mean.html delete mode 100644 docs/functions/offsetBusinessDays.html delete mode 100644 docs/functions/pctChange.html delete mode 100644 docs/functions/plotSeries.html delete mode 100644 docs/functions/plotSeriesHtml.html delete mode 100644 docs/functions/preparePlotData.html delete mode 100644 docs/functions/prevBusinessDay.html delete mode 100644 docs/functions/quantile.html delete mode 100644 docs/functions/randomGenerator.html delete mode 100644 docs/functions/reportHtml.html delete mode 100644 docs/functions/resampleToPeriodEnd.html delete mode 100644 docs/functions/sharpeplot.html delete mode 100644 docs/functions/sharpeplotHtml.html delete mode 100644 docs/functions/simulatePortfolios.html delete mode 100644 docs/functions/std.html delete mode 100644 docs/functions/timeseriesChain.html delete mode 100644 docs/hierarchy.html delete mode 100644 docs/index.html delete mode 100644 docs/interfaces/EfficientFrontierPoint.html delete mode 100644 docs/interfaces/LagSeries.html delete mode 100644 docs/interfaces/OrdLeastSquaresResult.html delete mode 100644 docs/interfaces/PlotSeriesOptions.html delete mode 100644 docs/interfaces/ReportOptions.html delete mode 100644 docs/interfaces/SharpePlotOptions.html delete mode 100644 docs/interfaces/SharpePlotPoint.html delete mode 100644 docs/interfaces/SimulatedPortfolio.html delete mode 100644 docs/modules.html delete mode 100644 docs/types/CaptorSeriesResponse.html delete mode 100644 docs/types/CountryCode.html delete mode 100644 docs/types/DateRangeOptions.html delete mode 100644 docs/types/LiteralBizDayFreq.html delete mode 100644 docs/types/LiteralPortfolioWeightings.html delete mode 100644 docs/types/LjungBoxResult.html delete mode 100644 docs/types/RandomGenerator.html delete mode 100644 docs/types/ResampleFreq.html diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..403763c --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,57 @@ +name: Deploy docs + +on: + push: + branches: [main, master] + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "24" + package-manager-cache: false + + - name: Use npm 12 + working-directory: ${{ runner.temp }} + run: npm install -g npm@12 + + - name: Install dependencies + run: npm ci + + - name: Build docs + run: npm run docs + + - name: Configure Pages + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + + - name: Upload docs artifact + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: docs + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.gitignore b/.gitignore index 7e8923e..25584d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ dist/ +docs/ coverage/ junit.xml .mypy_cache/ diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/assets/hierarchy.js b/docs/assets/hierarchy.js deleted file mode 100644 index fb85f0a..0000000 --- a/docs/assets/hierarchy.js +++ /dev/null @@ -1 +0,0 @@ -window.hierarchyData = "eJyrVirKzy8pVrKKjtVRKkpNy0lNLsnMzytWsqqurQUAmx4Kpg==" \ No newline at end of file diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css deleted file mode 100644 index c7af87d..0000000 --- a/docs/assets/highlight.css +++ /dev/null @@ -1,85 +0,0 @@ -:root { - --light-hl-0: #795E26; - --dark-hl-0: #DCDCAA; - --light-hl-1: #000000; - --dark-hl-1: #D4D4D4; - --light-hl-2: #A31515; - --dark-hl-2: #CE9178; - --light-hl-3: #AF00DB; - --dark-hl-3: #C586C0; - --light-hl-4: #001080; - --dark-hl-4: #9CDCFE; - --light-hl-5: #0000FF; - --dark-hl-5: #569CD6; - --light-hl-6: #0070C1; - --dark-hl-6: #4FC1FF; - --light-hl-7: #098658; - --dark-hl-7: #B5CEA8; - --light-hl-8: #008000; - --dark-hl-8: #6A9955; - --light-code-background: #FFFFFF; - --dark-code-background: #1E1E1E; -} - -@media (prefers-color-scheme: light) { :root { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --hl-6: var(--light-hl-6); - --hl-7: var(--light-hl-7); - --hl-8: var(--light-hl-8); - --code-background: var(--light-code-background); -} } - -@media (prefers-color-scheme: dark) { :root { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --hl-6: var(--dark-hl-6); - --hl-7: var(--dark-hl-7); - --hl-8: var(--dark-hl-8); - --code-background: var(--dark-code-background); -} } - -:root[data-theme='light'] { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --hl-6: var(--light-hl-6); - --hl-7: var(--light-hl-7); - --hl-8: var(--light-hl-8); - --code-background: var(--light-code-background); -} - -:root[data-theme='dark'] { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --hl-6: var(--dark-hl-6); - --hl-7: var(--dark-hl-7); - --hl-8: var(--dark-hl-8); - --code-background: var(--dark-code-background); -} - -.hl-0 { color: var(--hl-0); } -.hl-1 { color: var(--hl-1); } -.hl-2 { color: var(--hl-2); } -.hl-3 { color: var(--hl-3); } -.hl-4 { color: var(--hl-4); } -.hl-5 { color: var(--hl-5); } -.hl-6 { color: var(--hl-6); } -.hl-7 { color: var(--hl-7); } -.hl-8 { color: var(--hl-8); } -pre, code { background: var(--code-background); } diff --git a/docs/assets/icons.js b/docs/assets/icons.js deleted file mode 100644 index 3ae8f55..0000000 --- a/docs/assets/icons.js +++ /dev/null @@ -1,18 +0,0 @@ -(function() { - addIcons(); - function addIcons() { - if (document.readyState === "loading") return document.addEventListener("DOMContentLoaded", addIcons); - const svg = document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg")); - svg.innerHTML = `MMNEPVFCICPMFPCPTTAAATR`; - svg.style.display = "none"; - if (location.protocol === "file:") updateUseElements(); - } - - function updateUseElements() { - document.querySelectorAll("use").forEach(el => { - if (el.getAttribute("href").includes("#icon-")) { - el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); - } - }); - } -})() \ No newline at end of file diff --git a/docs/assets/icons.svg b/docs/assets/icons.svg deleted file mode 100644 index 10db10b..0000000 --- a/docs/assets/icons.svg +++ /dev/null @@ -1 +0,0 @@ -MMNEPVFCICPMFPCPTTAAATR \ No newline at end of file diff --git a/docs/assets/main.js b/docs/assets/main.js deleted file mode 100644 index 11d92ad..0000000 --- a/docs/assets/main.js +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -window.translations={"copy":"Copy","copied":"Copied!","normally_hidden":"This member is normally hidden due to your filter settings.","hierarchy_expand":"Expand","hierarchy_collapse":"Collapse","folder":"Folder","search_index_not_available":"The search index is not available","search_no_results_found_for_0":"No results found for {0}","kind_1":"Project","kind_2":"Module","kind_4":"Namespace","kind_8":"Enumeration","kind_16":"Enumeration Member","kind_32":"Variable","kind_64":"Function","kind_128":"Class","kind_256":"Interface","kind_512":"Constructor","kind_1024":"Property","kind_2048":"Method","kind_4096":"Call Signature","kind_8192":"Index Signature","kind_16384":"Constructor Signature","kind_32768":"Parameter","kind_65536":"Type Literal","kind_131072":"Type Parameter","kind_262144":"Accessor","kind_524288":"Get Signature","kind_1048576":"Set Signature","kind_2097152":"Type Alias","kind_4194304":"Reference","kind_8388608":"Document"}; -"use strict";(()=>{var Ke=Object.create;var he=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ye=Object.prototype.hasOwnProperty;var et=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var tt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ze(e))!Ye.call(t,i)&&i!==n&&he(t,i,{get:()=>e[i],enumerable:!(r=Ge(e,i))||r.enumerable});return t};var nt=(t,e,n)=>(n=t!=null?Ke(Xe(t)):{},tt(e||!t||!t.__esModule?he(n,"default",{value:t,enumerable:!0}):n,t));var ye=et((me,ge)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=(function(e){return function(n){e.console&&console.warn&&console.warn(n)}})(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,l],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. -`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(oc?d+=2:a==c&&(n+=r[l+1]*i[d+1],l+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}if(s.str.length==0&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),f=s.str.charAt(1),p;f in s.node.edges?p=s.node.edges[f]:(p=new t.TokenSet,s.node.edges[f]=p),s.str.length==1&&(p.final=!0),i.push({node:p,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),c=0;c1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}if(s.type===t.QueryLexer.TERM)return t.QueryParser.parseTerm;var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},(function(e,n){typeof define=="function"&&define.amd?define(n):typeof me=="object"?ge.exports=n():e.lunr=n()})(this,function(){return t})})()});var M,G={getItem(){return null},setItem(){}},K;try{K=localStorage,M=K}catch{K=G,M=G}var S={getItem:t=>M.getItem(t),setItem:(t,e)=>M.setItem(t,e),disableWritingLocalStorage(){M=G},disable(){localStorage.clear(),M=G},enable(){M=K}};window.TypeDoc||={disableWritingLocalStorage(){S.disableWritingLocalStorage()},disableLocalStorage:()=>{S.disable()},enableLocalStorage:()=>{S.enable()}};window.translations||={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings.",hierarchy_expand:"Expand",hierarchy_collapse:"Collapse",search_index_not_available:"The search index is not available",search_no_results_found_for_0:"No results found for {0}",folder:"Folder",kind_1:"Project",kind_2:"Module",kind_4:"Namespace",kind_8:"Enumeration",kind_16:"Enumeration Member",kind_32:"Variable",kind_64:"Function",kind_128:"Class",kind_256:"Interface",kind_512:"Constructor",kind_1024:"Property",kind_2048:"Method",kind_4096:"Call Signature",kind_8192:"Index Signature",kind_16384:"Constructor Signature",kind_32768:"Parameter",kind_65536:"Type Literal",kind_131072:"Type Parameter",kind_262144:"Accessor",kind_524288:"Get Signature",kind_1048576:"Set Signature",kind_2097152:"Type Alias",kind_4194304:"Reference",kind_8388608:"Document"};var pe=[];function X(t,e){pe.push({selector:e,constructor:t})}var Z=class{alwaysVisibleMember=null;constructor(){this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible()),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){pe.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e&&!rt(e)){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r,document.querySelector(".col-sidebar").scrollTop=r}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),n=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach(r=>{r.style.display="block";let i=Array.from(r.querySelectorAll(".tsd-index-link")).every(s=>s.offsetParent==null);r.style.display=i?"none":"block"}),e&&(e.open=n)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(!n)return;let r=n.offsetParent==null,i=n;for(;i!==document.body;)i instanceof HTMLDetailsElement&&(i.open=!0),i=i.parentElement;if(n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let s=document.createElement("p");s.classList.add("warning"),s.textContent=window.translations.normally_hidden,n.prepend(s)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent=window.translations.copy},100)},1e3)})})}};function rt(t){let e=t.getBoundingClientRect(),n=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(e.bottom<0||e.top-n>=0)}var fe=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var Ie=nt(ye(),1);async function R(t){let e=Uint8Array.from(atob(t),s=>s.charCodeAt(0)),r=new Blob([e]).stream().pipeThrough(new DecompressionStream("deflate")),i=await new Response(r).text();return JSON.parse(i)}var Y="closing",ae="tsd-overlay";function it(){let t=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.body.style.overflow="hidden",document.body.style.paddingRight=`${t}px`}function st(){document.body.style.removeProperty("overflow"),document.body.style.removeProperty("padding-right")}function xe(t,e){t.addEventListener("animationend",()=>{t.classList.contains(Y)&&(t.classList.remove(Y),document.getElementById(ae)?.remove(),t.close(),st())}),t.addEventListener("cancel",n=>{n.preventDefault(),ve(t)}),e?.closeOnClick&&document.addEventListener("click",n=>{t.open&&!t.contains(n.target)&&ve(t)},!0)}function Ee(t){if(t.open)return;let e=document.createElement("div");e.id=ae,document.body.appendChild(e),t.showModal(),it()}function ve(t){if(!t.open)return;document.getElementById(ae)?.classList.add(Y),t.classList.add(Y)}var I=class{el;app;constructor(e){this.el=e.el,this.app=e.app}};var be=document.head.appendChild(document.createElement("style"));be.dataset.for="filters";var le={};function we(t){for(let e of t.split(/\s+/))if(le.hasOwnProperty(e)&&!le[e])return!0;return!1}var ee=class extends I{key;value;constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),be.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } -`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=S.getItem(this.key);return e?e==="true":this.el.checked}setLocalStorage(e){S.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),le[`tsd-is-${this.el.name}`]=this.value,this.app.filterChanged(),this.app.updateIndexVisibility()}};var Le=0;async function Se(t,e){if(!window.searchData)return;let n=await R(window.searchData);t.data=n,t.index=Ie.Index.load(n.index),e.innerHTML=""}function _e(){let t=document.getElementById("tsd-search-trigger"),e=document.getElementById("tsd-search"),n=document.getElementById("tsd-search-input"),r=document.getElementById("tsd-search-results"),i=document.getElementById("tsd-search-script"),s=document.getElementById("tsd-search-status");if(!(t&&e&&n&&r&&i&&s))throw new Error("Search controls missing");let o={base:document.documentElement.dataset.base};o.base.endsWith("/")||(o.base+="/"),i.addEventListener("error",()=>{let a=window.translations.search_index_not_available;Pe(s,a)}),i.addEventListener("load",()=>{Se(o,s)}),Se(o,s),ot({trigger:t,searchEl:e,results:r,field:n,status:s},o)}function ot(t,e){let{field:n,results:r,searchEl:i,status:s,trigger:o}=t;xe(i,{closeOnClick:!0});function a(){Ee(i),n.setSelectionRange(0,n.value.length)}o.addEventListener("click",a),n.addEventListener("input",fe(()=>{at(r,n,s,e)},200)),n.addEventListener("keydown",l=>{if(r.childElementCount===0||l.ctrlKey||l.metaKey||l.altKey)return;let d=n.getAttribute("aria-activedescendant"),f=d?document.getElementById(d):null;if(f){let p=!1,v=!1;switch(l.key){case"Home":case"End":case"ArrowLeft":case"ArrowRight":v=!0;break;case"ArrowDown":case"ArrowUp":p=l.shiftKey;break}(p||v)&&ke(n)}if(!l.shiftKey)switch(l.key){case"Enter":f?.querySelector("a")?.click();break;case"ArrowUp":Te(r,n,f,-1),l.preventDefault();break;case"ArrowDown":Te(r,n,f,1),l.preventDefault();break}});function c(){ke(n)}n.addEventListener("change",c),n.addEventListener("blur",c),n.addEventListener("click",c),document.body.addEventListener("keydown",l=>{if(l.altKey||l.metaKey||l.shiftKey)return;let d=l.ctrlKey&&l.key==="k",f=!l.ctrlKey&&!ut()&&l.key==="/";(d||f)&&(l.preventDefault(),a())})}function at(t,e,n,r){if(!r.index||!r.data)return;t.innerHTML="",n.innerHTML="",Le+=1;let i=e.value.trim(),s;if(i){let a=i.split(" ").map(c=>c.length?`*${c}*`:"").join(" ");s=r.index.search(a).filter(({ref:c})=>{let l=r.data.rows[Number(c)].classes;return!l||!we(l)})}else s=[];if(s.length===0&&i){let a=window.translations.search_no_results_found_for_0.replace("{0}",` "${te(i)}" `);Pe(n,a);return}for(let a=0;ac.score-a.score);let o=Math.min(10,s.length);for(let a=0;a`,f=Ce(c.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(f+=` (score: ${s[a].score.toFixed(2)})`),c.parent&&(f=` - ${Ce(c.parent,i)}.${f}`);let p=document.createElement("li");p.id=`tsd-search:${Le}-${a}`,p.role="option",p.ariaSelected="false",p.classList.value=c.classes??"";let v=document.createElement("a");v.tabIndex=-1,v.href=r.base+c.url,v.innerHTML=d+`${f}`,p.append(v),t.appendChild(p)}}function Te(t,e,n,r){let i;if(r===1?i=n?.nextElementSibling||t.firstElementChild:i=n?.previousElementSibling||t.lastElementChild,i!==n){if(!i||i.role!=="option"){console.error("Option missing");return}i.ariaSelected="true",i.scrollIntoView({behavior:"smooth",block:"nearest"}),e.setAttribute("aria-activedescendant",i.id),n?.setAttribute("aria-selected","false")}}function ke(t){let e=t.getAttribute("aria-activedescendant");(e?document.getElementById(e):null)?.setAttribute("aria-selected","false"),t.setAttribute("aria-activedescendant","")}function Ce(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(te(t.substring(s,o)),`${te(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(te(t.substring(s))),i.join("")}var lt={"&":"&","<":"<",">":">","'":"'",'"':"""};function te(t){return t.replace(/[&<>"'"]/g,e=>lt[e])}function Pe(t,e){t.innerHTML=e?`
${e}
`:""}var ct=["button","checkbox","file","hidden","image","radio","range","reset","submit"];function ut(){let t=document.activeElement;return t?t.isContentEditable||t.tagName==="TEXTAREA"||t.tagName==="SEARCH"?!0:t.tagName==="INPUT"&&!ct.includes(t.type):!1}var D="mousedown",Me="mousemove",$="mouseup",ne={x:0,y:0},Qe=!1,ce=!1,dt=!1,F=!1,Oe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(Oe?"is-mobile":"not-mobile");Oe&&"ontouchstart"in document.documentElement&&(dt=!0,D="touchstart",Me="touchmove",$="touchend");document.addEventListener(D,t=>{ce=!0,F=!1;let e=D=="touchstart"?t.targetTouches[0]:t;ne.y=e.pageY||0,ne.x=e.pageX||0});document.addEventListener(Me,t=>{if(ce&&!F){let e=D=="touchstart"?t.targetTouches[0]:t,n=ne.x-(e.pageX||0),r=ne.y-(e.pageY||0);F=Math.sqrt(n*n+r*r)>10}});document.addEventListener($,()=>{ce=!1});document.addEventListener("click",t=>{Qe&&(t.preventDefault(),t.stopImmediatePropagation(),Qe=!1)});var re=class extends I{active;className;constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener($,n=>this.onPointerUp(n)),this.el.addEventListener("click",n=>n.preventDefault()),document.addEventListener(D,n=>this.onDocumentPointerDown(n)),document.addEventListener($,n=>this.onDocumentPointerUp(n))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let n=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(n),setTimeout(()=>document.documentElement.classList.remove(n),500)}onPointerUp(e){F||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!F&&this.active&&e.target.closest(".col-sidebar")){let n=e.target.closest("a");if(n){let r=window.location.href;r.indexOf("#")!=-1&&(r=r.substring(0,r.indexOf("#"))),n.href.substring(0,r.length)==r&&setTimeout(()=>this.setActive(!1),250)}}}};var ue=new Map,de=class{open;accordions=[];key;constructor(e,n){this.key=e,this.open=n}add(e){this.accordions.push(e),e.open=this.open,e.addEventListener("toggle",()=>{this.toggle(e.open)})}toggle(e){for(let n of this.accordions)n.open=e;S.setItem(this.key,e.toString())}},ie=class extends I{constructor(e){super(e);let n=this.el.querySelector("summary"),r=n.querySelector("a");r&&r.addEventListener("click",()=>{location.assign(r.href)});let i=`tsd-accordion-${n.dataset.key??n.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`,s;if(ue.has(i))s=ue.get(i);else{let o=S.getItem(i),a=o?o==="true":this.el.open;s=new de(i,a),ue.set(i,s)}s.add(this.el)}};function He(t){let e=S.getItem("tsd-theme")||"os";t.value=e,Ae(e),t.addEventListener("change",()=>{S.setItem("tsd-theme",t.value),Ae(t.value)})}function Ae(t){document.documentElement.dataset.theme=t}var se;function Ne(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",Re),Re())}async function Re(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let e=await R(window.navigationData);se=document.documentElement.dataset.base,se.endsWith("/")||(se+="/"),t.innerHTML="";for(let n of e)Be(n,t,[]);window.app.createComponents(t),window.app.showPage(),window.app.ensureActivePageVisible()}function Be(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-accordion`:"tsd-accordion";let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.dataset.key=i.join("$"),o.innerHTML='',De(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let c=a.appendChild(document.createElement("ul"));c.className="tsd-nested-navigation";for(let l of t.children)Be(l,c,i)}else De(t,r,t.class)}function De(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));if(r.href=se+t.path,n&&(r.className=n),location.pathname===r.pathname&&!r.href.includes("#")&&(r.classList.add("current"),r.ariaCurrent="page"),t.kind){let i=window.translations[`kind_${t.kind}`].replaceAll('"',""");r.innerHTML=``}r.appendChild(Fe(t.text,document.createElement("span")))}else{let r=e.appendChild(document.createElement("span")),i=window.translations.folder.replaceAll('"',""");r.innerHTML=``,r.appendChild(Fe(t.text,document.createElement("span")))}}function Fe(t,e){let n=t.split(/(?<=[^A-Z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[_-])(?=[^_-])/);for(let r=0;r{let i=r.target;for(;i.parentElement&&i.parentElement.tagName!="LI";)i=i.parentElement;i.dataset.dropdown&&(i.dataset.dropdown=String(i.dataset.dropdown!=="true"))});let t=new Map,e=new Set;for(let r of document.querySelectorAll(".tsd-full-hierarchy [data-refl]")){let i=r.querySelector("ul");t.has(r.dataset.refl)?e.add(r.dataset.refl):i&&t.set(r.dataset.refl,i)}for(let r of e)n(r);function n(r){let i=t.get(r).cloneNode(!0);i.querySelectorAll("[id]").forEach(s=>{s.removeAttribute("id")}),i.querySelectorAll("[data-dropdown]").forEach(s=>{s.dataset.dropdown="false"});for(let s of document.querySelectorAll(`[data-refl="${r}"]`)){let o=gt(),a=s.querySelector("ul");s.insertBefore(o,a),o.dataset.dropdown=String(!!a),a||s.appendChild(i.cloneNode(!0))}}}function pt(){let t=document.getElementById("tsd-hierarchy-script");t&&(t.addEventListener("load",Ve),Ve())}async function Ve(){let t=document.querySelector(".tsd-panel.tsd-hierarchy:has(h4 a)");if(!t||!window.hierarchyData)return;let e=+t.dataset.refl,n=await R(window.hierarchyData),r=t.querySelector("ul"),i=document.createElement("ul");if(i.classList.add("tsd-hierarchy"),ft(i,n,e),r.querySelectorAll("li").length==i.querySelectorAll("li").length)return;let s=document.createElement("span");s.classList.add("tsd-hierarchy-toggle"),s.textContent=window.translations.hierarchy_expand,t.querySelector("h4 a")?.insertAdjacentElement("afterend",s),s.insertAdjacentText("beforebegin",", "),s.addEventListener("click",()=>{s.textContent===window.translations.hierarchy_expand?(r.insertAdjacentElement("afterend",i),r.remove(),s.textContent=window.translations.hierarchy_collapse):(i.insertAdjacentElement("afterend",r),i.remove(),s.textContent=window.translations.hierarchy_expand)})}function ft(t,e,n){let r=e.roots.filter(i=>mt(e,i,n));for(let i of r)t.appendChild(je(e,i,n))}function je(t,e,n,r=new Set){if(r.has(e))return;r.add(e);let i=t.reflections[e],s=document.createElement("li");if(s.classList.add("tsd-hierarchy-item"),e===n){let o=s.appendChild(document.createElement("span"));o.textContent=i.name,o.classList.add("tsd-hierarchy-target")}else{for(let a of i.uniqueNameParents||[]){let c=t.reflections[a],l=s.appendChild(document.createElement("a"));l.textContent=c.name,l.href=oe+c.url,l.className=c.class+" tsd-signature-type",s.append(document.createTextNode("."))}let o=s.appendChild(document.createElement("a"));o.textContent=t.reflections[e].name,o.href=oe+i.url,o.className=i.class+" tsd-signature-type"}if(i.children){let o=s.appendChild(document.createElement("ul"));o.classList.add("tsd-hierarchy");for(let a of i.children){let c=je(t,a,n,r);c&&o.appendChild(c)}}return r.delete(e),s}function mt(t,e,n){if(e===n)return!0;let r=new Set,i=[t.reflections[e]];for(;i.length;){let s=i.pop();if(!r.has(s)){r.add(s);for(let o of s.children||[]){if(o===n)return!0;i.push(t.reflections[o])}}}return!1}function gt(){let t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("width","20"),t.setAttribute("height","20"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.innerHTML='',t}X(re,"a[data-toggle]");X(ie,".tsd-accordion");X(ee,".tsd-filter-item input[type=checkbox]");var qe=document.getElementById("tsd-theme");qe&&He(qe);var yt=new Z;Object.defineProperty(window,"app",{value:yt});_e();Ne();$e();"virtualKeyboard"in navigator&&(navigator.virtualKeyboard.overlaysContent=!0);})(); -/*! Bundled license information: - -lunr/lunr.js: - (** - * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 - * Copyright (C) 2020 Oliver Nightingale - * @license MIT - *) - (*! - * lunr.utils - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Set - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.tokenizer - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Pipeline - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Vector - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.stemmer - * Copyright (C) 2020 Oliver Nightingale - * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt - *) - (*! - * lunr.stopWordFilter - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.trimmer - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.TokenSet - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Index - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Builder - * Copyright (C) 2020 Oliver Nightingale - *) -*/ diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js deleted file mode 100644 index 6ed8c96..0000000 --- a/docs/assets/navigation.js +++ /dev/null @@ -1 +0,0 @@ -window.navigationData = "eJyV1t9v0zAQB/D/Jc8TZRMbsLe1XQGpo1VbgQDxcCSXxJDY2fkytSD+d9Sk5Kdz6V5zX3/sOLbjb388xj17t94nSHLcHTL0LrwMOPZuPdR5aidV4UXMaeJdeL+UDrzbN38vqrZzYLxLVKRT1HxPZKhG/ASsRTvpZ9re5VVT/KB9Q4Q+31GUH1vMTPrDDNBCWO5DsYKkeL+vSMO6Iya5D2qPQRHnQ4Z2gHWlJPWj+YwqinnIa9claZWhXhCk2Eeq0lj7nUpxi6TQupG6LkkbtJBmCc6BYWns0Ks5Y7LLOemtSvMEWBntItsJSbsPQ+Ur1Lwgo1khrY3SXJtKM1IIPtqJO9rGr65vGvgSou48NryqKhErCpYIlrePORDaDdo8cQ/PmZTodWK4HMAqO06Te5S9lERuMDPEEtdKSNQ2Bsrw2LvE9VLnkcMfuZMRuXKBYbA2xKFJlHGLvZiEziBjQ+WEb9BmRtvGVi5Ok4kr0zFfvn19eX3VdE2umQ4zE/S5ujSmHM/5DegIe9+kpLr1MW+pGAmSqfo9h8OC8LEL9gJnitVcl+em0lFvrMPJ0T5+5jqamn13M57cVnXM2oAOTPoONRJw83wssU55VDsdpq6pbNbGnAAYF2pfE2Gu/eKLTk6ltnDzqtN4Z7ZMQ82LogBg96B1Qb2QAIbIftzcNS6wF3oOOAX247PUIinRKmGkaW6VRmvncHAPtpcaJXfmPLSdE9ioXJU4gwR1AFRtfpc9GBY74DXhkzK5bQxpiqEh3JkADu6ORhoJHapmExfeCghQApYbyVX4YDQ714c7+Rz6C4JzgziDApwiaJdzfC40M2FokceWVj8lkJnPs3hoIVVFCajuLE6hqp5FvC8zAnNMSBRhBlTcKY6XXKfVjsjY08gi7UQE7DEHzSpxzvP/mtCchv5dtULS/6uNFRfDocmuqyJR/uF2Zo2kTHCvA7fViwmoLS6Ex4/tsurqWcTQ67UTEnW6TFa3FucK76ckkp2zZFmaFVYp2mLxz2JQznOjE+lh3/8B983PwQ==" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js deleted file mode 100644 index daa45a3..0000000 --- a/docs/assets/search.js +++ /dev/null @@ -1 +0,0 @@ -window.searchData = "eJytXWuP27iS/S+er42MinrnWx6Tu1l0JoNONhe7jcFAbdOOJrLkK8mdF+a/L0hJdpEsSSW7PyVok1V8HBbJcyjy56quvjar5/c/V1/ycrN6ntysymwvV89Xn7LiKD9+P8jVzepYF6vnK1ke982vp78/+9zui9XNal1kTSOb1fPV6p+bwQ5EJ0O//fvdi78+vbibtPOL/LrP/nrMatPgzeqQ1bJsjfJMeHl/y/FSFZd6+ePu7avfpl0c6nwtL7V/99vt3ce736c91LKo27q82Mf729uXv318MeOkKooH2WbXeHn1/m6m15WXdVVf3Ovayyy2tJcrsKW8vP39zfu7Fx/fvp93lZfbqs7avLrGHwMGVXE1DlhNd2XLzQ5K7ePyMcloqcWtJM5x8HXWyhdFviv3smx/q+uqPjnrDf7qJpmMjSGIk/V1VTZtfVy3fLO/mHnoWhGlpqv3tlTjT67bF/XuqBK/qvYPFV3PibRPUuE5+6yaT1VorAnyNs8KDYT/k/Vo5YlUT1TtMcvMClPFp6v6Lv8mNzpl+/0gG7qmVKInqeioYVY9ybLT1fy9+rfMd5/bkQqaPz9J1QiTrEpZJaWr8/4gyze1+r/t9vTLk1TCtMYq/7loqOieCJC/4rgvb7MHWTTzDlXaYkh7sceyafP2KMuW4dFIe7HHY9nWuWS4Oye80FfbbLZzbvo0F3r42gFyzsk5Gd+PiAQEZ0/bvG7at5tvc650ulynu9hX3sr9K9X8c85UwnWf8GJvRcaqmEp2Zb0KWe7az7OOhlQX+znIOq82b8sX/yuz2cjRJc7L7LucWDuSXr3gHPeyzeZjvpeN5IytbLNpceJLfR7bqt+RTLs7p7vQU7+7mvQyuQOb9bDODu2xlnf9XmQ6NHVpp/ct8x7V0qt4l7V1Pgv+Lu1+SHuhx21etLL+WL08Nnkpm+Z19n0WKl2etnro82y6PBeWQG33WE08vy+c9fW3LBtZvigOn2eh0yXN+qQX+ttnX+QfVd1uq2K+firxASW+2Oe313X2dVN9Lec9ftuck17v72XVttVe7Z0WeH7QmTZdpkvLIOud/MCKczrptVGuqje3MmvaD/85ZrVs3uSz02JVbwqVo+lybPOF8yP2Xssm2x8K+bH6Q08Uv5WbOfdDlrbq5haps1zsvz3W5Su92pxt7y7x+pT4Qp9tNYCM181tNeDr2r5u62z9JS939F7Idtsnln3ii30eyzVny/KLTrntUy5YsVrbI7VOmGjY889PtlGyTLJ3S6ikF20nXL+cPQXD67GuZbn+znN6TnyNTxU0ebUcUl7jLdcdpCiht3S8sZ2eM+TT0Wbet97UspwOKa/yVq2z4hWzL3Xi9dV9uc/qL3Jk22i7PKe9xmM5Fl5sd+VcdJn3dd5aMLFzznA1dka3/I7PuX3/vK9Hxa/xOvGU9Gp/LVYZZ132qRd6XUI92G5Z/APH6xQt4MaBJ/I5ThA4LudZAo7HboXWTHEFtuc+C4cx4JSgOWTl++3oVtD2rpJX29ldIMezKv62ztYsvyjxUq8GZbHmhYcu3VWe6rz9vJdtvr6T9I7B8XnKUcvpHQPD+xQ14zjm8DPzPpVs/HpsJ+qsih6zenYvOu9TL/rzjXwtH3NFF/CcD7k2KNc1pVBHJT5l9ZtjyQOzSv+Y1dsu/dWeq2KZ56p4As9sMsmdIRYySoyy1NX+tZSHdXXgreNUhs05wzW+d7LiDvCdrK4f2TvZfmw229fs7cBOtmqxc+GugPL9ib/w6Z1fuv4xvH851m3V5DzHKPE1Pou/j+XuZcVchqjED9Ul65AlpJ67Q+Axe4s8z9B7E2VgcnzzpTlwJ+vD9bP1IavVwYAXS6bNPs8TzZ6Hqsnb/FF++JzVvDYfcjR9jmu8c2lGuwxLuUZOSdpPVTEuErglaB+rYl4rmPfcyPZ3+fWWzT40si3l1ws5CNPzF/mV57JLeJWvqm7zckKFcXx2GZ6ihdvq1XFfM2fLtloPia/zySCTXd8LGOX5Mujpj7tK0Imvr7c285G9NunogidYnyzZBDzNHqA7D8nwNnFuku3pTV3tPzF36mqhXVf7qTOhPL9fq7rhdeOQ8mpv76qSyYTo5Ps++TV+f3xYV8yp70fTJ7121/Cirtn7lrraZ0Pyq3crWSunRDVyw5K1kqOt8Urw/uFvueaBSiWvhuRLGUwkPt31i4XXWZvdVs3IiUMy1ZNIUeOWWYoUXfyxqiol9EO+PxY0LWEneKIKEkaZdbPKO6ZCbUmhkna8mdYquT7/Pu4PzW2237jnOGi/OkPRZ3gC3++OSxzvj0/j9UO+2y+qcdNnuM73Xmbli7I8ZkWXg1kClS3T2eoh21OV4xMxv88VYmqu55agPO4fZP1++yHfu0GaLkCXpdo2XZbr/DdSupsw2m+f9Dp/bZ1t8nJHEnm02z7HJIN3gfe3JSmGzJYhLycVkYmSWMpELbMi/yE372RWLhoFQ0YFxMvHwUhp+ONgyHHhKHD8N8eCUKvHfA+pl/u19m0Ta6QRLFScNRK3BGrZ86+HPdO3Sr3Tqa/3elvtyqreZ9z+VnkKlOf6ErxTDH3538f9YVkL7HU+NR09VVv8vrQhrmiFEH0ju93m61yW7Zu6Kttc1n9UOToQn5etrLfZWja/0ikn13NG4MN8CM/sL1O79JGCj80xn7MaHShg+j/lepIitBv5uLgEfaanKID9EQezCHMfdcwWAsPtNttZ9BQqxelHPqiKbMcw9UufjK7AuUy8AzDjbmbkH8oRbpz35gncOz3DUG7JhPxGW1dy6LNl1n8xc45skclajJ6/a2W9loelBcH5nqAYdXeEebOwFCjbZYXAvf9HUbUdPN4fVMAmAeck4vd6ttncVruKb1V9PlN0OejauSUec904Qh/DezOr9vELcGwrRd0scX9sq6rLcqXzbV5I41zivHOU5UrnqgP/py4W+FY5jvX4woLtus3bYkmlh/TL3eJhdKe/N5kYQkaCJxk+rsXZoWOWcnnfES7n+o3lcrTPCIfT/TXmDvfVB72+Uj070V9OoifpM9rqbL+5JR4NeY1srU+cGe5VrpmPnflFmAh6Y/7ngh7b+VTQG3E+G/TYzicGzojvucHDdj06gEYcTw+iKbf0QBrdvllJliyx8UGBGYsznyrY5Vy2VSQdTu0Rme5Gd2akw+ktGdPlxF6MdDq3CRt3a8CkYwPkxv1+ExfASXX1Jn/E5HTnuYVdvLkf8zuzsV/gehQ6Y56n0cN2PAWgEdezGJpyLrw0hvAsz73KDm1VdwuyO9kcqrI594C+jOVXKsmCTar97dmM0fnvz8gis75Cm3M9feZ0id98w3Y68Q3REo/mhDXndHq6WuLXIlXmHM9QKzOeHfTqDyS/v6o2TtXPv0xi1baoSPy7rNxJeyXbmbV/5o+D4RQFx+Dp+MRoOznFHFMl1TmXRh0Cus3QkZwp310WTdFnE2dzuCU4fTGkNLI3+Tdpjwy6FKevhvSHNH2260rSKTQs750wc4lHG0+3eSvrrHiZ/3idfX9Ty/9Y/p3fF6G1z30K9N2FU3m5s3E7nnCZv/54uUVp9j6MHxfZvcvKTbX/lyzVJSXooEhn2Pp1meX+EAzR9PinSZuROZ+8QfefqA9TNAR+7X9ZYuhj9aGtR0zp37jGpE3dE0adNFzjW9muP+O4TBh30lxs/GXWrj9zPOiEbDf6Gx7y0x/kwkm0zPzIt0W2AzMZ18WuQ798lRWy3GT1KQQRfkbT8p21f9TyMa+ODSrrS7mtavmx2mTfSaczebjOc5yfcGT8zjWqpjKU7f3WPC96tk4nvNiNcTBkwotKx3WiDmsQNtWfuSaq7baR7Qxc3URc84d1++rzCDhPv7GNnQhjytrpx+Xm/qvLMG5SJWCbraVaHqiduzpvSdk1Uyww/Dg9IKwUXMP/OWZlmxdUHw0/cU3VI9P32WK9YArHhjX5PNJR5x/55sa/GsJ2nVRcBx0foRBE2D3/uNzcSBOYCdhme4LgtBqkRpabiG2+pVq1admteL5f49XnLKdinZWCMvznzSovN/Lb6vnP1aOsG3V05vlKPPOfpaub1TaXxUZdjr8amGp1Fkgzrhv1HY/67599sk9SHUVWibvUv3qrm3vvJgieRYn488+b+yGz/kH/YbBx/ovOCKube7gJ0mdxauQDJx8Y+cTq5l4Q+YSTTxj5/NXNvU/k8518vpEvWN3cB0S+wMkXGPnC1c19SOQLnXyhkS9a3dxHRL7IyRcZ+eLVzX1M5IudfLGRL1nd3CdEvsTJlxj50tXNfUrkS518qdnvCgbgUT3vQgYszGjQkKghYGPiBhQcgEIOuNABEzugIAEUesCFD5j4AQULCG58eOb75hABF0NggggUNoCCEbg4AhNIEI07dsEEJppAgQQoHIILKDARBcm4YxdVYMIKFFqAAjK4yAITWsIbdSxcbAkTW0JjixoJwsWWsGKSGHdMxCUTXEKDixpKwgWXMMElxsElXHAJE1xC4UVQI1G44BImuISCi6BGonCxJUxsCQUXIahJQ7jgEia4hIKL8MnMLriECS6h8CKCGz95lniBmdlFlzDR5Su8iJDy7Lvo8k10+QowghpPvosu30SXr6e8mHTsosu3pj0FGJGQmYmpz4SXrwAjKGj6Lrp8E12+AoxPoct30eWb6PIVYHwgC+3Cyzfh5SvA+FSg9110+Sa6fIUXn1wmuODyTXD5Ci4+tVTwXWz5JrYChRY/vAngmQ+xuc5wsRWY2AoUXHwKW4GLrcDEVqDQ4lPhNnChFZjQCvSSioqYgYuswFpVKbD4KdXDAbGyMqEVKLQE5KozcLEVmNgKFFoCKnIFLrQCE1qBQktAQStwoRWY0AoUWgKf7GIXW4GJrUDBJSCXoS62AhNboUJLQMat0MVWaGIrVHAJKGyFLrZCE1uhgktAYSt0sRWa2AoVXAIKW6GLrdDEVjg+KYYutkJr2R6OTk4hsXQ3sRVqbJGoDl1whSa4QoWXkER16KIrNNEVKryEFKpDF1yhCa5Q4SWkq+yiKzTRFSm8hFTEjFxwRSa4IoWXkEJ15IIrMsEVKbyE1Mo4csEVmeCKFF5CcpPlgisywRUFo+uPyAVXZIIr0pvCmIoBkQuuyNoYRmNb7YjYG5rYiuLRtUvkYisysRUlo+uPyAVXZIIrSkfXH5ELrsgEV6zBRUWB2AVXbIIr1uCi1i6xC67YBFes8BJRa5fYBVdsgitWeImokRi74IpNcMUKLhE1v8QutmITW3E4umaKXWzFJrZizTpQozh2sRVbxINCS0SN4pjgHkxoxQosETWKYxdZsYmsWGElokZx7AIrNoGVjK+3EhdZiYmsRIEloua1xEVWYiIr0cgi+RYXWYmJrEQji0J04iIrMZGVKLDEFKITF1mJiaxEYSWmEJ24wEpMYCUKKzGF6MQFVmICK4lH14iJi6zEorWS0TViQlBbJrQShZaYGg6JC63EhFaqwBJTwyF1kZWayEoVWGJqOKQuslITWakYXV+mLrRSE1qpQktMjaXUhVZqQivV0KKGQ+pCKzWhlWpoUcMhdaGVmtBKNbRICtKFVmpCK1VgSajhkLrISk1kpcnoejp1kZVarKkCS0KNpZQgTm3mVKElISlMj+JOLfLUU4BJSBbTI+hTz+JPPQWZhAJ295Od3aJQPYWahKQyPYJE9SwW1VPASUhC0iNoVM/iUT2FnYSkFT2CSfUsKtVT8EkonHY/2dktMtXTcKOg2v1kZ7f4VE9hKKUpc4JQ9SxG1dNUPcmaewSn6lmo0xx8SqKOYuwdyh7G2WCStbdgp6n4lEQtRdzbzH1H3Y+4J3Bns/eakE9J1FP0vc3fa04+JVFPMfg2ha9Z+ZREPcXh2yS+JuZTEvUUjW/z+JqaT0nUU0S+zeRrdj4lUU9x+RaZDx2b75GwJ+h8sPh86Ah9j8Q9QemDxelDR+p7tGJESUYW8jpe3yORSzD7YFH70HH7Hgk9gtwHi90HzdiDR2KPIPjBYvhBs/bgkeAjSH6wWH7QxD14JPoInh8soh80dw8eCT+C6geL6wdN34NH4o9g+8Gi+0Ez+EArlQThDxbjD34nVpL4I0h/sFh/0EQ+0IolwfuDRfyD5vIByBUhENw/WOQ/aEIfIKBWOkAIAGApAKBZfQBymwWECgCWDACa2af1GiCEALCUANDsPtAyJiEGgKUGgGb4gVYjCUEALEUANMtP8z1AiAJgqQIQdBAkhwChC4AlDEDQQZAcAoQ2AJY4AEGnmZNDgNAHwBIIQJP+QMqEQGgEYIkEoHl/EOQQIGQCsHQC0NQ/CHoIEFIBWFoBaP4fBBmDCbkALL0AtAYANPEGhGYAlmgAWgcAJRxSBggIWsIBaDEABI1BQjwASz0ALQio6xGpQUgICGApCKBVASBVRCBEBLBUBAjFRCcSSgJYUgKE/kQTEHICWHoCdILCWBMQOLQ0BdAyAZBiKBCqAliyAoTRVBMQOLSkBdBqAfjkQCTEBbDUBQiTCRwTCgNYEgOE6QSOCZUBLJkBIm+iEwmpASytASKY6ERCbwBLcAAtIgApLAOhOYAlOkCnOpAyCxC6A1jCA0TBxHxOaA9giQ8QTU3HhP4AlgAB0cR0TGgQYIkQEHUoJFfEhAwBlg4BUTLVAgQKLS0CtLwwtqIh5Aiw9AiIvYkmJDQJsEQJ0ELDSBMSugRYwgTEHQjJCYnQJsASJ0ALDrRCCYQ+AZZAAVp0oEVKIDQKsEQKiLtISG5KCJkCLJ0C4mhiFBNaBVhiBWgBYmRJRugVYAkWoEUIIE9bAKFZgCVagBYigDxxAYRuAZZwAVqLAPLUBRDSBVjaBWg9AnxyNibkC7D0C0i6o27kVEZIGGBpGJB0fAw5ExEyBlg6BiSduE9GYULKAEvLAK1PQEDGIELOAEvPgKQ7VUkOQELSAEvTAC1TAE0fAyFrgKVrQNKdriQBSCgbYEkboOUKII9lAKFugCVvQNodsiQBSCgcYEkckHZ8IAlAQuUAS+YArVxASAKQEDrAUjpAqxdAHpUAQuwAS+0ArWCoryqp/AQALcUDtIpBS49AiB5gqR6glQwgT1wAIXyApXyAVjOAPHUBhPgBlvoBWtAA8uQFEPoHWAIIaFEDyNMXQGggYIkgQqsaEFL4FYQKIiwVRGhZA8hDBYKQQYQlgwivwx95XpfQQYSlgwgtbAB5uEAQQoiwhBChlQ0gDxgIQgkRlhIitLQB5CEDQUghwpJChNY2gDwrIAgtRFhaiPC6k+UU/gQhhghLDBFa3QDyzIAg1BBhqSHCS8cDsCD0EGHpIaL7gIE8eCAIQURYgojQAgct1ApCEBGWICK6DxnI8weCUESEpYiIThEhzyAIQhERliIiug8ayHMIgpBEhCWJiO6bBvIsgiA0EWFpIqL7roE8jyAIUWT4m/4G6lHWrdy87b6Fur/vnhT9ufqr/zoqguG7q5+r2F89//nPP+evoZ7//Ad9EKV+U35Ol6udraiN+smMopR0TkVL9P+JuJbPn3Zh+753Nu+HPFvm86SoxgLVOODZQndY4koHuNLMKuKr4ZAtH/WD4iJYtk5PuaGWQnb8qMsYM1vsdGscrmOI6xgP/ZmwLD5I9SksKhxqep9Xx7X+5r9DRH26oAg3HO6EWLCNHmvZvxGGyodQ7POqaFyli4oFKW43YNpSN8G74BAI/YLXl/oRlbw9yrI1TSF4CB5ijfdYUA0N8Pe46AEHSfev8Pp/+zgg+nThkB5g+A8v9Ci0y2KftbW6hAN1HCqMnzJNqRuCrDgjEEBFD/aQ2+L6xqG1vosI4zPC+GSC6nQH1tlQgAAVDu3MjNjn14tRGERYj3lIUBeTZEW+K9VfZfcaEq4pqiivXMrg1uxJtU07m0l4fans1OpSgWq4tQkXCxuM+QYNKyEaguEQBZmzhzLWVk1rDZ8EFSv1eJb6F4rOZlI8CoFZHvc5aQQLZDDmhehTANyerp/B9cSBMOUFQsfiobsOE8dXgdHGC/vqNem/9PN2yBAys8CIeqkEhQ0UNdhGTi9qo8ZHky0zVBgvZCNLKOowMa+v2MHTrdFMeAAoguEiiw/d7T7YLG7/lBc1zhfM4nUKDrNBMqxTmFXXN/OYL3zjQmKspbxBRj8bjmYs1NVBP00m/b+KAOH5qJs23xjxE6/X/N5exBvH+MXAs8EEj1+Pb6m7QQ3HYRzwEl7Ac94RRJEPA9LjDRbzHXU0WtAUkfDCwOn9HFRDD9dQ8IuE3sLB1nDDCyaQ3TdtcMzETebze4AoHOBx6/ObbHiXEfUjtuTxqjnccLXub7g6zf/msMULkpS3xNn1b94jbKBOTXhxbyfbQ38XFhr+D/ourLa7PwsXE0/hKW+A9e/UO8uUCGEm4UVT68n7s60YoSXhBT11lyke8XjvyNyE5qVe46/brN7pX9bV/qFyF5vYNNfytnJ3fGjaYO7S8jJX76jrBvsha6JsxoqfaVNtsdSfzCbE0yNzz42eVMHTIx76AQ/GOUav2fi49VNmuVq513skY7ZCTcWMIn/LspFlVhw+m9QCCuHM+uF3N1E8wnVjQuv0kCYyg0EAvOCDn8VElvD+hYmnL8e6rZrcHM8ISwmvXv0t8AiPaCXUra3Upp8XaLrHm/AcgivGpFuUEXdxaow4JrGk7uBD+K62/ZvQGObYbMqbmhyz3RuP2CqqtpJquFbthR4y4/f8SsRsRFnuzKoKNMn5fm+MWeHuatmH/Mcm+77V16zi3R9eOjNnkd7iYbh57Cu61RabxtM7F9DqjtqHymjIGBUx4Q3UwUzd34OLS4Vnc665ap0Va5PuwYuXiAmS4fELHPfxGAuGERv6w9DlWd5nX+Th/NYAiroINwEvDOyz+os0SUm8Aop4s8A++0ZR8j5a/wQ9yZjw4gGy+FC1rbuBCdAUOigcCW/AdVd24hiQ4BjArLLzZDGaI/DOA/iFQq8PI2N44wG8KLCX9Y7QbQI05zAFkr267FsvrvQ1ze7qCiOaWTjrSnO8RMV1ZW79bO4Br4Yi3tKj7IMaUT2MDGZ5jFec8Q4SL/oEb6h3t76OUyEpBi6vskpTcohLrI8IXuRQdmh5EHOpIdNYvSnUk37d03/NNjdwgaetgBc/LIPE1IC7FgJedxwsuTZG0wKTHD9ktdqvUGJhjAIvk4I+rNv1Z2erHWGFyuP1QHfFf15m9gpJIGj4vCXD6bkAxxiOtDGzisTbA3iGx6OKyQioK1qJdSsW39WplWWmultPsTnMQ3u8FdHZHKWdYD0MAmYBqyZv80epLqc1UBKjOMkUAvpLk1UhN5mpJQMWsNSRG6a9x7FNLVY+BJPoPNT52qgjFpBZFs7XMOOihLgovOm8u2J5d76EGUMW72mTXr4STLKNeiQeTzJ4wSt4EDEefMe2cDmZSncti7o1y4RKxC2PWt264ynCczEveHSmyLGElxohD//DXdQK/EXVuMuFFA9QdhE7o+5mDe93mUvbwVhbdWFTlka0xJu0QZVJh9MAwG6EY9FaSxtcVOZBBovYBVOwPm2JTmcZuA2ghgQhUOCdYMAdaspWc37sHfc0Li3wpp1ato9V4ZCeMWo8puZWV0Vhn+ZBg5U5VKuisJcgqCjMXlRGLBEXbQl4cVsZIflgTPazLdnxBw10Zr9XRWHr0oa8xbdiRVQsrjBH2+kxbBy7sB3mRt9uFUOx5+G3kVY5PFwO5vaokW0pvzpUZoxAw9R0h+cGcfvi2c8/hQ5et+PnAvC0gwlCbkudTLmzmLGj5PXd2Rx5ogZjk3k86mzRPcuBjwUCcwc9vE+wIXkpwCf5gKl/DyYP6F0E3I54x8o8atN8kV8N0KG+YIr8TVW3eelGqhhHGV7obA5ZWW3tPT3e0sfMIdWawxJLhYKpmfQvaOKxhFd//nCGOBr+w9y9nRmCdfd6BC4n3m8xRZmzPUuawzMXb1T1ry7ikIgpgXA4/nE6HhkNxyOZB/Ra9QdrmZOgvmGqy8Pzd3hpiAMvU1nuzBArI3VDCgrj7EL19CzB/+ClSN+KTFmyrbP1l7zcOStrvBhmrtbbOtvk5c4hzTxj5uPFN2SrIyJMizi8Memztj6Wa4eHw8ctQ2bRmo3BSeGz/6Jf40e8+Kh5XhuwCGpM0c09vIBFtlME8Qf9g3mwsWOh7QMhCe5Npn534rOxITQwh4NavGFOnOZNMCCYgoK1VkzwUoZJ7aqTh3W1t9auCQ7kTDbw9KoxwhUmZIauG75pgOh0BppX269VbXL/Cd5CMsk3bcQRihMczpi8m+YW68w8tIkQwfyS4UezrkyWLcFTCocW+/NmdcgPsshLuXp+/+c///w/6jcV/w=="; \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css deleted file mode 100644 index 44328e9..0000000 --- a/docs/assets/style.css +++ /dev/null @@ -1,1633 +0,0 @@ -@layer typedoc { - :root { - --dim-toolbar-contents-height: 2.5rem; - --dim-toolbar-border-bottom-width: 1px; - --dim-header-height: calc( - var(--dim-toolbar-border-bottom-width) + - var(--dim-toolbar-contents-height) - ); - - /* 0rem For mobile; unit is required for calculation in `calc` */ - --dim-container-main-margin-y: 0rem; - - --dim-footer-height: 3.5rem; - - --modal-animation-duration: 0.2s; - } - - :root { - /* Light */ - --light-color-background: #f2f4f8; - --light-color-background-secondary: #eff0f1; - /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ - --light-color-background-active: #d6d8da; - --light-color-background-warning: #e6e600; - --light-color-warning-text: #222; - --light-color-accent: #c5c7c9; - --light-color-active-menu-item: var(--light-color-background-active); - --light-color-text: #222; - --light-color-contrast-text: #000; - --light-color-text-aside: #5e5e5e; - - --light-color-icon-background: var(--light-color-background); - --light-color-icon-text: var(--light-color-text); - - --light-color-comment-tag-text: var(--light-color-text); - --light-color-comment-tag: var(--light-color-background); - - --light-color-link: #1f70c2; - --light-color-focus-outline: #3584e4; - - --light-color-ts-keyword: #056bd6; - --light-color-ts-project: #b111c9; - --light-color-ts-module: var(--light-color-ts-project); - --light-color-ts-namespace: var(--light-color-ts-project); - --light-color-ts-enum: #7e6f15; - --light-color-ts-enum-member: var(--light-color-ts-enum); - --light-color-ts-variable: #4760ec; - --light-color-ts-function: #572be7; - --light-color-ts-class: #1f70c2; - --light-color-ts-interface: #108024; - --light-color-ts-constructor: var(--light-color-ts-class); - --light-color-ts-property: #9f5f30; - --light-color-ts-method: #be3989; - --light-color-ts-reference: #ff4d82; - --light-color-ts-call-signature: var(--light-color-ts-method); - --light-color-ts-index-signature: var(--light-color-ts-property); - --light-color-ts-constructor-signature: var( - --light-color-ts-constructor - ); - --light-color-ts-parameter: var(--light-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --light-color-ts-type-parameter: #a55c0e; - --light-color-ts-accessor: #c73c3c; - --light-color-ts-get-signature: var(--light-color-ts-accessor); - --light-color-ts-set-signature: var(--light-color-ts-accessor); - --light-color-ts-type-alias: #d51270; - /* reference not included as links will be colored with the kind that it points to */ - --light-color-document: #000000; - - --light-color-alert-note: #0969d9; - --light-color-alert-tip: #1a7f37; - --light-color-alert-important: #8250df; - --light-color-alert-warning: #9a6700; - --light-color-alert-caution: #cf222e; - - --light-external-icon: url("data:image/svg+xml;utf8,"); - --light-color-scheme: light; - } - - :root { - /* Dark */ - --dark-color-background: #2b2e33; - --dark-color-background-secondary: #1e2024; - /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ - --dark-color-background-active: #5d5d6a; - --dark-color-background-warning: #bebe00; - --dark-color-warning-text: #222; - --dark-color-accent: #9096a2; - --dark-color-active-menu-item: var(--dark-color-background-active); - --dark-color-text: #f5f5f5; - --dark-color-contrast-text: #ffffff; - --dark-color-text-aside: #dddddd; - - --dark-color-icon-background: var(--dark-color-background-secondary); - --dark-color-icon-text: var(--dark-color-text); - - --dark-color-comment-tag-text: var(--dark-color-text); - --dark-color-comment-tag: var(--dark-color-background); - - --dark-color-link: #00aff4; - --dark-color-focus-outline: #4c97f2; - - --dark-color-ts-keyword: #3399ff; - --dark-color-ts-project: #e358ff; - --dark-color-ts-module: var(--dark-color-ts-project); - --dark-color-ts-namespace: var(--dark-color-ts-project); - --dark-color-ts-enum: #f4d93e; - --dark-color-ts-enum-member: var(--dark-color-ts-enum); - --dark-color-ts-variable: #798dff; - --dark-color-ts-function: #a280ff; - --dark-color-ts-class: #8ac4ff; - --dark-color-ts-interface: #6cff87; - --dark-color-ts-constructor: var(--dark-color-ts-class); - --dark-color-ts-property: #ff984d; - --dark-color-ts-method: #ff4db8; - --dark-color-ts-reference: #ff4d82; - --dark-color-ts-call-signature: var(--dark-color-ts-method); - --dark-color-ts-index-signature: var(--dark-color-ts-property); - --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); - --dark-color-ts-parameter: var(--dark-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --dark-color-ts-type-parameter: #e07d13; - --dark-color-ts-accessor: #ff6060; - --dark-color-ts-get-signature: var(--dark-color-ts-accessor); - --dark-color-ts-set-signature: var(--dark-color-ts-accessor); - --dark-color-ts-type-alias: #ff6492; - /* reference not included as links will be colored with the kind that it points to */ - --dark-color-document: #ffffff; - - --dark-color-alert-note: #0969d9; - --dark-color-alert-tip: #1a7f37; - --dark-color-alert-important: #8250df; - --dark-color-alert-warning: #9a6700; - --dark-color-alert-caution: #cf222e; - - --dark-external-icon: url("data:image/svg+xml;utf8,"); - --dark-color-scheme: dark; - } - - @media (prefers-color-scheme: light) { - :root { - --color-background: var(--light-color-background); - --color-background-secondary: var( - --light-color-background-secondary - ); - --color-background-active: var(--light-color-background-active); - --color-background-warning: var(--light-color-background-warning); - --color-warning-text: var(--light-color-warning-text); - --color-accent: var(--light-color-accent); - --color-active-menu-item: var(--light-color-active-menu-item); - --color-text: var(--light-color-text); - --color-contrast-text: var(--light-color-contrast-text); - --color-text-aside: var(--light-color-text-aside); - - --color-icon-background: var(--light-color-icon-background); - --color-icon-text: var(--light-color-icon-text); - - --color-comment-tag-text: var(--light-color-text); - --color-comment-tag: var(--light-color-background); - - --color-link: var(--light-color-link); - --color-focus-outline: var(--light-color-focus-outline); - - --color-ts-keyword: var(--light-color-ts-keyword); - --color-ts-project: var(--light-color-ts-project); - --color-ts-module: var(--light-color-ts-module); - --color-ts-namespace: var(--light-color-ts-namespace); - --color-ts-enum: var(--light-color-ts-enum); - --color-ts-enum-member: var(--light-color-ts-enum-member); - --color-ts-variable: var(--light-color-ts-variable); - --color-ts-function: var(--light-color-ts-function); - --color-ts-class: var(--light-color-ts-class); - --color-ts-interface: var(--light-color-ts-interface); - --color-ts-constructor: var(--light-color-ts-constructor); - --color-ts-property: var(--light-color-ts-property); - --color-ts-method: var(--light-color-ts-method); - --color-ts-reference: var(--light-color-ts-reference); - --color-ts-call-signature: var(--light-color-ts-call-signature); - --color-ts-index-signature: var(--light-color-ts-index-signature); - --color-ts-constructor-signature: var( - --light-color-ts-constructor-signature - ); - --color-ts-parameter: var(--light-color-ts-parameter); - --color-ts-type-parameter: var(--light-color-ts-type-parameter); - --color-ts-accessor: var(--light-color-ts-accessor); - --color-ts-get-signature: var(--light-color-ts-get-signature); - --color-ts-set-signature: var(--light-color-ts-set-signature); - --color-ts-type-alias: var(--light-color-ts-type-alias); - --color-document: var(--light-color-document); - - --color-alert-note: var(--light-color-alert-note); - --color-alert-tip: var(--light-color-alert-tip); - --color-alert-important: var(--light-color-alert-important); - --color-alert-warning: var(--light-color-alert-warning); - --color-alert-caution: var(--light-color-alert-caution); - - --external-icon: var(--light-external-icon); - --color-scheme: var(--light-color-scheme); - } - } - - @media (prefers-color-scheme: dark) { - :root { - --color-background: var(--dark-color-background); - --color-background-secondary: var( - --dark-color-background-secondary - ); - --color-background-active: var(--dark-color-background-active); - --color-background-warning: var(--dark-color-background-warning); - --color-warning-text: var(--dark-color-warning-text); - --color-accent: var(--dark-color-accent); - --color-active-menu-item: var(--dark-color-active-menu-item); - --color-text: var(--dark-color-text); - --color-contrast-text: var(--dark-color-contrast-text); - --color-text-aside: var(--dark-color-text-aside); - - --color-icon-background: var(--dark-color-icon-background); - --color-icon-text: var(--dark-color-icon-text); - - --color-comment-tag-text: var(--dark-color-text); - --color-comment-tag: var(--dark-color-background); - - --color-link: var(--dark-color-link); - --color-focus-outline: var(--dark-color-focus-outline); - - --color-ts-keyword: var(--dark-color-ts-keyword); - --color-ts-project: var(--dark-color-ts-project); - --color-ts-module: var(--dark-color-ts-module); - --color-ts-namespace: var(--dark-color-ts-namespace); - --color-ts-enum: var(--dark-color-ts-enum); - --color-ts-enum-member: var(--dark-color-ts-enum-member); - --color-ts-variable: var(--dark-color-ts-variable); - --color-ts-function: var(--dark-color-ts-function); - --color-ts-class: var(--dark-color-ts-class); - --color-ts-interface: var(--dark-color-ts-interface); - --color-ts-constructor: var(--dark-color-ts-constructor); - --color-ts-property: var(--dark-color-ts-property); - --color-ts-method: var(--dark-color-ts-method); - --color-ts-reference: var(--dark-color-ts-reference); - --color-ts-call-signature: var(--dark-color-ts-call-signature); - --color-ts-index-signature: var(--dark-color-ts-index-signature); - --color-ts-constructor-signature: var( - --dark-color-ts-constructor-signature - ); - --color-ts-parameter: var(--dark-color-ts-parameter); - --color-ts-type-parameter: var(--dark-color-ts-type-parameter); - --color-ts-accessor: var(--dark-color-ts-accessor); - --color-ts-get-signature: var(--dark-color-ts-get-signature); - --color-ts-set-signature: var(--dark-color-ts-set-signature); - --color-ts-type-alias: var(--dark-color-ts-type-alias); - --color-document: var(--dark-color-document); - - --color-alert-note: var(--dark-color-alert-note); - --color-alert-tip: var(--dark-color-alert-tip); - --color-alert-important: var(--dark-color-alert-important); - --color-alert-warning: var(--dark-color-alert-warning); - --color-alert-caution: var(--dark-color-alert-caution); - - --external-icon: var(--dark-external-icon); - --color-scheme: var(--dark-color-scheme); - } - } - - :root[data-theme="light"] { - --color-background: var(--light-color-background); - --color-background-secondary: var(--light-color-background-secondary); - --color-background-active: var(--light-color-background-active); - --color-background-warning: var(--light-color-background-warning); - --color-warning-text: var(--light-color-warning-text); - --color-icon-background: var(--light-color-icon-background); - --color-accent: var(--light-color-accent); - --color-active-menu-item: var(--light-color-active-menu-item); - --color-text: var(--light-color-text); - --color-contrast-text: var(--light-color-contrast-text); - --color-text-aside: var(--light-color-text-aside); - --color-icon-text: var(--light-color-icon-text); - - --color-comment-tag-text: var(--light-color-text); - --color-comment-tag: var(--light-color-background); - - --color-link: var(--light-color-link); - --color-focus-outline: var(--light-color-focus-outline); - - --color-ts-keyword: var(--light-color-ts-keyword); - --color-ts-project: var(--light-color-ts-project); - --color-ts-module: var(--light-color-ts-module); - --color-ts-namespace: var(--light-color-ts-namespace); - --color-ts-enum: var(--light-color-ts-enum); - --color-ts-enum-member: var(--light-color-ts-enum-member); - --color-ts-variable: var(--light-color-ts-variable); - --color-ts-function: var(--light-color-ts-function); - --color-ts-class: var(--light-color-ts-class); - --color-ts-interface: var(--light-color-ts-interface); - --color-ts-constructor: var(--light-color-ts-constructor); - --color-ts-property: var(--light-color-ts-property); - --color-ts-method: var(--light-color-ts-method); - --color-ts-reference: var(--light-color-ts-reference); - --color-ts-call-signature: var(--light-color-ts-call-signature); - --color-ts-index-signature: var(--light-color-ts-index-signature); - --color-ts-constructor-signature: var( - --light-color-ts-constructor-signature - ); - --color-ts-parameter: var(--light-color-ts-parameter); - --color-ts-type-parameter: var(--light-color-ts-type-parameter); - --color-ts-accessor: var(--light-color-ts-accessor); - --color-ts-get-signature: var(--light-color-ts-get-signature); - --color-ts-set-signature: var(--light-color-ts-set-signature); - --color-ts-type-alias: var(--light-color-ts-type-alias); - --color-document: var(--light-color-document); - - --color-note: var(--light-color-note); - --color-tip: var(--light-color-tip); - --color-important: var(--light-color-important); - --color-warning: var(--light-color-warning); - --color-caution: var(--light-color-caution); - - --external-icon: var(--light-external-icon); - --color-scheme: var(--light-color-scheme); - } - - :root[data-theme="dark"] { - --color-background: var(--dark-color-background); - --color-background-secondary: var(--dark-color-background-secondary); - --color-background-active: var(--dark-color-background-active); - --color-background-warning: var(--dark-color-background-warning); - --color-warning-text: var(--dark-color-warning-text); - --color-icon-background: var(--dark-color-icon-background); - --color-accent: var(--dark-color-accent); - --color-active-menu-item: var(--dark-color-active-menu-item); - --color-text: var(--dark-color-text); - --color-contrast-text: var(--dark-color-contrast-text); - --color-text-aside: var(--dark-color-text-aside); - --color-icon-text: var(--dark-color-icon-text); - - --color-comment-tag-text: var(--dark-color-text); - --color-comment-tag: var(--dark-color-background); - - --color-link: var(--dark-color-link); - --color-focus-outline: var(--dark-color-focus-outline); - - --color-ts-keyword: var(--dark-color-ts-keyword); - --color-ts-project: var(--dark-color-ts-project); - --color-ts-module: var(--dark-color-ts-module); - --color-ts-namespace: var(--dark-color-ts-namespace); - --color-ts-enum: var(--dark-color-ts-enum); - --color-ts-enum-member: var(--dark-color-ts-enum-member); - --color-ts-variable: var(--dark-color-ts-variable); - --color-ts-function: var(--dark-color-ts-function); - --color-ts-class: var(--dark-color-ts-class); - --color-ts-interface: var(--dark-color-ts-interface); - --color-ts-constructor: var(--dark-color-ts-constructor); - --color-ts-property: var(--dark-color-ts-property); - --color-ts-method: var(--dark-color-ts-method); - --color-ts-reference: var(--dark-color-ts-reference); - --color-ts-call-signature: var(--dark-color-ts-call-signature); - --color-ts-index-signature: var(--dark-color-ts-index-signature); - --color-ts-constructor-signature: var( - --dark-color-ts-constructor-signature - ); - --color-ts-parameter: var(--dark-color-ts-parameter); - --color-ts-type-parameter: var(--dark-color-ts-type-parameter); - --color-ts-accessor: var(--dark-color-ts-accessor); - --color-ts-get-signature: var(--dark-color-ts-get-signature); - --color-ts-set-signature: var(--dark-color-ts-set-signature); - --color-ts-type-alias: var(--dark-color-ts-type-alias); - --color-document: var(--dark-color-document); - - --color-note: var(--dark-color-note); - --color-tip: var(--dark-color-tip); - --color-important: var(--dark-color-important); - --color-warning: var(--dark-color-warning); - --color-caution: var(--dark-color-caution); - - --external-icon: var(--dark-external-icon); - --color-scheme: var(--dark-color-scheme); - } - - html { - color-scheme: var(--color-scheme); - @media (prefers-reduced-motion: no-preference) { - scroll-behavior: smooth; - } - } - - *:focus-visible, - .tsd-accordion-summary:focus-visible svg { - outline: 2px solid var(--color-focus-outline); - } - - .always-visible, - .always-visible .tsd-signatures { - display: inherit !important; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - line-height: 1.2; - } - - h1 { - font-size: 1.875rem; - margin: 0.67rem 0; - } - - h2 { - font-size: 1.5rem; - margin: 0.83rem 0; - } - - h3 { - font-size: 1.25rem; - margin: 1rem 0; - } - - h4 { - font-size: 1.05rem; - margin: 1.33rem 0; - } - - h5 { - font-size: 1rem; - margin: 1.5rem 0; - } - - h6 { - font-size: 0.875rem; - margin: 2.33rem 0; - } - - dl, - menu, - ol, - ul { - margin: 1em 0; - } - - dd { - margin: 0 0 0 34px; - } - - .container { - max-width: 1700px; - padding: 0 2rem; - } - - /* Footer */ - footer { - border-top: 1px solid var(--color-accent); - padding-top: 1rem; - padding-bottom: 1rem; - max-height: var(--dim-footer-height); - } - footer > p { - margin: 0 1em; - } - - .container-main { - margin: var(--dim-container-main-margin-y) auto; - /* toolbar, footer, margin */ - min-height: calc( - 100svh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - } - - @keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - @keyframes fade-out { - from { - opacity: 1; - visibility: visible; - } - to { - opacity: 0; - } - } - @keyframes pop-in-from-right { - from { - transform: translate(100%, 0); - } - to { - transform: translate(0, 0); - } - } - @keyframes pop-out-to-right { - from { - transform: translate(0, 0); - visibility: visible; - } - to { - transform: translate(100%, 0); - } - } - body { - background: var(--color-background); - font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", - Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; - font-size: 16px; - color: var(--color-text); - margin: 0; - } - - a { - color: var(--color-link); - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - a.external[target="_blank"] { - background-image: var(--external-icon); - background-position: top 3px right; - background-repeat: no-repeat; - padding-right: 13px; - } - a.tsd-anchor-link { - color: var(--color-text); - } - :target { - scroll-margin-block: calc(var(--dim-header-height) + 0.5rem); - } - - code, - pre { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - padding: 0.2em; - margin: 0; - font-size: 0.875rem; - border-radius: 0.8em; - } - - pre { - position: relative; - white-space: pre-wrap; - word-wrap: break-word; - padding: 10px; - border: 1px solid var(--color-accent); - margin-bottom: 8px; - } - pre code { - padding: 0; - font-size: 100%; - } - pre > button { - position: absolute; - top: 10px; - right: 10px; - opacity: 0; - transition: opacity 0.1s; - box-sizing: border-box; - } - pre:hover > button, - pre > button.visible, - pre > button:focus-visible { - opacity: 1; - } - - blockquote { - margin: 1em 0; - padding-left: 1em; - border-left: 4px solid gray; - } - - img { - max-width: 100%; - } - - * { - scrollbar-width: thin; - scrollbar-color: var(--color-accent) var(--color-icon-background); - } - - *::-webkit-scrollbar { - width: 0.75rem; - } - - *::-webkit-scrollbar-track { - background: var(--color-icon-background); - } - - *::-webkit-scrollbar-thumb { - background-color: var(--color-accent); - border-radius: 999rem; - border: 0.25rem solid var(--color-icon-background); - } - - dialog { - border: none; - outline: none; - padding: 0; - background-color: var(--color-background); - } - dialog::backdrop { - display: none; - } - #tsd-overlay { - background-color: rgba(0, 0, 0, 0.5); - position: fixed; - z-index: 9999; - top: 0; - left: 0; - right: 0; - bottom: 0; - animation: fade-in var(--modal-animation-duration) forwards; - } - #tsd-overlay.closing { - animation-name: fade-out; - } - - .tsd-typography { - line-height: 1.333em; - } - .tsd-typography ul { - list-style: square; - padding: 0 0 0 20px; - margin: 0; - } - .tsd-typography .tsd-index-panel h3, - .tsd-index-panel .tsd-typography h3, - .tsd-typography h4, - .tsd-typography h5, - .tsd-typography h6 { - font-size: 1em; - } - .tsd-typography h5, - .tsd-typography h6 { - font-weight: normal; - } - .tsd-typography p, - .tsd-typography ul, - .tsd-typography ol { - margin: 1em 0; - } - .tsd-typography table { - border-collapse: collapse; - border: none; - } - .tsd-typography td, - .tsd-typography th { - padding: 6px 13px; - border: 1px solid var(--color-accent); - } - .tsd-typography thead, - .tsd-typography tr:nth-child(even) { - background-color: var(--color-background-secondary); - } - - .tsd-alert { - padding: 8px 16px; - margin-bottom: 16px; - border-left: 0.25em solid var(--alert-color); - } - .tsd-alert blockquote > :last-child, - .tsd-alert > :last-child { - margin-bottom: 0; - } - .tsd-alert-title { - color: var(--alert-color); - display: inline-flex; - align-items: center; - } - .tsd-alert-title span { - margin-left: 4px; - } - - .tsd-alert-note { - --alert-color: var(--color-alert-note); - } - .tsd-alert-tip { - --alert-color: var(--color-alert-tip); - } - .tsd-alert-important { - --alert-color: var(--color-alert-important); - } - .tsd-alert-warning { - --alert-color: var(--color-alert-warning); - } - .tsd-alert-caution { - --alert-color: var(--color-alert-caution); - } - - .tsd-breadcrumb { - margin: 0; - margin-top: 1rem; - padding: 0; - color: var(--color-text-aside); - } - .tsd-breadcrumb a { - color: var(--color-text-aside); - text-decoration: none; - } - .tsd-breadcrumb a:hover { - text-decoration: underline; - } - .tsd-breadcrumb li { - display: inline; - } - .tsd-breadcrumb li:after { - content: " / "; - } - - .tsd-comment-tags { - display: flex; - flex-direction: column; - } - dl.tsd-comment-tag-group { - display: flex; - align-items: center; - overflow: hidden; - margin: 0.5em 0; - } - dl.tsd-comment-tag-group dt { - display: flex; - margin-right: 0.5em; - font-size: 0.875em; - font-weight: normal; - } - dl.tsd-comment-tag-group dd { - margin: 0; - } - code.tsd-tag { - padding: 0.25em 0.4em; - border: 0.1em solid var(--color-accent); - margin-right: 0.25em; - font-size: 70%; - } - h1 code.tsd-tag:first-of-type { - margin-left: 0.25em; - } - - dl.tsd-comment-tag-group dd:before, - dl.tsd-comment-tag-group dd:after { - content: " "; - } - dl.tsd-comment-tag-group dd pre, - dl.tsd-comment-tag-group dd:after { - clear: both; - } - dl.tsd-comment-tag-group p { - margin: 0; - } - - .tsd-panel.tsd-comment .lead { - font-size: 1.1em; - line-height: 1.333em; - margin-bottom: 2em; - } - .tsd-panel.tsd-comment .lead:last-child { - margin-bottom: 0; - } - - .tsd-filter-visibility h4 { - font-size: 1rem; - padding-top: 0.75rem; - padding-bottom: 0.5rem; - margin: 0; - } - .tsd-filter-item:not(:last-child) { - margin-bottom: 0.5rem; - } - .tsd-filter-input { - display: flex; - width: -moz-fit-content; - width: fit-content; - align-items: center; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: pointer; - } - .tsd-filter-input input[type="checkbox"] { - cursor: pointer; - position: absolute; - width: 1.5em; - height: 1.5em; - opacity: 0; - } - .tsd-filter-input input[type="checkbox"]:disabled { - pointer-events: none; - } - .tsd-filter-input svg { - cursor: pointer; - width: 1.5em; - height: 1.5em; - margin-right: 0.5em; - border-radius: 0.33em; - /* Leaving this at full opacity breaks event listeners on Firefox. - Don't remove unless you know what you're doing. */ - opacity: 0.99; - } - .tsd-filter-input input[type="checkbox"]:focus-visible + svg { - outline: 2px solid var(--color-focus-outline); - } - .tsd-checkbox-background { - fill: var(--color-accent); - } - input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { - stroke: var(--color-text); - } - .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { - fill: var(--color-background); - stroke: var(--color-accent); - stroke-width: 0.25rem; - } - .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { - stroke: var(--color-accent); - } - - .settings-label { - font-weight: bold; - text-transform: uppercase; - display: inline-block; - } - - .tsd-filter-visibility .settings-label { - margin: 0.75rem 0 0.5rem 0; - } - - .tsd-theme-toggle .settings-label { - margin: 0.75rem 0.75rem 0 0; - } - - .tsd-hierarchy h4 label:hover span { - text-decoration: underline; - } - - .tsd-hierarchy { - list-style: square; - margin: 0; - } - .tsd-hierarchy-target { - font-weight: bold; - } - .tsd-hierarchy-toggle { - color: var(--color-link); - cursor: pointer; - } - - .tsd-full-hierarchy:not(:last-child) { - margin-bottom: 1em; - padding-bottom: 1em; - border-bottom: 1px solid var(--color-accent); - } - .tsd-full-hierarchy, - .tsd-full-hierarchy ul { - list-style: none; - margin: 0; - padding: 0; - } - .tsd-full-hierarchy ul { - padding-left: 1.5rem; - } - .tsd-full-hierarchy a { - padding: 0.25rem 0 !important; - font-size: 1rem; - display: inline-flex; - align-items: center; - color: var(--color-text); - } - .tsd-full-hierarchy svg[data-dropdown] { - cursor: pointer; - } - .tsd-full-hierarchy svg[data-dropdown="false"] { - transform: rotate(-90deg); - } - .tsd-full-hierarchy svg[data-dropdown="false"] ~ ul { - display: none; - } - - .tsd-panel-group.tsd-index-group { - margin-bottom: 0; - } - .tsd-index-panel .tsd-index-list { - list-style: none; - line-height: 1.333em; - margin: 0; - padding: 0.25rem 0 0 0; - overflow: hidden; - display: grid; - grid-template-columns: repeat(3, 1fr); - column-gap: 1rem; - grid-template-rows: auto; - } - @media (max-width: 1024px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(2, 1fr); - } - } - @media (max-width: 768px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(1, 1fr); - } - } - .tsd-index-panel .tsd-index-list li { - -webkit-page-break-inside: avoid; - -moz-page-break-inside: avoid; - -ms-page-break-inside: avoid; - -o-page-break-inside: avoid; - page-break-inside: avoid; - } - - .tsd-flag { - display: inline-block; - padding: 0.25em 0.4em; - border-radius: 4px; - color: var(--color-comment-tag-text); - background-color: var(--color-comment-tag); - text-indent: 0; - font-size: 75%; - line-height: 1; - font-weight: normal; - } - - .tsd-anchor { - position: relative; - top: -100px; - } - - .tsd-member { - position: relative; - } - .tsd-member .tsd-anchor + h3 { - display: flex; - align-items: center; - margin-top: 0; - margin-bottom: 0; - border-bottom: none; - } - - .tsd-navigation.settings { - margin: 0; - margin-bottom: 1rem; - } - .tsd-navigation > a, - .tsd-navigation .tsd-accordion-summary { - width: calc(100% - 0.25rem); - display: flex; - align-items: center; - } - .tsd-navigation a, - .tsd-navigation summary > span, - .tsd-page-navigation a { - display: flex; - width: calc(100% - 0.25rem); - align-items: center; - padding: 0.25rem; - color: var(--color-text); - text-decoration: none; - box-sizing: border-box; - } - .tsd-navigation a.current, - .tsd-page-navigation a.current { - background: var(--color-active-menu-item); - color: var(--color-contrast-text); - } - .tsd-navigation a:hover, - .tsd-page-navigation a:hover { - text-decoration: underline; - } - .tsd-navigation ul, - .tsd-page-navigation ul { - margin-top: 0; - margin-bottom: 0; - padding: 0; - list-style: none; - } - .tsd-navigation li, - .tsd-page-navigation li { - padding: 0; - max-width: 100%; - } - .tsd-navigation .tsd-nav-link { - display: none; - } - .tsd-nested-navigation { - margin-left: 3rem; - } - .tsd-nested-navigation > li > details { - margin-left: -1.5rem; - } - .tsd-small-nested-navigation { - margin-left: 1.5rem; - } - .tsd-small-nested-navigation > li > details { - margin-left: -1.5rem; - } - - .tsd-page-navigation-section > summary { - padding: 0.25rem; - } - .tsd-page-navigation-section > summary > svg { - margin-right: 0.25rem; - } - .tsd-page-navigation-section > div { - margin-left: 30px; - } - .tsd-page-navigation ul { - padding-left: 1.75rem; - } - - #tsd-sidebar-links a { - margin-top: 0; - margin-bottom: 0.5rem; - line-height: 1.25rem; - } - #tsd-sidebar-links a:last-of-type { - margin-bottom: 0; - } - - a.tsd-index-link { - padding: 0.25rem 0 !important; - font-size: 1rem; - line-height: 1.25rem; - display: inline-flex; - align-items: center; - color: var(--color-text); - } - .tsd-accordion-summary { - list-style-type: none; /* hide marker on non-safari */ - outline: none; /* broken on safari, so just hide it */ - display: flex; - align-items: center; - gap: 0.25rem; - box-sizing: border-box; - } - .tsd-accordion-summary::-webkit-details-marker { - display: none; /* hide marker on safari */ - } - .tsd-accordion-summary, - .tsd-accordion-summary a { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - - cursor: pointer; - } - .tsd-accordion-summary a { - width: calc(100% - 1.5rem); - } - .tsd-accordion-summary > * { - margin-top: 0; - margin-bottom: 0; - padding-top: 0; - padding-bottom: 0; - } - /* - * We need to be careful to target the arrow indicating whether the accordion - * is open, but not any other SVGs included in the details element. - */ - .tsd-accordion:not([open]) > .tsd-accordion-summary > svg:first-child { - transform: rotate(-90deg); - } - .tsd-index-content > :not(:first-child) { - margin-top: 0.75rem; - } - .tsd-index-summary { - margin-top: 1.5rem; - margin-bottom: 0.75rem; - display: flex; - align-content: center; - } - - .tsd-no-select { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - .tsd-kind-icon { - margin-right: 0.5rem; - width: 1.25rem; - height: 1.25rem; - min-width: 1.25rem; - min-height: 1.25rem; - } - .tsd-signature > .tsd-kind-icon { - margin-right: 0.8rem; - } - - .tsd-panel { - margin-bottom: 2.5rem; - } - .tsd-panel.tsd-member { - margin-bottom: 4rem; - } - .tsd-panel:empty { - display: none; - } - .tsd-panel > h1, - .tsd-panel > h2, - .tsd-panel > h3 { - margin: 1.5rem -1.5rem 0.75rem -1.5rem; - padding: 0 1.5rem 0.75rem 1.5rem; - } - .tsd-panel > h1.tsd-before-signature, - .tsd-panel > h2.tsd-before-signature, - .tsd-panel > h3.tsd-before-signature { - margin-bottom: 0; - border-bottom: none; - } - - .tsd-panel-group { - margin: 2rem 0; - } - .tsd-panel-group.tsd-index-group { - margin: 2rem 0; - } - .tsd-panel-group.tsd-index-group details { - margin: 2rem 0; - } - .tsd-panel-group > .tsd-accordion-summary { - margin-bottom: 1rem; - } - - #tsd-search[open] { - animation: fade-in var(--modal-animation-duration) ease-out forwards; - } - #tsd-search[open].closing { - animation-name: fade-out; - } - - /* Avoid setting `display` on closed dialog */ - #tsd-search[open] { - display: flex; - flex-direction: column; - padding: 1rem; - width: 32rem; - max-width: 90vw; - max-height: calc(100vh - env(keyboard-inset-height, 0px) - 25vh); - /* Anchor dialog to top */ - margin-top: 10vh; - border-radius: 6px; - will-change: max-height; - } - #tsd-search-input { - box-sizing: border-box; - width: 100%; - padding: 0 0.625rem; /* 10px */ - outline: 0; - border: 2px solid var(--color-accent); - background-color: transparent; - color: var(--color-text); - border-radius: 4px; - height: 2.5rem; - flex: 0 0 auto; - font-size: 0.875rem; - transition: border-color 0.2s, background-color 0.2s; - } - #tsd-search-input:focus-visible { - background-color: var(--color-background-active); - border-color: transparent; - color: var(--color-contrast-text); - } - #tsd-search-input::placeholder { - color: inherit; - opacity: 0.8; - } - #tsd-search-results { - margin: 0; - padding: 0; - list-style: none; - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow-y: auto; - } - #tsd-search-results:not(:empty) { - margin-top: 0.5rem; - } - #tsd-search-results > li { - background-color: var(--color-background); - line-height: 1.5; - box-sizing: border-box; - border-radius: 4px; - } - #tsd-search-results > li:nth-child(even) { - background-color: var(--color-background-secondary); - } - #tsd-search-results > li:is(:hover, [aria-selected="true"]) { - background-color: var(--color-background-active); - color: var(--color-contrast-text); - } - /* It's important that this takes full size of parent `li`, to capture a click on `li` */ - #tsd-search-results > li > a { - display: flex; - align-items: center; - padding: 0.5rem 0.25rem; - box-sizing: border-box; - width: 100%; - } - #tsd-search-results > li > a > .text { - flex: 1 1 auto; - min-width: 0; - overflow-wrap: anywhere; - } - #tsd-search-results > li > a .parent { - color: var(--color-text-aside); - } - #tsd-search-results > li > a mark { - color: inherit; - background-color: inherit; - font-weight: bold; - } - #tsd-search-status { - flex: 1; - display: grid; - place-content: center; - text-align: center; - overflow-wrap: anywhere; - } - #tsd-search-status:not(:empty) { - min-height: 6rem; - } - - .tsd-signature { - margin: 0 0 1rem 0; - padding: 1rem 0.5rem; - border: 1px solid var(--color-accent); - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - font-size: 14px; - overflow-x: auto; - } - - .tsd-signature-keyword { - color: var(--color-ts-keyword); - font-weight: normal; - } - - .tsd-signature-symbol { - color: var(--color-text-aside); - font-weight: normal; - } - - .tsd-signature-type { - font-style: italic; - font-weight: normal; - } - - .tsd-signatures { - padding: 0; - margin: 0 0 1em 0; - list-style-type: none; - } - .tsd-signatures .tsd-signature { - margin: 0; - border-color: var(--color-accent); - border-width: 1px 0; - transition: background-color 0.1s; - } - .tsd-signatures .tsd-index-signature:not(:last-child) { - margin-bottom: 1em; - } - .tsd-signatures .tsd-index-signature .tsd-signature { - border-width: 1px; - } - .tsd-description .tsd-signatures .tsd-signature { - border-width: 1px; - } - - ul.tsd-parameter-list, - ul.tsd-type-parameter-list { - list-style: square; - margin: 0; - padding-left: 20px; - } - ul.tsd-parameter-list > li.tsd-parameter-signature, - ul.tsd-type-parameter-list > li.tsd-parameter-signature { - list-style: none; - margin-left: -20px; - } - ul.tsd-parameter-list h5, - ul.tsd-type-parameter-list h5 { - font-size: 16px; - margin: 1em 0 0.5em 0; - } - .tsd-sources { - margin-top: 1rem; - font-size: 0.875em; - } - .tsd-sources a { - color: var(--color-text-aside); - text-decoration: underline; - } - .tsd-sources ul { - list-style: none; - padding: 0; - } - - .tsd-page-toolbar { - position: sticky; - z-index: 1; - top: 0; - left: 0; - width: 100%; - color: var(--color-text); - background: var(--color-background-secondary); - border-bottom: var(--dim-toolbar-border-bottom-width) - var(--color-accent) solid; - transition: transform 0.3s ease-in-out; - } - .tsd-page-toolbar a { - color: var(--color-text); - } - .tsd-toolbar-contents { - display: flex; - align-items: center; - height: var(--dim-toolbar-contents-height); - margin: 0 auto; - } - .tsd-toolbar-contents > .title { - font-weight: bold; - margin-right: auto; - } - #tsd-toolbar-links { - display: flex; - align-items: center; - gap: 1.5rem; - margin-right: 1rem; - } - - .tsd-widget { - box-sizing: border-box; - display: inline-block; - opacity: 0.8; - height: 2.5rem; - width: 2.5rem; - transition: opacity 0.1s, background-color 0.1s; - text-align: center; - cursor: pointer; - border: none; - background-color: transparent; - } - .tsd-widget:hover { - opacity: 0.9; - } - .tsd-widget:active { - opacity: 1; - background-color: var(--color-accent); - } - #tsd-toolbar-menu-trigger { - display: none; - } - - .tsd-member-summary-name { - display: inline-flex; - align-items: center; - padding: 0.25rem; - text-decoration: none; - } - - .tsd-anchor-icon { - display: inline-flex; - align-items: center; - margin-left: 0.5rem; - color: var(--color-text); - vertical-align: middle; - } - - .tsd-anchor-icon svg { - width: 1em; - height: 1em; - visibility: hidden; - } - - .tsd-member-summary-name:hover > .tsd-anchor-icon svg, - .tsd-anchor-link:hover > .tsd-anchor-icon svg, - .tsd-anchor-icon:focus-visible svg { - visibility: visible; - } - - .deprecated { - text-decoration: line-through !important; - } - - .warning { - padding: 1rem; - color: var(--color-warning-text); - background: var(--color-background-warning); - } - - .tsd-kind-project { - color: var(--color-ts-project); - } - .tsd-kind-module { - color: var(--color-ts-module); - } - .tsd-kind-namespace { - color: var(--color-ts-namespace); - } - .tsd-kind-enum { - color: var(--color-ts-enum); - } - .tsd-kind-enum-member { - color: var(--color-ts-enum-member); - } - .tsd-kind-variable { - color: var(--color-ts-variable); - } - .tsd-kind-function { - color: var(--color-ts-function); - } - .tsd-kind-class { - color: var(--color-ts-class); - } - .tsd-kind-interface { - color: var(--color-ts-interface); - } - .tsd-kind-constructor { - color: var(--color-ts-constructor); - } - .tsd-kind-property { - color: var(--color-ts-property); - } - .tsd-kind-method { - color: var(--color-ts-method); - } - .tsd-kind-reference { - color: var(--color-ts-reference); - } - .tsd-kind-call-signature { - color: var(--color-ts-call-signature); - } - .tsd-kind-index-signature { - color: var(--color-ts-index-signature); - } - .tsd-kind-constructor-signature { - color: var(--color-ts-constructor-signature); - } - .tsd-kind-parameter { - color: var(--color-ts-parameter); - } - .tsd-kind-type-parameter { - color: var(--color-ts-type-parameter); - } - .tsd-kind-accessor { - color: var(--color-ts-accessor); - } - .tsd-kind-get-signature { - color: var(--color-ts-get-signature); - } - .tsd-kind-set-signature { - color: var(--color-ts-set-signature); - } - .tsd-kind-type-alias { - color: var(--color-ts-type-alias); - } - - /* if we have a kind icon, don't color the text by kind */ - .tsd-kind-icon ~ span { - color: var(--color-text); - } - - /* mobile */ - @media (max-width: 769px) { - #tsd-toolbar-menu-trigger { - display: inline-block; - /* temporary fix to vertically align, for compatibility */ - line-height: 2.5; - } - #tsd-toolbar-links { - display: none; - } - - .container-main { - display: flex; - } - .col-content { - float: none; - max-width: 100%; - width: 100%; - } - .col-sidebar { - position: fixed !important; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - z-index: 1024; - top: 0 !important; - bottom: 0 !important; - left: auto !important; - right: 0 !important; - padding: 1.5rem 1.5rem 0 0; - width: 75vw; - visibility: hidden; - background-color: var(--color-background); - transform: translate(100%, 0); - } - .col-sidebar > *:last-child { - padding-bottom: 20px; - } - .overlay { - content: ""; - display: block; - position: fixed; - z-index: 1023; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.75); - visibility: hidden; - } - - .to-has-menu .overlay { - animation: fade-in 0.4s; - } - - .to-has-menu .col-sidebar { - animation: pop-in-from-right 0.4s; - } - - .from-has-menu .overlay { - animation: fade-out 0.4s; - } - - .from-has-menu .col-sidebar { - animation: pop-out-to-right 0.4s; - } - - .has-menu body { - overflow: hidden; - } - .has-menu .overlay { - visibility: visible; - } - .has-menu .col-sidebar { - visibility: visible; - transform: translate(0, 0); - display: flex; - flex-direction: column; - gap: 1.5rem; - max-height: 100vh; - padding: 1rem 2rem; - } - .has-menu .tsd-navigation { - max-height: 100%; - } - .tsd-navigation .tsd-nav-link { - display: flex; - } - } - - /* one sidebar */ - @media (min-width: 770px) { - .container-main { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); - grid-template-areas: "sidebar content"; - --dim-container-main-margin-y: 2rem; - } - - .tsd-breadcrumb { - margin-top: 0; - } - - .col-sidebar { - grid-area: sidebar; - } - .col-content { - grid-area: content; - padding: 0 1rem; - } - } - @media (min-width: 770px) and (max-width: 1399px) { - .col-sidebar { - max-height: calc( - 100vh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - overflow: auto; - position: sticky; - top: calc( - var(--dim-header-height) + var(--dim-container-main-margin-y) - ); - } - .site-menu { - margin-top: 1rem; - } - } - - /* two sidebars */ - @media (min-width: 1200px) { - .container-main { - grid-template-columns: - minmax(0, 1fr) minmax(0, 2.5fr) minmax( - 0, - 20rem - ); - grid-template-areas: "sidebar content toc"; - } - - .col-sidebar { - display: contents; - } - - .page-menu { - grid-area: toc; - padding-left: 1rem; - } - .site-menu { - grid-area: sidebar; - } - - .site-menu { - margin-top: 0rem; - } - - .page-menu, - .site-menu { - max-height: calc( - 100vh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - overflow: auto; - position: sticky; - top: calc( - var(--dim-header-height) + var(--dim-container-main-margin-y) - ); - } - } -} diff --git a/docs/classes/DateAlignmentError.html b/docs/classes/DateAlignmentError.html deleted file mode 100644 index 825f61c..0000000 --- a/docs/classes/DateAlignmentError.html +++ /dev/null @@ -1,32 +0,0 @@ -DateAlignmentError | @captor/openseries-ts - v1.1.0
@captor/openseries-ts - v1.1.0
    Preparing search index...

    Class DateAlignmentError

    Hierarchy

    • Error
      • DateAlignmentError
    Index

    Constructors

    Properties

    message: string
    name: string
    stack?: string
    stackTraceLimit: number

    The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

    -

    The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

    -

    If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

    -

    Methods

    • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

      -
      const myObject = {};
      Error.captureStackTrace(myObject);
      myObject.stack; // Similar to `new Error().stack` -
      - -

      The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

      -

      The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

      -

      The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

      -
      function a() {
      b();
      }

      function b() {
      c();
      }

      function c() {
      // Create an error without stack trace to avoid calculating the stack trace twice.
      const { stackTraceLimit } = Error;
      Error.stackTraceLimit = 0;
      const error = new Error();
      Error.stackTraceLimit = stackTraceLimit;

      // Capture the stack trace above function b
      Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
      throw error;
      }

      a(); -
      - -

      Parameters

      • targetObject: object
      • OptionalconstructorOpt: Function

      Returns void

    diff --git a/docs/classes/IncorrectArgumentComboError.html b/docs/classes/IncorrectArgumentComboError.html deleted file mode 100644 index a8bf274..0000000 --- a/docs/classes/IncorrectArgumentComboError.html +++ /dev/null @@ -1,32 +0,0 @@ -IncorrectArgumentComboError | @captor/openseries-ts - v1.1.0
    @captor/openseries-ts - v1.1.0
      Preparing search index...

      Class IncorrectArgumentComboError

      Hierarchy

      • Error
        • IncorrectArgumentComboError
      Index

      Constructors

      Properties

      message: string
      name: string
      stack?: string
      stackTraceLimit: number

      The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

      -

      The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

      -

      If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

      -

      Methods

      • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

        -
        const myObject = {};
        Error.captureStackTrace(myObject);
        myObject.stack; // Similar to `new Error().stack` -
        - -

        The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

        -

        The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

        -

        The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

        -
        function a() {
        b();
        }

        function b() {
        c();
        }

        function c() {
        // Create an error without stack trace to avoid calculating the stack trace twice.
        const { stackTraceLimit } = Error;
        Error.stackTraceLimit = 0;
        const error = new Error();
        Error.stackTraceLimit = stackTraceLimit;

        // Capture the stack trace above function b
        Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
        throw error;
        }

        a(); -
        - -

        Parameters

        • targetObject: object
        • OptionalconstructorOpt: Function

        Returns void

      diff --git a/docs/classes/InitialValueZeroError.html b/docs/classes/InitialValueZeroError.html deleted file mode 100644 index 5db616d..0000000 --- a/docs/classes/InitialValueZeroError.html +++ /dev/null @@ -1,32 +0,0 @@ -InitialValueZeroError | @captor/openseries-ts - v1.1.0
      @captor/openseries-ts - v1.1.0
        Preparing search index...

        Class InitialValueZeroError

        Hierarchy

        • Error
          • InitialValueZeroError
        Index

        Constructors

        Properties

        message: string
        name: string
        stack?: string
        stackTraceLimit: number

        The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

        -

        The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

        -

        If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

        -

        Methods

        • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

          -
          const myObject = {};
          Error.captureStackTrace(myObject);
          myObject.stack; // Similar to `new Error().stack` -
          - -

          The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

          -

          The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

          -

          The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

          -
          function a() {
          b();
          }

          function b() {
          c();
          }

          function c() {
          // Create an error without stack trace to avoid calculating the stack trace twice.
          const { stackTraceLimit } = Error;
          Error.stackTraceLimit = 0;
          const error = new Error();
          Error.stackTraceLimit = stackTraceLimit;

          // Capture the stack trace above function b
          Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
          throw error;
          }

          a(); -
          - -

          Parameters

          • targetObject: object
          • OptionalconstructorOpt: Function

          Returns void

        diff --git a/docs/classes/MixedValuetypesError.html b/docs/classes/MixedValuetypesError.html deleted file mode 100644 index 0a25f43..0000000 --- a/docs/classes/MixedValuetypesError.html +++ /dev/null @@ -1,32 +0,0 @@ -MixedValuetypesError | @captor/openseries-ts - v1.1.0
        @captor/openseries-ts - v1.1.0
          Preparing search index...

          Class MixedValuetypesError

          Hierarchy

          • Error
            • MixedValuetypesError
          Index

          Constructors

          Properties

          message: string
          name: string
          stack?: string
          stackTraceLimit: number

          The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

          -

          The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

          -

          If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

          -

          Methods

          • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

            -
            const myObject = {};
            Error.captureStackTrace(myObject);
            myObject.stack; // Similar to `new Error().stack` -
            - -

            The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

            -

            The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

            -

            The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

            -
            function a() {
            b();
            }

            function b() {
            c();
            }

            function c() {
            // Create an error without stack trace to avoid calculating the stack trace twice.
            const { stackTraceLimit } = Error;
            Error.stackTraceLimit = 0;
            const error = new Error();
            Error.stackTraceLimit = stackTraceLimit;

            // Capture the stack trace above function b
            Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
            throw error;
            }

            a(); -
            - -

            Parameters

            • targetObject: object
            • OptionalconstructorOpt: Function

            Returns void

          diff --git a/docs/classes/NoWeightsError.html b/docs/classes/NoWeightsError.html deleted file mode 100644 index 5ec069c..0000000 --- a/docs/classes/NoWeightsError.html +++ /dev/null @@ -1,32 +0,0 @@ -NoWeightsError | @captor/openseries-ts - v1.1.0
          @captor/openseries-ts - v1.1.0
            Preparing search index...

            Class NoWeightsError

            Hierarchy

            • Error
              • NoWeightsError
            Index

            Constructors

            Properties

            message: string
            name: string
            stack?: string
            stackTraceLimit: number

            The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

            -

            The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

            -

            If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

            -

            Methods

            • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

              -
              const myObject = {};
              Error.captureStackTrace(myObject);
              myObject.stack; // Similar to `new Error().stack` -
              - -

              The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

              -

              The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

              -

              The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

              -
              function a() {
              b();
              }

              function b() {
              c();
              }

              function c() {
              // Create an error without stack trace to avoid calculating the stack trace twice.
              const { stackTraceLimit } = Error;
              Error.stackTraceLimit = 0;
              const error = new Error();
              Error.stackTraceLimit = stackTraceLimit;

              // Capture the stack trace above function b
              Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
              throw error;
              }

              a(); -
              - -

              Parameters

              • targetObject: object
              • OptionalconstructorOpt: Function

              Returns void

            diff --git a/docs/classes/OpenFrame.html b/docs/classes/OpenFrame.html deleted file mode 100644 index 2f1c123..0000000 --- a/docs/classes/OpenFrame.html +++ /dev/null @@ -1,62 +0,0 @@ -OpenFrame | @captor/openseries-ts - v1.1.0
            @captor/openseries-ts - v1.1.0
              Preparing search index...

              Class OpenFrame

              Collection of aligned timeseries with portfolio and correlation methods.

              -
              Index

              Constructors

              • Parameters

                • constituents: OpenTimeSeries[]
                • weights: number[] | null = null
                • Optionaloptions: { countries?: string | string[] }

                Returns OpenFrame

              Properties

              columnLabels: string[]
              constituents: OpenTimeSeries[]
              countries: string[]

              Country code(s) for business calendar (holidays, resampling). Used when adapting data to business days.

              -
              tsdf: { columns: number[][]; dates: string[] }
              weights: number[] | null

              Accessors

              Methods

              • Lag-k autocorrelation per constituent. Matches Python OpenFrame.autocorr_func.

                -

                Parameters

                • lag: number = 1
                • squared: boolean = false

                Returns number[]

              • Parameters

                • assetColumn: number
                • marketColumn: number

                Returns number

              • CAGR-based capture ratio vs benchmark column. -Matches Python openseries capture_ratio_func behavior: uses frame data as-is (no resample) -with dynamic time_factor = observations / (span_days/365.25).

                -

                Parameters

                • ratio: "both" | "up" | "down"

                  "up" | "down" | "both" (up/down or both = up/down)

                  -
                • baseColumn: number = -1

                  Benchmark column index (-1 = last)

                  -
                • Optionalopts: { freq?: ResampleFreq }
                  • Optionalfreq?: ResampleFreq

                    If set, resample to period-end before computing (e.g. "ME" for monthly). -When omitted, uses frame data as-is to match Python default.

                    -

                Returns number[]

              • Filters tsdf to retain only business days. Mutates in place.

                -

                Returns this

              • Parameters

                • baseColumn: number = -1

                Returns number[]

              • Parameters

                • assetColumn: number
                • marketColumn: number
                • riskfreeRate: number = 0

                Returns number

              • Max drawdown per column (price series). Returns array of max drawdowns.

                -

                Returns number[]

              • Date when max drawdown bottom occurs per column. -Returns array of date strings (or undefined when no drawdown).

                -

                Returns (string | undefined)[]

              • Parameters

                • how: "inner" | "outer" = "outer"

                Returns this

              • Ordinary Least Squares fit of y on x. -Regresses tsdf column yColumn (dependent) on xColumn (explanatory). -Matches Python openseries ord_least_squares_fit.

                -

                Parameters

                • yColumn: number

                  Column index of dependent variable y

                  -
                • xColumn: number

                  Column index of exogenous variable x

                  -
                • Optionalopts: { fittedSeries?: boolean }
                  • OptionalfittedSeries?: boolean

                    If true, add fitted values as new column (default true)

                    -

                Returns OrdLeastSquaresResult

                Object with coefficient (slope), intercept, and rsquared

                -
              • Resamples all constituents to business period-end frequency, then re-merges. -Throws if any constituent is a return series.

                -

                Parameters

                Returns this

              • Returns return columns (first element 0). Throws if mixed PRICE/RTRN.

                -

                Returns number[][]

              • Converts each column to drawdown series (value / running peak - 1). -Operates on the frame's aligned tsdf. Call after mergeSeries and truncate -so drawdown is computed on the truncated date range.

                -

                Returns this

              • Parameters

                • baseColumn: number = -1
                • Optional_opts: { fromDate?: string; toDate?: string }

                Returns number[]

              • Truncates frame and constituents to a common date range.

                -

                Parameters

                • opts: { endCut?: string; startCut?: string; where?: "before" | "after" | "both" } = {}

                  Truncation options

                  -
                  • OptionalendCut?: string

                    New last date (default: earliest last date if where includes 'after')

                    -
                  • OptionalstartCut?: string

                    New first date (default: latest first date of all constituents if where includes 'before')

                    -
                  • Optionalwhere?: "before" | "after" | "both"

                    Which end(s) to truncate when cuts not provided

                    -

                Returns this

              diff --git a/docs/classes/OpenTimeSeries.html b/docs/classes/OpenTimeSeries.html deleted file mode 100644 index 0d9ca47..0000000 --- a/docs/classes/OpenTimeSeries.html +++ /dev/null @@ -1,78 +0,0 @@ -OpenTimeSeries | @captor/openseries-ts - v1.1.0
              @captor/openseries-ts - v1.1.0
                Preparing search index...

                Class OpenTimeSeries

                Timeseries of dates and values with methods for risk metrics.

                -
                Index

                Constructors

                • Parameters

                  • params: {
                        countries?: string | string[];
                        currency?: string;
                        dates: string[];
                        instrumentId?: string;
                        label?: string;
                        localCcy?: boolean;
                        markets?: string | string[] | null;
                        name: string;
                        timeseriesId?: string;
                        values: number[];
                        valuetype?: ValueType;
                    }

                  Returns OpenTimeSeries

                Properties

                countries: string | string[]

                Country code(s) for business calendar (holidays, resampling). Default "SE".

                -
                currency: string
                dates: string[]
                instrumentId: string
                label: string
                localCcy: boolean
                markets: string | string[] | null
                name: string
                timeseriesId: string
                tsdf: { date: string; value: number }[]
                values: number[]
                valuetype: ValueType

                Accessors

                Methods

                • Autocorrelation function for specified lags. -If lags is an int, compute ACF from lag 0 through that value (inclusive).

                  -

                  Parameters

                  Returns LagSeries

                • Lag-k autocorrelation of demeaned returns. -For price series, returns are derived via pct_change; for return series, -values are demeaned. Matches Python openseries autocorr_func.

                  -

                  Parameters

                  Returns number

                • Parameters

                  • lmbda: number = 0.94
                  • dayChunk: number = 11
                  • level: number = 0.95
                  • opts: DateRangeOptions = {}

                  Returns number[]

                • Filters tsdf to retain only business days. Mutates in place.

                  -

                  Returns this

                • Returns the date when the max drawdown bottom occurs (the date of the lowest point -relative to the preceding peak). Returns undefined if no drawdown occurs.

                  -

                  Parameters

                  Returns string | undefined

                • Partial autocorrelation function for specified lags. -If lags is an int, compute PACF from lag 0 through that value (inclusive).

                  -

                  Parameters

                  Returns LagSeries

                • Partial autocorrelation at a given lag.

                  -

                  Parameters

                  Returns number

                • Resamples to business period-end frequency (week, month, quarter, year). -Mutates tsdf. Throws on return series (use price series).

                  -

                  Parameters

                  Returns this

                • Parameters

                  • riskfreeRate: number = 0
                  • minAcceptedReturn: number = 0
                  • opts: DateRangeOptions = {}

                  Returns number

                • Worst single calendar month return (business-month-end based). -Uses filterToBusinessDays + resampleToPeriodEnd(ME) + min of monthly returns.

                  -

                  Parameters

                  Returns number

                • Creates an OpenTimeSeries from a name, dates array, and values array.

                  -

                  Parameters

                  • name: string
                  • dates: string[]
                  • values: number[]
                  • Optionaloptions: {
                        baseccy?: string;
                        countries?: string | string[];
                        instrumentId?: string;
                        localCcy?: boolean;
                        timeseriesId?: string;
                        valuetype?: ValueType;
                    }

                  Returns OpenTimeSeries

                • Creates an OpenTimeSeries from simulation dateColumns by column index.

                  -

                  Parameters

                  • dateColumns: { columns: { name: string; values: number[] }[]; dates: string[] }
                  • Optionaloptions: { columnIndex?: number; countries?: string | string[]; valuetype?: ValueType }

                  Returns OpenTimeSeries

                • Creates an OpenTimeSeries from a record or array of {date, value}.

                  -

                  Parameters

                  • data: Record<string, number> | { date: string; value: number }[]

                  Returns OpenTimeSeries

                diff --git a/docs/classes/ResampleDataLossError.html b/docs/classes/ResampleDataLossError.html deleted file mode 100644 index bb5c27f..0000000 --- a/docs/classes/ResampleDataLossError.html +++ /dev/null @@ -1,32 +0,0 @@ -ResampleDataLossError | @captor/openseries-ts - v1.1.0
                @captor/openseries-ts - v1.1.0
                  Preparing search index...

                  Class ResampleDataLossError

                  Hierarchy

                  • Error
                    • ResampleDataLossError
                  Index

                  Constructors

                  Properties

                  message: string
                  name: string
                  stack?: string
                  stackTraceLimit: number

                  The Error.stackTraceLimit property specifies the number of stack frames -collected by a stack trace (whether generated by new Error().stack or -Error.captureStackTrace(obj)).

                  -

                  The default value is 10 but may be set to any valid JavaScript number. Changes -will affect any stack trace captured after the value has been changed.

                  -

                  If set to a non-number value, or set to a negative number, stack traces will -not capture any frames.

                  -

                  Methods

                  • Creates a .stack property on targetObject, which when accessed returns -a string representing the location in the code at which -Error.captureStackTrace() was called.

                    -
                    const myObject = {};
                    Error.captureStackTrace(myObject);
                    myObject.stack; // Similar to `new Error().stack` -
                    - -

                    The first line of the trace will be prefixed with -${myObject.name}: ${myObject.message}.

                    -

                    The optional constructorOpt argument accepts a function. If given, all frames -above constructorOpt, including constructorOpt, will be omitted from the -generated stack trace.

                    -

                    The constructorOpt argument is useful for hiding implementation -details of error generation from the user. For instance:

                    -
                    function a() {
                    b();
                    }

                    function b() {
                    c();
                    }

                    function c() {
                    // Create an error without stack trace to avoid calculating the stack trace twice.
                    const { stackTraceLimit } = Error;
                    Error.stackTraceLimit = 0;
                    const error = new Error();
                    Error.stackTraceLimit = stackTraceLimit;

                    // Capture the stack trace above function b
                    Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
                    throw error;
                    }

                    a(); -
                    - -

                    Parameters

                    • targetObject: object
                    • OptionalconstructorOpt: Function

                    Returns void

                  diff --git a/docs/classes/ReturnSimulation.html b/docs/classes/ReturnSimulation.html deleted file mode 100644 index 4e1b7be..0000000 --- a/docs/classes/ReturnSimulation.html +++ /dev/null @@ -1,21 +0,0 @@ -ReturnSimulation | @captor/openseries-ts - v1.1.0
                  @captor/openseries-ts - v1.1.0
                    Preparing search index...

                    Class ReturnSimulation

                    Monte Carlo return simulation with optional seed for reproducibility.

                    -
                    Index

                    Constructors

                    • Parameters

                      • params: {
                            dframe: number[][];
                            jumps_lamda?: number;
                            jumps_mu?: number;
                            jumps_sigma?: number;
                            mean_annual_return: number;
                            mean_annual_vol: number;
                            number_of_sims: number;
                            seed?: number;
                            trading_days: number;
                            trading_days_in_year: number;
                        }

                      Returns ReturnSimulation

                    Properties

                    dframe: number[][]
                    jumpsLamda: number
                    jumpsMu: number
                    jumpsSigma: number
                    meanAnnualReturn: number
                    meanAnnualVol: number
                    numberOfSims: number
                    seed?: number
                    tradingDays: number
                    tradingDaysInYear: number

                    Accessors

                    Methods

                    • Parameters

                      • name: string
                      • Optionaloptions: { asReturns?: boolean; end?: string; start?: string }

                      Returns { columns: { name: string; values: number[] }[]; dates: string[] }

                    • Parameters

                      • number_of_sims: number
                      • mean_annual_return: number
                      • mean_annual_vol: number
                      • trading_days: number
                      • trading_days_in_year: number = 252
                      • Optionalseed: number

                      Returns ReturnSimulation

                    • Parameters

                      • number_of_sims: number
                      • mean_annual_return: number
                      • mean_annual_vol: number
                      • trading_days: number
                      • trading_days_in_year: number = 252
                      • Optionalseed: number

                      Returns ReturnSimulation

                    • Parameters

                      • number_of_sims: number
                      • trading_days: number
                      • mean_annual_return: number
                      • mean_annual_vol: number
                      • jumps_lamda: number
                      • jumps_sigma: number = 0
                      • jumps_mu: number = 0
                      • trading_days_in_year: number = 252
                      • Optionalseed: number

                      Returns ReturnSimulation

                    • Parameters

                      • number_of_sims: number
                      • mean_annual_return: number
                      • mean_annual_vol: number
                      • trading_days: number
                      • trading_days_in_year: number = 252
                      • Optionalseed: number

                      Returns ReturnSimulation

                    diff --git a/docs/enums/ValueType.html b/docs/enums/ValueType.html deleted file mode 100644 index 4ee86a4..0000000 --- a/docs/enums/ValueType.html +++ /dev/null @@ -1,13 +0,0 @@ -ValueType | @captor/openseries-ts - v1.1.0
                    @captor/openseries-ts - v1.1.0
                      Preparing search index...

                      Enumeration ValueType

                      Index

                      Enumeration Members

                      EWMA_VAR: "EWMA VaR"
                      EWMA_VOL: "EWMA volatility"
                      PRICE: "Price(Close)"
                      RELRTRN: "Relative return"
                      ROLLBETA: "Beta"
                      ROLLCORR: "Rolling correlation"
                      ROLLCVAR: "Rolling CVaR"
                      ROLLINFORATIO: "Information Ratio"
                      ROLLRTRN: "Rolling returns"
                      ROLLVAR: "Rolling VaR"
                      ROLLVOL: "Rolling volatility"
                      RTRN: "Return(Total)"
                      diff --git a/docs/functions/dateFix.html b/docs/functions/dateFix.html deleted file mode 100644 index 97a0cc4..0000000 --- a/docs/functions/dateFix.html +++ /dev/null @@ -1,2 +0,0 @@ -dateFix | @captor/openseries-ts - v1.1.0
                      @captor/openseries-ts - v1.1.0
                        Preparing search index...

                        Function dateFix

                        • Normalizes string or Date input to a Date.

                          -

                          Parameters

                          • input: string | Date

                          Returns Date

                        diff --git a/docs/functions/dateToStr.html b/docs/functions/dateToStr.html deleted file mode 100644 index 945635f..0000000 --- a/docs/functions/dateToStr.html +++ /dev/null @@ -1,2 +0,0 @@ -dateToStr | @captor/openseries-ts - v1.1.0
                        @captor/openseries-ts - v1.1.0
                          Preparing search index...

                          Function dateToStr

                          • Returns a Date as YYYY-MM-DD string.

                            -

                            Parameters

                            • d: Date

                            Returns string

                          diff --git a/docs/functions/efficientFrontier.html b/docs/functions/efficientFrontier.html deleted file mode 100644 index 04ae9af..0000000 --- a/docs/functions/efficientFrontier.html +++ /dev/null @@ -1,2 +0,0 @@ -efficientFrontier | @captor/openseries-ts - v1.1.0
                          @captor/openseries-ts - v1.1.0
                            Preparing search index...

                            Function efficientFrontier

                            diff --git a/docs/functions/fetchCaptorSeries.html b/docs/functions/fetchCaptorSeries.html deleted file mode 100644 index dbfdb50..0000000 --- a/docs/functions/fetchCaptorSeries.html +++ /dev/null @@ -1,4 +0,0 @@ -fetchCaptorSeries | @captor/openseries-ts - v1.1.0
                            @captor/openseries-ts - v1.1.0
                              Preparing search index...

                              Function fetchCaptorSeries

                              • Fetches a single timeseries from the Captor Open API.

                                -

                                Parameters

                                • id: string

                                  The timeseries ID (e.g. "638f681e0c2f4c8d28a13392")

                                  -

                                Returns Promise<CaptorSeriesResponse>

                                The timeseries data with dates and values arrays

                                -
                              diff --git a/docs/functions/fetchCaptorSeriesBatch.html b/docs/functions/fetchCaptorSeriesBatch.html deleted file mode 100644 index e412e9c..0000000 --- a/docs/functions/fetchCaptorSeriesBatch.html +++ /dev/null @@ -1,4 +0,0 @@ -fetchCaptorSeriesBatch | @captor/openseries-ts - v1.1.0
                              @captor/openseries-ts - v1.1.0
                                Preparing search index...

                                Function fetchCaptorSeriesBatch

                                diff --git a/docs/functions/filterBusinessDays.html b/docs/functions/filterBusinessDays.html deleted file mode 100644 index bb495ec..0000000 --- a/docs/functions/filterBusinessDays.html +++ /dev/null @@ -1,6 +0,0 @@ -filterBusinessDays | @captor/openseries-ts - v1.1.0
                                @captor/openseries-ts - v1.1.0
                                  Preparing search index...

                                  Function filterBusinessDays

                                  • Filters an array of date strings to keep only business days. -Business day = not weekend (Sat/Sun) and not a holiday in any of the specified countries.

                                    -

                                    Parameters

                                    • dates: string[]

                                      Array of date strings (YYYY-MM-DD)

                                      -
                                    • countries: string | string[]

                                      Country code(s) for holiday calendar, e.g. "SE", "US", ["SE", "NO"]

                                      -

                                    Returns string[]

                                    Array of business-day date strings (subsequence of input, preserving order)

                                    -
                                  diff --git a/docs/functions/filterToBusinessDays.html b/docs/functions/filterToBusinessDays.html deleted file mode 100644 index e788df9..0000000 --- a/docs/functions/filterToBusinessDays.html +++ /dev/null @@ -1,3 +0,0 @@ -filterToBusinessDays | @captor/openseries-ts - v1.1.0
                                  @captor/openseries-ts - v1.1.0
                                    Preparing search index...

                                    Function filterToBusinessDays

                                    • Filters (dates, columns) to retain only rows where the date is a business day. -Preserves alignment across all columns.

                                      -

                                      Parameters

                                      • dates: string[]
                                      • columns: number[][]
                                      • countries: string | string[]

                                      Returns { columns: number[][]; dates: string[] }

                                    diff --git a/docs/functions/generateCalendarDateRange.html b/docs/functions/generateCalendarDateRange.html deleted file mode 100644 index 1c87ec7..0000000 --- a/docs/functions/generateCalendarDateRange.html +++ /dev/null @@ -1,2 +0,0 @@ -generateCalendarDateRange | @captor/openseries-ts - v1.1.0
                                    @captor/openseries-ts - v1.1.0
                                      Preparing search index...

                                      Function generateCalendarDateRange

                                      • Returns an array of business-day date strings (excludes weekends).

                                        -

                                        Parameters

                                        • tradingDays: number
                                        • Optionaloptions: { end?: string; start?: string }

                                        Returns string[]

                                      diff --git a/docs/functions/getPreviousBusinessDayBeforeToday.html b/docs/functions/getPreviousBusinessDayBeforeToday.html deleted file mode 100644 index e7f8c4b..0000000 --- a/docs/functions/getPreviousBusinessDayBeforeToday.html +++ /dev/null @@ -1,3 +0,0 @@ -getPreviousBusinessDayBeforeToday | @captor/openseries-ts - v1.1.0
                                      @captor/openseries-ts - v1.1.0
                                        Preparing search index...

                                        Function getPreviousBusinessDayBeforeToday

                                        • Returns the most recent business day strictly before today. -Uses the given country code(s) for holiday calendar (e.g. "SE" for XSTO/Stockholm).

                                          -

                                          Parameters

                                          • countries: string | string[]

                                          Returns string

                                        diff --git a/docs/functions/isBusinessDay.html b/docs/functions/isBusinessDay.html deleted file mode 100644 index 5b7bec7..0000000 --- a/docs/functions/isBusinessDay.html +++ /dev/null @@ -1,2 +0,0 @@ -isBusinessDay | @captor/openseries-ts - v1.1.0
                                        @captor/openseries-ts - v1.1.0
                                          Preparing search index...

                                          Function isBusinessDay

                                          • Checks whether a date is a business day.

                                            -

                                            Parameters

                                            • dateStr: string
                                            • countries: string | string[]

                                            Returns boolean

                                          diff --git a/docs/functions/lastBusinessDayOfMonth.html b/docs/functions/lastBusinessDayOfMonth.html deleted file mode 100644 index 1b1e168..0000000 --- a/docs/functions/lastBusinessDayOfMonth.html +++ /dev/null @@ -1,2 +0,0 @@ -lastBusinessDayOfMonth | @captor/openseries-ts - v1.1.0
                                          @captor/openseries-ts - v1.1.0
                                            Preparing search index...

                                            Function lastBusinessDayOfMonth

                                            • Last business day of the given month (1-indexed).

                                              -

                                              Parameters

                                              • year: number
                                              • month: number
                                              • countries: string | string[]

                                              Returns string

                                            diff --git a/docs/functions/lastBusinessDayOfYear.html b/docs/functions/lastBusinessDayOfYear.html deleted file mode 100644 index 03339e8..0000000 --- a/docs/functions/lastBusinessDayOfYear.html +++ /dev/null @@ -1,2 +0,0 @@ -lastBusinessDayOfYear | @captor/openseries-ts - v1.1.0
                                            @captor/openseries-ts - v1.1.0
                                              Preparing search index...

                                              Function lastBusinessDayOfYear

                                              • Last business day of the given year.

                                                -

                                                Parameters

                                                • year: number
                                                • countries: string | string[]

                                                Returns string

                                              diff --git a/docs/functions/mean.html b/docs/functions/mean.html deleted file mode 100644 index 5b19018..0000000 --- a/docs/functions/mean.html +++ /dev/null @@ -1,2 +0,0 @@ -mean | @captor/openseries-ts - v1.1.0
                                              @captor/openseries-ts - v1.1.0
                                                Preparing search index...

                                                Function mean

                                                • Returns the arithmetic mean of an array.

                                                  -

                                                  Parameters

                                                  • arr: number[]

                                                  Returns number

                                                diff --git a/docs/functions/offsetBusinessDays.html b/docs/functions/offsetBusinessDays.html deleted file mode 100644 index e48ceef..0000000 --- a/docs/functions/offsetBusinessDays.html +++ /dev/null @@ -1,2 +0,0 @@ -offsetBusinessDays | @captor/openseries-ts - v1.1.0
                                                @captor/openseries-ts - v1.1.0
                                                  Preparing search index...

                                                  Function offsetBusinessDays

                                                  • Offsets a date by a number of business days.

                                                    -

                                                    Parameters

                                                    • ddate: Date
                                                    • days: number

                                                    Returns Date

                                                  diff --git a/docs/functions/pctChange.html b/docs/functions/pctChange.html deleted file mode 100644 index 93e2458..0000000 --- a/docs/functions/pctChange.html +++ /dev/null @@ -1,2 +0,0 @@ -pctChange | @captor/openseries-ts - v1.1.0
                                                  @captor/openseries-ts - v1.1.0
                                                    Preparing search index...

                                                    Function pctChange

                                                    • Returns period-over-period percentage change. First element is 0.

                                                      -

                                                      Parameters

                                                      • values: number[]

                                                      Returns number[]

                                                    diff --git a/docs/functions/plotSeries.html b/docs/functions/plotSeries.html deleted file mode 100644 index 5103353..0000000 --- a/docs/functions/plotSeries.html +++ /dev/null @@ -1,6 +0,0 @@ -plotSeries | @captor/openseries-ts - v1.1.0
                                                    @captor/openseries-ts - v1.1.0
                                                      Preparing search index...

                                                      Function plotSeries

                                                      • Generate full-page series plot HTML, write to file, and optionally open in browser. -Analogous to Python plot_series with auto_open.

                                                        -

                                                        Parameters

                                                        Returns Promise<string>

                                                        Path to the written HTML file

                                                        -
                                                      diff --git a/docs/functions/plotSeriesHtml.html b/docs/functions/plotSeriesHtml.html deleted file mode 100644 index 27794da..0000000 --- a/docs/functions/plotSeriesHtml.html +++ /dev/null @@ -1,7 +0,0 @@ -plotSeriesHtml | @captor/openseries-ts - v1.1.0
                                                      @captor/openseries-ts - v1.1.0
                                                        Preparing search index...

                                                        Function plotSeriesHtml

                                                        • Generate full-page HTML with a line chart of the series (or multiple series). -Plots cumulative returns (base 1). Percent display is formatting only. -Works with OpenTimeSeries or OpenFrame. For OpenFrame, use mergeSeries("inner") first.

                                                          -

                                                          Parameters

                                                          Returns string

                                                          HTML string

                                                          -
                                                        diff --git a/docs/functions/preparePlotData.html b/docs/functions/preparePlotData.html deleted file mode 100644 index 2b89423..0000000 --- a/docs/functions/preparePlotData.html +++ /dev/null @@ -1,3 +0,0 @@ -preparePlotData | @captor/openseries-ts - v1.1.0
                                                        @captor/openseries-ts - v1.1.0
                                                          Preparing search index...

                                                          Function preparePlotData

                                                          diff --git a/docs/functions/prevBusinessDay.html b/docs/functions/prevBusinessDay.html deleted file mode 100644 index fab2b4a..0000000 --- a/docs/functions/prevBusinessDay.html +++ /dev/null @@ -1,2 +0,0 @@ -prevBusinessDay | @captor/openseries-ts - v1.1.0
                                                          @captor/openseries-ts - v1.1.0
                                                            Preparing search index...

                                                            Function prevBusinessDay

                                                            • Finds the last business day on or before the given date.

                                                              -

                                                              Parameters

                                                              • dateStr: string
                                                              • countries: string | string[]

                                                              Returns string

                                                            diff --git a/docs/functions/quantile.html b/docs/functions/quantile.html deleted file mode 100644 index ff879b6..0000000 --- a/docs/functions/quantile.html +++ /dev/null @@ -1,2 +0,0 @@ -quantile | @captor/openseries-ts - v1.1.0
                                                            @captor/openseries-ts - v1.1.0
                                                              Preparing search index...

                                                              Function quantile

                                                              • Returns the quantile at q (0-1) using linear interpolation.

                                                                -

                                                                Parameters

                                                                • arr: number[]
                                                                • q: number
                                                                • sorted: boolean = false

                                                                Returns number

                                                              diff --git a/docs/functions/randomGenerator.html b/docs/functions/randomGenerator.html deleted file mode 100644 index 60b5f92..0000000 --- a/docs/functions/randomGenerator.html +++ /dev/null @@ -1,2 +0,0 @@ -randomGenerator | @captor/openseries-ts - v1.1.0
                                                              @captor/openseries-ts - v1.1.0
                                                                Preparing search index...

                                                                Function randomGenerator

                                                                • Returns a seeded RNG function returning values in [0, 1).

                                                                  -

                                                                  Parameters

                                                                  • Optionalseed: number

                                                                  Returns () => number

                                                                diff --git a/docs/functions/reportHtml.html b/docs/functions/reportHtml.html deleted file mode 100644 index ca0e331..0000000 --- a/docs/functions/reportHtml.html +++ /dev/null @@ -1,11 +0,0 @@ -reportHtml | @captor/openseries-ts - v1.1.0
                                                                @captor/openseries-ts - v1.1.0
                                                                  Preparing search index...

                                                                  Function reportHtml

                                                                  • Generate HTML report from an OpenFrame. -Analogous to Python openseries report_html(data: OpenFrame, ...). -The frame should have mergeSeries("inner") already applied.

                                                                    -

                                                                    Requires at least 2 constituents: the first N-1 are compared against the last -(benchmark). Benchmark-relative metrics (Capture Ratio, Information Ratio, etc.) -are empty for the benchmark series.

                                                                    -

                                                                    Parameters

                                                                    • frame: OpenFrame

                                                                      OpenFrame with aligned series (mergeSeries("inner"))

                                                                      -
                                                                    • options: ReportOptions = {}

                                                                      Report options (title, logo). Countries come from frame.countries.

                                                                      -

                                                                    Returns string

                                                                    HTML string

                                                                    -

                                                                    Error when frame has fewer than 2 constituents

                                                                    -
                                                                  diff --git a/docs/functions/resampleToPeriodEnd.html b/docs/functions/resampleToPeriodEnd.html deleted file mode 100644 index 6d856e6..0000000 --- a/docs/functions/resampleToPeriodEnd.html +++ /dev/null @@ -1,7 +0,0 @@ -resampleToPeriodEnd | @captor/openseries-ts - v1.1.0
                                                                  @captor/openseries-ts - v1.1.0
                                                                    Preparing search index...

                                                                    Function resampleToPeriodEnd

                                                                    • Resamples dates and columns to end-of-business period frequency. -Each period takes the last observation that falls on a business day within that period.

                                                                      -

                                                                      Parameters

                                                                      • dates: string[]

                                                                        Sorted array of date strings

                                                                        -
                                                                      • columns: number[][]

                                                                        Value columns (same length as dates)

                                                                        -
                                                                      • freq: ResampleFreq

                                                                        WE (week-end), ME (month-end), QE (quarter-end), YE (year-end)

                                                                        -
                                                                      • countries: string | string[]

                                                                        Country code(s) for holiday filtering

                                                                        -

                                                                      Returns { columns: number[][]; dates: string[] }

                                                                    diff --git a/docs/functions/sharpeplot.html b/docs/functions/sharpeplot.html deleted file mode 100644 index 2f4b86f..0000000 --- a/docs/functions/sharpeplot.html +++ /dev/null @@ -1,2 +0,0 @@ -sharpeplot | @captor/openseries-ts - v1.1.0
                                                                    @captor/openseries-ts - v1.1.0
                                                                      Preparing search index...

                                                                      Function sharpeplot

                                                                      diff --git a/docs/functions/sharpeplotHtml.html b/docs/functions/sharpeplotHtml.html deleted file mode 100644 index 15cc3b0..0000000 --- a/docs/functions/sharpeplotHtml.html +++ /dev/null @@ -1,3 +0,0 @@ -sharpeplotHtml | @captor/openseries-ts - v1.1.0
                                                                      @captor/openseries-ts - v1.1.0
                                                                        Preparing search index...

                                                                        Function sharpeplotHtml

                                                                        diff --git a/docs/functions/simulatePortfolios.html b/docs/functions/simulatePortfolios.html deleted file mode 100644 index a22b35f..0000000 --- a/docs/functions/simulatePortfolios.html +++ /dev/null @@ -1,2 +0,0 @@ -simulatePortfolios | @captor/openseries-ts - v1.1.0
                                                                        @captor/openseries-ts - v1.1.0
                                                                          Preparing search index...

                                                                          Function simulatePortfolios

                                                                          diff --git a/docs/functions/std.html b/docs/functions/std.html deleted file mode 100644 index f619783..0000000 --- a/docs/functions/std.html +++ /dev/null @@ -1,2 +0,0 @@ -std | @captor/openseries-ts - v1.1.0
                                                                          @captor/openseries-ts - v1.1.0
                                                                            Preparing search index...

                                                                            Function std

                                                                            • Returns the sample standard deviation.

                                                                              -

                                                                              Parameters

                                                                              • arr: number[]
                                                                              • ddof: number = 1

                                                                              Returns number

                                                                            diff --git a/docs/functions/timeseriesChain.html b/docs/functions/timeseriesChain.html deleted file mode 100644 index c479434..0000000 --- a/docs/functions/timeseriesChain.html +++ /dev/null @@ -1,2 +0,0 @@ -timeseriesChain | @captor/openseries-ts - v1.1.0
                                                                            @captor/openseries-ts - v1.1.0
                                                                              Preparing search index...

                                                                              Function timeseriesChain

                                                                              diff --git a/docs/hierarchy.html b/docs/hierarchy.html deleted file mode 100644 index 3749549..0000000 --- a/docs/hierarchy.html +++ /dev/null @@ -1 +0,0 @@ -@captor/openseries-ts - v1.1.0
                                                                              @captor/openseries-ts - v1.1.0
                                                                                Preparing search index...

                                                                                @captor/openseries-ts - v1.1.0

                                                                                Hierarchy Summary

                                                                                diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index b61268c..0000000 --- a/docs/index.html +++ /dev/null @@ -1,292 +0,0 @@ -@captor/openseries-ts - v1.1.0
                                                                                @captor/openseries-ts - v1.1.0
                                                                                  Preparing search index...

                                                                                  @captor/openseries-ts - v1.1.0

                                                                                  openseries (TypeScript)

                                                                                  -

                                                                                  npm version -Node version -GitHub Action Test Suite -codecov -Documentation -npm -ESLint -GitHub License

                                                                                  -

                                                                                  Tools for analyzing financial timeseries of a single asset or a group of assets. -Designed for daily or less frequent data. -TypeScript port of the -Python openseries package.

                                                                                  - -
                                                                                  npm install @captor/openseries-ts
                                                                                  -
                                                                                  - -

                                                                                  The published package requires Node.js 22 or later.

                                                                                  -

                                                                                  To develop this repository you need npm 12+ and Node.js 22, 24, or 26 -(^22.22.2 || ^24.15.0 || >=26.0.0). Those versions are enforced via -package.json engines, devEngines, and packageManager (npm@12.0.2). -CI runs the test suite on Node 22, 24, and 26.

                                                                                  - -
                                                                                  import { OpenTimeSeries } from "@captor/openseries-ts";

                                                                                  const dates = ["2020-01-02", "2020-01-03", "2020-01-06", "2020-01-07"];
                                                                                  const values = [100, 101, 102, 99];

                                                                                  const series = OpenTimeSeries.fromArrays("My Series", dates, values);

                                                                                  console.log(series.geoRet()); // CAGR
                                                                                  console.log(series.vol()); // Annualized volatility
                                                                                  console.log(series.maxDrawdown()); // Max drawdown
                                                                                  console.log(series.autocorr()); // lag-1 autocorrelation of demeaned returns -
                                                                                  - - -
                                                                                    -
                                                                                  • OpenTimeSeries: Single timeseries with risk metrics -(CAGR, volatility, VaR, CVaR, Sortino ratio, max drawdown, autocorrelation, etc.)
                                                                                  • -
                                                                                  • OpenFrame: Multi-series comparison, correlation, portfolio construction, -rebalancing
                                                                                  • -
                                                                                  • ReturnSimulation: Monte Carlo with reproducible seeds -(normal, lognormal, GBM, Merton jump-diffusion)
                                                                                  • -
                                                                                  • Portfolio tools: Efficient frontier, simulated portfolios, weight strategies
                                                                                  • -
                                                                                  • Date utilities: Business day calendars (via date-holidays), date offsets, -period-end alignment
                                                                                  • -
                                                                                  • Captor API: Fetch timeseries from Captor Open API -(fetchCaptorSeries, fetchCaptorSeriesBatch)
                                                                                  • -
                                                                                  • Report: reportHtml(frame, options) — programmatic HTML report; -CLI via npm run report
                                                                                  • -
                                                                                  • Plot: plotSeriesHtml(), plotSeries() — full-page series line chart -(like Python plot_series)
                                                                                  • -
                                                                                  - - -
                                                                                    -
                                                                                  • fromArrays(), fromObject(), fromDateColumns() — create from dates/values -or simulation output
                                                                                  • -
                                                                                  • valueToRet(), toCumret() - Convert price ↔ returns
                                                                                  • -
                                                                                  • geoRet(), arithmeticRet(), vol(), varDown(), cvarDown()
                                                                                  • -
                                                                                  • sortinoRatio(), retVolRatio(), maxDrawdown(), maxDrawdownBottomDate(), downsideDeviation()
                                                                                  • -
                                                                                  • autocorr(lag?, opts?, squared?) — lag-k autocorrelation of demeaned returns
                                                                                  • -
                                                                                  • acf(lags, opts?, squared?), pacf(lags, opts?, squared?), partialAutocorr(lag?, opts?, squared?)
                                                                                  • -
                                                                                  • ljungBox(lags, opts?, squared?) — Ljung–Box test (statistic, pvalue, lags)
                                                                                  • -
                                                                                  • ewmaVolFunc(), ewmaVarFunc() - EWMA risk measures
                                                                                  • -
                                                                                  - -
                                                                                    -
                                                                                  • mergeSeries(), truncFrame() - Align multiple series
                                                                                  • -
                                                                                  • toDrawdownSeries() - Convert aligned columns to drawdown (value/peak - 1)
                                                                                  • -
                                                                                  • makePortfolio() - Weighted portfolio (eq_weights, inv_vol, max_div, min_vol_overweight)
                                                                                  • -
                                                                                  • correlMatrix(), trackingError(), infoRatio(), beta(), jensenAlpha()
                                                                                  • -
                                                                                  • autocorr(lag?, squared?) — per-constituent lag-k autocorrelation (number[])
                                                                                  • -
                                                                                  • maxDrawdown(), maxDrawdownBottomDate() - Per-column drawdown metrics
                                                                                  • -
                                                                                  • captureRatio(ratio, baseColumn?, opts?) - CAGR-based capture vs benchmark -(opts.freq optional; when omitted, uses frame data as-is)
                                                                                  • -
                                                                                  • ordLeastSquaresFit(), filterToBusinessDays(), resampleToPeriodEnd()
                                                                                  • -
                                                                                  - -
                                                                                    -
                                                                                  • fromNormal(), fromLognormal(), fromGbm(), fromMertonJumpGbm() — all accept -optional seed for reproducibility
                                                                                  • -
                                                                                  • toDateColumns(name, options?) — returns dates and columns -(as returns or cumulative prices)
                                                                                  • -
                                                                                  • randomGenerator(seed?) — seeded RNG for custom use
                                                                                  • -
                                                                                  - -
                                                                                    -
                                                                                  • fetchCaptorSeries(id) — fetch a single series from Captor Open API
                                                                                  • -
                                                                                  • fetchCaptorSeriesBatch(ids) — fetch multiple series
                                                                                  • -
                                                                                  - -
                                                                                    -
                                                                                  • reportHtml(frame, options?) — generate HTML report (cumulative performance, -annual returns, stats) from an OpenFrame. -Options: title, logoUrl, addLogo. -Countries for business-day metrics come from frame.countries.
                                                                                  • -
                                                                                  - -
                                                                                    -
                                                                                  • plotSeriesHtml(seriesOrFrame, options?) — generate full-page HTML with a line -chart of cumulative returns (base 1). -Works with OpenTimeSeries or OpenFrame (use mergeSeries("inner") first). -Options: title, logoUrl, addLogo, asDrawdown (plot drawdown series).
                                                                                  • -
                                                                                  • plotSeries(seriesOrFrame, options?) — async: writes HTML to file and optionally -opens in browser. -Options: title, logoUrl, addLogo, filename (default: ~/Documents/plot.html), -autoOpen (default: true).
                                                                                  • -
                                                                                  - -

                                                                                  API reference: https://captorab.github.io/openseries-ts/

                                                                                  -

                                                                                  To regenerate docs locally:

                                                                                  -
                                                                                  npm run docs
                                                                                  -
                                                                                  - -

                                                                                  This writes static HTML to docs/. To serve them via GitHub Pages:

                                                                                  -
                                                                                    -
                                                                                  1. Run npm run docs and commit the docs/ folder
                                                                                  2. -
                                                                                  3. In the repo: Settings → Pages
                                                                                  4. -
                                                                                  5. Under Source, choose Deploy from a branch
                                                                                  6. -
                                                                                  7. Branch: main (or your default branch), folder: /docs
                                                                                  8. -
                                                                                  -

                                                                                  Docs will be available at https://<username>.github.io/<repo>/.

                                                                                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                                                                  CommandDescription
                                                                                  npm run buildBuild dist/ (ESM + CJS + declarations)
                                                                                  npm run testRun Vitest test suite
                                                                                  npm run test:coverageRun tests with Istanbul coverage report
                                                                                  npm run lintRun ESLint on src/
                                                                                  npm run lint:fixESLint with auto-fix
                                                                                  npm run typecheckTypeScript check (tsc --noEmit)
                                                                                  npm run checkRun lint + typecheck
                                                                                  npm run docsGenerate API docs to docs/ (TypeDoc)
                                                                                  npm publishpublish to npm
                                                                                  - -

                                                                                  Generates an HTML portfolio report from Captor API timeseries -(cumulative performance, annual returns, statistics).

                                                                                  - - - - - - - - - - - - - - - - - - - - - -
                                                                                  CommandDescription
                                                                                  npm run reportReport with custom or default Captor series IDs
                                                                                  npm run report:irisPreset: Captor Iris Bond + Benchmark Index
                                                                                  npm run report:captorSame as report (default Captor IDs)
                                                                                  -

                                                                                  Default output (in ~/Documents): iris_report.html (Iris preset), captor_report.html -(default Captor preset), or report.html (custom --ids).

                                                                                  -

                                                                                  Options (pass after --): --ids id1 id2 ..., --iris, --title "Title", ---countries "SE,US", --from-date YYYY-MM-DD, --to-date YYYY-MM-DD, ---filename path, --no-open, --no-logo.

                                                                                  -

                                                                                  Examples:

                                                                                  -
                                                                                  npm run report -- --ids 638f681e 5b72a10c 5c1115fb
                                                                                  npm run report:iris -- --from-date 2023-01-01 --to-date 2024-12-31 --no-open -
                                                                                  - - -

                                                                                  Generates a full-page HTML line chart of cumulative returns (base 1) -from Captor API timeseries. -With the default Captor preset (no --ids), an equal-weight portfolio series is included.

                                                                                  - - - - - - - - - - - - - - - - - - - - - - - - - -
                                                                                  CommandDescription
                                                                                  npm run plotPlot with custom or default Captor series IDs
                                                                                  npm run plot:irisPreset: Captor Iris Bond + Benchmark Index
                                                                                  npm run plot:captorSame as plot
                                                                                  npm run plot:drawdownDEFAULT_SERIES as drawdown series
                                                                                  -

                                                                                  Default output (in ~/Documents): iris_plot.html (Iris preset), captor_plot.html -(default Captor preset), drawdown_plot.html (drawdown preset), or plot.html (custom --ids).

                                                                                  -

                                                                                  Options (pass after --): same as Report (--ids, --iris, --drawdown, --title, ---countries, --from-date, --to-date, --filename, --no-open, --no-logo).

                                                                                  -

                                                                                  Examples:

                                                                                  -
                                                                                  npm run plot:iris
                                                                                  npm run plot -- --ids id1 id2 --no-open --filename my-plot.html -
                                                                                  - - -

                                                                                  Simulates asset returns (lognormal), builds portfolio frame, computes efficient -frontier and max-Sharpe portfolio, and plots simulated portfolios, frontier, -and labeled points (assets, current, optimum). -Mirrors the Python openseries Jupyter notebook workflow.

                                                                                  - - - - - - - - - - - - - -
                                                                                  CommandDescription
                                                                                  npm run efficient-frontierRun efficient frontier demo
                                                                                  -

                                                                                  Options (pass after --): --simulations N (default: 5000), --points N -(default: 30), --seed N (default: 71), --countries "SE", --title "Title", ---filename path, --no-open, --no-logo.

                                                                                  -

                                                                                  Example:

                                                                                  -
                                                                                  npm run efficient-frontier -- --simulations 3000 --points 25 --no-open
                                                                                  -
                                                                                  - - -

                                                                                  Compares TypeScript openseries-ts metrics against Python openseries metrics. -Loads timeseries data from iris.json, computes metrics with the TS -implementation, and displays them side-by-side with Python metrics from -data.json.

                                                                                  -

                                                                                  Prerequisites: Run the Python script first to create the reference data in ~/Documents/:

                                                                                  -
                                                                                  python scripts/load_py_openseries_data.py
                                                                                  -
                                                                                  - -

                                                                                  This fetches the Captor Iris Bond timeseries from the API, saves it to -~/Documents/iris.json, and exports Python-calculated metrics to -~/Documents/data.json.

                                                                                  - - - - - - - - - - - - - -
                                                                                  CommandDescription
                                                                                  npm run compare-metricsCompare TS vs Python metrics (default: 4 decimal places)
                                                                                  -

                                                                                  Options: --decimals=N (pass after --).

                                                                                  -

                                                                                  Examples:

                                                                                  -
                                                                                  npm run compare-metrics
                                                                                  npm run compare-metrics -- --decimals=6 -
                                                                                  - -
                                                                                  diff --git a/docs/interfaces/EfficientFrontierPoint.html b/docs/interfaces/EfficientFrontierPoint.html deleted file mode 100644 index 4f97a9a..0000000 --- a/docs/interfaces/EfficientFrontierPoint.html +++ /dev/null @@ -1,5 +0,0 @@ -EfficientFrontierPoint | @captor/openseries-ts - v1.1.0
                                                                                  @captor/openseries-ts - v1.1.0
                                                                                    Preparing search index...

                                                                                    Interface EfficientFrontierPoint

                                                                                    interface EfficientFrontierPoint {
                                                                                        ret: number;
                                                                                        sharpe: number;
                                                                                        stdev: number;
                                                                                        weights: number[];
                                                                                    }
                                                                                    Index

                                                                                    Properties

                                                                                    Properties

                                                                                    ret: number
                                                                                    sharpe: number
                                                                                    stdev: number
                                                                                    weights: number[]
                                                                                    diff --git a/docs/interfaces/LagSeries.html b/docs/interfaces/LagSeries.html deleted file mode 100644 index 203cf79..0000000 --- a/docs/interfaces/LagSeries.html +++ /dev/null @@ -1,4 +0,0 @@ -LagSeries | @captor/openseries-ts - v1.1.0
                                                                                    @captor/openseries-ts - v1.1.0
                                                                                      Preparing search index...

                                                                                      Interface LagSeries

                                                                                      Autocorrelation or partial autocorrelation values indexed by lag.

                                                                                      -
                                                                                      interface LagSeries {
                                                                                          lags: number[];
                                                                                          values: number[];
                                                                                      }
                                                                                      Index

                                                                                      Properties

                                                                                      Properties

                                                                                      lags: number[]
                                                                                      values: number[]
                                                                                      diff --git a/docs/interfaces/OrdLeastSquaresResult.html b/docs/interfaces/OrdLeastSquaresResult.html deleted file mode 100644 index dd9160d..0000000 --- a/docs/interfaces/OrdLeastSquaresResult.html +++ /dev/null @@ -1,5 +0,0 @@ -OrdLeastSquaresResult | @captor/openseries-ts - v1.1.0
                                                                                      @captor/openseries-ts - v1.1.0
                                                                                        Preparing search index...

                                                                                        Interface OrdLeastSquaresResult

                                                                                        Result of Ordinary Least Squares regression (ord_least_squares_fit).

                                                                                        -
                                                                                        interface OrdLeastSquaresResult {
                                                                                            coefficient: number;
                                                                                            intercept: number;
                                                                                            rsquared: number;
                                                                                        }
                                                                                        Index

                                                                                        Properties

                                                                                        coefficient: number
                                                                                        intercept: number
                                                                                        rsquared: number
                                                                                        diff --git a/docs/interfaces/PlotSeriesOptions.html b/docs/interfaces/PlotSeriesOptions.html deleted file mode 100644 index 6cf8f9b..0000000 --- a/docs/interfaces/PlotSeriesOptions.html +++ /dev/null @@ -1,13 +0,0 @@ -PlotSeriesOptions | @captor/openseries-ts - v1.1.0
                                                                                        @captor/openseries-ts - v1.1.0
                                                                                          Preparing search index...

                                                                                          Interface PlotSeriesOptions

                                                                                          interface PlotSeriesOptions {
                                                                                              addLogo?: boolean;
                                                                                              asDrawdown?: boolean;
                                                                                              autoOpen?: boolean;
                                                                                              filename?: string;
                                                                                              logoUrl?: string;
                                                                                              title?: string;
                                                                                          }
                                                                                          Index

                                                                                          Properties

                                                                                          addLogo?: boolean

                                                                                          If true, show logo in upper left. Default: true.

                                                                                          -
                                                                                          asDrawdown?: boolean

                                                                                          If true, data is drawdown series (0 to negative decimals). Plot raw values * 100 as %, skip cumulative conversion.

                                                                                          -
                                                                                          autoOpen?: boolean

                                                                                          If true, open the HTML file in the default browser. Default: true.

                                                                                          -
                                                                                          filename?: string

                                                                                          Output file path. Default: ~/Documents/plot.html (or ~/ if Documents missing).

                                                                                          -
                                                                                          logoUrl?: string

                                                                                          Logo URL (e.g. company logo). Shown in upper left when addLogo is true.

                                                                                          -
                                                                                          title?: string

                                                                                          Optional title above the chart.

                                                                                          -
                                                                                          diff --git a/docs/interfaces/ReportOptions.html b/docs/interfaces/ReportOptions.html deleted file mode 100644 index 0ec3154..0000000 --- a/docs/interfaces/ReportOptions.html +++ /dev/null @@ -1,4 +0,0 @@ -ReportOptions | @captor/openseries-ts - v1.1.0
                                                                                          @captor/openseries-ts - v1.1.0
                                                                                            Preparing search index...

                                                                                            Interface ReportOptions

                                                                                            interface ReportOptions {
                                                                                                addLogo?: boolean;
                                                                                                logoUrl?: string;
                                                                                                title?: string;
                                                                                            }
                                                                                            Index

                                                                                            Properties

                                                                                            Properties

                                                                                            addLogo?: boolean
                                                                                            logoUrl?: string
                                                                                            title?: string
                                                                                            diff --git a/docs/interfaces/SharpePlotOptions.html b/docs/interfaces/SharpePlotOptions.html deleted file mode 100644 index afff4f8..0000000 --- a/docs/interfaces/SharpePlotOptions.html +++ /dev/null @@ -1,8 +0,0 @@ -SharpePlotOptions | @captor/openseries-ts - v1.1.0
                                                                                            @captor/openseries-ts - v1.1.0
                                                                                              Preparing search index...

                                                                                              Interface SharpePlotOptions

                                                                                              interface SharpePlotOptions {
                                                                                                  addLogo?: boolean;
                                                                                                  assetLabels?: string[];
                                                                                                  autoOpen?: boolean;
                                                                                                  filename?: string;
                                                                                                  logoUrl?: string;
                                                                                                  title?: string;
                                                                                              }
                                                                                              Index

                                                                                              Properties

                                                                                              addLogo?: boolean
                                                                                              assetLabels?: string[]

                                                                                              Asset labels for frontier/portfolio weight tooltips (e.g. from frame.columnLabels).

                                                                                              -
                                                                                              autoOpen?: boolean
                                                                                              filename?: string
                                                                                              logoUrl?: string
                                                                                              title?: string
                                                                                              diff --git a/docs/interfaces/SharpePlotPoint.html b/docs/interfaces/SharpePlotPoint.html deleted file mode 100644 index ac612d4..0000000 --- a/docs/interfaces/SharpePlotPoint.html +++ /dev/null @@ -1,7 +0,0 @@ -SharpePlotPoint | @captor/openseries-ts - v1.1.0
                                                                                              @captor/openseries-ts - v1.1.0
                                                                                                Preparing search index...

                                                                                                Interface SharpePlotPoint

                                                                                                Point on the efficient-frontier plot (stdev and ret in decimal form).

                                                                                                -
                                                                                                interface SharpePlotPoint {
                                                                                                    label: string;
                                                                                                    ret: number;
                                                                                                    stdev: number;
                                                                                                    weights?: { asset: string; weight: number }[];
                                                                                                }
                                                                                                Index

                                                                                                Properties

                                                                                                Properties

                                                                                                label: string
                                                                                                ret: number
                                                                                                stdev: number
                                                                                                weights?: { asset: string; weight: number }[]

                                                                                                Optional asset weights for tooltip (e.g. Current Portfolio, Max Sharpe).

                                                                                                -
                                                                                                diff --git a/docs/interfaces/SimulatedPortfolio.html b/docs/interfaces/SimulatedPortfolio.html deleted file mode 100644 index a667da1..0000000 --- a/docs/interfaces/SimulatedPortfolio.html +++ /dev/null @@ -1,5 +0,0 @@ -SimulatedPortfolio | @captor/openseries-ts - v1.1.0
                                                                                                @captor/openseries-ts - v1.1.0
                                                                                                  Preparing search index...

                                                                                                  Interface SimulatedPortfolio

                                                                                                  interface SimulatedPortfolio {
                                                                                                      ret: number;
                                                                                                      sharpe: number;
                                                                                                      stdev: number;
                                                                                                      weights: number[];
                                                                                                  }
                                                                                                  Index

                                                                                                  Properties

                                                                                                  Properties

                                                                                                  ret: number
                                                                                                  sharpe: number
                                                                                                  stdev: number
                                                                                                  weights: number[]
                                                                                                  diff --git a/docs/modules.html b/docs/modules.html deleted file mode 100644 index b71147b..0000000 --- a/docs/modules.html +++ /dev/null @@ -1 +0,0 @@ -@captor/openseries-ts - v1.1.0
                                                                                                  @captor/openseries-ts - v1.1.0
                                                                                                    Preparing search index...
                                                                                                    diff --git a/docs/types/CaptorSeriesResponse.html b/docs/types/CaptorSeriesResponse.html deleted file mode 100644 index 031159e..0000000 --- a/docs/types/CaptorSeriesResponse.html +++ /dev/null @@ -1,6 +0,0 @@ -CaptorSeriesResponse | @captor/openseries-ts - v1.1.0
                                                                                                    @captor/openseries-ts - v1.1.0
                                                                                                      Preparing search index...

                                                                                                      Type Alias CaptorSeriesResponse

                                                                                                      type CaptorSeriesResponse = {
                                                                                                          currency?: string;
                                                                                                          dates: string[];
                                                                                                          id: string;
                                                                                                          title: string | null;
                                                                                                          values: number[];
                                                                                                          [key: string]: unknown;
                                                                                                      }

                                                                                                      Indexable

                                                                                                      • [key: string]: unknown
                                                                                                      Index

                                                                                                      Properties

                                                                                                      Properties

                                                                                                      currency?: string
                                                                                                      dates: string[]
                                                                                                      id: string
                                                                                                      title: string | null
                                                                                                      values: number[]
                                                                                                      diff --git a/docs/types/CountryCode.html b/docs/types/CountryCode.html deleted file mode 100644 index 3802a83..0000000 --- a/docs/types/CountryCode.html +++ /dev/null @@ -1 +0,0 @@ -CountryCode | @captor/openseries-ts - v1.1.0
                                                                                                      @captor/openseries-ts - v1.1.0
                                                                                                        Preparing search index...

                                                                                                        Type Alias CountryCode

                                                                                                        CountryCode: string
                                                                                                        diff --git a/docs/types/DateRangeOptions.html b/docs/types/DateRangeOptions.html deleted file mode 100644 index 8575d11..0000000 --- a/docs/types/DateRangeOptions.html +++ /dev/null @@ -1,6 +0,0 @@ -DateRangeOptions | @captor/openseries-ts - v1.1.0
                                                                                                        @captor/openseries-ts - v1.1.0
                                                                                                          Preparing search index...

                                                                                                          Type Alias DateRangeOptions

                                                                                                          Options to slice a series by date range.

                                                                                                          -
                                                                                                          type DateRangeOptions = {
                                                                                                              fromDate?: string;
                                                                                                              monthsFromLast?: number;
                                                                                                              periodsInYearFixed?: number;
                                                                                                              toDate?: string;
                                                                                                          }
                                                                                                          Index

                                                                                                          Properties

                                                                                                          fromDate?: string
                                                                                                          monthsFromLast?: number
                                                                                                          periodsInYearFixed?: number
                                                                                                          toDate?: string
                                                                                                          diff --git a/docs/types/LiteralBizDayFreq.html b/docs/types/LiteralBizDayFreq.html deleted file mode 100644 index 489c6b0..0000000 --- a/docs/types/LiteralBizDayFreq.html +++ /dev/null @@ -1 +0,0 @@ -LiteralBizDayFreq | @captor/openseries-ts - v1.1.0
                                                                                                          @captor/openseries-ts - v1.1.0
                                                                                                            Preparing search index...

                                                                                                            Type Alias LiteralBizDayFreq

                                                                                                            LiteralBizDayFreq: "B" | "BME" | "BQE" | "BYE"
                                                                                                            diff --git a/docs/types/LiteralPortfolioWeightings.html b/docs/types/LiteralPortfolioWeightings.html deleted file mode 100644 index b20b7a8..0000000 --- a/docs/types/LiteralPortfolioWeightings.html +++ /dev/null @@ -1 +0,0 @@ -LiteralPortfolioWeightings | @captor/openseries-ts - v1.1.0
                                                                                                            @captor/openseries-ts - v1.1.0
                                                                                                              Preparing search index...

                                                                                                              Type Alias LiteralPortfolioWeightings

                                                                                                              LiteralPortfolioWeightings:
                                                                                                                  | "eq_weights"
                                                                                                                  | "inv_vol"
                                                                                                                  | "max_div"
                                                                                                                  | "min_vol_overweight"
                                                                                                              diff --git a/docs/types/LjungBoxResult.html b/docs/types/LjungBoxResult.html deleted file mode 100644 index 25a30e8..0000000 --- a/docs/types/LjungBoxResult.html +++ /dev/null @@ -1,2 +0,0 @@ -LjungBoxResult | @captor/openseries-ts - v1.1.0
                                                                                                              @captor/openseries-ts - v1.1.0
                                                                                                                Preparing search index...

                                                                                                                Type Alias LjungBoxResult

                                                                                                                LjungBoxResult: [statistic: number, pvalue: number, lags: number[]]

                                                                                                                Result of the Ljung-Box test.

                                                                                                                -
                                                                                                                diff --git a/docs/types/RandomGenerator.html b/docs/types/RandomGenerator.html deleted file mode 100644 index c51a47c..0000000 --- a/docs/types/RandomGenerator.html +++ /dev/null @@ -1 +0,0 @@ -RandomGenerator | @captor/openseries-ts - v1.1.0
                                                                                                                @captor/openseries-ts - v1.1.0
                                                                                                                  Preparing search index...

                                                                                                                  Type Alias RandomGenerator

                                                                                                                  RandomGenerator: () => number

                                                                                                                  Type Declaration

                                                                                                                    • (): number
                                                                                                                    • Returns number

                                                                                                                  diff --git a/docs/types/ResampleFreq.html b/docs/types/ResampleFreq.html deleted file mode 100644 index 538604f..0000000 --- a/docs/types/ResampleFreq.html +++ /dev/null @@ -1 +0,0 @@ -ResampleFreq | @captor/openseries-ts - v1.1.0
                                                                                                                  @captor/openseries-ts - v1.1.0
                                                                                                                    Preparing search index...

                                                                                                                    Type Alias ResampleFreq

                                                                                                                    ResampleFreq: "WE" | "ME" | "QE" | "YE"
                                                                                                                    From ea3e74dd3d505bdfad9b532c4241811a4c31d436 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:32:47 +0200 Subject: [PATCH 6/8] test: close the largest branch-coverage gaps, raise the threshold Branches sat at a 76% threshold while statements/functions/lines were gated at 95%. Investigated with istanbul's HTML report rather than guessing from the summary table: - simulation.ts (72.7% branches): entirely unused default-parameter branches (trading_days_in_year, seed, jump params) - every call site passed every argument explicitly. Added tests that omit them. - portfoliotools.ts (64.9%, the worst file): the existing "covers vol=0 branch" test used a strictly increasing price series, which doesn't actually produce zero variance - fixed it to use flat prices. Added coverage for efficientFrontier's default parameters, a singular-covariance-matrix input (duplicate assets, which the analytic solver can't resolve into a frontier), and preparePlotData's too-few-valid-returns guards. - series.ts (74.6%): ~15 risk-metric methods share a `dates.length < 2` (etc.) guard that was never exercised. One single-point-series test closes all of them at once. Net: branches 81.6% -> 85.73% overall (portfoliotools.ts alone 64.9% -> 80.7%, simulation.ts to 100%). Raised the threshold to 84% to lock in the improvement. Remaining gaps in frame.ts/report.ts/ plot.ts are mostly defensive `??` fallbacks and matrix-math edge cases (singular/degenerate inputs) that would need contrived inputs disproportionate to their value; left as documented residual rather than chased to 100%. Co-Authored-By: Claude Sonnet 5 --- tests/portfoliotools.test.ts | 60 ++++++++++++++++++++++++++++++------ tests/series.test.ts | 18 +++++++++++ tests/simulation.test.ts | 26 ++++++++++++++++ vitest.config.ts | 2 +- 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/tests/portfoliotools.test.ts b/tests/portfoliotools.test.ts index aa8afc9..7c06124 100644 --- a/tests/portfoliotools.test.ts +++ b/tests/portfoliotools.test.ts @@ -22,7 +22,7 @@ describe("simulatePortfolios", () => { expect(sims.length).toBeGreaterThanOrEqual(0); }); - it("handles constant returns (covers vol=0 branch)", () => { + it("handles zero-variance returns (covers vol=0 branch)", () => { const dates = [ "2020-01-01", "2020-01-02", @@ -30,18 +30,14 @@ describe("simulatePortfolios", () => { "2020-01-06", "2020-01-07", ]; - const s1 = OpenTimeSeries.fromArrays("A", dates, [100, 101, 102, 103, 104]); - const s2 = OpenTimeSeries.fromArrays("B", dates, [100, 101, 102, 103, 104]); - s1.valueToRet(); - s2.valueToRet(); + // Perfectly flat prices produce identically-zero returns every period, + // so portfolio variance (and thus vol) is exactly 0 regardless of weights. + const s1 = OpenTimeSeries.fromArrays("A", dates, [100, 100, 100, 100, 100]); + const s2 = OpenTimeSeries.fromArrays("B", dates, [100, 100, 100, 100, 100]); const frame = new OpenFrame([s1, s2], [0.5, 0.5]); - frame.mergeSeries("inner"); const sims = simulatePortfolios(frame, 10, 71); expect(sims.length).toBeGreaterThan(0); - // With identical returns, portfolio vol is 0, sharpe gets 0 from vol===0 branch - expect(sims.every((s) => s.stdev >= 0 && Number.isFinite(s.sharpe))).toBe( - true, - ); + expect(sims.every((s) => s.stdev === 0 && s.sharpe === 0)).toBe(true); }); it("first portfolio ret, stdev, sharpe match expected (normal 0.07/0.15, seed 71)", () => { @@ -83,6 +79,32 @@ describe("efficientFrontier", () => { expect(ef.maxSharpe).toBeDefined(); }); + it("works with default numPorts, seed, and frontierPoints", () => { + const frame = simulatedFrame({ + meanRet: 0.07, + meanVol: 0.15, + process: "normal", + }); + const ef = efficientFrontier(frame); + expect(ef.frontier.length).toBeGreaterThanOrEqual(1); + expect(ef.simulated.length).toBeGreaterThan(0); + }); + + it("returns an empty frontier for a singular covariance matrix (duplicate assets)", () => { + const dates = Array.from({ length: 30 }, (_, i) => { + const d = new Date(2020, 0, 1 + i); + return d.toISOString().slice(0, 10); + }); + const values = dates.map((_, i) => 100 + i + (i % 3)); + // Two constituents with identical values make the covariance matrix + // singular, so the analytic solver can't find a well-defined frontier. + const s1 = OpenTimeSeries.fromArrays("A", dates, values); + const s2 = OpenTimeSeries.fromArrays("B", dates, values); + const frame = new OpenFrame([s1, s2], [0.5, 0.5]); + const ef = efficientFrontier(frame, 100, 71, 10); + expect(ef.frontier).toEqual([]); + }); + it("works with RTRN constituents (uses returns directly)", () => { const sim = ReturnSimulation.fromGbm(3, 0.05, 0.1, 252, 252, 71); const dc = sim.toDateColumns("Asset", { end: "2020-12-31" }); @@ -191,4 +213,22 @@ describe("preparePlotData", () => { expect(Number.isFinite(p.ret)).toBe(true); }); }); + + it("skips assets with fewer than 2 valid returns and a current portfolio with fewer than 2 points", () => { + // Only 2 dates means each asset has just 1 return after slicing off the + // forced leading 0, so every asset is skipped alongside the 1-point + // current portfolio - only the (externally supplied) optimum remains. + const dates = ["2020-01-01", "2020-01-02"]; + const s1 = OpenTimeSeries.fromArrays("A", dates, [100, 101]); + const s2 = OpenTimeSeries.fromArrays("B", dates, [50, 52]); + const frame = new OpenFrame([s1, s2], [0.5, 0.5]); + const singlePointPortfolio = { dates: ["2020-01-01"], values: [100] }; + const optimum = { stdev: 0.1, ret: 0.05, sharpe: 0.5, weights: [0.5, 0.5] }; + const points = preparePlotData(frame, singlePointPortfolio, optimum); + const labels = points.map((p) => p.label); + expect(labels).not.toContain("A"); + expect(labels).not.toContain("B"); + expect(labels).not.toContain("Current Portfolio"); + expect(labels).toEqual(["Max Sharpe Portfolio"]); + }); }); diff --git a/tests/series.test.ts b/tests/series.test.ts index f956d01..1cca0ac 100644 --- a/tests/series.test.ts +++ b/tests/series.test.ts @@ -151,6 +151,24 @@ describe("OpenTimeSeries", () => { expect(ret).toBeNaN(); }); + it("risk metrics return their too-short-data sentinel for a single-point series", () => { + const series = OpenTimeSeries.fromArrays("Test", ["2020-01-01"], [100]); + expect(series.vol()).toBeNaN(); + expect(series.maxDrawdown()).toBe(0); + expect(series.varDown()).toBeNaN(); + expect(series.cvarDown()).toBeNaN(); + expect(series.downsideDeviation()).toBeNaN(); + expect(series.positiveShare()).toBeNaN(); + expect(series.worst()).toBeNaN(); + expect(series.skew()).toBeNaN(); + expect(series.kurtosis()).toBeNaN(); + expect(series.zScore()).toBeNaN(); + expect(series.volFromVar()).toBeNaN(); + expect(series.worstMonth()).toBeNaN(); + expect(series.geoRet()).toBeNaN(); + expect(series.arithmeticRet()).toBeNaN(); + }); + it("converts to returns and back", () => { const dates = ["2020-01-01", "2020-01-02", "2020-01-03"]; const values = [100, 105, 102]; diff --git a/tests/simulation.test.ts b/tests/simulation.test.ts index 451fc06..ee433c7 100644 --- a/tests/simulation.test.ts +++ b/tests/simulation.test.ts @@ -73,6 +73,32 @@ describe("ReturnSimulation", () => { }); }); + describe("default parameters", () => { + it("fromNormal works with default trading_days_in_year and no seed", () => { + const sim = ReturnSimulation.fromNormal(1, 0.05, 0.1, 50); + expect(sim.tradingDaysInYear).toBe(252); + expect(sim.dframe[0]).toHaveLength(50); + }); + + it("fromGbm works with default trading_days_in_year and no seed", () => { + const sim = ReturnSimulation.fromGbm(1, 0.05, 0.1, 50); + expect(sim.tradingDaysInYear).toBe(252); + expect(sim.dframe[0]).toHaveLength(50); + }); + + it("fromLognormal works with default trading_days_in_year and no seed", () => { + const sim = ReturnSimulation.fromLognormal(1, 0.05, 0.1, 50); + expect(sim.tradingDaysInYear).toBe(252); + expect(sim.dframe[0]).toHaveLength(50); + }); + + it("fromMertonJumpGbm works with default jump and year parameters and no seed", () => { + const sim = ReturnSimulation.fromMertonJumpGbm(1, 50, 0.05, 0.1, 0.1); + expect(sim.tradingDaysInYear).toBe(252); + expect(sim.dframe[0]).toHaveLength(50); + }); + }); + describe("processes - numerical results (seed=71)", () => { const to9 = (x: number) => x.toFixed(9); diff --git a/vitest.config.ts b/vitest.config.ts index 1ab2fbe..b251853 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -23,7 +23,7 @@ export default defineConfig({ ], thresholds: { statements: 95, - branches: 76, + branches: 84, functions: 95, lines: 95, }, From d7cecbd1af0139763684a59952e277ba2ea9aedb Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:44:38 +0200 Subject: [PATCH 7/8] chore: bump version to 1.2.0 The typed-error commit on this branch adds two new exported error classes (InvalidArgumentError, CaptorApiError) to the public API - an additive, backwards-compatible change, so minor per semver. Co-Authored-By: Claude Sonnet 5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4202b8d..1f43941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@captor/openseries-ts", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@captor/openseries-ts", - "version": "1.1.0", + "version": "1.2.0", "license": "BSD-3-Clause", "dependencies": { "date-holidays": "^3.26.8", diff --git a/package.json b/package.json index 0e59651..f937984 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@captor/openseries-ts", - "version": "1.1.0", + "version": "1.2.0", "type": "module", "description": "Tools for analyzing financial timeseries. TypeScript port of the Python openseries package.", "main": "dist/index.cjs", From bb961f5e6696b10f7f36bdee05b9e17c27151a59 Mon Sep 17 00:00:00 2001 From: Martin H Karrin Date: Tue, 22 Sep 2026 21:51:04 +0200 Subject: [PATCH 8/8] docs: update README docs-publishing instructions The manual "run npm run docs, commit docs/, configure Settings > Pages to deploy from a branch" instructions were superseded by the GitHub Actions docs workflow added earlier on this branch, which now builds and deploys docs automatically on push to master. npm run docs itself is still useful for a local preview, so it stays. Co-Authored-By: Claude Sonnet 5 --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 50c3522..e281343 100644 --- a/README.md +++ b/README.md @@ -122,20 +122,19 @@ console.log(series.autocorr()); // lag-1 autocorrelation of demeaned returns API reference: -To regenerate docs locally: +Docs are built with [TypeDoc](https://typedoc.org/) and deployed to GitHub +Pages automatically by +[`.github/workflows/docs.yml`](.github/workflows/docs.yml) on every push to +`master`. The generated `docs/` folder is not committed to the repo +(see `.gitignore`). + +To preview docs locally: ```bash npm run docs ``` -This writes static HTML to `docs/`. To serve them via GitHub Pages: - -1. Run `npm run docs` and commit the `docs/` folder -2. In the repo: **Settings → Pages** -3. Under **Source**, choose **Deploy from a branch** -4. Branch: `main` (or your default branch), folder: `/docs` - -Docs will be available at `https://.github.io//`. +This writes static HTML to `docs/`. ## Scripts