lib/pages/changelog.md

# Changelog

## v0.14.0 (2026-03-11)

### Features

- Added `NeoFaker.Data.supported_locales/0` — returns the supported locale atoms from
  `priv/data/locale.exs`, cached in `:persistent_term`.
- Added `NeoFaker.Gravatar.profile/2` — generates a Gravatar profile URL with `:format` option
  (`:html`, `:json`, `:xml`, `:php`, `:vcf`, `:qr`).
- Added `NeoFaker.Gravatar.random/0` — generates a Gravatar image URL with a random size and
  fallback type.
- Added `NeoFaker.Gravatar.fallback_types/0`, `default_size/0`, and `size_range/0` as public
  introspection helpers.
- Added `NeoFaker.Gravatar.display/2` options `:rating` (`:g`, `:pg`, `:r`, `:x`) and
  `:force_default` (appends `&f=y` when `true`).
- Added `NeoFaker.App.Validator.validate_domain!/1` — raises `ArgumentError` on invalid domain
  strings, replacing silent `MatchError` in `bundle_id/1` and `package_name/1`.
- Added `NeoFaker.Internet.Validator.validate_ipv4_class!/1` — raises `ArgumentError` on invalid
  `:class` values in `ipv4/1`, replacing `FunctionClauseError`.
- Added `NeoFaker.Internet.Generator.reserved_ipv4?/3` — public predicate for all IANA-reserved
  IPv4 ranges, usable independently of the generator.
- Added `NeoFaker.Helpers.Formatter` for format conversions and `NeoFaker.Helpers.Options` for
  option extraction and validation.
- Added `NeoFaker.IdId.Person.npwp/0` for generating Indonesian tax identification numbers (NPWP).
- Added `NeoFaker.Address.Generator` with `latitude/1` and `longitude/1`.
- Consolidated all data-access helpers into `NeoFaker.Data`.

### Improvements

- **`public_ipv4/0`** — Now excludes all IANA-reserved ranges: `0.0.0.0/8`, `10.0.0.0/8`,
  `100.64.0.0/10`, `127.0.0.0/8`, `169.254.0.0/16`, `172.16.0.0/12`, `192.0.0.0/24`,
  `192.0.2.0/24`, `192.88.99.0/24`, `192.168.0.0/16`, `198.18.0.0/15`, `198.51.100.0/24`,
  `203.0.113.0/24`, `224.0.0.0/4`, and `240.0.0.0/4`. First-octet selection uses a compile-time
  cumulative weight table for O(1) performance.
- **`url_path/0` and `query_string/0`** — Multi-word entries from `Text.word/0` (e.g.
  `"ice cream"`) are slugified (spaces → `-`) before use in path segments and query keys.
- **`url/1`** — Fixed double-TLD output (e.g. `"gmail.com.net"`) for `:popular` and `:custom`
  domain types; TLD is now only appended for `:random` domains.
- **`set_locale/1`** — Validates the locale against `supported_locales/0` before storing; the
  error message lists all valid values.
- **`NeoFaker.Data`** — Locale file now resolved via `:code.priv_dir/1`, fixing lookup when
  NeoFaker is used as a Mix dependency.
- **`Crypto.token/2`** — Fixed guard that incorrectly matched any integer; `ArgumentError` is
  now raised only for non-positive lengths.
- **`Number.decimal/3`** — Delegates to `between/2` before rounding, inheriting `min > max`
  validation.
- Extracted `Validator` and `Generator` sub-modules across all major modules: `Address`, `App`,
  `Blood`, `Boolean`, `Color`, `Crypto`, `Date`, `Gravatar`, `HTTP`, `Internet`, `Lorem`,
  `Number`, `Person`, `Text`, and `Time`.
- Removed `NeoFaker.Helpers.Constants` in favour of module attributes.
- Added `@doc` to all sub-module functions for improved autocomplete.
- Bumped minimum Erlang/OTP to 28.0 and Elixir to 1.18.4. Pinned dev toolchain to OTP 28.3 and
  Elixir 1.19.4 in `mise.toml` and CI.
- Renamed the "Available Locales" docs page to "Locales".

### Bug Fixes

- `bundle_id/1` and `package_name/1` now raise `ArgumentError` (not `MatchError`) for domains
  with no dot or empty strings.
- `ipv4/1` now raises `ArgumentError` (not `FunctionClauseError`) for unsupported `:class` values.
- `public_ipv4/0` no longer generates loopback, private, link-local, multicast, CGN, or
  test/documentation addresses.
- Fixed off-by-one in `find_octet_in_table/2` cumulative weight lookup.
- Fixed `Address.city/0` returning `nil` for some locales.
- Fixed `Date.birthday/3` start date calculation.
- Fixed crash in `Time.time_zone/0` when locale data is incomplete.
- Scoped `:persistent_term` cache keys to tuples to prevent cross-module collisions.
- Added path-traversal validation on data file names in `NeoFaker.Data`.
- `domain_name/1` with `type: :custom` now raises `ArgumentError` for a non-string or empty
  `:domain_name`, preventing bad values from propagating into `email/1` and `url/1`.
- `validate_domain!/1` now enforces RFC 1123 label rules — alphanumeric start/end, letters,
  digits, and hyphens only, max 63 chars per label. Rejects trailing dots, `/`, `:`, and
  leading/trailing hyphens.
- `locale/0` now raises `ArgumentError` for unsupported atoms stored directly in the application
  env, preventing `get_locale/0` from reporting a different locale than generators actually use.
- `Number.decimal/3` now raises `ArgumentError` for negative precision (was `FunctionClauseError`).
  The `@spec` is widened to `number()` to reflect that integer bounds are accepted.

### Breaking Changes

- **`set_locale/1`** raises `ArgumentError` for any atom not in `priv/data/locale.exs` (or
  `:default`). Use `NeoFaker.Data.supported_locales/0` to list valid values.
- **`ipv4/0`** (public mode) no longer returns IANA-reserved addresses. Use `ipv4(private: true)`
  if you need a private range address.

### Tests

- Added comprehensive `GravatarTest` coverage: size, fallback types, `:rating`, `:force_default`,
  `profile/2` formats, `random/0`, and all introspection helpers.
- Replaced probabilistic IPv4 sampling with deterministic boundary assertions against
  `reserved_ipv4?/3`, covering all IANA blocks at both endpoints and adjacent public addresses.
  Class-specific private IPv4 tests also verify full four-octet structure.
- Added `AppTest` error-path coverage for `bundle_id/1` and `package_name/1` domain validation.
- Added `CryptoTest` coverage for `token/2` length errors and hash format checks.
- Added `NumberTest` coverage for `decimal/3` range errors, bounds, precision, and mixed-type
  float generation in `between/2`.
- Added `NeoFakerTest` coverage for `set_locale/1` and `locale/0` valid and invalid inputs.
- Refactored all test modules to follow ExUnit conventions: `async: true`, module aliases,
  `refute` over `not assert`, `for` over `Enum.each`, separate assertions over compound `assert`.

## v0.13.0 (2025-10-29)

### Features

Added new module `NeoFaker.Internet` to handle internet-related data generation, including:

- `NeoFaker.Internet.tld/1` for generating random top-level domains (TLDs).
- `NeoFaker.Internet.username/1` for generating random usernames.
- `NeoFaker.Internet.domain_name/1` for generating random domain names.
- `NeoFaker.Internet.email/1` for generating random email addresses.
- `NeoFaker.Internet.ipv4/1` for generating random IPv4 addresses.
- `NeoFaker.Internet.ipv6/1` for generating random IPv6 addresses.
- `NeoFaker.Internet.mac_address/1` for generating random MAC addresses.
- `NeoFaker.Internet.url/1` for generating random URLs.
- `NeoFaker.Internet.slug/2` for generating random URL slugs.

### Improvements

- Changed `.tool-versions` to `mise.toml` for better version management, now NeoFaker uses mise
  as the version manager.
- Upgraded mix dependencies.
- Fixed typo in `cheat.cheatmd` file.
- Refactored `NeoFaker.Data.Cache` and `NeoFaker.Data.Disk` for improved file handling and caching
  mechanisms.

### Module Changes

**Breaking Changes**: Renamed `NeoFaker.Http` to `NeoFaker.HTTP` for consistency.

## v0.12.0 (2025-06-10)

### Features

- Added `NeoFaker.Address` for generating random address components: building numbers, cities, countries, and coordinates.
- Added `NeoFaker.Time.time_zone/0` for generating random time zones.

### Improvements

- Unified and clarified documentation for all public functions.
- Refactored generator modules: `NeoFaker.Data.Cache`, `NeoFaker.Data.Disk`,
  `NeoFaker.Data.Generator`, and `NeoFaker.Data.Resolver` for improved organization and
  readability.
- Updated `NeoFaker.Data.Cache.put_cache!/3` to use `Stream.uniq/1` for duplicate removal before
  caching.
- Upgraded mix dependencies.

**Breaking:** Renamed `NeoFaker.Internet` to `NeoFaker.HTTP` with expanded features.

#### `NeoFaker.http` (formerly `NeoFaker.Internet`)

- Added `Http.request_method/0` for random HTTP methods.
- Added `Http.referrer_policy/0` for random referrer policies.
- Added `Http.status_code/1` for random HTTP status codes with filtering.
- Enhanced `Http.user_agent/1` to support `:type` filtering (`:browser` or `:crawler`).

### Argument Standardization

**Breaking:** Default arguments now use explicit atoms:

- `NeoFaker.Color.hex/1` defaults to `:six_digit` (was `nil`).
- `NeoFaker.Color.keyword/1` defaults to `:all` (was `nil`).

### Organization & Locale

- Split large utility modules into smaller, focused modules.
- Improved documentation and examples.
- Added Indonesian locale support.