# ADR 0001 — Zero Runtime Dependencies

| Field | Value |
|---|---|
| **Status** | Accepted |
| **Date** | 2026-03-04 (v1.1.0) |
| **Deciders** | Core team |
| **Supersedes** | — |

---

## Context

When designing `xml-xsd-engine`, we faced a fundamental choice: build on top of existing npm packages (e.g. `sax`, `xmldom`, `fast-xml-parser`, `ajv`) or hand-implement every algorithm from scratch.

The XML/XSD/XPath ecosystem has many well-established packages. Using them would reduce initial development effort. However, every runtime dependency brings:

1. **Security risk** — each dependency is a potential CVE. Supply-chain attacks (e.g. `event-stream`, `colors`) affect any package in the transitive dependency graph.
2. **Bundle size** — a validation library used in browser builds must be minimal. Transitive dependencies compound rapidly.
3. **Maintenance burden** — upstream breaking changes, deprecations, and unmaintained packages become blockers.
4. **API mismatch** — adapting foreign APIs to a cohesive TypeScript-first interface often adds more code than implementing the feature directly.
5. **Auditability** — enterprises adopting the library in regulated environments (finance, healthcare, government) need to audit every line of shipped code.

---

## Decision

**`xml-xsd-engine` will have zero runtime dependencies, forever.**

Every algorithm — the lexer, DOM builder, SAX parser, namespace resolver, XSD parser, schema compiler, validation engine, XPath evaluator, SHA-256 hasher, XSLT transformer, JSON transforms, LRU cache, and diff engine — is hand-implemented in TypeScript within `src/`.

The `devDependencies` (TypeScript, Jest, ts-jest, ESLint) are allowed and will never appear in the published package.

This is enforced by:
1. Keeping `dependencies: {}` in `package.json`
2. The `no-restricted-imports` ESLint rule, configured to reject imports from any non-relative, non-Node.js-builtin specifier
3. PR review — any addition to `dependencies` is a blocker

---

## Consequences

### Positive

- **Zero CVEs from upstream** — the security surface is limited to code we wrote and control
- **Minimal bundle** — ~165 kB published size; tree-shakable via `"sideEffects": false`
- **Long-term stability** — no risk of upstream breaking changes or abandonment
- **Full auditability** — every line in the published package is reviewed by the core team
- **Consistent API** — all exports follow our naming conventions and TypeScript design patterns
- **Browser-ready** — the `/browser` entry point has no Node.js API dependencies because we never took them on

### Negative

- **Higher initial implementation cost** — writing SHA-256, an LRU cache, and a streaming XML lexer from scratch takes time
- **Larger codebase** — ~8,000 lines of implementation vs. ~2,000 if we delegated to deps
- **No ecosystem leverage** — cannot benefit from upstream bug fixes in delegated packages

### Mitigations

The high implementation cost is offset by a rigorous test suite (1333 tests) and the long-term benefits. For algorithms with well-known implementations (SHA-256, LRU), we implement the standard algorithm directly.

---

## Alternatives Considered

| Alternative | Rejected Because |
|---|---|
| Use `sax` / `saxes` for SAX parsing | Would hide our token stream; prevent line/col tracking in lexer; add a dependency |
| Use `xmldom` for DOM | Different API shape; no TypeScript-first design; security history |
| Use `fast-xml-parser` for parsing | No XSD validation; incompatible internal model |
| Use `ajv` for JSON Schema validation | Unrelated to XSD; would create a dep for the codegen output, not the engine itself |
| Use Node.js `crypto` for SHA-256 | Not available in browsers/Deno/Bun; would break the `/browser` entry point |

