hazo_core 2.0.3 → 2.3.0
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/README.md +2 -2
- package/config/hazo_core_config.ini +4 -0
- package/dist/http/rate_limit.d.ts +49 -0
- package/dist/http/rate_limit.d.ts.map +1 -0
- package/dist/http/rate_limit.js +84 -0
- package/dist/http/rate_limit.js.map +1 -0
- package/dist/index.client.d.ts +4 -2
- package/dist/index.client.d.ts.map +1 -1
- package/dist/index.client.js +2 -1
- package/dist/index.client.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/dates.d.ts +8 -1
- package/dist/utils/dates.d.ts.map +1 -1
- package/dist/utils/dates.js +7 -1
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/index.d.ts +23 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +119 -6
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/partial_date.d.ts +90 -0
- package/dist/utils/partial_date.d.ts.map +1 -0
- package/dist/utils/partial_date.js +357 -0
- package/dist/utils/partial_date.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,8 +70,8 @@ import { loadConfig, defineConfig, createLogger, createDebug,
|
|
|
70
70
|
|
|
71
71
|
```ts
|
|
72
72
|
import { withRetry, isUuid, parseListLimit, parseListOffset,
|
|
73
|
-
createDebouncedSaver } from 'hazo_core';
|
|
74
|
-
// all
|
|
73
|
+
createDebouncedSaver, rateLimit, withRateLimit, getClientIp } from 'hazo_core';
|
|
74
|
+
// all are env-agnostic and also available from 'hazo_core/client'
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
### Browser-safe subset
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
; Override with HAZO_INCLUDE_STACK=1 to force on.
|
|
8
8
|
include_stack = false
|
|
9
9
|
|
|
10
|
+
[format]
|
|
11
|
+
; BCP 47 locale for number/currency/date formatting (default: en-AU)
|
|
12
|
+
; locale = en-AU
|
|
13
|
+
|
|
10
14
|
[env]
|
|
11
15
|
; This section is an example of the per-env overlay convention.
|
|
12
16
|
; Create hazo_core_config.<env>.ini alongside this file to override values
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Options for {@link rateLimit}. */
|
|
2
|
+
export interface RateLimitOptions {
|
|
3
|
+
/** Bucket identifier (e.g. IP address or user ID). */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Namespace / feature name (prevents cross-feature key collisions). */
|
|
6
|
+
scope: string;
|
|
7
|
+
/** Maximum requests allowed within the window. */
|
|
8
|
+
limit: number;
|
|
9
|
+
/** Window duration in milliseconds. */
|
|
10
|
+
window_ms: number;
|
|
11
|
+
}
|
|
12
|
+
export type RateLimitResult = {
|
|
13
|
+
ok: true;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
retry_after_seconds: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Fixed-window token-bucket check. Increments the bucket for `scope:key` and
|
|
20
|
+
* reports whether the caller is still under `limit` within `window_ms`.
|
|
21
|
+
*
|
|
22
|
+
* @example rateLimit({ key: '1.2.3.4', scope: 'login', limit: 5, window_ms: 60_000 })
|
|
23
|
+
*/
|
|
24
|
+
export declare function rateLimit(opts: RateLimitOptions): RateLimitResult;
|
|
25
|
+
/** Clear all buckets. Used in tests only. */
|
|
26
|
+
export declare function _clearBuckets(): void;
|
|
27
|
+
type RateLimitRouteHandler = (req: Request, ...args: unknown[]) => Promise<Response> | Response;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps an HTTP route handler with rate limiting. Returns 429 with
|
|
30
|
+
* `Retry-After`/`X-RateLimit-Limit` headers when the limit is exceeded.
|
|
31
|
+
*
|
|
32
|
+
* Keys by client IP (`getClientIp`) by default; pass `getKey` to key by
|
|
33
|
+
* something else (e.g. a session/user id).
|
|
34
|
+
*
|
|
35
|
+
* Does NOT import from 'next' — uses the standard Request/Response types.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* export const POST = withRateLimit(myHandler, { scope: 'login', limit: 5, window_ms: 15 * 60 * 1000 });
|
|
39
|
+
*/
|
|
40
|
+
export declare function withRateLimit(handler: RateLimitRouteHandler, opts: Omit<RateLimitOptions, 'key'> & {
|
|
41
|
+
getKey?: (req: Request) => string;
|
|
42
|
+
}): RateLimitRouteHandler;
|
|
43
|
+
/**
|
|
44
|
+
* Best-effort client IP from standard proxy headers.
|
|
45
|
+
* Checks `x-forwarded-for` (first entry), then `x-real-ip`; falls back to `'unknown'`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getClientIp(req: Request): string;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=rate_limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate_limit.d.ts","sourceRoot":"","sources":["../../src/http/rate_limit.ts"],"names":[],"mappings":"AAeA,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC;AAS/C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,CAsBjE;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAMD,KAAK,qBAAqB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAEhG;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAA;CAAE,GAC1E,qBAAqB,CAsBvB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAIhD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// file_description: In-memory token-bucket rate limiter plus a framework-agnostic
|
|
2
|
+
// HTTP route-handler wrapper.
|
|
3
|
+
//
|
|
4
|
+
// `rateLimit`/`_clearBuckets` are a simple per-process Map-backed fixed-window
|
|
5
|
+
// counter — single-process only; swap for a Postgres/Redis-backed store before
|
|
6
|
+
// running multiple instances behind a load balancer.
|
|
7
|
+
//
|
|
8
|
+
// `withRateLimit`/`getClientIp` wrap a route handler using the standard
|
|
9
|
+
// Request/Response types (not 'next/server'), so the same code works as-is in
|
|
10
|
+
// a Next.js App Router route handler — NextRequest extends Request and a
|
|
11
|
+
// returned plain Response is a valid handler return value — mirroring
|
|
12
|
+
// `withRequestIdRouteHandler` in `request_id_middleware.ts`.
|
|
13
|
+
//
|
|
14
|
+
// Promoted from taxclientdocs' lib/rate-limit/{token-bucket,middleware}.ts.
|
|
15
|
+
const _buckets = new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Fixed-window token-bucket check. Increments the bucket for `scope:key` and
|
|
18
|
+
* reports whether the caller is still under `limit` within `window_ms`.
|
|
19
|
+
*
|
|
20
|
+
* @example rateLimit({ key: '1.2.3.4', scope: 'login', limit: 5, window_ms: 60_000 })
|
|
21
|
+
*/
|
|
22
|
+
export function rateLimit(opts) {
|
|
23
|
+
const { key, scope, limit, window_ms } = opts;
|
|
24
|
+
const bucketKey = `${scope}:${key}`;
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
const existing = _buckets.get(bucketKey);
|
|
27
|
+
if (!existing || now - existing.window_start >= window_ms) {
|
|
28
|
+
// New window
|
|
29
|
+
_buckets.set(bucketKey, { count: 1, window_start: now });
|
|
30
|
+
return { ok: true };
|
|
31
|
+
}
|
|
32
|
+
if (existing.count < limit) {
|
|
33
|
+
existing.count += 1;
|
|
34
|
+
return { ok: true };
|
|
35
|
+
}
|
|
36
|
+
// Limit exceeded
|
|
37
|
+
const elapsed = now - existing.window_start;
|
|
38
|
+
const retry_after_seconds = Math.ceil((window_ms - elapsed) / 1000);
|
|
39
|
+
return { ok: false, retry_after_seconds };
|
|
40
|
+
}
|
|
41
|
+
/** Clear all buckets. Used in tests only. */
|
|
42
|
+
export function _clearBuckets() {
|
|
43
|
+
_buckets.clear();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Wraps an HTTP route handler with rate limiting. Returns 429 with
|
|
47
|
+
* `Retry-After`/`X-RateLimit-Limit` headers when the limit is exceeded.
|
|
48
|
+
*
|
|
49
|
+
* Keys by client IP (`getClientIp`) by default; pass `getKey` to key by
|
|
50
|
+
* something else (e.g. a session/user id).
|
|
51
|
+
*
|
|
52
|
+
* Does NOT import from 'next' — uses the standard Request/Response types.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* export const POST = withRateLimit(myHandler, { scope: 'login', limit: 5, window_ms: 15 * 60 * 1000 });
|
|
56
|
+
*/
|
|
57
|
+
export function withRateLimit(handler, opts) {
|
|
58
|
+
const getKey = opts.getKey ?? getClientIp;
|
|
59
|
+
return async (req, ...args) => {
|
|
60
|
+
const key = getKey(req);
|
|
61
|
+
const result = rateLimit({ ...opts, key });
|
|
62
|
+
if (!result.ok) {
|
|
63
|
+
return Response.json({ error: 'Too many requests. Please try again later.' }, {
|
|
64
|
+
status: 429,
|
|
65
|
+
headers: {
|
|
66
|
+
'Retry-After': String(result.retry_after_seconds),
|
|
67
|
+
'X-RateLimit-Limit': String(opts.limit),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return handler(req, ...args);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Best-effort client IP from standard proxy headers.
|
|
76
|
+
* Checks `x-forwarded-for` (first entry), then `x-real-ip`; falls back to `'unknown'`.
|
|
77
|
+
*/
|
|
78
|
+
export function getClientIp(req) {
|
|
79
|
+
const xff = req.headers.get('x-forwarded-for');
|
|
80
|
+
if (xff)
|
|
81
|
+
return xff.split(',')[0].trim();
|
|
82
|
+
return req.headers.get('x-real-ip') ?? 'unknown';
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=rate_limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate_limit.js","sourceRoot":"","sources":["../../src/http/rate_limit.ts"],"names":[],"mappings":"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"}
|
package/dist/index.client.d.ts
CHANGED
|
@@ -12,11 +12,13 @@ export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoC
|
|
|
12
12
|
export type { HazoErrorOptions, HazoValidationErrorOptions, ValidationIssue, HazoAuthErrorOptions, HazoNotFoundErrorOptions, HazoConflictErrorOptions, HazoConfigErrorOptions, HazoExternalErrorOptions, HazoRateLimitErrorOptions, HazoUnavailableErrorOptions, HazoInternalErrorOptions, } from './errors/index.js';
|
|
13
13
|
export { setBrowserCorrelationId, getContext, getCorrelationId, withContext, } from './context/client.js';
|
|
14
14
|
export type { HazoContext } from './context/types.js';
|
|
15
|
-
export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
|
|
16
|
-
export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, } from './utils/index.js';
|
|
15
|
+
export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
|
|
16
|
+
export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './utils/index.js';
|
|
17
17
|
export { fetchWithRequestId } from './http/fetch_with_request_id.client.js';
|
|
18
18
|
export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
|
|
19
19
|
export { parseListLimit, parseListOffset } from './http/list_params.js';
|
|
20
|
+
export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
|
|
21
|
+
export type { RateLimitOptions, RateLimitResult } from './http/rate_limit.js';
|
|
20
22
|
export { createLogger } from './logger/index.client.js';
|
|
21
23
|
export type { HazoCoreLogger } from './logger/index.js';
|
|
22
24
|
//# sourceMappingURL=index.client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI9E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.client.js
CHANGED
|
@@ -15,11 +15,12 @@ export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoC
|
|
|
15
15
|
// Context (browser — mutable ref, NOT AsyncLocalStorage)
|
|
16
16
|
export { setBrowserCorrelationId, getContext, getCorrelationId, withContext, } from './context/client.js';
|
|
17
17
|
// Safe utils (no Node deps)
|
|
18
|
-
export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
|
|
18
|
+
export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
|
|
19
19
|
// HTTP — browser-safe variants (Fetch API, no AsyncLocalStorage)
|
|
20
20
|
export { fetchWithRequestId } from './http/fetch_with_request_id.client.js';
|
|
21
21
|
export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
|
|
22
22
|
export { parseListLimit, parseListOffset } from './http/list_params.js';
|
|
23
|
+
export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
|
|
23
24
|
// Logger — client-side stub emits to the browser console (server version
|
|
24
25
|
// requires node:module + process.stderr, neither available in browsers/edge)
|
|
25
26
|
export { createLogger } from './logger/index.client.js';
|
package/dist/index.client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.client.js","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEvE,4DAA4D;AAC5D,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.client.js","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEvE,4DAA4D;AAC5D,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAgB1B,iEAAiE;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG5F,yEAAyE;AACzE,6EAA6E;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { REQUEST_ID_HEADER, HAZO_ERROR_SYMBOL, HAZO_SINGLETONS_KEY } from './constants.js';
|
|
8
8
|
export { registerSingleton, getSingleton, globalSingleton, resetGlobalSingleton } from './singleton/index.js';
|
|
9
|
-
export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
|
|
10
|
-
export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, } from './utils/index.js';
|
|
9
|
+
export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
|
|
10
|
+
export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './utils/index.js';
|
|
11
11
|
export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoConflictError, HazoConfigError, HazoExternalError, HazoRateLimitError, HazoUnavailableError, HazoInternalError, fromZodValidation, fromZodConfig, } from './errors/index.js';
|
|
12
12
|
export type { HazoErrorOptions, HazoValidationErrorOptions, ValidationIssue, HazoAuthErrorOptions, HazoNotFoundErrorOptions, HazoConflictErrorOptions, HazoConfigErrorOptions, HazoExternalErrorOptions, HazoRateLimitErrorOptions, HazoUnavailableErrorOptions, HazoInternalErrorOptions, } from './errors/index.js';
|
|
13
13
|
export { withContext, getContext, getCorrelationId, } from './context/index.js';
|
|
@@ -22,4 +22,6 @@ export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/re
|
|
|
22
22
|
export { fetchWithRequestId } from './http/fetch_with_request_id.js';
|
|
23
23
|
export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
|
|
24
24
|
export { parseListLimit, parseListOffset } from './http/list_params.js';
|
|
25
|
+
export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
|
|
26
|
+
export type { RateLimitOptions, RateLimitResult } from './http/rate_limit.js';
|
|
25
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9G,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9G,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACjH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { REQUEST_ID_HEADER, HAZO_ERROR_SYMBOL, HAZO_SINGLETONS_KEY } from './con
|
|
|
9
9
|
// Singleton registry
|
|
10
10
|
export { registerSingleton, getSingleton, globalSingleton, resetGlobalSingleton } from './singleton/index.js';
|
|
11
11
|
// Utilities
|
|
12
|
-
export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
|
|
12
|
+
export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
|
|
13
13
|
// Errors
|
|
14
14
|
export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoConflictError, HazoConfigError, HazoExternalError, HazoRateLimitError, HazoUnavailableError, HazoInternalError, fromZodValidation, fromZodConfig, } from './errors/index.js';
|
|
15
15
|
// Context (server — AsyncLocalStorage)
|
|
@@ -25,4 +25,5 @@ export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/re
|
|
|
25
25
|
export { fetchWithRequestId } from './http/fetch_with_request_id.js';
|
|
26
26
|
export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
|
|
27
27
|
export { parseListLimit, parseListOffset } from './http/list_params.js';
|
|
28
|
+
export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
|
|
28
29
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,YAAY;AACZ,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,YAAY;AACZ,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAgB1B,SAAS;AACT,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,uCAAuC;AACvC,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGjH,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO;AACP,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/utils/dates.d.ts
CHANGED
|
@@ -18,7 +18,14 @@
|
|
|
18
18
|
* 'iso' — YYYY-MM-DD (locale-independent, SSR-safe)
|
|
19
19
|
* 'dmy' — DD/MM/YYYY
|
|
20
20
|
* 'mdy' — MM/DD/YYYY
|
|
21
|
-
* 'locale' — Use environment locale (NOT SSR-safe; may cause hydration mismatch)
|
|
21
|
+
* 'locale' — Use environment locale (NOT SSR-safe; may cause hydration mismatch).
|
|
22
|
+
* @deprecated SSR-unsafe: the server and browser can resolve different
|
|
23
|
+
* default locales, so the same date renders differently on each,
|
|
24
|
+
* which is exactly the shape of bug that causes Next.js hydration
|
|
25
|
+
* mismatches. `format_date` THROWS when called with 'locale' outside
|
|
26
|
+
* production (see below) to surface this during development; in
|
|
27
|
+
* production it still renders (unchanged behavior for existing
|
|
28
|
+
* deployments). Prefer an explicit locale, or 'iso'/'dmy'/'mdy'.
|
|
22
29
|
*/
|
|
23
30
|
export type DateFormat = 'iso' | 'dmy' | 'mdy' | 'locale';
|
|
24
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH
|
|
1
|
+
{"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,MAAM,GAAE,UAAgC,GACvC,MAAM,CA8CR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACpC,MAAM,GAAE,UAAgC,GACvC,MAAM,CAQR"}
|
package/dist/utils/dates.js
CHANGED
|
@@ -51,7 +51,13 @@ export function format_date(date, format = DEFAULT_DATE_FORMAT) {
|
|
|
51
51
|
case 'mdy':
|
|
52
52
|
return `${month}/${day}/${year}`;
|
|
53
53
|
case 'locale':
|
|
54
|
-
// Uses environment locale — not SSR-safe (may cause hydration mismatch in Next.js)
|
|
54
|
+
// Uses environment locale — not SSR-safe (may cause hydration mismatch in Next.js).
|
|
55
|
+
// Outside production this throws instead of silently rendering inconsistent output
|
|
56
|
+
// (FR-032 Stage 4); production behavior is unchanged so already-deployed callers
|
|
57
|
+
// that rely on it don't break.
|
|
58
|
+
if (process.env['NODE_ENV'] !== 'production') {
|
|
59
|
+
throw new Error("format_date('locale') is SSR-unsafe — pass an explicit locale or use 'iso'/'dmy'/'mdy'.");
|
|
60
|
+
}
|
|
55
61
|
return date_obj.toLocaleDateString();
|
|
56
62
|
default:
|
|
57
63
|
return `${year}-${month}-${day}`;
|
package/dist/utils/dates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkBH;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAe,KAAK,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsC,EACtC,SAAqB,mBAAmB;IAExC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,uBAAuB;IACvB,IAAI,QAAc,CAAC;IACnB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,oFAAoF;QACpF,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,gBAAgB;IAChB,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAExD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,GAAG,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,QAAQ;YACX,oFAAoF;YACpF,mFAAmF;YACnF,iFAAiF;YACjF,+BAA+B;YAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,YAAY,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QAEvC;YACE,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAsC,EACtC,EAAoC,EACpC,SAAqB,mBAAmB;IAExC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAEvC,IAAI,QAAQ,IAAI,MAAM;QAAE,OAAO,GAAG,QAAQ,MAAM,MAAM,EAAE,CAAC;IACzD,IAAI,QAAQ;QAAE,OAAO,QAAQ,QAAQ,EAAE,CAAC;IACxC,IAAI,MAAM;QAAE,OAAO,MAAM,MAAM,EAAE,CAAC;IAClC,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -34,17 +34,31 @@ export declare function sleep(ms: number): Promise<void>;
|
|
|
34
34
|
export declare function formatBytes(bytes: number, decimals?: number): string;
|
|
35
35
|
export { format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './dates.js';
|
|
36
36
|
export type { DateFormat } from './dates.js';
|
|
37
|
+
export { getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './partial_date.js';
|
|
38
|
+
export type { PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './partial_date.js';
|
|
37
39
|
export { withRetry } from './retry.js';
|
|
38
40
|
export type { RetryOptions } from './retry.js';
|
|
39
41
|
export { isUuid } from './uuid.js';
|
|
40
42
|
export { createDebouncedSaver } from './debounced_saver.js';
|
|
41
43
|
export type { DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, } from './debounced_saver.js';
|
|
44
|
+
/**
|
|
45
|
+
* Best-effort load of `[format].locale` from `hazo_core_config.ini`. Cached
|
|
46
|
+
* per process; safe to call repeatedly. Exported (module-internal — not part
|
|
47
|
+
* of the public `hazo_core`/`hazo_core/client` surface) so tests can `await`
|
|
48
|
+
* it directly instead of polling. `configDir` is test-only; production calls
|
|
49
|
+
* always use `loadConfig`'s default (`process.cwd()/config`).
|
|
50
|
+
*/
|
|
51
|
+
export declare function __loadIniFormatLocaleForTests(configDir?: string): Promise<void>;
|
|
52
|
+
/** Test-only: clear cached locale resolution state between test cases. */
|
|
53
|
+
export declare function __resetFormatLocaleCacheForTests(): void;
|
|
42
54
|
/**
|
|
43
55
|
* Format a date as "28 May 2026"
|
|
56
|
+
* @deprecated Use hazo_i18n/format when available
|
|
44
57
|
*/
|
|
45
58
|
export declare function formatDateShort(date: Date | string): string;
|
|
46
59
|
/**
|
|
47
60
|
* Format a date as "Wednesday, 28 May 2026"
|
|
61
|
+
* @deprecated Use hazo_i18n/format when available
|
|
48
62
|
*/
|
|
49
63
|
export declare function formatDateLong(date: Date | string): string;
|
|
50
64
|
/**
|
|
@@ -69,10 +83,12 @@ export interface FormatCurrencyOptions {
|
|
|
69
83
|
compact?: boolean;
|
|
70
84
|
}
|
|
71
85
|
/**
|
|
72
|
-
* Format a number as currency
|
|
86
|
+
* Format a number as currency. Locale defaults to `en-AU` — override via
|
|
87
|
+
* HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's `[format].locale`.
|
|
73
88
|
*
|
|
74
89
|
* @param amount - The value to format.
|
|
75
90
|
* @param options - {@link FormatCurrencyOptions} (currency, fractionDigits, absolute, compact).
|
|
91
|
+
* @deprecated Use hazo_i18n/format when available
|
|
76
92
|
*/
|
|
77
93
|
export declare function formatCurrency(amount: number, options?: FormatCurrencyOptions): string;
|
|
78
94
|
/**
|
|
@@ -80,18 +96,23 @@ export declare function formatCurrency(amount: number, options?: FormatCurrencyO
|
|
|
80
96
|
*
|
|
81
97
|
* @param fraction - Value in the 0–1 range (0.05 = 5%).
|
|
82
98
|
* @param decimals - Fraction digits to show. Default 1.
|
|
99
|
+
* @deprecated Use hazo_i18n/format when available
|
|
83
100
|
*/
|
|
84
101
|
export declare function formatPercent(fraction: number, decimals?: number): string;
|
|
85
102
|
/**
|
|
86
|
-
* Format a number with optional decimal places.
|
|
103
|
+
* Format a number with optional decimal places. Locale defaults to `en-AU` —
|
|
104
|
+
* override via HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's
|
|
105
|
+
* `[format].locale`.
|
|
87
106
|
* @example formatNumber(1234567.89) → "1,234,567.89"
|
|
88
107
|
* @example formatNumber(1234567.89, 0) → "1,234,568"
|
|
108
|
+
* @deprecated Use hazo_i18n/format when available
|
|
89
109
|
*/
|
|
90
110
|
export declare function formatNumber(n: number, decimals?: number): string;
|
|
91
111
|
/**
|
|
92
112
|
* Format a boolean as a human-readable string.
|
|
93
113
|
* @example formatBoolean(true) → "Yes"
|
|
94
114
|
* @example formatBoolean(false) → "No"
|
|
115
|
+
* @deprecated Use hazo_i18n/format when available — hardcodes "Yes"/"No" (English-only)
|
|
95
116
|
*/
|
|
96
117
|
export declare function formatBoolean(val: boolean): string;
|
|
97
118
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/index.js
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
// The type assertion avoids the TS2305 error when checked against the wrong installed version.
|
|
3
3
|
import * as uuidPkg from 'uuid';
|
|
4
4
|
const uuidv7 = uuidPkg['v7'];
|
|
5
|
+
// zod is a plain dependency (no Node built-ins) so it's safe to import statically
|
|
6
|
+
// here even though this file is also re-exported by the browser entry
|
|
7
|
+
// (index.client.ts) — see the "Format locale resolution" section below.
|
|
8
|
+
import { z } from 'zod';
|
|
5
9
|
export { getCurrentEnv } from './env.js';
|
|
6
10
|
// ---------------------------------------------------------------------------
|
|
7
11
|
// Request ID generation
|
|
@@ -88,6 +92,10 @@ export function formatBytes(bytes, decimals = 2) {
|
|
|
88
92
|
// ---------------------------------------------------------------------------
|
|
89
93
|
export { format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './dates.js';
|
|
90
94
|
// ---------------------------------------------------------------------------
|
|
95
|
+
// Partial/fuzzy dates (year-only, month-year, GEDCOM qualifiers, BCE, ranges)
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
export { getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './partial_date.js';
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
91
99
|
// Retry with backoff
|
|
92
100
|
// ---------------------------------------------------------------------------
|
|
93
101
|
export { withRetry } from './retry.js';
|
|
@@ -100,6 +108,102 @@ export { isUuid } from './uuid.js';
|
|
|
100
108
|
// ---------------------------------------------------------------------------
|
|
101
109
|
export { createDebouncedSaver } from './debounced_saver.js';
|
|
102
110
|
// ---------------------------------------------------------------------------
|
|
111
|
+
// Format locale resolution (FR-032 Stage 3)
|
|
112
|
+
//
|
|
113
|
+
// formatCurrency/formatNumber/formatDateShort/formatDateLong used to hardcode
|
|
114
|
+
// the Intl locale to the literal 'en-AU'. This section makes that
|
|
115
|
+
// configurable while defaulting to 'en-AU' so existing consumers see no
|
|
116
|
+
// output change unless they opt in.
|
|
117
|
+
//
|
|
118
|
+
// Resolution order: HAZO_CORE_FORMAT_LOCALE env var > [format].locale in
|
|
119
|
+
// hazo_core_config.ini (via loadConfig) > 'en-AU' default.
|
|
120
|
+
//
|
|
121
|
+
// The INI lookup goes through `loadConfig`, which pulls in `node:fs` /
|
|
122
|
+
// `dotenv` (via ../config/index.js) — imports that must never land in the
|
|
123
|
+
// browser bundle produced from this same file via index.client.ts. It is
|
|
124
|
+
// therefore loaded with `optional_import`, not a static import, and — per
|
|
125
|
+
// the 2.0.3 CHANGE_LOG entry — the specifier is passed as a *variable*
|
|
126
|
+
// (`configModulePath`), not a string literal: Vite's import-analysis plugin
|
|
127
|
+
// resolves literal dynamic-import specifiers before honoring
|
|
128
|
+
// `@vite-ignore`/`webpackIgnore`/`turbopackIgnore`, so a literal would still
|
|
129
|
+
// get eagerly bundled. In a real browser the load simply fails (no such
|
|
130
|
+
// chunk to fetch); `optional_import` swallows that and formatters fall back
|
|
131
|
+
// to the env var or default. Because the load is async, the INI value can
|
|
132
|
+
// only take effect once it resolves — the very first formatter call(s) in a
|
|
133
|
+
// process may still see the env-var-or-default value even when an INI
|
|
134
|
+
// override exists; subsequent calls pick it up.
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
const DEFAULT_FORMAT_LOCALE = 'en-AU';
|
|
137
|
+
const formatConfigSchema = z.object({
|
|
138
|
+
format: z
|
|
139
|
+
.object({
|
|
140
|
+
locale: z.string().optional(),
|
|
141
|
+
})
|
|
142
|
+
.prefault({}),
|
|
143
|
+
});
|
|
144
|
+
let cachedIniFormatLocale;
|
|
145
|
+
let iniFormatLocalePromise = null;
|
|
146
|
+
let warnedFormatLocale = false;
|
|
147
|
+
/**
|
|
148
|
+
* Best-effort load of `[format].locale` from `hazo_core_config.ini`. Cached
|
|
149
|
+
* per process; safe to call repeatedly. Exported (module-internal — not part
|
|
150
|
+
* of the public `hazo_core`/`hazo_core/client` surface) so tests can `await`
|
|
151
|
+
* it directly instead of polling. `configDir` is test-only; production calls
|
|
152
|
+
* always use `loadConfig`'s default (`process.cwd()/config`).
|
|
153
|
+
*/
|
|
154
|
+
export function __loadIniFormatLocaleForTests(configDir) {
|
|
155
|
+
if (iniFormatLocalePromise)
|
|
156
|
+
return iniFormatLocalePromise;
|
|
157
|
+
const configModulePath = '../config/index.js';
|
|
158
|
+
iniFormatLocalePromise = optional_import(configModulePath).then((mod) => {
|
|
159
|
+
if (!mod)
|
|
160
|
+
return;
|
|
161
|
+
try {
|
|
162
|
+
// `configDir` is only ever passed by tests (production always uses
|
|
163
|
+
// loadConfig's cwd-based default) — when present, force a fresh read.
|
|
164
|
+
// loadConfig's cache key is `${pkg}:${env}` and does not include
|
|
165
|
+
// configDir, so without this, two tests pointing pkg 'core' at
|
|
166
|
+
// different temp directories would collide on the same cache entry.
|
|
167
|
+
if (configDir) {
|
|
168
|
+
mod.reloadConfig('core');
|
|
169
|
+
}
|
|
170
|
+
const config = mod.loadConfig({
|
|
171
|
+
pkg: 'core',
|
|
172
|
+
...(configDir ? { configDir } : {}),
|
|
173
|
+
schema: formatConfigSchema,
|
|
174
|
+
envAliases: { 'format.locale': ['HAZO_CORE_FORMAT_LOCALE'] },
|
|
175
|
+
});
|
|
176
|
+
cachedIniFormatLocale = config.format.locale;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Config unavailable or invalid — formatters fall back to env var/default.
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return iniFormatLocalePromise;
|
|
183
|
+
}
|
|
184
|
+
/** Test-only: clear cached locale resolution state between test cases. */
|
|
185
|
+
export function __resetFormatLocaleCacheForTests() {
|
|
186
|
+
cachedIniFormatLocale = undefined;
|
|
187
|
+
iniFormatLocalePromise = null;
|
|
188
|
+
warnedFormatLocale = false;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve the BCP 47 locale used by formatCurrency/formatNumber/
|
|
192
|
+
* formatDateShort/formatDateLong. See the section comment above for
|
|
193
|
+
* resolution order and the async-INI caveat.
|
|
194
|
+
*/
|
|
195
|
+
function resolveFormatLocale() {
|
|
196
|
+
void __loadIniFormatLocaleForTests();
|
|
197
|
+
const locale = process.env['HAZO_CORE_FORMAT_LOCALE'] ?? cachedIniFormatLocale ?? DEFAULT_FORMAT_LOCALE;
|
|
198
|
+
if (process.env['NODE_ENV'] !== 'production' && !warnedFormatLocale) {
|
|
199
|
+
warnedFormatLocale = true;
|
|
200
|
+
console.warn(`[hazo_core] Number/currency/date formatters are using locale "${locale}". ` +
|
|
201
|
+
'Override via the HAZO_CORE_FORMAT_LOCALE env var or a [format].locale key in ' +
|
|
202
|
+
'hazo_core_config.ini. (This notice only appears outside production.)');
|
|
203
|
+
}
|
|
204
|
+
return locale;
|
|
205
|
+
}
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
103
207
|
// Date formatters
|
|
104
208
|
// ---------------------------------------------------------------------------
|
|
105
209
|
function toDate(date) {
|
|
@@ -107,10 +211,11 @@ function toDate(date) {
|
|
|
107
211
|
}
|
|
108
212
|
/**
|
|
109
213
|
* Format a date as "28 May 2026"
|
|
214
|
+
* @deprecated Use hazo_i18n/format when available
|
|
110
215
|
*/
|
|
111
216
|
export function formatDateShort(date) {
|
|
112
217
|
const d = toDate(date);
|
|
113
|
-
return d.toLocaleDateString(
|
|
218
|
+
return d.toLocaleDateString(resolveFormatLocale(), {
|
|
114
219
|
day: 'numeric',
|
|
115
220
|
month: 'short',
|
|
116
221
|
year: 'numeric',
|
|
@@ -118,10 +223,11 @@ export function formatDateShort(date) {
|
|
|
118
223
|
}
|
|
119
224
|
/**
|
|
120
225
|
* Format a date as "Wednesday, 28 May 2026"
|
|
226
|
+
* @deprecated Use hazo_i18n/format when available
|
|
121
227
|
*/
|
|
122
228
|
export function formatDateLong(date) {
|
|
123
229
|
const d = toDate(date);
|
|
124
|
-
return d.toLocaleDateString(
|
|
230
|
+
return d.toLocaleDateString(resolveFormatLocale(), {
|
|
125
231
|
weekday: 'long',
|
|
126
232
|
day: 'numeric',
|
|
127
233
|
month: 'long',
|
|
@@ -139,15 +245,17 @@ export function formatDateSlash(date) {
|
|
|
139
245
|
return `${day}/${month}/${year}`;
|
|
140
246
|
}
|
|
141
247
|
/**
|
|
142
|
-
* Format a number as currency
|
|
248
|
+
* Format a number as currency. Locale defaults to `en-AU` — override via
|
|
249
|
+
* HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's `[format].locale`.
|
|
143
250
|
*
|
|
144
251
|
* @param amount - The value to format.
|
|
145
252
|
* @param options - {@link FormatCurrencyOptions} (currency, fractionDigits, absolute, compact).
|
|
253
|
+
* @deprecated Use hazo_i18n/format when available
|
|
146
254
|
*/
|
|
147
255
|
export function formatCurrency(amount, options = {}) {
|
|
148
256
|
const { currency = 'AUD', fractionDigits = 2, absolute = false, compact = false } = options;
|
|
149
257
|
const value = absolute ? Math.abs(amount) : amount;
|
|
150
|
-
return new Intl.NumberFormat(
|
|
258
|
+
return new Intl.NumberFormat(resolveFormatLocale(), {
|
|
151
259
|
style: 'currency',
|
|
152
260
|
currency,
|
|
153
261
|
minimumFractionDigits: fractionDigits,
|
|
@@ -160,18 +268,22 @@ export function formatCurrency(amount, options = {}) {
|
|
|
160
268
|
*
|
|
161
269
|
* @param fraction - Value in the 0–1 range (0.05 = 5%).
|
|
162
270
|
* @param decimals - Fraction digits to show. Default 1.
|
|
271
|
+
* @deprecated Use hazo_i18n/format when available
|
|
163
272
|
*/
|
|
164
273
|
export function formatPercent(fraction, decimals = 1) {
|
|
165
274
|
const safe = Number.isFinite(fraction) ? fraction : 0;
|
|
166
275
|
return `${(safe * 100).toFixed(decimals)}%`;
|
|
167
276
|
}
|
|
168
277
|
/**
|
|
169
|
-
* Format a number with optional decimal places.
|
|
278
|
+
* Format a number with optional decimal places. Locale defaults to `en-AU` —
|
|
279
|
+
* override via HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's
|
|
280
|
+
* `[format].locale`.
|
|
170
281
|
* @example formatNumber(1234567.89) → "1,234,567.89"
|
|
171
282
|
* @example formatNumber(1234567.89, 0) → "1,234,568"
|
|
283
|
+
* @deprecated Use hazo_i18n/format when available
|
|
172
284
|
*/
|
|
173
285
|
export function formatNumber(n, decimals) {
|
|
174
|
-
return new Intl.NumberFormat(
|
|
286
|
+
return new Intl.NumberFormat(resolveFormatLocale(), {
|
|
175
287
|
minimumFractionDigits: decimals,
|
|
176
288
|
maximumFractionDigits: decimals,
|
|
177
289
|
}).format(n);
|
|
@@ -183,6 +295,7 @@ export function formatNumber(n, decimals) {
|
|
|
183
295
|
* Format a boolean as a human-readable string.
|
|
184
296
|
* @example formatBoolean(true) → "Yes"
|
|
185
297
|
* @example formatBoolean(false) → "No"
|
|
298
|
+
* @deprecated Use hazo_i18n/format when available — hardcodes "Yes"/"No" (English-only)
|
|
186
299
|
*/
|
|
187
300
|
export function formatBoolean(val) {
|
|
188
301
|
return val ? 'Yes' : 'No';
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for genealogy-style partial/fuzzy dates (year-only, year-month,
|
|
3
|
+
* GEDCOM qualifiers ABT/BEF/AFT/EST/CAL, BET...AND ranges, BCE eras).
|
|
4
|
+
*/
|
|
5
|
+
export type PartialDatePrecision = 'year' | 'month' | 'day';
|
|
6
|
+
export type PartialDateQualifier = 'circa' | 'before' | 'after' | 'estimated' | 'calculated';
|
|
7
|
+
export type PartialDateEra = 'CE' | 'BCE';
|
|
8
|
+
export interface PartialDate {
|
|
9
|
+
year: number;
|
|
10
|
+
month?: number;
|
|
11
|
+
day?: number;
|
|
12
|
+
qualifier?: PartialDateQualifier;
|
|
13
|
+
era?: PartialDateEra;
|
|
14
|
+
}
|
|
15
|
+
export interface PartialDateRange {
|
|
16
|
+
from: PartialDate;
|
|
17
|
+
to: PartialDate;
|
|
18
|
+
}
|
|
19
|
+
export type ParsedPartialDate = PartialDate | PartialDateRange | {
|
|
20
|
+
freeform: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Derives precision from which fields are populated. Precision is never
|
|
24
|
+
* stored on the object — it is always computed from month/day presence.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPartialDatePrecision(d: PartialDate): PartialDatePrecision;
|
|
27
|
+
/**
|
|
28
|
+
* Structural invariants for a PartialDate:
|
|
29
|
+
* - year is a finite positive integer (BCE-ness is carried by `era`, never a negative year)
|
|
30
|
+
* - month, if present, is an integer 1-12
|
|
31
|
+
* - day, if present, is an integer 1-31 AND month must also be present
|
|
32
|
+
* - era, if present, is 'CE' or 'BCE'
|
|
33
|
+
* - qualifier, if present, is one of the 5 valid qualifiers
|
|
34
|
+
*/
|
|
35
|
+
export declare function isValidPartialDate(d: PartialDate): boolean;
|
|
36
|
+
/** Type guard distinguishing a PartialDateRange from a plain PartialDate/freeform result. */
|
|
37
|
+
export declare function isPartialDateRange(d: ParsedPartialDate): d is PartialDateRange;
|
|
38
|
+
/**
|
|
39
|
+
* Parses a partial-date string. Tries, in order: strict ISO (YYYY, YYYY-MM,
|
|
40
|
+
* YYYY-MM-DD), GEDCOM `BET ... AND ...` ranges, GEDCOM qualifier prefixes
|
|
41
|
+
* (ABT/BEF/AFT/EST/CAL), then bare GEDCOM day/month/year/BCE. Empty or
|
|
42
|
+
* whitespace-only input returns null; unparseable non-empty input returns
|
|
43
|
+
* `{ freeform: <trimmed input> }`. Never throws.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parsePartialDate(input: string): ParsedPartialDate | null;
|
|
46
|
+
/**
|
|
47
|
+
* Renders a PartialDate/PartialDateRange for display. `opts.precision`, when
|
|
48
|
+
* given, may only coarsen the rendering (e.g. requesting 'year' on a
|
|
49
|
+
* day-precision date drops the month/day) — it can never invent detail finer
|
|
50
|
+
* than the value actually has, so a request finer than the value's own
|
|
51
|
+
* precision is clamped down to that own precision. Never mutates `d`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function formatPartialDate(d: PartialDate | PartialDateRange, opts?: {
|
|
54
|
+
precision?: PartialDatePrecision;
|
|
55
|
+
locale?: string;
|
|
56
|
+
}): string;
|
|
57
|
+
/**
|
|
58
|
+
* Convenience wrapper for callers that hold a raw string rather than an
|
|
59
|
+
* already-parsed PartialDate (matches the shape of kinstripe's prior
|
|
60
|
+
* `formatPartialDate(s: string, opts)`, kept as a separate function here
|
|
61
|
+
* since #formatPartialDate now takes a PartialDate, not a string).
|
|
62
|
+
*/
|
|
63
|
+
export declare function formatPartialDateString(input: string, opts?: {
|
|
64
|
+
precision?: PartialDatePrecision;
|
|
65
|
+
locale?: string;
|
|
66
|
+
}): string;
|
|
67
|
+
/**
|
|
68
|
+
* Serializes a PartialDate/PartialDateRange back to a string. A plain date
|
|
69
|
+
* (no qualifier, no BCE era) round-trips through the ISO form; a qualified
|
|
70
|
+
* and/or BCE date round-trips through the GEDCOM form. `parsePartialDate`
|
|
71
|
+
* accepts the output of this function.
|
|
72
|
+
*/
|
|
73
|
+
export declare function serializePartialDate(d: PartialDate | PartialDateRange): string;
|
|
74
|
+
/**
|
|
75
|
+
* Chronological comparator, like a standard `Array#sort` comparator
|
|
76
|
+
* (negative when `a` is earlier than `b`, zero when tied, positive when
|
|
77
|
+
* `a` is later). Each rule below applies only when every prior rule ties:
|
|
78
|
+
*
|
|
79
|
+
* 1. Era — BCE sorts before CE.
|
|
80
|
+
* 2. Year — within CE, smaller year is earlier; within BCE, a LARGER
|
|
81
|
+
* year number is chronologically earlier (200 BCE happened
|
|
82
|
+
* before 100 BCE, so it sorts first).
|
|
83
|
+
* 3. Month — absent (coarser) sorts before present; otherwise numeric.
|
|
84
|
+
* 4. Day — same rule as month.
|
|
85
|
+
* 5. Qualifier — 'before' sorts before no-qualifier/circa/estimated/
|
|
86
|
+
* calculated, which all sort before 'after'. circa/estimated/
|
|
87
|
+
* calculated/undefined are mutually equal at this step.
|
|
88
|
+
*/
|
|
89
|
+
export declare function comparePartialDate(a: PartialDate, b: PartialDate): number;
|
|
90
|
+
//# sourceMappingURL=partial_date.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partial_date.d.ts","sourceRoot":"","sources":["../../src/utils/partial_date.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAC5D,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,CAAC;AAC7F,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,KAAK,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,WAAW,CAAC;CACjB;AAED,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAiDtF;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,WAAW,GAAG,oBAAoB,CAI5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAa1D;AAED,6FAA6F;AAC7F,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,iBAAiB,GAAG,CAAC,IAAI,gBAAgB,CAE9E;AA0FD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAmBxE;AAWD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,WAAW,GAAG,gBAAgB,EACjC,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CA8BR;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CAKR;AAwCD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,GAAG,MAAM,CAK9E;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAwBzE"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for genealogy-style partial/fuzzy dates (year-only, year-month,
|
|
3
|
+
* GEDCOM qualifiers ABT/BEF/AFT/EST/CAL, BET...AND ranges, BCE eras).
|
|
4
|
+
*/
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Internal tables
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const MONTH_ABBREVS = [
|
|
9
|
+
'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC',
|
|
10
|
+
];
|
|
11
|
+
const MONTH_ABBREV_TO_INDEX = Object.fromEntries(MONTH_ABBREVS.map((m, i) => [m, i + 1]));
|
|
12
|
+
const QUALIFIER_PREFIX_TO_NAME = {
|
|
13
|
+
ABT: 'circa',
|
|
14
|
+
BEF: 'before',
|
|
15
|
+
AFT: 'after',
|
|
16
|
+
EST: 'estimated',
|
|
17
|
+
CAL: 'calculated',
|
|
18
|
+
};
|
|
19
|
+
const QUALIFIER_NAME_TO_PREFIX = {
|
|
20
|
+
circa: 'ABT',
|
|
21
|
+
before: 'BEF',
|
|
22
|
+
after: 'AFT',
|
|
23
|
+
estimated: 'EST',
|
|
24
|
+
calculated: 'CAL',
|
|
25
|
+
};
|
|
26
|
+
const QUALIFIER_WORD = {
|
|
27
|
+
circa: 'circa',
|
|
28
|
+
before: 'before',
|
|
29
|
+
after: 'after',
|
|
30
|
+
estimated: 'estimated',
|
|
31
|
+
calculated: 'calculated',
|
|
32
|
+
};
|
|
33
|
+
const VALID_QUALIFIERS = [
|
|
34
|
+
'circa', 'before', 'after', 'estimated', 'calculated',
|
|
35
|
+
];
|
|
36
|
+
const VALID_ERAS = ['CE', 'BCE'];
|
|
37
|
+
const PRECISION_ORDER = { year: 0, month: 1, day: 2 };
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Precision / validity
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Derives precision from which fields are populated. Precision is never
|
|
43
|
+
* stored on the object — it is always computed from month/day presence.
|
|
44
|
+
*/
|
|
45
|
+
export function getPartialDatePrecision(d) {
|
|
46
|
+
if (d.day !== undefined)
|
|
47
|
+
return 'day';
|
|
48
|
+
if (d.month !== undefined)
|
|
49
|
+
return 'month';
|
|
50
|
+
return 'year';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Structural invariants for a PartialDate:
|
|
54
|
+
* - year is a finite positive integer (BCE-ness is carried by `era`, never a negative year)
|
|
55
|
+
* - month, if present, is an integer 1-12
|
|
56
|
+
* - day, if present, is an integer 1-31 AND month must also be present
|
|
57
|
+
* - era, if present, is 'CE' or 'BCE'
|
|
58
|
+
* - qualifier, if present, is one of the 5 valid qualifiers
|
|
59
|
+
*/
|
|
60
|
+
export function isValidPartialDate(d) {
|
|
61
|
+
if (!d || typeof d !== 'object')
|
|
62
|
+
return false;
|
|
63
|
+
if (!Number.isInteger(d.year) || d.year <= 0)
|
|
64
|
+
return false;
|
|
65
|
+
if (d.month !== undefined && (!Number.isInteger(d.month) || d.month < 1 || d.month > 12)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (d.day !== undefined) {
|
|
69
|
+
if (!Number.isInteger(d.day) || d.day < 1 || d.day > 31)
|
|
70
|
+
return false;
|
|
71
|
+
if (d.month === undefined)
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
if (d.era !== undefined && !VALID_ERAS.includes(d.era))
|
|
75
|
+
return false;
|
|
76
|
+
if (d.qualifier !== undefined && !VALID_QUALIFIERS.includes(d.qualifier))
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
/** Type guard distinguishing a PartialDateRange from a plain PartialDate/freeform result. */
|
|
81
|
+
export function isPartialDateRange(d) {
|
|
82
|
+
return !!d && typeof d === 'object' && 'from' in d && 'to' in d;
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Parsing
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* Parses a "bare" day/month/year expression with an optional trailing BCE
|
|
89
|
+
* suffix — no qualifier prefix. Shared by the standalone GEDCOM path and by
|
|
90
|
+
* each side of a BET...AND range.
|
|
91
|
+
*/
|
|
92
|
+
function parseBareDate(raw) {
|
|
93
|
+
let s = raw.trim();
|
|
94
|
+
if (!s)
|
|
95
|
+
return null;
|
|
96
|
+
let era;
|
|
97
|
+
const bceMatch = s.match(/^(.*?)\s+BCE$/i);
|
|
98
|
+
if (bceMatch) {
|
|
99
|
+
era = 'BCE';
|
|
100
|
+
s = bceMatch[1].trim();
|
|
101
|
+
}
|
|
102
|
+
const upper = s.toUpperCase();
|
|
103
|
+
let m = upper.match(/^(\d{1,2})\s+([A-Z]{3})\s+(\d{1,4})$/);
|
|
104
|
+
if (m) {
|
|
105
|
+
const monthIdx = MONTH_ABBREV_TO_INDEX[m[2]];
|
|
106
|
+
if (monthIdx === undefined)
|
|
107
|
+
return null;
|
|
108
|
+
const result = { year: parseInt(m[3], 10), month: monthIdx, day: parseInt(m[1], 10) };
|
|
109
|
+
if (era)
|
|
110
|
+
result.era = era;
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
m = upper.match(/^([A-Z]{3})\s+(\d{1,4})$/);
|
|
114
|
+
if (m) {
|
|
115
|
+
const monthIdx = MONTH_ABBREV_TO_INDEX[m[1]];
|
|
116
|
+
if (monthIdx === undefined)
|
|
117
|
+
return null;
|
|
118
|
+
const result = { year: parseInt(m[2], 10), month: monthIdx };
|
|
119
|
+
if (era)
|
|
120
|
+
result.era = era;
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
m = upper.match(/^(\d{1,4})$/);
|
|
124
|
+
if (m) {
|
|
125
|
+
const result = { year: parseInt(m[1], 10) };
|
|
126
|
+
if (era)
|
|
127
|
+
result.era = era;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/** Parses a strict ISO date (YYYY, YYYY-MM, or YYYY-MM-DD). */
|
|
133
|
+
function parseIsoDate(s) {
|
|
134
|
+
const isoMatch = s.match(/^(\d{4})(-(\d{2})(-(\d{2}))?)?$/);
|
|
135
|
+
if (!isoMatch)
|
|
136
|
+
return null;
|
|
137
|
+
const candidate = { year: parseInt(isoMatch[1], 10) };
|
|
138
|
+
if (isoMatch[3])
|
|
139
|
+
candidate.month = parseInt(isoMatch[3], 10);
|
|
140
|
+
if (isoMatch[5])
|
|
141
|
+
candidate.day = parseInt(isoMatch[5], 10);
|
|
142
|
+
return isValidPartialDate(candidate) ? candidate : null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Parses one "side" of a date expression: either a strict ISO date, or an
|
|
146
|
+
* optional GEDCOM qualifier prefix (ABT/BEF/AFT/EST/CAL) followed by a bare
|
|
147
|
+
* day/month/year/BCE expression. Used both standalone and recursively inside
|
|
148
|
+
* BET...AND ranges (a plain, non-qualified date serializes as ISO even
|
|
149
|
+
* inside a range, so ranges must accept ISO sides to round-trip).
|
|
150
|
+
*/
|
|
151
|
+
function parseGedcomSide(raw) {
|
|
152
|
+
const s = raw.trim();
|
|
153
|
+
if (!s)
|
|
154
|
+
return null;
|
|
155
|
+
const iso = parseIsoDate(s);
|
|
156
|
+
if (iso)
|
|
157
|
+
return iso;
|
|
158
|
+
const upper = s.toUpperCase();
|
|
159
|
+
const prefixMatch = upper.match(/^(ABT|BEF|AFT|EST|CAL)\s+(.+)$/);
|
|
160
|
+
if (prefixMatch) {
|
|
161
|
+
const qualifier = QUALIFIER_PREFIX_TO_NAME[prefixMatch[1]];
|
|
162
|
+
const bare = parseBareDate(prefixMatch[2]);
|
|
163
|
+
if (!bare)
|
|
164
|
+
return null;
|
|
165
|
+
const result = { ...bare, qualifier };
|
|
166
|
+
return isValidPartialDate(result) ? result : null;
|
|
167
|
+
}
|
|
168
|
+
const bare = parseBareDate(upper);
|
|
169
|
+
if (!bare)
|
|
170
|
+
return null;
|
|
171
|
+
return isValidPartialDate(bare) ? bare : null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Parses a partial-date string. Tries, in order: strict ISO (YYYY, YYYY-MM,
|
|
175
|
+
* YYYY-MM-DD), GEDCOM `BET ... AND ...` ranges, GEDCOM qualifier prefixes
|
|
176
|
+
* (ABT/BEF/AFT/EST/CAL), then bare GEDCOM day/month/year/BCE. Empty or
|
|
177
|
+
* whitespace-only input returns null; unparseable non-empty input returns
|
|
178
|
+
* `{ freeform: <trimmed input> }`. Never throws.
|
|
179
|
+
*/
|
|
180
|
+
export function parsePartialDate(input) {
|
|
181
|
+
if (typeof input !== 'string')
|
|
182
|
+
return null;
|
|
183
|
+
const trimmed = input.trim();
|
|
184
|
+
if (trimmed === '')
|
|
185
|
+
return null;
|
|
186
|
+
const iso = parseIsoDate(trimmed);
|
|
187
|
+
if (iso)
|
|
188
|
+
return iso;
|
|
189
|
+
const betMatch = trimmed.match(/^BET\s+(.+?)\s+AND\s+(.+)$/i);
|
|
190
|
+
if (betMatch) {
|
|
191
|
+
const from = parseGedcomSide(betMatch[1]);
|
|
192
|
+
const to = parseGedcomSide(betMatch[2]);
|
|
193
|
+
if (from && to)
|
|
194
|
+
return { from, to };
|
|
195
|
+
}
|
|
196
|
+
const side = parseGedcomSide(trimmed);
|
|
197
|
+
if (side)
|
|
198
|
+
return side;
|
|
199
|
+
return { freeform: trimmed };
|
|
200
|
+
}
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Formatting
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
function monthName(month, locale) {
|
|
205
|
+
// Fixed dummy year — only the month field is ever read back out.
|
|
206
|
+
return new Intl.DateTimeFormat(locale, { month: 'long' }).format(new Date(2000, month - 1, 1));
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Renders a PartialDate/PartialDateRange for display. `opts.precision`, when
|
|
210
|
+
* given, may only coarsen the rendering (e.g. requesting 'year' on a
|
|
211
|
+
* day-precision date drops the month/day) — it can never invent detail finer
|
|
212
|
+
* than the value actually has, so a request finer than the value's own
|
|
213
|
+
* precision is clamped down to that own precision. Never mutates `d`.
|
|
214
|
+
*/
|
|
215
|
+
export function formatPartialDate(d, opts) {
|
|
216
|
+
if (isPartialDateRange(d)) {
|
|
217
|
+
return `between ${formatPartialDate(d.from, opts)} and ${formatPartialDate(d.to, opts)}`;
|
|
218
|
+
}
|
|
219
|
+
const ownPrecision = getPartialDatePrecision(d);
|
|
220
|
+
let effectivePrecision = ownPrecision;
|
|
221
|
+
if (opts?.precision !== undefined && PRECISION_ORDER[opts.precision] < PRECISION_ORDER[ownPrecision]) {
|
|
222
|
+
effectivePrecision = opts.precision;
|
|
223
|
+
}
|
|
224
|
+
const locale = opts?.locale ?? 'en';
|
|
225
|
+
let datePart;
|
|
226
|
+
if (effectivePrecision === 'day') {
|
|
227
|
+
datePart = `${d.day} ${monthName(d.month, locale)} ${d.year}`;
|
|
228
|
+
}
|
|
229
|
+
else if (effectivePrecision === 'month') {
|
|
230
|
+
datePart = `${monthName(d.month, locale)} ${d.year}`;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
datePart = `${d.year}`;
|
|
234
|
+
}
|
|
235
|
+
if (d.era === 'BCE') {
|
|
236
|
+
datePart = `${datePart} BCE`;
|
|
237
|
+
}
|
|
238
|
+
if (d.qualifier) {
|
|
239
|
+
datePart = `${QUALIFIER_WORD[d.qualifier]} ${datePart}`;
|
|
240
|
+
}
|
|
241
|
+
return datePart;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Convenience wrapper for callers that hold a raw string rather than an
|
|
245
|
+
* already-parsed PartialDate (matches the shape of kinstripe's prior
|
|
246
|
+
* `formatPartialDate(s: string, opts)`, kept as a separate function here
|
|
247
|
+
* since #formatPartialDate now takes a PartialDate, not a string).
|
|
248
|
+
*/
|
|
249
|
+
export function formatPartialDateString(input, opts) {
|
|
250
|
+
const parsed = parsePartialDate(input);
|
|
251
|
+
if (parsed === null)
|
|
252
|
+
return '';
|
|
253
|
+
if ('freeform' in parsed)
|
|
254
|
+
return parsed.freeform;
|
|
255
|
+
return formatPartialDate(parsed, opts);
|
|
256
|
+
}
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
// Serialization
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
function serializeSide(d) {
|
|
261
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
262
|
+
let core;
|
|
263
|
+
if (d.qualifier || d.era === 'BCE') {
|
|
264
|
+
// GEDCOM-flavoured rendering (month abbreviation, unpadded day).
|
|
265
|
+
if (d.day !== undefined && d.month !== undefined) {
|
|
266
|
+
core = `${d.day} ${MONTH_ABBREVS[d.month - 1]} ${d.year}`;
|
|
267
|
+
}
|
|
268
|
+
else if (d.month !== undefined) {
|
|
269
|
+
core = `${MONTH_ABBREVS[d.month - 1]} ${d.year}`;
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
core = `${d.year}`;
|
|
273
|
+
}
|
|
274
|
+
if (d.qualifier) {
|
|
275
|
+
core = `${QUALIFIER_NAME_TO_PREFIX[d.qualifier]} ${core}`;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
// Plain ISO rendering.
|
|
280
|
+
if (d.day !== undefined && d.month !== undefined) {
|
|
281
|
+
core = `${d.year}-${pad(d.month)}-${pad(d.day)}`;
|
|
282
|
+
}
|
|
283
|
+
else if (d.month !== undefined) {
|
|
284
|
+
core = `${d.year}-${pad(d.month)}`;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
core = `${d.year}`;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (d.era === 'BCE') {
|
|
291
|
+
core = `${core} BCE`;
|
|
292
|
+
}
|
|
293
|
+
return core;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Serializes a PartialDate/PartialDateRange back to a string. A plain date
|
|
297
|
+
* (no qualifier, no BCE era) round-trips through the ISO form; a qualified
|
|
298
|
+
* and/or BCE date round-trips through the GEDCOM form. `parsePartialDate`
|
|
299
|
+
* accepts the output of this function.
|
|
300
|
+
*/
|
|
301
|
+
export function serializePartialDate(d) {
|
|
302
|
+
if (isPartialDateRange(d)) {
|
|
303
|
+
return `BET ${serializeSide(d.from)} AND ${serializeSide(d.to)}`;
|
|
304
|
+
}
|
|
305
|
+
return serializeSide(d);
|
|
306
|
+
}
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// Comparison
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
function qualifierRank(q) {
|
|
311
|
+
if (q === 'before')
|
|
312
|
+
return -1;
|
|
313
|
+
if (q === 'after')
|
|
314
|
+
return 1;
|
|
315
|
+
return 0; // circa / estimated / calculated / undefined are mutually equal here
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Chronological comparator, like a standard `Array#sort` comparator
|
|
319
|
+
* (negative when `a` is earlier than `b`, zero when tied, positive when
|
|
320
|
+
* `a` is later). Each rule below applies only when every prior rule ties:
|
|
321
|
+
*
|
|
322
|
+
* 1. Era — BCE sorts before CE.
|
|
323
|
+
* 2. Year — within CE, smaller year is earlier; within BCE, a LARGER
|
|
324
|
+
* year number is chronologically earlier (200 BCE happened
|
|
325
|
+
* before 100 BCE, so it sorts first).
|
|
326
|
+
* 3. Month — absent (coarser) sorts before present; otherwise numeric.
|
|
327
|
+
* 4. Day — same rule as month.
|
|
328
|
+
* 5. Qualifier — 'before' sorts before no-qualifier/circa/estimated/
|
|
329
|
+
* calculated, which all sort before 'after'. circa/estimated/
|
|
330
|
+
* calculated/undefined are mutually equal at this step.
|
|
331
|
+
*/
|
|
332
|
+
export function comparePartialDate(a, b) {
|
|
333
|
+
const eraA = a.era ?? 'CE';
|
|
334
|
+
const eraB = b.era ?? 'CE';
|
|
335
|
+
if (eraA !== eraB) {
|
|
336
|
+
return eraA === 'BCE' ? -1 : 1;
|
|
337
|
+
}
|
|
338
|
+
if (a.year !== b.year) {
|
|
339
|
+
return eraA === 'BCE' ? b.year - a.year : a.year - b.year;
|
|
340
|
+
}
|
|
341
|
+
if (a.month === undefined && b.month !== undefined)
|
|
342
|
+
return -1;
|
|
343
|
+
if (a.month !== undefined && b.month === undefined)
|
|
344
|
+
return 1;
|
|
345
|
+
if (a.month !== undefined && b.month !== undefined && a.month !== b.month) {
|
|
346
|
+
return a.month - b.month;
|
|
347
|
+
}
|
|
348
|
+
if (a.day === undefined && b.day !== undefined)
|
|
349
|
+
return -1;
|
|
350
|
+
if (a.day !== undefined && b.day === undefined)
|
|
351
|
+
return 1;
|
|
352
|
+
if (a.day !== undefined && b.day !== undefined && a.day !== b.day) {
|
|
353
|
+
return a.day - b.day;
|
|
354
|
+
}
|
|
355
|
+
return qualifierRank(a.qualifier) - qualifierRank(b.qualifier);
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=partial_date.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partial_date.js","sourceRoot":"","sources":["../../src/utils/partial_date.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED