You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -115,7 +115,8 @@ xx.xx.xxxx
115
115
***Breaking** - `kebabToCamel` and `camelToKebab` now use lossless encoding — digit-leading segments are preserved with `_` (e.g. `grid-2x2` → `grid_2x2`), and every uppercase letter gets its own hyphen (e.g. `arrowDownAZ` → `arrow-down-a-z`). Both accept a `separator` option to customize the digit-boundary character. `camelToKebab` now normalizes leading uppercase by default for DOM-safe output (e.g. `FooBar` → `foo-bar`); pass `{ lossless: true }` to preserve it for exact round-trips.
116
116
***Feature** - Added [`humanize`](https://next.semantic-ui.com/docs/api/utils/strings#humanize) — turns a machine identifier (`snake_case`, `kebab-case`, `camelCase`, `PascalCase`) into human-readable label text, keeping acronym runs whole including plurals (`getURLsFromPage` → `Get URLs from page`), dropping a trailing `id` (`user_id` → `User`), and sentence-casing by default. `titleCase` switches to header casing, `constantCase` sentence-cases shouting enums (`IN_PROGRESS` → `In progress`). The display-side inverse of `tokenize`
117
117
***Enhancement** - `humanize` rescues common lowercase acronyms out of the box (`api_url` → `API URL`) through a `humanize.config` vocabulary seeded with `id`/`url`/`api`. Extend it once at app boot and every call inherits it, or pass a per-call `terms` map that layers over the global. `humanize.config` also carries the default `titleCase`/`dropId`/`constantCase`
118
-
* **Feature** - Added a coercion suite — [`toBoolean`](https://next.semantic-ui.com/docs/api/utils/coercion#toboolean), [`toNumber`](https://next.semantic-ui.com/docs/api/utils/coercion#tonumber), [`toInteger`](https://next.semantic-ui.com/docs/api/utils/coercion#tointeger), [`toDate`](https://next.semantic-ui.com/docs/api/utils/coercion#todate), [`toString`](https://next.semantic-ui.com/docs/api/utils/coercion#tostring), with `coerceX` aliases — best-effort conversion of loose input to a target type. Each returns the type or `null` when there is no clean reading, never a poison value, so results compose with `??`. `toBoolean` reads a generous set of true/false spellings, `toNumber` never yields `NaN` or `Infinity`, `toDate` takes ISO strings and epoch-ms numbers only (ambiguous formats like `01/15/2024` return null rather than a guessed Date), and `toString` returns null for objects instead of `"[object Object]"`. `toBoolean` and `toString` take `{ loose: true }` to fall back to native truthiness or JSON rendering. Every helper takes `{ onInvalid: 'passthrough' }` to return the original value on a failed coercion instead of `null`, so a schema or validator sees the bad input rather than an erasing `null` (the passthrough return widens the TypeScript type to include the input). `toBoolean` reads its vocabulary and defaults from an editable `toBoolean.config` (mirroring `humanize.config`), so a locale or domain teaches it new true/false spellings once at boot instead of on every call
118
+
* **Feature** - Added a coercion suite — [`toBoolean`](https://next.semantic-ui.com/docs/api/utils/coercion#toboolean), [`toNumber`](https://next.semantic-ui.com/docs/api/utils/coercion#tonumber), [`toInteger`](https://next.semantic-ui.com/docs/api/utils/coercion#tointeger), [`toDate`](https://next.semantic-ui.com/docs/api/utils/coercion#todate), [`toDuration`](https://next.semantic-ui.com/docs/api/utils/coercion#toduration), [`toString`](https://next.semantic-ui.com/docs/api/utils/coercion#tostring), with `coerceX` aliases — best-effort conversion of loose input to a target type. Each returns the type or `null` when there is no clean reading, never a poison value, so results compose with `??`. `toBoolean` reads a generous set of true/false spellings, `toNumber` never yields `NaN` or `Infinity`, `toDate` takes ISO strings and epoch-ms numbers only (ambiguous formats like `01/15/2024` return null rather than a guessed Date), and `toString` returns null for objects instead of `"[object Object]"`. `toBoolean` and `toString` take `{ loose: true }` to fall back to native truthiness or JSON rendering. Every helper takes `{ onInvalid: 'passthrough' }` to return the original value on a failed coercion instead of `null`, so a schema or validator sees the bad input rather than an erasing `null` (the passthrough return widens the TypeScript type to include the input). `toBoolean` reads its vocabulary and defaults from an editable `toBoolean.config` (mirroring `humanize.config`), so a locale or domain teaches it new true/false spellings once at boot instead of on every call
119
+
***Feature** - Added [`toDuration`](https://next.semantic-ui.com/docs/api/utils/coercion#toduration) — reads a duration expression as milliseconds, so `'5s'`, `'1.5h'`, and `'300msecs'` all become numbers a timer or TTL takes directly. One number and one optional unit, case-insensitive, with the space optional, and unit words, abbreviations, and plurals all read (`'10 minutes'`, `'2hrs'`, `'.5d'`). A unitless string reads as milliseconds so `'1500'` and `1500` agree, the sign is kept, and a compound form like `'1h 30m'` returns `null` rather than a partial reading. Milliseconds through weeks are built in because each is a fixed span. Years and months are not: a year is a judgment call (the `ms` package reads it as 365.25 days) and a month has no length without a calendar date, so `toDuration.config.units` names your own value once at boot rather than inheriting someone else's guess
119
120
***Feature** - Added a bytes module — [`toBase64`](https://next.semantic-ui.com/docs/api/utils/bytes#tobase64) and [`fromBase64`](https://next.semantic-ui.com/docs/api/utils/bytes#frombase64) — unicode-safe base64 encode/decode, the pair `btoa`/`atob` never were. A string round-trips through its UTF-8 bytes (emoji and accents survive), `toBase64` also takes an `ArrayBuffer` or typed array and a `{ urlSafe }` option, and `fromBase64` decodes both alphabets, strips MIME/PEM line wrapping, and returns a string or `Uint8Array` — or `null` on malformed input, never a throw
120
121
***Feature** - Added [`configured`](https://next.semantic-ui.com/docs/api/utils/functions#configured) — attaches an editable `fn.config` to a function as one tree-shakable expression. All configured utilities (`humanize`, `toTitleCase`, `getArticle`, `toBoolean`, `formatDate`) use it, so a bundle only pays for the vocabularies it imports — the attribute-codec path that pulls in string casing no longer carries any of them
121
122
***Feature** - Arbitrary vocabularies now live in editable configs, set once at app boot: [`toTitleCase.config.stopWords`](https://next.semantic-ui.com/docs/api/utils/strings#totitlecase) (style guides disagree on the list, `humanize`'s `titleCase` reads the same one), [`getArticle.config.exceptions`](https://next.semantic-ui.com/docs/api/utils/strings#getarticle) for sound-contradicts-spelling words (`an hour`, `a university` now correct out of the box), and [`formatDate.config.timezones`](https://next.semantic-ui.com/docs/api/utils/dates#formatdate) for remapping an ambiguous shorthand like `IST`. `toDate` reads unix-second timestamps (a JWT `exp`) via `{ epoch: 'seconds' }`
Best-effort conversion of loose input (attribute strings, query params, JSON) to a target type. Each returns the type or `null` when there is no clean reading, so results compose with `??`. Also exported as `coerceBoolean`/`coerceNumber`/`coerceInteger`/`coerceDate`/`coerceString`.
580
+
Best-effort conversion of loose input (attribute strings, query params, JSON) to a target type. Each returns the type or `null` when there is no clean reading, so results compose with `??`. Also exported as `coerceBoolean`/`coerceNumber`/`coerceInteger`/`coerceDate`/`coerceDuration`/`coerceString`.
tip: 'Unit words and abbreviations both read, so 10 minutes, 2hrs, and 300msecs all work. Years and months have no fixed length, so name your own value with toDuration.config.units'
Each helper is also exported as `coerceBoolean`, `coerceNumber`, `coerceInteger`, `coerceDate`, and `coerceString` for callers who think in coercion terms.
18
+
Each helper is also exported as `coerceBoolean`, `coerceNumber`, `coerceInteger`, `coerceDate`, `coerceDuration`, and `coerceString` for callers who think in coercion terms.
19
19
20
20
Every helper accepts an `onInvalid` setting. It defaults to `'null'` (the failed coercion returns `null`, composing with `??`). Pass `{ onInvalid:'passthrough' }` to return the *original* value instead, so a schema or validator can flag the bad input rather than see an erasing `null` — and the TypeScript return widens to include the input type (`number | string` for `toNumber(str, { onInvalid:'passthrough' })`).
Coerces a duration expression to milliseconds, or `null` when it reads as no duration at all. A number is already milliseconds, and a string takes one number followed by one optional unit, case-insensitively, with an optional space between the two: `'5s'`, `'1.5h'`, `'10 minutes'`, `'2hrs'`, `'300msecs'`, `'.5d'`. Leave the unit off and the number reads as milliseconds, so `'1500'` and `1500` agree.
202
+
203
+
The sign is kept, so `'-1.5h'` is `-5400000`. Compound expressions like `'1h 30m'` are a different grammar and return `null` rather than a partial reading, as do unknown units, bare numbers with trailing junk, and exponent notation.
Every unit here is a fixed span. Years and months are absent because neither has one: a year is a judgment call (the `ms` package reads it as 365.25 days) and a month has no length without a calendar date to anchor it. Name your own value in `toDuration.config.units` rather than inheriting someone else's guess.
`toDuration.config.units` holds the milliseconds per unit, keyed by the lowercase spelling accepted after the number. Edit it once at app boot to teach the grammar a unit your domain uses, and every call inherits it.
0 commit comments