bimorph 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -39
  3. package/package.json +2 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Oleksandr Zhuravlov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,57 +1,87 @@
1
1
  # bimorph
2
2
 
3
- A TypeScript library for **bidirectional data mapping**. Define a mapping **once**,
4
- get both directions for free:
3
+ [![npm](https://img.shields.io/npm/v/bimorph)](https://www.npmjs.com/package/bimorph)
4
+ [![license: MIT](https://img.shields.io/npm/l/bimorph)](LICENSE)
5
5
 
6
- - `decode` external representation domain value
7
- - `encode` domain valueexternal representation
6
+ **Bidirectional data mapping for TypeScript.** Define a mapping once and get both
7
+ directions `decode` (wire domain) and `encode` (domain wire) — with the reverses
8
+ that *don't* invert cleanly surfaced in the type instead of failing silently.
8
9
 
9
- The interesting part is not the happy path (a `Record` already does that). It's
10
- that **most real mappings do not invert cleanly** — duplicate values, lossy
11
- transforms, missing keys, read-only fields, and reverses that need runtime context
12
- the value doesn't carry. bimorph's thesis: *embrace that reality, surface it early,
13
- and give the caller explicit, legible escape hatches* — rather than pretend every
14
- mapping is a clean isomorphism.
10
+ ```ts
11
+ import { Enum } from 'bimorph';
15
12
 
16
- ## Status
13
+ const Status = Enum([
14
+ [1, 'active'],
15
+ [0, 'inactive'],
16
+ ]);
17
17
 
18
- Design phase + a **typechecked prototype** proving the load-bearing type machinery.
18
+ Status.decode(1); // 'active' — wire domain
19
+ Status.encode('active'); // 1 — domain → wire
20
+ ```
19
21
 
20
- Docs:
22
+ One declaration, both directions — no hand-written reverse lookup drifting out of sync.
21
23
 
22
- - [`apps/docs/`](apps/docs) the full documentation site (Fumadocs + Next.js App
23
- Router). Every `ts twoslash` example is type-checked against `src/index.ts` at
24
- build time. Run it with `npm run docs`, then open http://localhost:3411.
25
- - [`docs/DESIGN.md`](docs/DESIGN.md) — principles, contracts, and the API surface.
26
- - [`docs/SCENARIOS.md`](docs/SCENARIOS.md) — ~28 real-world scenarios gathered to test the design against.
27
- - [`docs/DOGFOOD.md`](docs/DOGFOOD.md) the design written against those scenarios, and the gaps it exposed.
24
+ ## The problem it kills
25
+
26
+ The happy path is easy; a lookup object already does that. The pain is the *reverse*:
27
+
28
+ ```ts
29
+ const STATUSES = { 0: 'BAD', 1: 'OK' };
30
+ const label = STATUSES[0]; // easy
31
+ const value = Object.entries(STATUSES).find(([, v]) => v === 'OK')?.[0]; // ugh — and it drifts
32
+ ```
33
+
34
+ And most real mappings *don't* invert cleanly: duplicate values, lossy transforms,
35
+ missing keys, read-only fields, reverses that need runtime context the value doesn't
36
+ carry. Most tools ignore that or hide it. bimorph's thesis: **surface non-invertibility
37
+ in the type, and give explicit escape hatches** — instead of pretending every mapping is
38
+ a clean isomorphism.
39
+
40
+ That shows up as:
28
41
 
29
- Prototype:
42
+ - **Fidelity tiers** — `iso` (exact round-trip), `lossy` (no round-trip promised),
43
+ `partial` (the inverse can fail). A `partial` codec doesn't even offer a throwing
44
+ `decode`; the type forces you through `safeDecode`.
45
+ - **Doors, not flags** — `decode` throws with a path, `safeDecode` returns a `Result`,
46
+ `decodeOr` falls back, `validate` accumulates every error. The behavior is visible at
47
+ the call site, never a hidden config flag.
48
+ - **Aliases** — several wire values decode to one domain value, but `encode` only ever
49
+ emits the canonical one (narrowed in the type), so a migration can't leak a legacy
50
+ spelling.
51
+ - **Context** — a codec that needs a `region` or `locale` says so in its type; you can't
52
+ silently forget to pass it.
30
53
 
31
- - [`src/index.ts`](src/index.ts) — minimal runtime, but the **real** types: `iso` / `lossy` /
32
- `partial` / `Enum` (with aliases) / `Struct` / `Field` / `bind`.
54
+ ## Install
33
55
 
34
56
  ```bash
35
- npm install
36
- npm run typecheck # tsc --noEmit over src/
37
- npm run check:runtime # runtime-behaviour regression gate over src/
38
- npm run docs # run the documentation site (apps/docs) at http://localhost:3411
57
+ npm install bimorph
39
58
  ```
40
59
 
41
- What the prototype proves compiles (see the MDX for the assertions):
60
+ > **Early release expect breaking changes before 1.0.** The API has just stabilized,
61
+ > but the package currently ships TypeScript source (`src/index.ts`): it works in a
62
+ > TypeScript project with a bundler, and a compiled `dist/` (`.js` + `.d.ts`) for plain
63
+ > Node/JS is on the way. Pin the version.
42
64
 
43
- 1. **Alias narrowing** — `Enum` decode accepts the *wide* union (primaries + aliases),
44
- `encode` returns the *narrow* canonical-only union. A migration cannot emit a legacy spelling.
45
- 2. **Contextual codecs** — a `Ctx` third param whose trailing argument is required
46
- (`decode(b)` without it is a type error), `.bind(ctx)` erases it back to a plain codec,
47
- and `Struct` **intersects** the contexts of its fields into one merged bag.
48
- 3. **`Partial` removes the throwing decode door** at the type level — you're forced to `safeDecode`.
65
+ ## Documentation
49
66
 
50
- ## The one-line motivation
67
+ The full documentation site — Fumadocs, with every `ts twoslash` example type-checked
68
+ against the real types at build time — lives in [`apps/docs/`](apps/docs). Run it with
69
+ `npm run docs` and open http://localhost:3411.
51
70
 
52
- ```ts
53
- // The problem this exists to kill:
54
- const STATUSES = { 0: "BAD", 1: "OK" };
55
- const label = STATUSES[0]; // easy
56
- const value = Object.entries(STATUSES).find(([, v]) => v === "OK")?.[0]; // ugh
71
+ Design record:
72
+
73
+ - [`docs/DESIGN.md`](docs/DESIGN.md) principles, the codec contract, and the API surface.
74
+ - [`docs/SCENARIOS.md`](docs/SCENARIOS.md) — ~28 real-world mappings the design was tested against.
75
+ - [`docs/DOGFOOD.md`](docs/DOGFOOD.md) the design written against those scenarios, and the gaps it exposed.
76
+
77
+ ## Development
78
+
79
+ ```bash
80
+ npm run typecheck # tsc --noEmit over src/
81
+ npm run check:runtime # runtime-behaviour regression gate
82
+ npm run docs # the documentation site at http://localhost:3411
57
83
  ```
84
+
85
+ ## License
86
+
87
+ [MIT](LICENSE) © 2026 Oleksandr Zhuravlov
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "bimorph",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
+ "license": "MIT",
5
6
  "description": "Bidirectional data mapping for TypeScript — define a mapping once, get decode and encode, with non-invertibility surfaced in the type.",
6
7
  "exports": {
7
8
  ".": "./src/index.ts"