@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.
- package/ARCHITECTURE.md +229 -26
- package/README.md +64 -10
- package/dist/types/array.d.ts +13 -0
- package/dist/types/cache.d.ts +166 -0
- package/dist/types/chunk.d.ts +102 -0
- package/dist/types/color.d.ts +64 -0
- package/dist/types/convert/convert.d.ts +33 -0
- package/dist/types/convert/currency.d.ts +47 -0
- package/dist/types/convert/index.d.ts +9 -0
- package/dist/types/convert/registry.d.ts +55 -0
- package/dist/types/dates/civil.d.ts +146 -0
- package/dist/types/dates/duration.d.ts +83 -0
- package/dist/types/dates/format.d.ts +59 -0
- package/dist/types/dates/index.d.ts +4 -0
- package/dist/types/{dates.d.ts → dates/rfc3339.d.ts} +57 -3
- package/dist/types/errors.d.ts +77 -0
- package/dist/types/finance/amortization.d.ts +51 -0
- package/dist/types/finance/bond.d.ts +45 -0
- package/dist/types/finance/cashflow.d.ts +44 -0
- package/dist/types/finance/depreciation.d.ts +26 -0
- package/dist/types/finance/index.d.ts +16 -0
- package/dist/types/finance/indicators.d.ts +76 -0
- package/dist/types/finance/interest.d.ts +44 -0
- package/dist/types/finance/returns.d.ts +43 -0
- package/dist/types/finance/tvm.d.ts +50 -0
- package/dist/types/geo/angle.d.ts +4 -0
- package/dist/types/geo/bbox.d.ts +32 -0
- package/dist/types/geo/distance.d.ts +67 -0
- package/dist/types/geo/geohash.d.ts +63 -0
- package/dist/types/geo/geojson.d.ts +108 -0
- package/dist/types/geo/index-tree.d.ts +52 -0
- package/dist/types/geo/index.d.ts +11 -0
- package/dist/types/geo/mercator.d.ts +57 -0
- package/dist/types/geo/predicates.d.ts +44 -0
- package/dist/types/geo/ring.d.ts +80 -0
- package/dist/types/geo/simplify.d.ts +31 -0
- package/dist/types/geo/valid.d.ts +24 -0
- package/dist/types/geo/wkt.d.ts +16 -0
- package/dist/types/math/float64.d.ts +126 -3
- package/dist/types/math/format.d.ts +58 -0
- package/dist/types/math/index.d.ts +5 -0
- package/dist/types/math/mat4.d.ts +60 -0
- package/dist/types/math/project.d.ts +54 -0
- package/dist/types/math/solve.d.ts +67 -0
- package/dist/types/math/word.d.ts +82 -0
- package/dist/types/message.d.ts +52 -0
- package/dist/types/object.d.ts +151 -0
- package/dist/types/scan.d.ts +30 -0
- package/dist/types/schema.d.ts +24 -0
- package/dist/types/string.d.ts +96 -0
- package/dist/types/text/base64.d.ts +6 -4
- package/dist/types/text/email.d.ts +0 -1
- package/dist/types/text/host.d.ts +39 -8
- package/dist/types/text/i18n.d.ts +13 -1
- package/dist/types/text/index.d.ts +1 -0
- package/dist/types/text/misc.d.ts +15 -1
- package/dist/types/text/punycode.d.ts +45 -85
- package/docs/CONVERT.md +45 -0
- package/docs/DATES.md +78 -0
- package/docs/FINANCE.md +59 -0
- package/docs/GEO.md +114 -0
- package/docs/MATH.md +75 -0
- package/package.json +57 -4
- package/src/array.js +16 -0
- package/src/cache.js +206 -0
- package/src/chunk.js +159 -0
- package/src/color.js +125 -0
- package/src/convert/convert.js +59 -0
- package/src/convert/currency.js +74 -0
- package/src/convert/index.js +11 -0
- package/src/convert/registry.js +213 -0
- package/src/dates/civil.js +360 -0
- package/src/dates/duration.js +225 -0
- package/src/dates/format.js +238 -0
- package/src/dates/index.js +30 -0
- package/src/dates/rfc3339.js +621 -0
- package/src/errors.js +102 -0
- package/src/finance/amortization.js +50 -0
- package/src/finance/bond.js +100 -0
- package/src/finance/cashflow.js +122 -0
- package/src/finance/depreciation.js +54 -0
- package/src/finance/index.js +27 -0
- package/src/finance/indicators.js +207 -0
- package/src/finance/interest.js +63 -0
- package/src/finance/returns.js +90 -0
- package/src/finance/tvm.js +94 -0
- package/src/function.js +0 -2
- package/src/geo/angle.js +12 -0
- package/src/geo/bbox.js +80 -0
- package/src/geo/distance.js +155 -0
- package/src/geo/geohash.js +224 -0
- package/src/geo/geojson.js +361 -0
- package/src/geo/index-tree.js +294 -0
- package/src/geo/index.js +52 -0
- package/src/geo/mercator.js +124 -0
- package/src/geo/predicates.js +313 -0
- package/src/geo/ring.js +182 -0
- package/src/geo/simplify.js +130 -0
- package/src/geo/valid.js +142 -0
- package/src/geo/wkt.js +262 -0
- package/src/math/float64.js +228 -11
- package/src/math/format.js +157 -0
- package/src/math/index.js +5 -0
- package/src/math/mat4.js +131 -0
- package/src/math/project.js +49 -0
- package/src/math/solve.js +112 -0
- package/src/math/word.js +177 -0
- package/src/message.js +119 -0
- package/src/object.js +329 -0
- package/src/scan.js +42 -0
- package/src/schema.js +37 -0
- package/src/string.js +189 -0
- package/src/text/base64.js +15 -52
- package/src/text/email.js +0 -5
- package/src/text/host.js +515 -140
- package/src/text/i18n.js +13 -6
- package/src/text/identifiers.js +1 -1
- package/src/text/index.js +1 -0
- package/src/text/misc.js +81 -5
- package/src/text/punycode.js +235 -323
- 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;
|
|
@@ -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;
|