# Changelog
## 0.3.0
### Bug fixes
- **`$..[*]` / `$..[0]` / `$..[1:3]` no longer return duplicates** when descending into maps whose values are lists. (`collect_all_lists` was double-counting list values found inside maps.)
- **Infix `!` is now rejected by the parser instead of crashing the evaluator.** `!` only participates as a prefix operator (`!@.x`, `!(...)`); using it as a binary operator used to bypass the parser and crash inside a non-existent binary `Kernel.!` function.
- **Built-in functions are crash-safe.** `min()`/`max()` on `[]`, `sum()`/`avg()` on non-numeric or empty data, `concat()` on a map, and `length()` on unsupported types all return `nil` (or `0` for sum) instead of raising.
- **Division and modulo by zero in filters no longer crash.** They propagate a "Nothing" marker that the filter treats as no match.
- **Missing keys are distinguishable from explicit `null` inside filters.** `@.missing == null` now returns `false`; `@.missing != null` returns `true`. Two missing paths still compare equal (Nothing == Nothing). Top-level `$.missing` still returns `nil` for backward compatibility.
- **Mixed-type ordering comparisons return `false`** instead of leaking BEAM term-order (e.g. `"hello" > 10` is no longer truthy in filters).
- **Parser errors include line numbers and the unparsed remainder** when the parser only partially consumes input.
- **Parser accepts non-binary input gracefully** — returns `{:error, _}` rather than `FunctionClauseError`.
### Performance
- **Array slicing is now linear-time.** A `$[::2]` slice on a 100,000-element list went from ~9 s to ~3 ms (~3,000× faster). `$[::-1]` went from ~18 s to ~5 ms.
- **Single-index access avoids tuple allocation**, so root-reference filters like `$[?(@.value > $[0].value)]` are ~25× faster and use ~50× less memory.
- **`Enum.reduce` + reverse replaces `++` appends** in multi-key bracket access and in the comparison-chain grouping helper, removing quadratic behavior on larger inputs.
- **`collect_all_lists` is no longer recursive into already-collected lists**, which also speeds up `$..[…]` queries.
### New features
- **Full RFC 9535 escape sequences** in single- and double-quoted strings: `\n`, `\t`, `\r`, `\b`, `\f`, `\/`, `\\`, `\'`, `\"`, and `\uXXXX`. Unknown escapes pass through unchanged so regex patterns can be embedded inline.
- **Unicode member names** in dot notation: `$.屬性`, `$.имя`, etc. Previously these required bracket notation.
- **Scientific-notation float literals**: `1.5e2`, `-1e-3`, `2E+2`, `-0.123e2`.
- **`count()` built-in** (postfix and prefix). Returns the length of a list or the size of a map.
- **Prefix-style function calls in filters**: `length(@)`, `count(@.x)`, `sum(@.nums)`, `min(@.scores)`, `max(@.scores)`, `avg(@.values)`, `concat(@.parts)`, `match(@.s, "regex")`, `search(@.s, "regex")`.
- **`match()` and `search()` regex built-ins**. `match()` requires the whole string to match (RFC 9535 semantics); `search()` matches anywhere. Invalid regex patterns return `false` instead of raising.
- **`JSONPathEx.evaluate!/2`** — raises on parse failure and returns the evaluation result directly.
### Code quality
- Removed dead `min: 1` option passes to `NimbleParsec.repeat/3` (the option was silently ignored).
- Dropped `unwrap_and_tag` from punctuation combinators that are then wrapped in `ignore` (`[`, `]`, `(`, `)`, `,`, `:`, `'`, `"`).
- Removed unused `is_list(result)` branch from multi-key bracket access on lists (`get/2` on a list always returns a list).
- Improved internal sentinels (`@missing`) are namespaced (`:"$$__jsonpath_ex_missing__$$"`) to avoid collision with user-supplied atoms.
### Test suite
- 116 → 206 tests, including:
- `test/jsonpath_ex/regression_test.exs` — one test per fixed bug, asserting the corrected behavior.
- `test/jsonpath_ex/feature_test.exs` — coverage for every new feature.
- `test/jsonpath_ex/stress_test.exs` — `@tag :performance` deep/wide stress cases (run with `mix test --include performance`).
### Benchmarks
- New `bench/` directory with Benchee suites for parsing, evaluation, slicing, filters, and recursion. Run any of them with `mix run bench/<file>.exs`.
---
## 0.2.0
Initial public release on Hex.