@softure-ai/core 0.1.10 → 0.2.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/CHANGELOG.md +40 -0
- package/README.md +77 -12
- package/dist/calendar-day.d.ts +3 -0
- package/dist/calendar-day.d.ts.map +1 -1
- package/dist/calendar-day.js +5 -0
- package/dist/calendar-day.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -2
- package/dist/config.js.map +1 -1
- package/dist/format.d.ts +51 -7
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +98 -12
- package/dist/format.js.map +1 -1
- package/dist/i18n.d.ts +34 -11
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +40 -10
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/memoize.d.ts +16 -0
- package/dist/memoize.d.ts.map +1 -0
- package/dist/memoize.js +81 -0
- package/dist/memoize.js.map +1 -0
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/messages/index.js +1 -2
- package/dist/messages/index.js.map +1 -1
- package/dist/og/index.d.ts +2 -0
- package/dist/og/index.d.ts.map +1 -0
- package/dist/og/index.js +4 -0
- package/dist/og/index.js.map +1 -0
- package/dist/og/og-fonts.d.ts +37 -0
- package/dist/og/og-fonts.d.ts.map +1 -0
- package/dist/og/og-fonts.js +95 -0
- package/dist/og/og-fonts.js.map +1 -0
- package/package.json +6 -1
- package/src/calendar-day.ts +4 -0
- package/src/config.ts +11 -2
- package/src/format.ts +131 -17
- package/src/i18n.ts +53 -19
- package/src/index.ts +21 -2
- package/src/memoize.ts +89 -0
- package/src/messages/index.ts +1 -2
- package/src/og/index.ts +12 -0
- package/src/og/og-fonts.ts +127 -0
- package/dist/messages/pl.d.ts +0 -3
- package/dist/messages/pl.d.ts.map +0 -1
- package/dist/messages/pl.js +0 -7
- package/dist/messages/pl.js.map +0 -1
- package/src/messages/pl.ts +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,46 @@ Newest first. Each version lists what changed for an app that uses `@softure-ai/
|
|
|
4
4
|
production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
|
|
5
5
|
"Definition of done"). Versions before the first one below are described in their GitHub Releases (`core@x.y.z`).
|
|
6
6
|
|
|
7
|
+
## 0.2.0
|
|
8
|
+
|
|
9
|
+
- **Breaking (#446):** English is the only built-in language.
|
|
10
|
+
- `LOCALES` is removed; `Locale` is any BCP 47 tag, `isLocale(value)` says whether a value is a well-formed one,
|
|
11
|
+
`DEFAULT_LOCALE` is `"en"`. `defineSoftureConfig` takes any tag as `locale` and refuses one that is not.
|
|
12
|
+
- `coreMessages` and every module ship `en` only. `Dictionaries<T>` is a complete `en` plus any other locales;
|
|
13
|
+
`MessageOverrides<T>` is keyed by any tag, and `mergeMessages` builds a locale without its own defaults on `en`.
|
|
14
|
+
- New `selectMessages(dictionaries, locale)` (the locale, then its language, then `en`), `pickLocalizedText` and
|
|
15
|
+
`LocalizedText` for an app's per-locale option texts.
|
|
16
|
+
- Migrate: an app that shows Polish keeps its own translation and passes it per module as the overrides for its
|
|
17
|
+
locale, `auth({ messages: { pl: authPl } })`; a key it leaves out reads English. Read a module's copy with
|
|
18
|
+
`selectMessages(module.messages, config.locale)` instead of `module.messages[config.locale]`.
|
|
19
|
+
- **Breaking (#438):** core's formatters build in no language besides English.
|
|
20
|
+
- `formatCalendarMonth` drops the `"genitive"` style; `CalendarMonthStyle` is `"long" | "roman"`. A full date's
|
|
21
|
+
month form stays available through `formatCalendarDay`.
|
|
22
|
+
- `formatDuration(months, options?)` takes `{ locale?, messages? }` instead of a locale. Its words default to
|
|
23
|
+
English (`DEFAULT_DURATION_MESSAGES`); an app plugs in its own translation with `messages: DurationMessages` and
|
|
24
|
+
the `locale` whose plural rules pick a form. Migrate `formatDuration(n, "en")` to `formatDuration(n)`.
|
|
25
|
+
- `coreMessages` no longer has the `duration` group.
|
|
26
|
+
- `formatCalendarDay`, `formatCalendarMonth`, `formatMoney`, `formatPercent` and `selectPlural` take any BCP 47 locale
|
|
27
|
+
tag, not only `LOCALES` (#438). Exported: `DurationMessages`, `FormatDurationOptions`, `DEFAULT_DURATION_MESSAGES`.
|
|
28
|
+
- `formatPercent(basisPoints, locale, { fractionDigits })` prints exactly that many fraction digits (`19.00%`,
|
|
29
|
+
`+3.0%`), an integer from 0 to 20 (otherwise a `RangeError`). A value that rounds to zero at that precision stays
|
|
30
|
+
unsigned (`0.0%`). Without it, nothing changes: at most two digits (#455).
|
|
31
|
+
|
|
32
|
+
## 0.1.11
|
|
33
|
+
|
|
34
|
+
- Formatting (#410): `formatCalendarMonth(month, locale, "long" | "genitive" | "roman")` for `YYYY-MM` months
|
|
35
|
+
(`isCalendarMonth`) or days, `formatDuration(months, locale)` ("3 years and 2 months", plural forms from
|
|
36
|
+
`coreMessages`), and `formatPercent(basisPoints, locale, { signed, tight })`. `formatPercent` never puts a minus on
|
|
37
|
+
a value that rounds to zero, as `formatMoney` does.
|
|
38
|
+
- `memoizeByContent(fn, { max })`: an LRU cache keyed by the arguments' content, no TTL (#410).
|
|
39
|
+
- The config takes `landingOrigin` (optional; `SoftureConfig.landingOrigin` defaults to `appOrigin`), the public
|
|
40
|
+
landing site beside an app on a subdomain (#410).
|
|
41
|
+
- `calendarDaySchema`: a zod schema for a `YYYY-MM-DD` calendar day (#410).
|
|
42
|
+
- New server-only entry `@softure-ai/core/og`: the OG card font loader the modules share (#414).
|
|
43
|
+
`createOgFontLoader({ root, label?, readFile?, fetchImpl? })` and `loadOgFonts(fonts)` (from the working
|
|
44
|
+
directory) read a `.ttf`, `.otf` or `.woff` path or https URL once and answer `{ ok, fonts }` or `{ ok: false, error }`;
|
|
45
|
+
with `OgFontSource`, `OgFont`, `OgFontWeight`, `OG_FONT_WEIGHTS`. Moved from the blog.
|
|
46
|
+
|
|
7
47
|
## 0.1.10
|
|
8
48
|
|
|
9
49
|
- `formatMoney` never puts a minus on zero: a negative zero, or an amount that rounds to zero under `rounded` or
|
package/README.md
CHANGED
|
@@ -6,8 +6,10 @@ The contract every SOFTURE module stands on. Standard:
|
|
|
6
6
|
## 1. What it provides
|
|
7
7
|
|
|
8
8
|
The app configuration (`defineSoftureConfig`), the module contract (`defineModule`), `Result`
|
|
9
|
-
with namespaced error codes, an injectable `Clock`,
|
|
9
|
+
with namespaced error codes, an injectable `Clock`, English messages with partial overrides and app-supplied translations,
|
|
10
10
|
and `safeError` with `PublicError`. `@softure-ai/core/cli` loads the app's config for the modules' command-line tools.
|
|
11
|
+
`@softure-ai/core/og` (server only) is the OG card font loader the modules share (`createOgFontLoader`,
|
|
12
|
+
`loadOgFonts`); an app takes it from `@softure-ai/seo/server`, where it is documented.
|
|
11
13
|
|
|
12
14
|
## 2. Installation
|
|
13
15
|
|
|
@@ -25,9 +27,10 @@ interface SoftureConfigInput {
|
|
|
25
27
|
url: string;
|
|
26
28
|
handle?: () => DatabaseHandle | Promise<DatabaseHandle>; // the app's own handle, see below
|
|
27
29
|
} | null;
|
|
28
|
-
locale: "en"
|
|
30
|
+
locale: string; // a BCP 47 tag, e.g. "en" or "de-AT"
|
|
29
31
|
timezone: string; // IANA zone, e.g. "Europe/Warsaw"
|
|
30
32
|
appOrigin: string; // http(s) origin without a path
|
|
33
|
+
landingOrigin?: string; // the public landing site beside the app (default: appOrigin)
|
|
31
34
|
origins?: { // read by resolveAppOrigin, see "Request origins" below
|
|
32
35
|
trustedOrigins?: string[]; // other origins the app is served under (at most 16)
|
|
33
36
|
trustRequestHost?: boolean; // trust Host for any host (default false)
|
|
@@ -44,7 +47,7 @@ import { notes } from "@softure-ai/notes";
|
|
|
44
47
|
|
|
45
48
|
const config = defineSoftureConfig({
|
|
46
49
|
database: { url: process.env.DATABASE_URL ?? "" },
|
|
47
|
-
locale: "
|
|
50
|
+
locale: "en",
|
|
48
51
|
timezone: "Europe/Warsaw",
|
|
49
52
|
appOrigin: process.env.APP_ORIGIN ?? "http://localhost:3000",
|
|
50
53
|
modules: [notes({ limit: 10, routes: { list: "/my-notes" }, messages: { en: { list: { title: "My notes" } } } })],
|
|
@@ -54,6 +57,10 @@ registerSoftureConfig(config);
|
|
|
54
57
|
export default config;
|
|
55
58
|
```
|
|
56
59
|
|
|
60
|
+
`landingOrigin` names the public landing site when the app lives on a subdomain beside it (`https://example.com`
|
|
61
|
+
next to `https://app.example.com`); `SoftureConfig.landingOrigin` is always filled, with `appOrigin` when the app names
|
|
62
|
+
none. Use it for links from the app to its marketing pages, never for the app's own absolute URLs.
|
|
63
|
+
|
|
57
64
|
`defineSoftureConfig` throws `SoftureConfigError` with every problem listed (`issues`): an
|
|
58
65
|
unknown locale or zone, an origin with a path, a module listed twice, two modules on one database
|
|
59
66
|
schema, a required dependency missing, a dependency outside its version range (also an optional
|
|
@@ -242,14 +249,32 @@ None. Tokens, slots and styles live in `@softure-ai/ui`.
|
|
|
242
249
|
|
|
243
250
|
## 9. Copy
|
|
244
251
|
|
|
245
|
-
-
|
|
246
|
-
`
|
|
247
|
-
-
|
|
248
|
-
|
|
252
|
+
- English is the only built-in language: every module ships one complete `en` dictionary, and
|
|
253
|
+
`DEFAULT_LOCALE` is `"en"`. `Locale` is any BCP 47 tag; `isLocale(value)` says whether a value is a
|
|
254
|
+
well-formed one, and `defineSoftureConfig` refuses a `locale` that is not.
|
|
255
|
+
- `Dictionaries<T>` is a complete `en` plus any other locales; `MessageOverrides<T>` partial dictionaries keyed
|
|
256
|
+
by locale. `mergeMessages(defaults, overrides)` returns `en` and every locale the defaults or the overrides
|
|
257
|
+
name; a locale without its own defaults is built on `en`. Unknown keys and a string in place of a group are
|
|
258
|
+
ignored.
|
|
259
|
+
- `selectMessages(dictionaries, locale)` picks the exact locale, then its language (`de-AT` reads `de`), then
|
|
260
|
+
`en`. `pickLocalizedText(text, locale, fallback?)` does the same for an app's `LocalizedText`
|
|
261
|
+
(`{ en: "Monthly", de: "Monatlich" }`).
|
|
262
|
+
- **Another language is the app's own translation.** The app sets `locale` and passes its dictionary as the
|
|
263
|
+
overrides for that locale, per module; a key it leaves out reads English:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
defineSoftureConfig({
|
|
267
|
+
locale: "de",
|
|
268
|
+
// ...
|
|
269
|
+
modules: [auth({ messages: { de: authDe } })], // authDe: DeepPartial<AuthMessages>, kept in the app
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The ui and charts components take the same translation through their `messages` prop (or the ui provider).
|
|
249
274
|
- `formatMessage("{count} of {total}", { count, total })` fills placeholders; a missing value
|
|
250
275
|
stays visible as `{name}`.
|
|
251
276
|
- `selectPlural(locale, count, { one, few, many, other })` uses `Intl.PluralRules`, built once per
|
|
252
|
-
locale and reused.
|
|
277
|
+
locale and reused. `locale` is any BCP 47 tag; a category the forms leave out falls back to `other`.
|
|
253
278
|
- `getMessage(dictionary, "errors.unexpected")` reads a dotted path.
|
|
254
279
|
- Core's own keys (`coreMessages`): `errors.database_failed`, `errors.unexpected`, the copy for
|
|
255
280
|
the `core.database_failed` and `core.unexpected` codes.
|
|
@@ -308,20 +333,60 @@ or a fractional count.
|
|
|
308
333
|
| `calendarDaysBetween(from, to)` | `to - from` in days; negative when `to` comes first. |
|
|
309
334
|
| `wholeMonthsBetween(from, to)` | The most months `n` with `addCalendarMonths(from, n)` (clamped) not after `to`: Jan 31 to Feb 28 is 1. Swapping the days turns the sign. |
|
|
310
335
|
|
|
336
|
+
`calendarDaySchema` is `isCalendarDay` as a zod schema, for tool and form inputs that take a day.
|
|
337
|
+
|
|
311
338
|
**Display.** One way to show days, money and percentages in every module and app, in `config.locale`:
|
|
312
339
|
|
|
313
340
|
```ts
|
|
314
341
|
formatCalendarDay("2026-10-04", "en"); // "October 4, 2026"; "medium": "Oct 4, 2026"; "numeric": "10/04/2026"
|
|
315
342
|
formatCalendarDay(toCalendarDay(instant, config.timezone), config.locale); // an instant's day in the app's zone
|
|
316
|
-
formatMoney(123456, "PLN", "en"); // "PLN 1,234.56";
|
|
343
|
+
formatMoney(123456, "PLN", "en"); // "PLN 1,234.56"; thousands always grouped, also where a locale would not
|
|
317
344
|
formatMoney(-123456, "PLN", "en", { rounded: true, signed: true }); // "-PLN 1,235"; { compact: true }: "PLN 1.2K"
|
|
318
345
|
formatPercent(1250, "en"); // "12.5%" (basis points, at most two fraction digits)
|
|
346
|
+
formatPercent(-50, "en", { signed: true, tight: true }); // "-0.5%"; 1250 signed: "+12.5%"
|
|
347
|
+
formatPercent(1900, "en", { fractionDigits: 2 }); // "19.00%"; 300 at one digit, signed: "+3.0%"
|
|
348
|
+
formatCalendarMonth("2026-10", "en"); // "October 2026"; "roman": "X 2026"
|
|
349
|
+
formatDuration(38); // "3 years and 2 months" (whole months, as wholeMonthsBetween returns them)
|
|
319
350
|
```
|
|
320
351
|
|
|
321
|
-
|
|
322
|
-
|
|
352
|
+
Every formatter takes any BCP 47 locale tag (an invalid tag throws `Intl`'s `RangeError`), and
|
|
353
|
+
writes it as `Intl` does. A day is formatted at UTC midnight in UTC, so no zone moves it. `formatMoney` takes the amount in the currency's minor unit, read from the pinned ISO 4217
|
|
323
354
|
table `CURRENCY_MINOR_UNIT_DIGITS` (a code outside it gets `Intl`'s digits), and always groups thousands.
|
|
324
|
-
Zero never carries a sign: a negative zero (`Math.round(-0.4)`) or an amount that rounds to zero shows as `PLN 0.00
|
|
355
|
+
Zero never carries a sign: a negative zero (`Math.round(-0.4)`) or an amount that rounds to zero shows as `PLN 0.00`,
|
|
356
|
+
and a percentage that rounds to zero as `0%`. `signed` puts a `+` before a positive amount or percentage; the minus is
|
|
357
|
+
the one `Intl` writes (a hyphen-minus in en). `tight` drops any space a locale's pattern puts before `%`.
|
|
358
|
+
`fractionDigits` fixes the number of fraction digits (an integer from 0 to 20) so a column reads equally precise; a
|
|
359
|
+
value that rounds to zero at that precision is still unsigned (`0.0%`).
|
|
360
|
+
|
|
361
|
+
`formatCalendarMonth(month, locale, style)` takes `YYYY-MM` (`isCalendarMonth`) or a `YYYY-MM-DD` day. `long` is the
|
|
362
|
+
month as written alone, `roman` the month in Roman numerals for compact tables.
|
|
363
|
+
|
|
364
|
+
`formatDuration(months, { locale, messages })` writes years and months; a part that is zero is left out, and zero
|
|
365
|
+
itself is "0 months". Its only built-in words are English (`DEFAULT_DURATION_MESSAGES`). An app that shows another
|
|
366
|
+
language passes its own `DurationMessages` and the locale whose plural rules pick among them; a locale alone keeps the
|
|
367
|
+
English words:
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
const durationDe: DurationMessages = {
|
|
371
|
+
years: { one: "{count} Jahr", other: "{count} Jahre" },
|
|
372
|
+
months: { one: "{count} Monat", other: "{count} Monate" },
|
|
373
|
+
both: "{years} und {months}",
|
|
374
|
+
};
|
|
375
|
+
formatDuration(13, { locale: "de", messages: durationDe }); // "1 Jahr und 1 Monat"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Give every plural category the locale uses (`Intl.PluralRules`: `one`, `few`, `many`, `other`, ...); a missing one
|
|
379
|
+
falls back to `other`.
|
|
380
|
+
|
|
381
|
+
**Memoization.** `memoizeByContent(fn, { max })` caches a pure function of plain data by the content of its arguments:
|
|
382
|
+
two equal objects built apart (key order aside) hit the same entry. The least recently used entry goes beyond `max`;
|
|
383
|
+
nothing expires by time, and `clear()` empties the cache. Arguments may hold primitives, arrays, `Date`s and plain
|
|
384
|
+
objects; anything else (a function, a `Map`, a class instance, a cycle) throws a `TypeError`. A promise that rejects
|
|
385
|
+
is dropped, so the next call tries again.
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
const getProjection = memoizeByContent((input: ProjectionInput) => simulate(input), { max: 100 });
|
|
389
|
+
```
|
|
325
390
|
|
|
326
391
|
## 10. Hooks
|
|
327
392
|
|
package/dist/calendar-day.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import type { Clock } from "./clock.js";
|
|
2
3
|
/** The calendar day (`YYYY-MM-DD`) of `instant` in `timeZone`. Throws a `RangeError` for an invalid date or zone. */
|
|
3
4
|
export declare function toCalendarDay(instant: Date, timeZone: string): string;
|
|
@@ -7,6 +8,8 @@ export declare function getCalendarDay(clock: Clock, timeZone: string): string;
|
|
|
7
8
|
export type EndOfMonth = "clamp" | "overflow";
|
|
8
9
|
/** Whether `value` is a real calendar day written `YYYY-MM-DD` (`2026-02-29` and `2026-1-1` are not). */
|
|
9
10
|
export declare function isCalendarDay(value: unknown): value is string;
|
|
11
|
+
/** A `YYYY-MM-DD` calendar day in tool and form input: `isCalendarDay` as a zod schema. */
|
|
12
|
+
export declare const calendarDaySchema: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
10
13
|
/** `day` moved by `days` calendar days (negative goes back). Throws a `RangeError` for a malformed day or count. */
|
|
11
14
|
export declare function addCalendarDays(day: string, days: number): string;
|
|
12
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar-day.d.ts","sourceRoot":"","sources":["../src/calendar-day.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,qHAAqH;AACrH,wBAAgB,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAiCD,8FAA8F;AAC9F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAE9C,yGAAyG;AACzG,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE7D;AAED,oHAAoH;AACpH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAO,GAAG,MAAM,CAQzH;AAED,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAOnE"}
|
|
1
|
+
{"version":3,"file":"calendar-day.d.ts","sourceRoot":"","sources":["../src/calendar-day.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,qHAAqH;AACrH,wBAAgB,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQrE;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAiCD,8FAA8F;AAC9F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAE9C,yGAAyG;AACzG,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE7D;AAED,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,mFAAyF,CAAC;AAExH,oHAAoH;AACpH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAO,GAAG,MAAM,CAQzH;AAED,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAOnE"}
|
package/dist/calendar-day.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// The calendar day of an instant in a given IANA time zone, as `YYYY-MM-DD`. "Today" computed in the
|
|
2
|
+
// process zone is a classic date bug: on a server in UTC, an evening in New York is already tomorrow.
|
|
3
|
+
import { z } from "zod";
|
|
1
4
|
const formatters = new Map();
|
|
2
5
|
/** The calendar day (`YYYY-MM-DD`) of `instant` in `timeZone`. Throws a `RangeError` for an invalid date or zone. */
|
|
3
6
|
export function toCalendarDay(instant, timeZone) {
|
|
@@ -38,6 +41,8 @@ const DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
|
38
41
|
export function isCalendarDay(value) {
|
|
39
42
|
return typeof value === "string" && parseCivilDate(value) !== null;
|
|
40
43
|
}
|
|
44
|
+
/** A `YYYY-MM-DD` calendar day in tool and form input: `isCalendarDay` as a zod schema. */
|
|
45
|
+
export const calendarDaySchema = z.string().refine(isCalendarDay, "must be a YYYY-MM-DD calendar day, e.g. 2026-10-04");
|
|
41
46
|
/** `day` moved by `days` calendar days (negative goes back). Throws a `RangeError` for a malformed day or count. */
|
|
42
47
|
export function addCalendarDays(day, days) {
|
|
43
48
|
const operation = "addCalendarDays";
|
package/dist/calendar-day.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar-day.js","sourceRoot":"","sources":["../src/calendar-day.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"calendar-day.js","sourceRoot":"","sources":["../src/calendar-day.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -52,6 +52,11 @@ export interface SoftureConfig {
|
|
|
52
52
|
readonly timezone: string;
|
|
53
53
|
/** Scheme, host and port of the app, without a path: `https://app.example.com`. */
|
|
54
54
|
readonly appOrigin: string;
|
|
55
|
+
/**
|
|
56
|
+
* The public landing site (`https://example.com`) when the app lives on a subdomain beside it; `appOrigin` when
|
|
57
|
+
* the app does not name one. For links from the app to its marketing pages, not for the app's own URLs.
|
|
58
|
+
*/
|
|
59
|
+
readonly landingOrigin: string;
|
|
55
60
|
/** Every origin the app is served under besides `appOrigin`, read by `resolveAppOrigin`. */
|
|
56
61
|
readonly origins: SoftureOrigins;
|
|
57
62
|
/** Enabled modules, in the order the app listed them. */
|
|
@@ -63,6 +68,8 @@ export interface SoftureConfigInput {
|
|
|
63
68
|
readonly locale: Locale;
|
|
64
69
|
readonly timezone: string;
|
|
65
70
|
readonly appOrigin: string;
|
|
71
|
+
/** The public landing site beside the app; defaults to `appOrigin`. */
|
|
72
|
+
readonly landingOrigin?: string;
|
|
66
73
|
readonly origins?: SoftureOriginsInput;
|
|
67
74
|
readonly modules: readonly AnySoftureModule[];
|
|
68
75
|
}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAGnD;;;GAGG;AAEH,MAAM,WAAW,0BAA0B;CAAG;AAE9C,iHAAiH;AACjH,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,OAAO,CAAC;AAE5H,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,YAAY,CAAC,qBAAqB,CAAC,CAAC;CAC7D;AAED,qHAAqH;AACrH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC/C;AAED,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC/C;AA+BD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAoB5E;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GACnC,MAAM,CAAC,gBAAgB,EAAE,EAAE,uBAAuB,CAAC,CAGrD"}
|
package/dist/config.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { formatIssues, SoftureConfigError } from "./config-error.js";
|
|
5
5
|
import { isDatabaseOptional } from "./database-requirement.js";
|
|
6
|
-
import {
|
|
6
|
+
import { isLocale } from "./i18n.js";
|
|
7
7
|
import { err, ok } from "./result.js";
|
|
8
8
|
import { parseVersionRange, satisfiesRange } from "./version-range.js";
|
|
9
9
|
const CONFIG_SUBJECT = "softure.config (defineSoftureConfig)";
|
|
@@ -20,9 +20,10 @@ const configSchema = z.object({
|
|
|
20
20
|
})
|
|
21
21
|
.nullable()
|
|
22
22
|
.default(null),
|
|
23
|
-
locale: z.
|
|
23
|
+
locale: z.string().refine(isLocale, "must be a BCP 47 language tag, e.g. en or de-AT"),
|
|
24
24
|
timezone: z.string().refine(isTimeZone, "must be an IANA time zone, e.g. Europe/Warsaw"),
|
|
25
25
|
appOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE),
|
|
26
|
+
landingOrigin: z.string().refine(isOrigin, ORIGIN_MESSAGE).optional(),
|
|
26
27
|
origins: z
|
|
27
28
|
.strictObject({
|
|
28
29
|
trustedOrigins: z.array(z.string().refine(isOrigin, ORIGIN_MESSAGE)).max(16, "takes at most 16 origins").default([]),
|
|
@@ -48,6 +49,7 @@ export function defineSoftureConfig(input) {
|
|
|
48
49
|
}
|
|
49
50
|
return Object.freeze({
|
|
50
51
|
...config,
|
|
52
|
+
landingOrigin: config.landingOrigin ?? config.appOrigin,
|
|
51
53
|
database: config.database === null ? null : Object.freeze({ ...config.database }),
|
|
52
54
|
origins: Object.freeze({ ...config.origins, trustedOrigins: Object.freeze([...config.origins.trustedOrigins]) }),
|
|
53
55
|
modules: Object.freeze([...config.modules]),
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,gEAAgE;AAChE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/format.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/** `long`: October 4, 2026
|
|
1
|
+
import { type PluralForms } from "./i18n.js";
|
|
2
|
+
/** `long`: October 4, 2026; `medium`: Oct 4, 2026; `numeric`: 10/04/2026 (each locale writes its own order and separators). */
|
|
3
3
|
export type CalendarDayStyle = "long" | "medium" | "numeric";
|
|
4
4
|
export interface FormatMoneyOptions {
|
|
5
5
|
/** Whole units only, rounded half away from zero: PLN 1,235 for 1234.56. */
|
|
@@ -9,16 +9,60 @@ export interface FormatMoneyOptions {
|
|
|
9
9
|
/** The locale's short notation for large amounts: PLN 1.2M. */
|
|
10
10
|
readonly compact?: boolean;
|
|
11
11
|
}
|
|
12
|
+
/** `long`: October 2026; `roman`: X 2026. */
|
|
13
|
+
export type CalendarMonthStyle = "long" | "roman";
|
|
14
|
+
/** The words `formatDuration` writes: plural forms with `{count}`, and `both` joining `{years}` and `{months}`. */
|
|
15
|
+
export interface DurationMessages {
|
|
16
|
+
readonly years: PluralForms;
|
|
17
|
+
readonly months: PluralForms;
|
|
18
|
+
readonly both: string;
|
|
19
|
+
}
|
|
20
|
+
export interface FormatDurationOptions {
|
|
21
|
+
/** The BCP 47 tag whose plural rules pick a form (default `"en"`). */
|
|
22
|
+
readonly locale?: string;
|
|
23
|
+
/** The app's own words (default `DEFAULT_DURATION_MESSAGES`, English). */
|
|
24
|
+
readonly messages?: DurationMessages;
|
|
25
|
+
}
|
|
26
|
+
export interface FormatPercentOptions {
|
|
27
|
+
/** A `+` before a positive value (a `-` before a negative one is always there). Zero has neither in any mode. */
|
|
28
|
+
readonly signed?: boolean;
|
|
29
|
+
/** No space between the number and `%`, whatever the locale's pattern: `12,5%`, not `12,5 %`. */
|
|
30
|
+
readonly tight?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Exactly this many fraction digits, an integer from 0 to 20: `{ fractionDigits: 2 }` writes 1900 as `19.00%`.
|
|
33
|
+
* Without it a value has at most two fraction digits and no trailing zeros.
|
|
34
|
+
*/
|
|
35
|
+
readonly fractionDigits?: number;
|
|
36
|
+
}
|
|
37
|
+
/** The built-in, English words of `formatDuration`; any other category falls back to `other`. */
|
|
38
|
+
export declare const DEFAULT_DURATION_MESSAGES: DurationMessages;
|
|
12
39
|
/** A `YYYY-MM-DD` day as `locale` writes it. Throws a `RangeError` for a malformed day. */
|
|
13
|
-
export declare function formatCalendarDay(day: string, locale:
|
|
40
|
+
export declare function formatCalendarDay(day: string, locale: string, style?: CalendarDayStyle): string;
|
|
41
|
+
/** Whether `value` is a real calendar month written `YYYY-MM` (`2026-13` and `2026-1` are not). */
|
|
42
|
+
export declare function isCalendarMonth(value: unknown): value is string;
|
|
43
|
+
/**
|
|
44
|
+
* The month of a `YYYY-MM` month or a `YYYY-MM-DD` day, with its year, as `locale` writes it alone. Throws a
|
|
45
|
+
* `RangeError` for anything else.
|
|
46
|
+
*/
|
|
47
|
+
export declare function formatCalendarMonth(month: string, locale: string, style?: CalendarMonthStyle): string;
|
|
48
|
+
/**
|
|
49
|
+
* Whole months as years and months: 38 is "3 years and 2 months"; a part that is zero is left out, and zero itself is
|
|
50
|
+
* "0 months". English by default; an app passes its own `messages` and the `locale` whose plural rules pick among
|
|
51
|
+
* them. Throws a `RangeError` for a negative or fractional count, or an invalid locale tag.
|
|
52
|
+
*/
|
|
53
|
+
export declare function formatDuration(months: number, options?: FormatDurationOptions): string;
|
|
14
54
|
/**
|
|
15
55
|
* An amount in the currency's minor unit (2900 PLN = PLN 29.00) in `locale`'s notation, thousands always
|
|
16
|
-
* grouped (
|
|
56
|
+
* grouped (even where a locale's default would leave four digits together), and zero is never signed (`-0`
|
|
17
57
|
* and an amount that rounds to zero show as zero). The minor unit is the pinned ISO
|
|
18
58
|
* 4217 one (`CURRENCY_MINOR_UNIT_DIGITS`); a code outside the table gets `Intl`'s digits. Throws a
|
|
19
59
|
* `RangeError` for an amount that is not a whole number of minor units, or a code `Intl` refuses.
|
|
20
60
|
*/
|
|
21
|
-
export declare function formatMoney(minor: number, currency: string, locale:
|
|
22
|
-
/**
|
|
23
|
-
|
|
61
|
+
export declare function formatMoney(minor: number, currency: string, locale: string, options?: FormatMoneyOptions): string;
|
|
62
|
+
/**
|
|
63
|
+
* Basis points as a percentage in `locale`: 1250 is 12.5%, at most two fraction digits unless `fractionDigits` fixes
|
|
64
|
+
* them, and zero is never signed (`-0` and a value that rounds to zero show as `0%`, or `0.0%` at one digit). Throws a
|
|
65
|
+
* `RangeError` for a non-finite value or an invalid `fractionDigits`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatPercent(basisPoints: number, locale: string, options?: FormatPercentOptions): string;
|
|
24
68
|
//# sourceMappingURL=format.d.ts.map
|
package/dist/format.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAMA,OAAO,EAA+B,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE1E,+HAA+H;AAC/H,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,yKAAyK;IACzK,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,6CAA6C;AAC7C,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,mHAAmH;AACnH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,iHAAiH;IACjH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAMD,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,EAAE,gBAIvC,CAAC;AAeF,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,gBAAyB,GAAG,MAAM,CAGvG;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAM/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,kBAA2B,GAAG,MAAM,CAO7G;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAa1F;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,MAAM,CAarH;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAc7G"}
|
package/dist/format.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
// Days, money and percentages as people read them, one way for every module and app. A calendar day
|
|
2
|
-
// is formatted at UTC midnight in UTC, so neither the server's nor the reader's zone moves it.
|
|
2
|
+
// is formatted at UTC midnight in UTC, so neither the server's nor the reader's zone moves it. Every
|
|
3
|
+
// formatter takes any BCP 47 locale tag (an invalid one throws Intl's RangeError); the only built-in
|
|
4
|
+
// copy is English, and an app passes its own words where a formatter writes any.
|
|
3
5
|
import { isCalendarDay } from "./calendar-day.js";
|
|
4
6
|
import { CURRENCY_MINOR_UNIT_DIGITS } from "./currency-digits.js";
|
|
7
|
+
import { formatMessage, selectPlural } from "./i18n.js";
|
|
8
|
+
const MONTHS_PER_YEAR = 12;
|
|
9
|
+
const MONTH_PATTERN = /^(\d{4})-(\d{2})$/;
|
|
10
|
+
const ROMAN_MONTHS = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"];
|
|
11
|
+
/** The built-in, English words of `formatDuration`; any other category falls back to `other`. */
|
|
12
|
+
export const DEFAULT_DURATION_MESSAGES = {
|
|
13
|
+
years: { one: "{count} year", other: "{count} years" },
|
|
14
|
+
months: { one: "{count} month", other: "{count} months" },
|
|
15
|
+
both: "{years} and {months}",
|
|
16
|
+
};
|
|
5
17
|
const BASIS_POINTS_PER_UNIT = 10_000;
|
|
6
18
|
const MAX_PERCENT_FRACTION_DIGITS = 2;
|
|
19
|
+
const FRACTION_DIGITS_LIMIT = 20;
|
|
7
20
|
const dayFormatters = new Map();
|
|
8
21
|
const numberFormatters = new Map();
|
|
9
22
|
const DAY_STYLE_OPTIONS = {
|
|
@@ -15,17 +28,56 @@ const DAY_STYLE_OPTIONS = {
|
|
|
15
28
|
export function formatCalendarDay(day, locale, style = "long") {
|
|
16
29
|
if (!isCalendarDay(day))
|
|
17
30
|
throw new RangeError(`formatCalendarDay: "${String(day)}" is not a YYYY-MM-DD calendar day`);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
return getDayFormatter(`${locale}:${style}`, locale, DAY_STYLE_OPTIONS[style]).format(new Date(`${day}T00:00:00Z`));
|
|
32
|
+
}
|
|
33
|
+
/** Whether `value` is a real calendar month written `YYYY-MM` (`2026-13` and `2026-1` are not). */
|
|
34
|
+
export function isCalendarMonth(value) {
|
|
35
|
+
if (typeof value !== "string")
|
|
36
|
+
return false;
|
|
37
|
+
const match = MONTH_PATTERN.exec(value);
|
|
38
|
+
if (match === null)
|
|
39
|
+
return false;
|
|
40
|
+
const month = Number(match[2]);
|
|
41
|
+
return month >= 1 && month <= MONTHS_PER_YEAR;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The month of a `YYYY-MM` month or a `YYYY-MM-DD` day, with its year, as `locale` writes it alone. Throws a
|
|
45
|
+
* `RangeError` for anything else.
|
|
46
|
+
*/
|
|
47
|
+
export function formatCalendarMonth(month, locale, style = "long") {
|
|
48
|
+
const firstDay = isCalendarMonth(month) ? `${month}-01` : month;
|
|
49
|
+
if (!isCalendarDay(firstDay))
|
|
50
|
+
throw new RangeError(`formatCalendarMonth: "${String(month)}" is not a YYYY-MM month or a YYYY-MM-DD day`);
|
|
51
|
+
const date = new Date(`${firstDay}T00:00:00Z`);
|
|
52
|
+
const year = firstDay.slice(0, 4);
|
|
53
|
+
if (style === "roman")
|
|
54
|
+
return `${ROMAN_MONTHS[date.getUTCMonth()] ?? ""} ${year}`;
|
|
55
|
+
return getDayFormatter(`${locale}:month`, locale, { month: "long", year: "numeric" }).format(date);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Whole months as years and months: 38 is "3 years and 2 months"; a part that is zero is left out, and zero itself is
|
|
59
|
+
* "0 months". English by default; an app passes its own `messages` and the `locale` whose plural rules pick among
|
|
60
|
+
* them. Throws a `RangeError` for a negative or fractional count, or an invalid locale tag.
|
|
61
|
+
*/
|
|
62
|
+
export function formatDuration(months, options = {}) {
|
|
63
|
+
if (!Number.isSafeInteger(months) || months < 0) {
|
|
64
|
+
throw new RangeError(`formatDuration: ${String(months)} is not a whole, non-negative number of months`);
|
|
23
65
|
}
|
|
24
|
-
|
|
66
|
+
const locale = options.locale ?? "en";
|
|
67
|
+
const copy = options.messages ?? DEFAULT_DURATION_MESSAGES;
|
|
68
|
+
const years = Math.floor(months / MONTHS_PER_YEAR);
|
|
69
|
+
const rest = months % MONTHS_PER_YEAR;
|
|
70
|
+
const yearsText = formatMessage(selectPlural(locale, years, copy.years), { count: years });
|
|
71
|
+
const monthsText = formatMessage(selectPlural(locale, rest, copy.months), { count: rest });
|
|
72
|
+
if (years === 0)
|
|
73
|
+
return monthsText;
|
|
74
|
+
if (rest === 0)
|
|
75
|
+
return yearsText;
|
|
76
|
+
return formatMessage(copy.both, { years: yearsText, months: monthsText });
|
|
25
77
|
}
|
|
26
78
|
/**
|
|
27
79
|
* An amount in the currency's minor unit (2900 PLN = PLN 29.00) in `locale`'s notation, thousands always
|
|
28
|
-
* grouped (
|
|
80
|
+
* grouped (even where a locale's default would leave four digits together), and zero is never signed (`-0`
|
|
29
81
|
* and an amount that rounds to zero show as zero). The minor unit is the pinned ISO
|
|
30
82
|
* 4217 one (`CURRENCY_MINOR_UNIT_DIGITS`); a code outside the table gets `Intl`'s digits. Throws a
|
|
31
83
|
* `RangeError` for an amount that is not a whole number of minor units, or a code `Intl` refuses.
|
|
@@ -45,12 +97,46 @@ export function formatMoney(minor, currency, locale, options = {}) {
|
|
|
45
97
|
});
|
|
46
98
|
return format.format(minor / 10 ** digits);
|
|
47
99
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Basis points as a percentage in `locale`: 1250 is 12.5%, at most two fraction digits unless `fractionDigits` fixes
|
|
102
|
+
* them, and zero is never signed (`-0` and a value that rounds to zero show as `0%`, or `0.0%` at one digit). Throws a
|
|
103
|
+
* `RangeError` for a non-finite value or an invalid `fractionDigits`.
|
|
104
|
+
*/
|
|
105
|
+
export function formatPercent(basisPoints, locale, options = {}) {
|
|
50
106
|
if (!Number.isFinite(basisPoints))
|
|
51
107
|
throw new RangeError(`formatPercent: ${String(basisPoints)} is not a finite number of basis points`);
|
|
52
|
-
const format = getNumberFormatter(locale, {
|
|
53
|
-
|
|
108
|
+
const format = getNumberFormatter(locale, {
|
|
109
|
+
style: "percent",
|
|
110
|
+
...getPercentFractionDigits(options.fractionDigits),
|
|
111
|
+
signDisplay: options.signed === true ? "exceptZero" : "negative",
|
|
112
|
+
});
|
|
113
|
+
const value = basisPoints / BASIS_POINTS_PER_UNIT;
|
|
114
|
+
if (options.tight !== true)
|
|
115
|
+
return format.format(value);
|
|
116
|
+
const parts = format.formatToParts(value);
|
|
117
|
+
return parts
|
|
118
|
+
.filter((part, index) => !(part.type === "literal" && part.value.trim() === "" && isNextToPercentSign(parts, index)))
|
|
119
|
+
.map((part) => part.value)
|
|
120
|
+
.join("");
|
|
121
|
+
}
|
|
122
|
+
function getPercentFractionDigits(fractionDigits) {
|
|
123
|
+
if (fractionDigits === undefined)
|
|
124
|
+
return { maximumFractionDigits: MAX_PERCENT_FRACTION_DIGITS };
|
|
125
|
+
if (!Number.isInteger(fractionDigits) || fractionDigits < 0 || fractionDigits > FRACTION_DIGITS_LIMIT) {
|
|
126
|
+
throw new RangeError(`formatPercent: fractionDigits ${String(fractionDigits)} is not an integer from 0 to ${String(FRACTION_DIGITS_LIMIT)}`);
|
|
127
|
+
}
|
|
128
|
+
return { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits };
|
|
129
|
+
}
|
|
130
|
+
function isNextToPercentSign(parts, index) {
|
|
131
|
+
return parts[index - 1]?.type === "percentSign" || parts[index + 1]?.type === "percentSign";
|
|
132
|
+
}
|
|
133
|
+
function getDayFormatter(key, locale, options) {
|
|
134
|
+
let format = dayFormatters.get(key);
|
|
135
|
+
if (format === undefined) {
|
|
136
|
+
format = new Intl.DateTimeFormat(locale, { ...options, timeZone: "UTC" });
|
|
137
|
+
dayFormatters.set(key, format);
|
|
138
|
+
}
|
|
139
|
+
return format;
|
|
54
140
|
}
|
|
55
141
|
function getNumberFormatter(locale, options) {
|
|
56
142
|
const key = `${locale}:${JSON.stringify(options)}`;
|
package/dist/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,qGAAqG;AACrG,qGAAqG;AACrG,iFAAiF;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAoB,MAAM,WAAW,CAAC;AA2C1E,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAC1C,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,CAAU,CAAC;AAEzG,iGAAiG;AACjG,MAAM,CAAC,MAAM,yBAAyB,GAAqB;IACzD,KAAK,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE;IACtD,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACzD,IAAI,EAAE,sBAAsB;CAC7B,CAAC;AAEF,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AACtC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC,MAAM,aAAa,GAAG,IAAI,GAAG,EAA+B,CAAC;AAC7D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAE9D,MAAM,iBAAiB,GAAmE;IACxF,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;IAC3B,MAAM,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;IAC/B,OAAO,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;CAC/D,CAAC;AAEF,2FAA2F;AAC3F,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,MAAc,EAAE,QAA0B,MAAM;IAC7F,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,uBAAuB,MAAM,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IACtH,OAAO,eAAe,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC;AACtH,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,eAAe,CAAC;AAChD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa,EAAE,MAAc,EAAE,QAA4B,MAAM;IACnG,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAChE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,yBAAyB,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACzI,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,YAAY,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,OAAO;QAAE,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;IAClF,OAAO,eAAe,CAAC,GAAG,MAAM,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACrG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,UAAiC,EAAE;IAChF,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,UAAU,CAAC,mBAAmB,MAAM,CAAC,MAAM,CAAC,gDAAgD,CAAC,CAAC;IAC1G,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,yBAAyB,CAAC;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,GAAG,eAAe,CAAC;IACtC,MAAM,SAAS,GAAG,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3F,MAAM,UAAU,GAAG,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3F,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACnC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,QAAgB,EAAE,MAAc,EAAE,UAA8B,EAAE;IAC3G,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC7H,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,0BAA0B,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtH,MAAM,MAAM,GAAG,MAAM,IAAI,kBAAkB,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,eAAe,EAAE,CAAC,qBAAqB,IAAI,CAAC,CAAC;IAClI,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1D,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE;QACxC,KAAK,EAAE,UAAU;QACjB,QAAQ;QACR,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;QAChE,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,WAAW,EAAE,qBAAqB,EAAE,WAAW,EAAE,CAAC;KACrI,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,IAAI,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,MAAc,EAAE,UAAgC,EAAE;IACnG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,MAAM,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC;IACxI,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,EAAE;QACxC,KAAK,EAAE,SAAS;QAChB,GAAG,wBAAwB,CAAC,OAAO,CAAC,cAAc,CAAC;QACnD,WAAW,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU;KACjE,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,WAAW,GAAG,qBAAqB,CAAC;IAClD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;SACpH,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;SACzB,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,wBAAwB,CAAC,cAAkC;IAClE,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,CAAC;IAChG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,CAAC,IAAI,cAAc,GAAG,qBAAqB,EAAE,CAAC;QACtG,MAAM,IAAI,UAAU,CAAC,iCAAiC,MAAM,CAAC,cAAc,CAAC,gCAAgC,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC/I,CAAC;IACD,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,qBAAqB,EAAE,cAAc,EAAE,CAAC;AAC1F,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAuC,EAAE,KAAa;IACjF,OAAO,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,KAAK,aAAa,CAAC;AAC9F,CAAC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,MAAc,EAAE,OAAmC;IACvF,IAAI,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1E,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAc,EAAE,OAAiC;IAC3E,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnD,IAAI,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChD,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|