# Adding a New Identifier

This crate is organized so that every identifier type — CNPJ today, ISIN and CFI planned — follows the same shape, both
in `src/` and in this book. Sticking to the pattern keeps the crate predictable to use and cheap to review.

## Source layout

Each identifier gets its own module directory, named after the identifier in lowercase (mirror `src/cnpj/`):

```text
src/
  <identifier>.rs             # public type, module docs, inherent methods
  <identifier>/
    error.rs                  # the <Identifier>Error enum + Display
    fmt.rs                    # Display/Debug + any zero-allocation formatted-string helper
    parser.rs                 # string -> normalized candidate (formatting/case only)
    validation.rs              # normalized candidate -> Result<(), Error> (structural + checksum rules)
    serde.rs                   # #[cfg(feature = "serde")]
    schema.rs                  # #[cfg(feature = "schemars")]
    arbitrary.rs                # #[cfg(feature = "arbitrary")]
    proptest.rs                 # #[cfg(any(test, feature = "proptest"))], pub
    tests.rs                    # #[cfg(test)]
```

The **parser vs. validation split** matters: `parser` only knows about *formatting* (stripping punctuation, folding
case) and has no opinion on which characters are valid where; `validation` only knows about *rules* (character class,
checksum, degenerate input) and has no opinion on how the original string was formatted. This keeps each half testable
independently and makes it obvious where a new rule belongs.

## Feature flags

Follow the same `Cargo.toml` convention as CNPJ — every integration is optional and additive:

```toml
[features]
serde = ["dep:serde"]
schemars = ["dep:schemars", "serde"]
arbitrary = ["dep:arbitrary"]
proptest = ["dep:proptest"]
```

A new identifier should gate its `serde`/`schemars`/`arbitrary`/`proptest` modules behind the *same* feature names as
CNPJ (not per-identifier features like `cnpj-serde`), so enabling `serde` once turns it on for every identifier type in
the crate.

## lib.rs

Re-export the new public type (and its error type, and any formatted-string helper type) at the crate root, the same way
CNPJ does:

```rust,ignore
mod isin;
pub use isin::{Isin, IsinError, FormattedIsin};
```

Forgetting this step means the error type technically exists but can never be named by downstream code — the same gap
this documentation pass caught and fixed for `Cnpj`.

## Documentation checklist

For the module itself (`src/<identifier>.rs`):

- [ ] Module-level doc comment covering: what the identifier represents, its segment structure (a table works well),
  format history/variants if any, the full list of validation rules mapped to error variants, relevant design notes (
  allocation, `Copy`, ordering/hashing semantics), feature flags, and at least one runnable example.
- [ ] Every public method has a doc comment with a runnable `# Examples` section.
- [ ] Every public trait impl (`FromStr`, `TryFrom`, `AsRef`, ...) has a one-line doc comment on the implementing
  method.
- [ ] `# Errors` sections on every fallible public function.

For this book (`docs/src/identifiers/<identifier>/`):

- [ ] `README.md` — landing page: what the identifier is, a minimal example, a table of contents for the rest of the
  chapter.
- [ ] `format.md` — structure and any format history.
- [ ] `parsing-and-validation.md` — constructors and validation rules.
- [ ] `formatting-and-display.md` — rendering, `Display`/`Debug`.
- [ ] `error-handling.md` — error variant table and a matching example.
- [ ] `feature-flags.md` — one section per optional integration.
- [ ] `examples.md` — end-to-end usage beyond the quick start.

Code blocks in this book use ` ```rust,ignore ` rather than ` ```rust `, since `mdbook test` isn't currently wired up to
link against the compiled crate. The examples themselves should still mirror real, compiler-verified doctests from the
source — copy them from `src/<identifier>.rs` rather than writing new, untested snippets from scratch.

## Wiring it into `SUMMARY.md`

Replace the draft placeholder for your identifier with a real link, and add the same sub-chapters CNPJ has:

```markdown
- [ISIN](./identifiers/isin/README.md)
    - [Structure & Formats](./identifiers/isin/format.md)
    - [Parsing & Validation](./identifiers/isin/parsing-and-validation.md)
    - [Formatting & Display](./identifiers/isin/formatting-and-display.md)
    - [Error Handling](./identifiers/isin/error-handling.md)
    - [Feature Flags](./identifiers/isin/feature-flags.md)
    - [Examples](./identifiers/isin/examples.md)
```

A draft entry (`- [ISIN]()`, with no link target) renders as a disabled item in the sidebar and requires no file to
exist yet — that's how ISIN and CFI are currently listed. Only replace it once the chapter files actually exist; a link
to a missing file breaks the `mdbook build`.