# `A2UICore.Schema.ECMA262`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_core/lib/a2ui_core/schema/ecma_262.ex#L1)

ECMA-262 → PCRE regex translation for the `pattern` and
`patternProperties` keywords.

JSON Schema defines `pattern` as an unanchored ECMA-262 regular
expression with Unicode semantics. PCRE (Erlang's `:re`) differs in
ways the translation covers:

* **`$` anchor** — ECMA-262 `$` matches only at the end of the input
  when the pattern is not multiline; PCRE `$` also matches before a
  trailing newline. The reference implementation rewrites unescaped
  `$` outside character classes to an absolute end anchor; so does
  this module (`\z`).
* **Character classes** — `\d`, `\w` and `\b` are ASCII, as in
  ECMA-262, and are spelled out as ASCII classes: the PCRE of
  Erlang/OTP 27 and earlier counts Latin-1 letters such as `é` as word
  characters. `\s` is ECMA-262's white space and line terminators
  (PCRE's Unicode spaces plus U+FEFF), `\v` the vertical tab alone,
  and `.` any character but a line terminator.
* **Escapes** — `\uXXXX` (a surrogate pair of them is one code
  point) and `\u{X...}` become PCRE's `\x{...}`.
* **Unicode property names** — `\p{...}` and `\P{...}` take
  ECMA-262's names. PCRE knows the short General_Category values
  (`L`, `Lu`), scripts (`Script=Greek`, `scx=Grek`) and binary
  properties (`Alphabetic`, `XID_Start`), but not the long
  General_Category values (`Letter`, `Uppercase_Letter`), the
  `General_Category=`/`gc=` forms or `Assigned`; those are rewritten.
* **XID properties on older PCRE** — Erlang/OTP 28 and later bundle
  PCRE2, whose `XID_Start` and `XID_Continue` are exact. Older PCRE
  lacks them, so there they expand to their derivation: `XID_Start` ≈
  `\p{L}\p{Nl}` and the Other_ID_Start characters that stay
  identifiers under NFKC (`℘`, `℮`, U+1885, U+1886); `XID_Continue` ≈
  that, `\p{Mn}\p{Mc}\p{Nd}\p{Pc}` and the Other_ID_Continue
  characters (`·`, U+0387, U+1369 to U+1371, U+19DA).
* **Scripts on older PCRE** — older PCRE names a script bare
  (`\p{Greek}`), so `Script=` and `sc=` are dropped there, and
  `Script_Extensions=`/`scx=` fall back to the script. Only full script
  names (`Greek`, not `Grek`) are known to it.

Matching is *search* (unanchored), per JSON Schema. A search stops
after a million backtracking steps: patterns come from agents and
catalogs, and one such as `^(a+)+$` would otherwise run until PCRE's
own limit, ten times that, and then report no match.

# `compile`
*since 0.1.0* 

```elixir
@spec compile(String.t()) :: {:ok, Regex.t()} | {:error, A2UICore.Error.t()}
```

Compiles an ECMA-262 pattern into a PCRE `Regex` after translation.

Returns `{:ok, regex}` or `{:error, %A2UICore.Error{}}`.

# `compile!`
*since 0.1.0* 

```elixir
@spec compile!(String.t()) :: Regex.t()
```

Like `compile/1`, but raises `A2UICore.Error` when the pattern does not
compile.

# `match?`
*since 0.1.0* 

```elixir
@spec match?(String.t(), String.t()) :: boolean()
```

Like `search/2` but returns `false` on a pattern that fails to compile.

# `search`
*since 0.1.0* 

```elixir
@spec search(String.t(), String.t()) ::
  {:ok, boolean()} | {:error, A2UICore.Error.t()}
```

Searches `value` for the ECMA-262 `pattern` (unanchored, per JSON
Schema).

Returns `{:ok, boolean}`, or `{:error, error}` when the pattern itself
cannot compile (`INVALID_REGEX`) or the search takes more than a million
backtracking steps (`REGEX_LIMIT`); the caller decides how to surface
that.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
