# Vendored dependencies

Third-party source compiled directly into the `svelixir` application via
`@vendor_paths` in `mix.exs` (`elixirc_paths` adds `vendor/**/lib`). These are
**not** Hex dependencies: they carry no entry in `deps/0` and none in
`mix.lock`.

Nothing here is formatted, linted, or documented by this project's gates —
`.formatter.exs` `inputs`, `.credo.exs` `included:`, `.doctor.exs`
`ignore_paths` and `coveralls.json` `skip_files` all exclude `vendor/`. Upstream
source is therefore never reformatted or rewritten to satisfy a gate; the only
deviations from what Hex published are the ones under
[Local patches](#local-patches).

**Dialyzer is the exception, and it is not excludable by path.** It analyses the
compiled beams, and vendored `lib/` compiles into this application's own `ebin`,
so an upstream warning surfaces as this project's. `sourceror` produces one —
it pattern-matches its own `Sourceror.Zipper.path()` opaque type — and it is
recorded in `.dialyzer_ignore.exs` file-and-warning specifically rather than as
a blanket `vendor/` skip, which would also hide a warning caused by how this
project calls vendored code. Check for new entries when refreshing a package.

## Contents

Each directory holds the upstream `lib/` tree and the upstream licence file.
`README.md` is vendored only where the package reads it at compile time.

| Package       | `lib/`   | Licence      | `README.md`                 |
| ------------- | -------- | ------------ | --------------------------- |
| `simple_enum` | 1 file   | `LICENSE.md` | vendored — required         |
| `sourceror`   | 20 files | `LICENSE`    | vendored — required         |
| `typedstruct` | 2 files  | `LICENSE.md` | vendored — required         |
| `vex`         | 25 files | `LICENSE`    | not vendored — not required |

`simple_enum`, `typedstruct` and `sourceror` all read their `README.md` at
compile time for their `@moduledoc` and register it as an `@external_resource`,
so dropping it turns a missing file into a compile error. `vex` does not, so its
`README.md` is not carried.

`sourceror` is the only Apache-2.0 entry; the other three are MIT. It publishes
no `NOTICE` file, so carrying `LICENSE` satisfies §4(d) and nothing further is
required.

## Provenance

Vendored 2026-08-12 from the Hex releases below, copied out of `deps/` after a
`mix deps.get` that resolved these exact versions. The outer checksum is the one
Hex recorded in `mix.lock` before the entry was removed — it is what to verify
against when refreshing.

| Package       | Version | Licence | Outer checksum                                                     |
| ------------- | ------- | ------- | ------------------------------------------------------------------ |
| `simple_enum` | 1.0.0   | MIT        | `2b5788c38b76f11bf18d3c65fc329e819dc047e67d84128f3fe898f809df12d7` |
| `sourceror`   | 1.12.2  | Apache-2.0 | `da37d3da09c5b890528802c7056a8f585a061973820d7656b6e3649c14f0e9cb` |
| `typedstruct` | 0.5.4   | MIT     | `ffaef36d5dbaebdbf4ed07f7fb2ebd1037b2c1f757db6fb8e7bcbbfabbe608d8` |
| `vex`         | 0.9.2   | MIT     | `76e709a9762e98c6b462dfce92e9b5dfbf712839227f2da8add6dd11549b12cb` |

## Application dependencies

None of the four has a **Hex** dependency of its own, which is what makes
compiling their `lib/` straight into this application sound: there is no
transitive graph to resolve. `sourceror` declares eight, and every one of them
is `only: [:dev, :test]` — verified against its `mix.exs` before vendoring.

`sourceror` declares `extra_applications: [:logger]`, which this project already
lists. No change to `extra_applications` was required.

There is one **OTP application** dependency, and it does not come across on its
own. `vex` declared `applications: [:eex]` in its `mix.exs`, which vendoring
leaves behind — the app spec covering `lib/vex/error_renderers/eex.ex` stays
with the file it applies to. `:eex` is therefore listed in this project's
`extra_applications`. Without it dialyzer reports `EEx.eval_string/2` as
unknown, and a release that selected vex's EEx error renderer would fail at
runtime.

When refreshing a package, read its upstream `mix.exs` `application/0` before
discarding it, and carry anything it declares into `extra_applications`.

## Local patches

Kept to the minimum, and recorded here because a local edit that is not written
down is indistinguishable from upstream code to every reader and every tool.

There are exactly two, and they are the same edit for the same reason.
`simple_enum` and `vex` are byte-identical to what Hex published.

- **`typedstruct/lib/typed_struct.ex`** — the `@moduledoc`/`@external_resource`
  README path. Upstream reads `"README.md"` relative to the **current working
  directory**, which is correct only because Mix compiles a Hex dependency with
  the cwd set to `deps/typedstruct`. Vendored onto this application's
  `elixirc_paths` the cwd is the project root, so upstream would read _this_
  repo's `README.md`, find no `<!-- @moduledoc -->` marker, and raise
  `Enum.OutOfBoundsError` at compile time. Now resolved against `__DIR__`,
  which is how `simple_enum` already does it. Re-apply when refreshing.

- **`sourceror/lib/sourceror.ex`** — the `@moduledoc`/`@external_resource`
  README path. Identical in cause and fix to `typedstruct`'s above: upstream
  reads `"README.md"` relative to the current working directory, which for a
  vendored tree is this repository's root. It would find no `<!-- MDOC !-->`
  marker in this project's README and raise `Enum.OutOfBoundsError` at compile
  time. Now resolved against `__DIR__`. Re-apply when refreshing.

## Verified

48 `.ex` files compile and 89 vendored modules land in the application's own
`ebin`. All four work: `typedstruct` builds a struct with defaults,
`simple_enum`'s generated macros resolve, and `Vex.errors/1` reports and clears
correctly — `Svelixir.Config` and its sections are built entirely out of those
three, and its test suite covers them end to end. `sourceror` parses and patches
by range, which `Svelixir.MixExs` is built entirely out of; `Svelixir.VendorTest`
covers both that and the local patch above, since an unpatched `@moduledoc` path
would fail at COMPILE time rather than in a test.

Protocol consolidation is off in `:test` (`consolidate_protocols:` in
`mix.exs`). `use Vex.Struct` emits `defimpl Vex.Extract`, and a struct defined
in a test file compiles after consolidation has already fixed the dispatch, so
validating it would otherwise raise `Protocol.UndefinedError`.

To re-check a tree against upstream:

```sh
mix hex.package fetch <package> <version> --unpack --output /tmp/<package>
diff -r /tmp/<package>/lib vendor/<package>/lib
```

## Refreshing a vendored package

```sh
# --output is a DIRECTORY in both forms, not a filename.
mix hex.package fetch <package> <version> --output /tmp/pkg
shasum -a 256 /tmp/pkg/<package>-<version>.tar     # compare with the table above

mix hex.package fetch <package> <version> --unpack --output /tmp/<package>
```

Then, in order:

1. Replace `vendor/<package>/lib` wholesale.
2. Re-copy the licence file, and `README.md` if the package needs one.
3. Re-apply any local patch listed above, and update its entry.
4. Check the upstream `mix.exs` `application/0` for OTP applications to carry
   into `extra_applications`.
5. Update the provenance row and the file/module counts above.

Do not hand-patch vendored source without recording it here: a local edit that
is not written down is indistinguishable from upstream code to every reader and
every tool.
