@jarenjs/core 0.9.2 → 0.34.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/ARCHITECTURE.md +229 -26
  2. package/README.md +64 -10
  3. package/dist/types/array.d.ts +13 -0
  4. package/dist/types/cache.d.ts +166 -0
  5. package/dist/types/chunk.d.ts +102 -0
  6. package/dist/types/color.d.ts +64 -0
  7. package/dist/types/convert/convert.d.ts +33 -0
  8. package/dist/types/convert/currency.d.ts +47 -0
  9. package/dist/types/convert/index.d.ts +9 -0
  10. package/dist/types/convert/registry.d.ts +55 -0
  11. package/dist/types/dates/civil.d.ts +146 -0
  12. package/dist/types/dates/duration.d.ts +83 -0
  13. package/dist/types/dates/format.d.ts +59 -0
  14. package/dist/types/dates/index.d.ts +4 -0
  15. package/dist/types/{dates.d.ts → dates/rfc3339.d.ts} +57 -3
  16. package/dist/types/errors.d.ts +77 -0
  17. package/dist/types/finance/amortization.d.ts +51 -0
  18. package/dist/types/finance/bond.d.ts +45 -0
  19. package/dist/types/finance/cashflow.d.ts +44 -0
  20. package/dist/types/finance/depreciation.d.ts +26 -0
  21. package/dist/types/finance/index.d.ts +16 -0
  22. package/dist/types/finance/indicators.d.ts +76 -0
  23. package/dist/types/finance/interest.d.ts +44 -0
  24. package/dist/types/finance/returns.d.ts +43 -0
  25. package/dist/types/finance/tvm.d.ts +50 -0
  26. package/dist/types/geo/angle.d.ts +4 -0
  27. package/dist/types/geo/bbox.d.ts +32 -0
  28. package/dist/types/geo/distance.d.ts +67 -0
  29. package/dist/types/geo/geohash.d.ts +63 -0
  30. package/dist/types/geo/geojson.d.ts +108 -0
  31. package/dist/types/geo/index-tree.d.ts +52 -0
  32. package/dist/types/geo/index.d.ts +11 -0
  33. package/dist/types/geo/mercator.d.ts +57 -0
  34. package/dist/types/geo/predicates.d.ts +44 -0
  35. package/dist/types/geo/ring.d.ts +80 -0
  36. package/dist/types/geo/simplify.d.ts +31 -0
  37. package/dist/types/geo/valid.d.ts +24 -0
  38. package/dist/types/geo/wkt.d.ts +16 -0
  39. package/dist/types/math/float64.d.ts +126 -3
  40. package/dist/types/math/format.d.ts +58 -0
  41. package/dist/types/math/index.d.ts +5 -0
  42. package/dist/types/math/mat4.d.ts +60 -0
  43. package/dist/types/math/project.d.ts +54 -0
  44. package/dist/types/math/solve.d.ts +67 -0
  45. package/dist/types/math/word.d.ts +82 -0
  46. package/dist/types/message.d.ts +52 -0
  47. package/dist/types/object.d.ts +151 -0
  48. package/dist/types/scan.d.ts +30 -0
  49. package/dist/types/schema.d.ts +24 -0
  50. package/dist/types/string.d.ts +96 -0
  51. package/dist/types/text/base64.d.ts +6 -4
  52. package/dist/types/text/email.d.ts +0 -1
  53. package/dist/types/text/host.d.ts +39 -8
  54. package/dist/types/text/i18n.d.ts +13 -1
  55. package/dist/types/text/index.d.ts +1 -0
  56. package/dist/types/text/misc.d.ts +15 -1
  57. package/dist/types/text/punycode.d.ts +45 -85
  58. package/docs/CONVERT.md +45 -0
  59. package/docs/DATES.md +78 -0
  60. package/docs/FINANCE.md +59 -0
  61. package/docs/GEO.md +114 -0
  62. package/docs/MATH.md +75 -0
  63. package/package.json +57 -4
  64. package/src/array.js +16 -0
  65. package/src/cache.js +206 -0
  66. package/src/chunk.js +159 -0
  67. package/src/color.js +125 -0
  68. package/src/convert/convert.js +59 -0
  69. package/src/convert/currency.js +74 -0
  70. package/src/convert/index.js +11 -0
  71. package/src/convert/registry.js +213 -0
  72. package/src/dates/civil.js +360 -0
  73. package/src/dates/duration.js +225 -0
  74. package/src/dates/format.js +238 -0
  75. package/src/dates/index.js +30 -0
  76. package/src/dates/rfc3339.js +621 -0
  77. package/src/errors.js +102 -0
  78. package/src/finance/amortization.js +50 -0
  79. package/src/finance/bond.js +100 -0
  80. package/src/finance/cashflow.js +122 -0
  81. package/src/finance/depreciation.js +54 -0
  82. package/src/finance/index.js +27 -0
  83. package/src/finance/indicators.js +207 -0
  84. package/src/finance/interest.js +63 -0
  85. package/src/finance/returns.js +90 -0
  86. package/src/finance/tvm.js +94 -0
  87. package/src/function.js +0 -2
  88. package/src/geo/angle.js +12 -0
  89. package/src/geo/bbox.js +80 -0
  90. package/src/geo/distance.js +155 -0
  91. package/src/geo/geohash.js +224 -0
  92. package/src/geo/geojson.js +361 -0
  93. package/src/geo/index-tree.js +294 -0
  94. package/src/geo/index.js +52 -0
  95. package/src/geo/mercator.js +124 -0
  96. package/src/geo/predicates.js +313 -0
  97. package/src/geo/ring.js +182 -0
  98. package/src/geo/simplify.js +130 -0
  99. package/src/geo/valid.js +142 -0
  100. package/src/geo/wkt.js +262 -0
  101. package/src/math/float64.js +228 -11
  102. package/src/math/format.js +157 -0
  103. package/src/math/index.js +5 -0
  104. package/src/math/mat4.js +131 -0
  105. package/src/math/project.js +49 -0
  106. package/src/math/solve.js +112 -0
  107. package/src/math/word.js +177 -0
  108. package/src/message.js +119 -0
  109. package/src/object.js +329 -0
  110. package/src/scan.js +42 -0
  111. package/src/schema.js +37 -0
  112. package/src/string.js +189 -0
  113. package/src/text/base64.js +15 -52
  114. package/src/text/email.js +0 -5
  115. package/src/text/host.js +515 -140
  116. package/src/text/i18n.js +13 -6
  117. package/src/text/identifiers.js +1 -1
  118. package/src/text/index.js +1 -0
  119. package/src/text/misc.js +81 -5
  120. package/src/text/punycode.js +235 -323
  121. package/src/dates.js +0 -371
@@ -0,0 +1,83 @@
1
+ export type DurationParts = {
2
+ negative: boolean;
3
+ years: number;
4
+ months: number;
5
+ weeks: number;
6
+ days: number;
7
+ hours: number;
8
+ minutes: number;
9
+ /**
10
+ * - may be fractional
11
+ */
12
+ seconds: number;
13
+ };
14
+ /**
15
+ * Decompose an ISO 8601 / RFC 3339 duration string into its parts.
16
+ *
17
+ * This is a deliberate **superset** of `isValidDuration` (rfc3339.js),
18
+ * which stays strict because it backs the JSON Schema `duration` format
19
+ * and must reject what the RFC rejects. This parser additionally accepts
20
+ * a leading `-` and a fractional component (`PT1.5H`), both of which ISO
21
+ * 8601 allows. So `parseDuration(s) !== null` does not imply
22
+ * `isValidDuration(s)`, and a consumer that needs RFC strictness must
23
+ * ask the validator, not this.
24
+ *
25
+ * Designators must appear coarse-to-fine within each half (`P1Y2M`, not
26
+ * `P2M1Y`), each at most once, and `W` does not mix with `Y`/`M`/`D`.
27
+ * Returns null for anything it cannot read, so callers branch rather
28
+ * than catch.
29
+ *
30
+ * @param {any} str - the duration string, e.g. `'P1Y2M3DT4H5M6S'`
31
+ * @returns {DurationParts | null}
32
+ * @example
33
+ * parseDuration('P1Y2M3DT4H5M6S');
34
+ * // { negative: false, years: 1, months: 2, weeks: 0, days: 3,
35
+ * // hours: 4, minutes: 5, seconds: 6 }
36
+ */
37
+ export declare function parseDuration(str: any): DurationParts | null;
38
+ /**
39
+ * The fixed-width span of a duration in milliseconds — weeks, days,
40
+ * hours, minutes and seconds only.
41
+ *
42
+ * Returns NaN when the duration carries years or months, because those
43
+ * have no width without a date to stand on. That is a deliberate refusal
44
+ * rather than an approximation: silently calling a month 30 days is how
45
+ * "in 1 month" lands on the wrong day.
46
+ *
47
+ * @param {DurationParts} parts
48
+ * @returns {number} signed milliseconds, or NaN if not fixed-width
49
+ */
50
+ export declare function durationToMs(parts: DurationParts): number;
51
+ /**
52
+ * Whether a duration has a width independent of where it is applied.
53
+ * @param {DurationParts} parts
54
+ * @returns {boolean}
55
+ */
56
+ export declare function isFixedDuration(parts: DurationParts): boolean;
57
+ /**
58
+ * Apply a duration to a parts record, the operation that gives the
59
+ * calendar fields their meaning. Coarse units apply first, so
60
+ * `2026-01-31` plus `P1M1D` is February's clamped 28th plus a day, not
61
+ * March 1st plus a month.
62
+ *
63
+ * @param {object} dateParts - a parts record from `parseRFC3339Parts`
64
+ * @param {DurationParts} duration
65
+ * @param {number} [sign] - 1 to add (default), -1 to subtract
66
+ * @returns {object} a new parts record
67
+ */
68
+ export declare function addDuration(dateParts: object, duration: DurationParts, sign?: number): object;
69
+ /**
70
+ * Whole calendar months between two dates, ignoring the time of day —
71
+ * the building block `diff` needs for the units that are not fixed-width.
72
+ *
73
+ * "Whole" is defined by `addToParts`, so that adding the result back to
74
+ * `from` never overshoots `to`. That makes 2026-01-31 → 2026-02-28 **one**
75
+ * month, not zero, because the clamping rule already says Jan 31 plus a
76
+ * month IS Feb 28. Keeping the two operations inverse is worth more than
77
+ * matching moment here, which reports zero for the same pair.
78
+ *
79
+ * @param {object} from - a parts record
80
+ * @param {object} to - a parts record
81
+ * @returns {number} signed month count
82
+ */
83
+ export declare function monthsBetween(from: object, to: object): number;
@@ -0,0 +1,59 @@
1
+ export type DateNames = {
2
+ /**
3
+ * - 12 wide month names, January first
4
+ */
5
+ months?: string[];
6
+ /**
7
+ * - 12 abbreviated month names
8
+ */
9
+ monthsShort?: string[];
10
+ /**
11
+ * - 7 wide weekday names, Sunday first
12
+ */
13
+ weekdays?: string[];
14
+ /**
15
+ * - 7 abbreviated weekday names
16
+ */
17
+ weekdaysShort?: string[];
18
+ /**
19
+ * - the AM and PM markers
20
+ */
21
+ meridiem?: [string, string];
22
+ };
23
+ /**
24
+ * Compile an LDML date pattern into a formatter.
25
+ *
26
+ * The returned function takes a parts record (`parseRFC3339Parts`) and
27
+ * returns a string. It closes over nothing mutable and is reusable.
28
+ *
29
+ * @param {string} pattern - an LDML pattern, e.g. `"yyyy-MM-dd'T'HH:mm:ssXXX"`
30
+ * @param {DateNames} [names] - locale names, required only if the
31
+ * pattern uses `MMM`/`MMMM`/`EEE`/`EEEE`/`a`
32
+ * @returns {(parts: object) => string} the compiled formatter
33
+ * @throws {TypeError} on an unterminated quote, or a name token with no
34
+ * provider for it
35
+ * @example
36
+ * const iso = compileDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
37
+ * iso(parseRFC3339Parts('2026-07-27T14:30:05+02:00'));
38
+ * // '2026-07-27T14:30:05+02:00'
39
+ */
40
+ export declare function compileDateFormat(pattern: string, names?: DateNames): (parts: object) => string;
41
+ /**
42
+ * Render a parts record back to RFC 3339, the inverse of
43
+ * `parseRFC3339Parts`. The value keeps the shape it had: a record with
44
+ * no time half comes back a `full-date`, one with no date half a
45
+ * `full-time`, and the offset is the record's own rather than UTC.
46
+ *
47
+ * The round trip preserves the *value*, not necessarily the spelling: a
48
+ * fractional second is emitted only when non-zero and without trailing
49
+ * zeros, so `…:05.250Z` comes back `…:05.25Z`. The parts record holds
50
+ * the fraction as a number, so the original digit count is not
51
+ * recoverable — a consumer that must reproduce the input byte for byte
52
+ * (JOSL, which round-trips TOML) has to keep the literal text itself.
53
+ *
54
+ * @param {object} parts - a parts record
55
+ * @returns {string} an RFC 3339 string
56
+ * @example
57
+ * formatRFC3339Parts(parseRFC3339Parts('2026-07-27')); // '2026-07-27'
58
+ */
59
+ export declare function formatRFC3339Parts(parts: object): string;
@@ -0,0 +1,4 @@
1
+ export * from './rfc3339.js';
2
+ export * from './civil.js';
3
+ export * from './format.js';
4
+ export * from './duration.js';
@@ -1,14 +1,13 @@
1
+ import { isLeapYear } from './civil.js';
2
+ export { isLeapYear };
1
3
  export declare const CONST_TICKS_SECOND = 1000;
2
4
  export declare const CONST_TICKS_HOUR: number;
3
5
  export declare const CONST_TICKS_DAY: number;
4
6
  export declare const CONST_TIME_INSERTDATE = "1970-01-01T";
5
7
  export declare const CONST_DATE_APPENDTIME = "T00:00:00Z";
6
8
  export declare const CONST_RFC3339_DAYS: readonly number[];
7
- export declare const CONST_RFC3339_REGEX_ISDATE: RegExp;
8
- export declare const CONST_RFC3339_REGEX_ISTIME: RegExp;
9
9
  export declare function isDateType(data: any): boolean;
10
10
  export declare function isDateishType(data: any): boolean;
11
- export declare function isLeapYear(year: any): boolean;
12
11
  export declare function isDateOnlyInRange(year?: number, month?: number, day?: number): boolean;
13
12
  export declare function isDateOnlyRFC3339(str: any): boolean;
14
13
  export declare function isTimeOnlyInRange(hrs?: number, min?: number, sec?: number, tzh?: number, tzm?: number, tzSign?: number): boolean;
@@ -17,6 +16,59 @@ export declare function isDateTimeRFC3339(str: any): boolean;
17
16
  export declare function getDateTypeOfDateOnlyRFC3339(str: any, def?: undefined): Date | undefined;
18
17
  export declare function getDateTypeOfTimeOnlyRFC3339(str: any, def?: undefined): Date | undefined;
19
18
  export declare function getDateTypeOfDateTimeRFC3339(str: any, def?: undefined): Date | undefined;
19
+ export declare function getEpochOfDateOnlyRFC3339(str: any, def?: undefined): number | undefined;
20
+ export declare function getEpochOfTimeOnlyRFC3339(str: any, def?: undefined): number | undefined;
21
+ export declare function getEpochOfDateTimeRFC3339(str: any, def?: undefined): number | undefined;
22
+ /**
23
+ * Decompose an RFC 3339 date, time, or date-time string into its lexical
24
+ * components, without allocating a `Date` and without shifting anything
25
+ * to UTC — the components are the ones the string spells out, which is
26
+ * what a query grouping by year or month asks for.
27
+ *
28
+ * A missing half reads as -1: a full-date has no `hours`, a full-time no
29
+ * `year`. `offset` is minutes east of UTC, `null` only for a bare
30
+ * full-date (which RFC 3339 leaves offset-less).
31
+ *
32
+ * @param {any} str - The value to decompose
33
+ * @returns {{ year: number, month: number, day: number, hours: number,
34
+ * minutes: number, seconds: number, offset: number | null } | null}
35
+ * the components, or null when str is not an RFC 3339 value
36
+ * @example
37
+ * parseRFC3339Parts('2026-07-27T14:30:05.5+02:00');
38
+ * // { year: 2026, month: 7, day: 27, hours: 14, minutes: 30,
39
+ * // seconds: 5.5, offset: 120 }
40
+ */
41
+ export declare function parseRFC3339Parts(str: any): {
42
+ year: number;
43
+ month: number;
44
+ day: number;
45
+ hours: number;
46
+ minutes: number;
47
+ seconds: number;
48
+ offset: number | null;
49
+ } | null;
50
+ /**
51
+ * Milliseconds since 1970-01-01T00:00:00Z for RFC 3339 components that
52
+ * carry a date. Components without a date (a full-time) return NaN, as
53
+ * do out-of-range instants.
54
+ *
55
+ * A bare full-date has no offset and is read as UTC midnight. Note JS
56
+ * has no leap seconds: a `:60` second rolls into the following minute.
57
+ *
58
+ * @param {{ year: number, month: number, day: number, hours: number,
59
+ * minutes: number, seconds: number, offset: number | null }} parts -
60
+ * components from {@link parseRFC3339Parts}
61
+ * @returns {number} milliseconds since the epoch, or NaN
62
+ */
63
+ export declare function epochOfRFC3339Parts(parts: {
64
+ year: number;
65
+ month: number;
66
+ day: number;
67
+ hours: number;
68
+ minutes: number;
69
+ seconds: number;
70
+ offset: number | null;
71
+ }): number;
20
72
  /**
21
73
  * Validates a duration string per RFC 3339.
22
74
  * Duration format: P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
@@ -77,3 +129,5 @@ export declare function getDateTypeOfISODateTime(str: string, def?: any): Date |
77
129
  * @returns {Date|undefined} - The parsed Date or default value
78
130
  */
79
131
  export declare function getDateTypeOfISOTime(str: string, def?: any): Date | undefined;
132
+ export declare function getEpochOfISODateTime(str: any, def?: undefined): number | undefined;
133
+ export declare function getEpochOfISOTime(str: any, def?: undefined): number | undefined;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @file The suite's one coded-error contract. Every engine error that
3
+ * carries a stable diagnosis code derives from {@link CodedError}; the
4
+ * canonical form is the structured triple `{ code, reason, docPath |
5
+ * dataPath }`, and `message` is COMPOSED from it for the channels that
6
+ * have no structured reader (an uncaught throw, a console, a CI
7
+ * transcript, a model reading `{ error: err.message }`).
8
+ *
9
+ * The rendering decision, fixed here so every package agrees:
10
+ *
11
+ * `${code}: ${reason}` — no location
12
+ * `${code}: ${reason} at ${docPath}` — a document location
13
+ * `${code}: ${reason} in data ${dataPath}` — a data location
14
+ * `${code}: ${reason} at ${d} in data ${p}` — both
15
+ *
16
+ * `docPath` points into the offending *document* (a query, a stylesheet,
17
+ * an app document); `dataPath` points into the offending *data* the
18
+ * document was applied to. They are different facts and stay separately
19
+ * readable and separately identifiable — `at` always means document,
20
+ * `in data` always means data. A root pointer (`''`) is a real location
21
+ * and renders as `at ''`; absence is `undefined` and renders nothing.
22
+ * Absence must never be normalized to `''` — the AI repair loop's
23
+ * `docPath ?? instancePath ?? ''` fallback chain relies on `undefined`
24
+ * to fall through, and `''` is a legitimate root pointer.
25
+ *
26
+ * Cause presence uses the `hasOwn` form: the constructor takes an
27
+ * options bag, and `Object.hasOwn(options, 'cause')` decides whether an
28
+ * own `cause` is installed — so a host that threw `undefined` (passed as
29
+ * `{ cause: undefined }`) stays distinguishable from "no cause" (no
30
+ * options, or an options bag without the key). Positional-adapter
31
+ * subclasses that translate an optional trailing `cause` parameter MUST
32
+ * map an `undefined` argument to "no cause", never to
33
+ * `{ cause: undefined }`.
34
+ *
35
+ * Deliberately OUTSIDE this contract: `ValidationError`
36
+ * (keyword-keyed, locale-rendered, has its own `toJSON`), the
37
+ * `LabeledSyntaxError` family (`source`/`position` over a source
38
+ * string), and josl's line/column family (`line`/`column`/`hint`).
39
+ * Different shapes for different consumers — do not "finish the job" by
40
+ * folding them in.
41
+ *
42
+ * Localization: `@jarenjs/locales` keys its catalogs by JSON Schema
43
+ * KEYWORD (`form/minLength`, …), not by error code — coded errors are
44
+ * localizable by nothing today. Stated so nobody assumes otherwise; a
45
+ * code-keyed catalog would be a new locales feature, not a property of
46
+ * this base.
47
+ */
48
+ /**
49
+ * Base class for every coded error in the suite. Subclasses are thin
50
+ * per-package adapters that fix the public `name` (passed as a string
51
+ * literal because bundles are minified and a mangled class name must
52
+ * not leak into `error.name`) and translate their historical positional
53
+ * signatures into the location/options form.
54
+ */
55
+ export declare class CodedError extends Error {
56
+ code: string;
57
+ reason: string;
58
+ docPath: string | undefined;
59
+ dataPath: string | undefined;
60
+ /**
61
+ * @param {string} name - The public class name for `error.name`
62
+ * @param {string} code - Stable diagnosis code
63
+ * @param {string} reason - The bare reason; `message` is composed from
64
+ * `code`, `reason` and the location and must not be pre-composed
65
+ * @param {string | { docPath?: string, dataPath?: string }} [location]
66
+ * - A string is a `docPath`; the object form carries either or both
67
+ * @param {{ cause?: unknown }} [options] - `cause` is installed as an
68
+ * own property exactly when the key is present (`hasOwn` form),
69
+ * preserving "host threw `undefined`" as distinct from "no cause"
70
+ */
71
+ constructor(name: string, code: string, reason: string, location?: string | {
72
+ docPath?: string;
73
+ dataPath?: string;
74
+ }, options?: {
75
+ cause?: unknown;
76
+ });
77
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @file Loan amortization. Given a principal, a periodic
3
+ * rate and a term, produce the period-by-period split of each payment
4
+ * into interest and principal with the running balance.
5
+ */
6
+ export type AmortRow = {
7
+ /**
8
+ * 1-based period index
9
+ */
10
+ period: number;
11
+ /**
12
+ * total payment this period
13
+ */
14
+ payment: number;
15
+ /**
16
+ * interest portion
17
+ */
18
+ interest: number;
19
+ /**
20
+ * principal portion
21
+ */
22
+ principal: number;
23
+ /**
24
+ * remaining balance after this payment
25
+ */
26
+ balance: number;
27
+ };
28
+ /**
29
+ * @typedef {object} AmortRow
30
+ * @property {number} period 1-based period index
31
+ * @property {number} payment total payment this period
32
+ * @property {number} interest interest portion
33
+ * @property {number} principal principal portion
34
+ * @property {number} balance remaining balance after this payment
35
+ */
36
+ /**
37
+ * Build a full amortization schedule. The payment is derived from the
38
+ * standard annuity formula unless an explicit `payment` is supplied
39
+ * (e.g. a rounded real-world instalment); the final period absorbs any
40
+ * rounding residue so the balance lands exactly on zero.
41
+ *
42
+ * @param {number} principal loan amount (positive)
43
+ * @param {number} rate periodic interest rate
44
+ * @param {number} nper number of periods
45
+ * @param {{ payment?: number, type?: number }} [opts]
46
+ * @returns {AmortRow[]}
47
+ */
48
+ export declare function amortizationSchedule(principal: number, rate: number, nper: number, opts?: {
49
+ payment?: number;
50
+ type?: number;
51
+ }): AmortRow[];
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @file Bond math: price, yield-to-maturity, Macaulay and
3
+ * modified duration, and convexity. Basic day-count only (level coupons,
4
+ * whole periods to maturity); exotic conventions are out of scope.
5
+ *
6
+ * Rates and the coupon rate are annual; `freq` coupons are paid per year.
7
+ */
8
+ /**
9
+ * Clean price of a coupon bond.
10
+ * @param {number} face par/redemption value
11
+ * @param {number} couponRate annual coupon rate
12
+ * @param {number} ytm annual yield to maturity
13
+ * @param {number} years years to maturity
14
+ * @param {number} [freq] coupons per year
15
+ * @returns {number}
16
+ */
17
+ export declare function bondPrice(face: number, couponRate: number, ytm: number, years: number, freq?: number): number;
18
+ /**
19
+ * Yield to maturity from a market price (iterative).
20
+ * @param {number} price @param {number} face @param {number} couponRate
21
+ * @param {number} years @param {number} [freq]
22
+ * @returns {number}
23
+ */
24
+ export declare function bondYTM(price: number, face: number, couponRate: number, years: number, freq?: number): number;
25
+ /**
26
+ * Macaulay duration (in years).
27
+ * @param {number} face @param {number} couponRate @param {number} ytm
28
+ * @param {number} years @param {number} [freq]
29
+ * @returns {number}
30
+ */
31
+ export declare function macaulayDuration(face: number, couponRate: number, ytm: number, years: number, freq?: number): number;
32
+ /**
33
+ * Modified duration.
34
+ * @param {number} face @param {number} couponRate @param {number} ytm
35
+ * @param {number} years @param {number} [freq]
36
+ * @returns {number}
37
+ */
38
+ export declare function modifiedDuration(face: number, couponRate: number, ytm: number, years: number, freq?: number): number;
39
+ /**
40
+ * Convexity (in years²).
41
+ * @param {number} face @param {number} couponRate @param {number} ytm
42
+ * @param {number} years @param {number} [freq]
43
+ * @returns {number}
44
+ */
45
+ export declare function convexity(face: number, couponRate: number, ytm: number, years: number, freq?: number): number;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @file Cash-flow analysis: NPV, IRR, MIRR and their
3
+ * date-indexed variants XNPV/XIRR. Built on `math/solve`. Cash flows are
4
+ * arrays with element `t` occurring at period `t` (index 0 = now).
5
+ */
6
+ /**
7
+ * Net present value of a period-indexed cash-flow series.
8
+ * @param {number} rate discount rate per period
9
+ * @param {number[]} cashflows cashflows[t] at period t (index 0 = t0)
10
+ * @returns {number}
11
+ */
12
+ export declare function npv(rate: number, cashflows: number[]): number;
13
+ /**
14
+ * Internal rate of return: the rate for which `npv` is zero. Newton with
15
+ * a bisection fallback; returns `NaN` if no rate is found.
16
+ * @param {number[]} cashflows
17
+ * @param {number} [guess]
18
+ * @returns {number}
19
+ */
20
+ export declare function irr(cashflows: number[], guess?: number): number;
21
+ /**
22
+ * Modified internal rate of return.
23
+ * @param {number[]} cashflows
24
+ * @param {number} financeRate rate paid on negative flows
25
+ * @param {number} reinvestRate rate earned on positive flows
26
+ * @returns {number}
27
+ */
28
+ export declare function mirr(cashflows: number[], financeRate: number, reinvestRate: number): number;
29
+ /**
30
+ * Date-indexed NPV. `dates` may be `Date`s or ms timestamps.
31
+ * @param {number} rate annual discount rate
32
+ * @param {number[]} cashflows
33
+ * @param {Array<Date|number>} dates
34
+ * @returns {number}
35
+ */
36
+ export declare function xnpv(rate: number, cashflows: number[], dates: Array<Date | number>): number;
37
+ /**
38
+ * Date-indexed IRR.
39
+ * @param {number[]} cashflows
40
+ * @param {Array<Date|number>} dates
41
+ * @param {number} [guess]
42
+ * @returns {number}
43
+ */
44
+ export declare function xirr(cashflows: number[], dates: Array<Date | number>, guess?: number): number;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file Depreciation schedules: straight-line,
3
+ * declining-balance (double-declining when factor = 2) and
4
+ * sum-of-years-digits. Each returns an array of per-period depreciation
5
+ * amounts of length `life`.
6
+ */
7
+ /**
8
+ * Straight-line depreciation: equal charge each period.
9
+ * @param {number} cost @param {number} salvage @param {number} life periods
10
+ * @returns {number[]}
11
+ */
12
+ export declare function straightLine(cost: number, salvage: number, life: number): number[];
13
+ /**
14
+ * Declining-balance depreciation. `factor` = 2 is double-declining. Never
15
+ * depreciates below salvage; the final periods absorb the remainder.
16
+ * @param {number} cost @param {number} salvage @param {number} life
17
+ * @param {number} [factor]
18
+ * @returns {number[]}
19
+ */
20
+ export declare function decliningBalance(cost: number, salvage: number, life: number, factor?: number): number[];
21
+ /**
22
+ * Sum-of-years-digits depreciation.
23
+ * @param {number} cost @param {number} salvage @param {number} life
24
+ * @returns {number[]}
25
+ */
26
+ export declare function sumOfYearsDigits(cost: number, salvage: number, life: number): number[];
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file `@jarenjs/core/finance` — the finance & trading formula library.
3
+ * Pure, zero runtime dependencies (imports only `@jarenjs/core/math`).
4
+ * Every export is a plain function over numbers/number-arrays, reusable
5
+ * by any package: a calculator, a trading dashboard or a backtester. The
6
+ * math lives here; orchestration (which variable to solve, forms, display)
7
+ * lives in the consumer.
8
+ */
9
+ export { pmt, pv, fv, nper, rate } from './tvm.js';
10
+ export { npv, irr, mirr, xnpv, xirr } from './cashflow.js';
11
+ export { amortizationSchedule } from './amortization.js';
12
+ export { simpleInterest, compoundAmount, compoundInterest, nominalToEffective, effectiveToNominal, continuousCompound, } from './interest.js';
13
+ export { straightLine, decliningBalance, sumOfYearsDigits } from './depreciation.js';
14
+ export { bondPrice, bondYTM, macaulayDuration, modifiedDuration, convexity, } from './bond.js';
15
+ export { sma, ema, wma, macd, rsi, bollinger, stochastic, atr, roc, } from './indicators.js';
16
+ export { cagr, holdingPeriodReturn, returnsOf, volatility, sharpe, maxDrawdown, } from './returns.js';
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @file Technical / trading indicators over a price or OHLC
3
+ * series. Every function returns an array **aligned** to the input (same
4
+ * length), with `null` in warm-up positions where the indicator is not
5
+ * yet defined. Single-pass where the math allows; `Float64Array` inputs
6
+ * are accepted (array-like reads only).
7
+ */
8
+ /**
9
+ * Simple moving average.
10
+ * @param {ArrayLike<number>} values @param {number} period
11
+ * @returns {Array<number|null>}
12
+ */
13
+ export declare function sma(values: ArrayLike<number>, period: number): Array<number | null>;
14
+ /**
15
+ * Exponential moving average (SMA-seeded).
16
+ * @param {ArrayLike<number>} values @param {number} period
17
+ * @returns {Array<number|null>}
18
+ */
19
+ export declare function ema(values: ArrayLike<number>, period: number): Array<number | null>;
20
+ /**
21
+ * Weighted moving average (linear weights 1..period).
22
+ * @param {ArrayLike<number>} values @param {number} period
23
+ * @returns {Array<number|null>}
24
+ */
25
+ export declare function wma(values: ArrayLike<number>, period: number): Array<number | null>;
26
+ /**
27
+ * MACD: line = EMA(fast) − EMA(slow), signal = EMA(line, signalPeriod),
28
+ * histogram = line − signal. Each is an aligned array.
29
+ * @param {ArrayLike<number>} values
30
+ * @param {number} [fast] @param {number} [slow] @param {number} [signalPeriod]
31
+ * @returns {{ macd: Array<number|null>, signal: Array<number|null>, histogram: Array<number|null> }}
32
+ */
33
+ export declare function macd(values: ArrayLike<number>, fast?: number, slow?: number, signalPeriod?: number): {
34
+ macd: Array<number | null>;
35
+ signal: Array<number | null>;
36
+ histogram: Array<number | null>;
37
+ };
38
+ /**
39
+ * Relative Strength Index (Wilder's smoothing).
40
+ * @param {ArrayLike<number>} values @param {number} [period]
41
+ * @returns {Array<number|null>}
42
+ */
43
+ export declare function rsi(values: ArrayLike<number>, period?: number): Array<number | null>;
44
+ /**
45
+ * Bollinger Bands (population standard deviation).
46
+ * @param {ArrayLike<number>} values @param {number} [period] @param {number} [k]
47
+ * @returns {{ middle: Array<number|null>, upper: Array<number|null>, lower: Array<number|null> }}
48
+ */
49
+ export declare function bollinger(values: ArrayLike<number>, period?: number, k?: number): {
50
+ middle: Array<number | null>;
51
+ upper: Array<number | null>;
52
+ lower: Array<number | null>;
53
+ };
54
+ /**
55
+ * Stochastic oscillator (%K and its %D moving average).
56
+ * @param {ArrayLike<number>} high @param {ArrayLike<number>} low @param {ArrayLike<number>} close
57
+ * @param {number} [kPeriod] @param {number} [dPeriod]
58
+ * @returns {{ k: Array<number|null>, d: Array<number|null> }}
59
+ */
60
+ export declare function stochastic(high: ArrayLike<number>, low: ArrayLike<number>, close: ArrayLike<number>, kPeriod?: number, dPeriod?: number): {
61
+ k: Array<number | null>;
62
+ d: Array<number | null>;
63
+ };
64
+ /**
65
+ * Average True Range (Wilder's smoothing).
66
+ * @param {ArrayLike<number>} high @param {ArrayLike<number>} low @param {ArrayLike<number>} close
67
+ * @param {number} [period]
68
+ * @returns {Array<number|null>}
69
+ */
70
+ export declare function atr(high: ArrayLike<number>, low: ArrayLike<number>, close: ArrayLike<number>, period?: number): Array<number | null>;
71
+ /**
72
+ * Rate of change (percent) over `period`.
73
+ * @param {ArrayLike<number>} values @param {number} [period]
74
+ * @returns {Array<number|null>}
75
+ */
76
+ export declare function roc(values: ArrayLike<number>, period?: number): Array<number | null>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @file Interest math: simple and compound interest, nominal
3
+ * ↔ effective rate conversion, and continuous compounding. All pure.
4
+ */
5
+ /**
6
+ * Simple interest accrued (not the total).
7
+ * @param {number} principal @param {number} rate per period @param {number} time periods
8
+ * @returns {number}
9
+ */
10
+ export declare function simpleInterest(principal: number, rate: number, time: number): number;
11
+ /**
12
+ * Compound amount (principal + interest) after `time` years compounded
13
+ * `periodsPerYear` times per year.
14
+ * @param {number} principal @param {number} annualRate @param {number} time years
15
+ * @param {number} [periodsPerYear]
16
+ * @returns {number}
17
+ */
18
+ export declare function compoundAmount(principal: number, annualRate: number, time: number, periodsPerYear?: number): number;
19
+ /**
20
+ * Compound interest earned (amount − principal).
21
+ * @param {number} principal @param {number} annualRate @param {number} time
22
+ * @param {number} [periodsPerYear]
23
+ * @returns {number}
24
+ */
25
+ export declare function compoundInterest(principal: number, annualRate: number, time: number, periodsPerYear?: number): number;
26
+ /**
27
+ * Effective annual rate (APY/EAR) from a nominal annual rate compounded
28
+ * `periodsPerYear` times.
29
+ * @param {number} nominal @param {number} periodsPerYear
30
+ * @returns {number}
31
+ */
32
+ export declare function nominalToEffective(nominal: number, periodsPerYear: number): number;
33
+ /**
34
+ * Nominal annual rate from an effective annual rate.
35
+ * @param {number} effective @param {number} periodsPerYear
36
+ * @returns {number}
37
+ */
38
+ export declare function effectiveToNominal(effective: number, periodsPerYear: number): number;
39
+ /**
40
+ * Continuously-compounded amount: `P·e^(rt)`.
41
+ * @param {number} principal @param {number} annualRate @param {number} time
42
+ * @returns {number}
43
+ */
44
+ export declare function continuousCompound(principal: number, annualRate: number, time: number): number;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file Return & risk statistics: CAGR, holding-period
3
+ * return, volatility, Sharpe ratio and maximum drawdown. Pure.
4
+ */
5
+ /**
6
+ * Compound annual growth rate.
7
+ * @param {number} begin @param {number} end @param {number} years
8
+ * @returns {number}
9
+ */
10
+ export declare function cagr(begin: number, end: number, years: number): number;
11
+ /**
12
+ * Holding-period return, including any income.
13
+ * @param {number} begin @param {number} end @param {number} [income]
14
+ * @returns {number}
15
+ */
16
+ export declare function holdingPeriodReturn(begin: number, end: number, income?: number): number;
17
+ /**
18
+ * Convert a price series to a per-step simple-return series.
19
+ * @param {ArrayLike<number>} prices
20
+ * @returns {number[]}
21
+ */
22
+ export declare function returnsOf(prices: ArrayLike<number>): number[];
23
+ /**
24
+ * Volatility: the (sample) standard deviation of a return series.
25
+ * @param {ArrayLike<number>} returns
26
+ * @param {boolean} [population] use population (÷N) instead of sample (÷N−1)
27
+ * @returns {number}
28
+ */
29
+ export declare function volatility(returns: ArrayLike<number>, population?: boolean): number;
30
+ /**
31
+ * Sharpe ratio: mean excess return over its volatility.
32
+ * @param {ArrayLike<number>} returns
33
+ * @param {number} [riskFree] per-step risk-free rate
34
+ * @returns {number}
35
+ */
36
+ export declare function sharpe(returns: ArrayLike<number>, riskFree?: number): number;
37
+ /**
38
+ * Maximum drawdown of an equity curve: the largest peak-to-trough drop as
39
+ * a positive fraction (0.2 = a 20% drawdown).
40
+ * @param {ArrayLike<number>} values
41
+ * @returns {number}
42
+ */
43
+ export declare function maxDrawdown(values: ArrayLike<number>): number;