zopia 0.3.0

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 (47) hide show
  1. package/CHANGELOG.md +354 -0
  2. package/LICENSE +21 -0
  3. package/README.md +167 -0
  4. package/bin/zopia.js +20 -0
  5. package/docs/01-overview.md +94 -0
  6. package/docs/02-targets.md +55 -0
  7. package/docs/03-roadmap.md +205 -0
  8. package/docs/04-architecture.md +345 -0
  9. package/docs/05-concepts.md +239 -0
  10. package/docs/06-conversions.md +493 -0
  11. package/docs/07-api-docs.md +337 -0
  12. package/docs/08-components.md +223 -0
  13. package/docs/09-configuration.md +167 -0
  14. package/docs/10-usage.md +208 -0
  15. package/docs/11-testing.md +267 -0
  16. package/docs/12-standards.md +242 -0
  17. package/docs/README.md +42 -0
  18. package/docs/publish-workflow.yml.example +48 -0
  19. package/package.json +77 -0
  20. package/src/api-docs-navigation.ts +353 -0
  21. package/src/cli-command.ts +537 -0
  22. package/src/cli.ts +4 -0
  23. package/src/config.ts +190 -0
  24. package/src/conversions/api-docs-facade.ts +42 -0
  25. package/src/conversions/api-docs-generate.ts +567 -0
  26. package/src/conversions/api-docs-layout.ts +39 -0
  27. package/src/conversions/api-docs-plan.ts +130 -0
  28. package/src/conversions/api-docs-presets.ts +246 -0
  29. package/src/conversions/json-schema-to-zod.ts +931 -0
  30. package/src/conversions/manifest-staleness.ts +211 -0
  31. package/src/conversions/manifest-to-openapi.ts +1861 -0
  32. package/src/conversions/manifest-writer.ts +778 -0
  33. package/src/conversions/openapi-contracts.ts +333 -0
  34. package/src/conversions/openapi-external-ref.ts +233 -0
  35. package/src/conversions/openapi-ir.ts +74 -0
  36. package/src/conversions/openapi-ref.ts +38 -0
  37. package/src/conversions/openapi-to-api-docs-public.ts +466 -0
  38. package/src/conversions/openapi-to-api-docs.ts +203 -0
  39. package/src/conversions/openapi.ts +80 -0
  40. package/src/conversions/reverse-security.ts +68 -0
  41. package/src/conversions/yaml.ts +876 -0
  42. package/src/conversions/zod-to-json-schema.ts +536 -0
  43. package/src/diff.ts +353 -0
  44. package/src/errors.ts +114 -0
  45. package/src/index.ts +80 -0
  46. package/src/validation.ts +299 -0
  47. package/src/warnings.ts +164 -0
@@ -0,0 +1,94 @@
1
+ # ๐Ÿงญ Overview
2
+
3
+ zopia is a **type-safe OpenAPI โ†” Zod toolkit** for generating, validating, and
4
+ transforming API schemas. It converts between the four formats an API team
5
+ lives in โ€” **Swagger 2.0**, **OpenAPI 3.x**, **JSON Schema**, and **Zod v4** โ€”
6
+ and turns any of them into a tree of **type-safe `km-api` endpoint files** that
7
+ drop straight into a TypeScript codebase.
8
+
9
+ ## ๐ŸŒฉ๏ธ The problem
10
+
11
+ API teams keep the same knowledge in many places, and every copy drifts:
12
+
13
+ | ๐Ÿ˜– Pain | ๐Ÿ” Consequence |
14
+ | --- | --- |
15
+ | The spec (`swagger.json`) describes the API | โ€ฆbut the validation code is written by hand |
16
+ | Zod schemas validate at runtime | โ€ฆbut they are re-typed from the spec, field by field |
17
+ | Components (`$ref`) keep the DRY spec | โ€ฆbut the generated code duplicates the same shapes |
18
+ | Swagger 2.0 and OpenAPI 3.x differ subtly | โ€ฆand both must be supported to read legacy specs |
19
+
20
+ **Every copy is a source of bugs. Every re-typing is a waste of time.**
21
+
22
+ ## ๐Ÿ› ๏ธ The solution
23
+
24
+ zopia makes the spec and the code **two views of one fact**:
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ A["๐Ÿ“„ swagger.json<br/>(v2 / v3)"] -->|"โ‘ข openapi โ†’ api docs"| B["๐Ÿ“‚ api_docs/**<br/>(.ts ยท km-api ยท zod v4)"]
29
+ B -->|"โ‘ฃ api docs โ†’ openapi"| A
30
+ C["โš›๏ธ Zod v4 schemas"] -->|"โ‘  zod โ†’ JSON Schema"| D["๐Ÿ“ JSON Schema"]
31
+ D -->|"โ‘ก JSON Schema โ†’ zod"| C
32
+ ```
33
+
34
+ - **โ‘ข** reads a spec, resolves every `$ref`, and renders one **`index.ts` per
35
+ endpoint** โ€” each built with `makeApiConfig()` from **km-api** (0.4.x), with
36
+ request/response/params/query/headers/cookies validated by **Zod v4** schemas.
37
+ - **โ‘ฃ** reads that tree back and regenerates a complete OpenAPI document โ€” so
38
+ developer edits to the generated code become the new spec.
39
+ - **โ‘  / โ‘ก** are the two primitive schema converters the other engines are built on.
40
+
41
+ ## ๐ŸŽฏ The promise
42
+
43
+ > **Fast and valid developing.** A developer gets **valid, documented,
44
+ > type-safe** endpoint code **in seconds**, from a spec they already trust โ€”
45
+ > and can always get the spec back.
46
+
47
+ ## ๐Ÿงฐ The stack (fixed, by standard)
48
+
49
+ | ๐Ÿงฉ Piece | Version | Role in zopia |
50
+ | --- | --- | --- |
51
+ | โš›๏ธ [Zod](https://zod.dev/) | **v4** (`^4`) | Runtime validation + static types; built-in `z.toJSONSchema()` |
52
+ | ๐Ÿงฑ [km-api](https://www.npmjs.com/package/km-api) | **0.4.x** (`^0.4` from npm) | The "make function" โ€” `makeApiConfig()` builds every generated endpoint |
53
+ | ๐ŸŸฃ [Bun](https://bun.sh/) | `โ‰ฅ 1.1` | Primary runtime & toolchain (runs the package, tests, and generated code) |
54
+ | ๐Ÿงช [Vitest](https://vitest.dev/) | latest stable | Test runner for the full scenario matrix |
55
+ | ๐Ÿ”ท TypeScript | `5.9+`, `strict` | Language of the package and of every generated file |
56
+
57
+ ## ๐Ÿ‘ฅ Who is this for?
58
+
59
+ - ๐Ÿง‘โ€๐Ÿ’ป **TypeScript backend teams** that maintain a Swagger/OpenAPI spec and
60
+ want the validation layer generated, not hand-written
61
+ - ๐Ÿ”„ **Legacy teams** still on Swagger 2.0 who need a path to OpenAPI 3.x
62
+ - ๐Ÿค **Full-stack teams** that want one artifact (`api_docs/**`) shared between
63
+ server validation and client code
64
+
65
+ ## ๐Ÿšซ Non-goals (Phase 1)
66
+
67
+ Being explicit about what zopia **does not do** keeps the scope honest:
68
+
69
+ - ๐ŸŒ It is **not a runtime** โ€” no HTTP server, no client, no hosting of specs.
70
+ (km-api already provides client adapters; zopia generates the definitions.)
71
+ - โœ๏ธ It is **not a spec editor** โ€” it never edits your original spec file.
72
+ - ๐Ÿงฎ It does **not execute user code** except through the documented,
73
+ trusted-input contract of engine โ‘ฃ (see [Standards โ†’ Safety](12-standards.md#-safety)).
74
+ - ๐Ÿ“ **YAML input** โ€” v0.1.0 accepted JSON only; v0.2.x lifts that limit
75
+ (D-16): JSON/YAML objects, JSON/YAML text, and `spec.json` / `spec.yaml` /
76
+ `spec.yml` all enter the same normalized model through zopia's owned
77
+ deterministic YAML parser.
78
+
79
+ ## ๐Ÿ’Ž Core principles
80
+
81
+ | # | Principle | Meaning |
82
+ | --- | --- | --- |
83
+ | P-1 | ๐ŸŽฏ **Deterministic** | Same input + same options โ‡’ **byte-identical** output. No timestamps, no random order, no environment leakage. |
84
+ | P-2 | ๐Ÿ”’ **Lossless by design** | Every conversion is reversible; what cannot be represented in the target format is recorded (manifest + warnings), never silently dropped. |
85
+ | P-3 | ๐Ÿงผ **Pure core** | In-memory transforms stay pure; documented file reads, generated-tree writes/imports, and CLI process access live at explicit adapter boundaries. |
86
+ | P-4 | ๐Ÿ›ก๏ธ **Safe** | Fail loudly with typed, actionable errors; never write outside the configured output directory; never hide lossy conversions. |
87
+ | P-5 | ๐Ÿ“– **Documented** | Every public symbol has JSDoc; every rule is numbered; every decision is recorded. |
88
+ | P-6 | ๐Ÿ“ฆ **Dependency-light** | Zero bundled runtime dependencies; `zod` and `km-api` remain explicit peers (`zod` powers engines โ‘ /โ‘ก and generated schemas; km-api powers generated endpoints and their reverse imports). |
89
+
90
+ ## ๐Ÿ”— Next
91
+
92
+ - ๐ŸŽฏ The completed public targets โ†’ [Targets](02-targets.md)
93
+ - ๐Ÿ—บ๏ธ Release phases and deferred breadth โ†’ [Roadmap](03-roadmap.md)
94
+ - ๐Ÿงฉ Words you will keep seeing โ†’ [Concepts](05-concepts.md)
@@ -0,0 +1,55 @@
1
+ # ๐ŸŽฏ Targets
2
+
3
+ These are the **explicit, testable targets** of zopia. Every Phase 1 target maps
4
+ to its governing document and automated release-gate coverage โ€” see
5
+ [Testing โ†’ Scenario matrix](11-testing.md).
6
+
7
+ > โœ… **Complete** = implemented, documented, and covered by the release gate.
8
+ > Deferred work is listed explicitly under [Roadmap โ†’ Phase 2](03-roadmap.md#-phase-2--breadth-v02x-).
9
+
10
+ ## ๐Ÿ”„ Conversion targets
11
+
12
+ | # | ๐ŸŽฏ Target | Spec | Status |
13
+ | --- | --- | --- | --- |
14
+ | T-1 | **Convert Zod โ†’ JSON Schema** | [Conversions โ†’ Engine โ‘ ](06-conversions.md) | โœ… |
15
+ | T-2 | **Convert JSON Schema โ†’ Zod** | [Conversions โ†’ Engine โ‘ก](06-conversions.md) | โœ… |
16
+ | T-3 | **Convert OpenAPI โ†’ api docs** โ€” Swagger 2.0 *and* OpenAPI 3.0/3.1 | [Conversions โ†’ Engine โ‘ข](06-conversions.md) | โœ… |
17
+ | T-4 | **Convert api docs โ†’ OpenAPI** (the reverse direction) | [Conversions โ†’ Engine โ‘ฃ](06-conversions.md) | โœ… |
18
+
19
+ ## ๐Ÿ“‚ API docs targets
20
+
21
+ | # | ๐ŸŽฏ Target | Spec | Status |
22
+ | --- | --- | --- | --- |
23
+ | T-5 | **Layout mode `directory`** โ€” `api_docs/` + path segments as nested directories + a method-named directory at the last level + `index` file | [API docs format โ†’ directory mode](07-api-docs.md) | โœ… |
24
+ | T-6 | **Layout mode `flat`** โ€” `api_docs/` + one directory per API + method directory + `index` file | [API docs format โ†’ flat mode](07-api-docs.md#-mode--flat) | โœ… |
25
+ | T-7 | **`index.ts` files are TypeScript** and fill **all practical content** of the endpoint (method, path, operationId, summary, description, tags, auth, content types, request, response, examples) using **`makeApiConfig()` from km-api** (the package's make function) | [API docs format โ†’ `index.ts` contract](07-api-docs.md#-the-indexts-contract) | โœ… |
26
+ | T-8 | **Option `insertComponents: boolean`** โ€” when `true`, components are written into `api_docs` as their own schema files; **default `false`** | [Components](08-components.md) ยท [Configuration](09-configuration.md) | โœ… |
27
+ | T-9 | **Option `useComponentAsReference: boolean`** โ€” endpoints import emitted components recursively; requires `insertComponents: true`; **default `false`** | [Components โ†’ option matrix](08-components.md) | โœ… |
28
+
29
+ ## ๐Ÿ” Reverse-conversion targets
30
+
31
+ | # | ๐ŸŽฏ Target | Spec | Status |
32
+ | --- | --- | --- | --- |
33
+ | T-10 | **Reversible output** โ€” the generated tree contains everything needed to regenerate the spec (paths, methods, schemas, metadata), guaranteed by the manifest | [API docs format โ†’ manifest](07-api-docs.md) | โœ… |
34
+ | T-11 | **Round-trip stability** โ€” `openapi โ†’ api docs โ†’ openapi` and `zod โ†’ JSON Schema โ†’ zod` converge: re-running the pipeline on its own output is a no-op (idempotent) | [Testing โ†’ round-trip tests](11-testing.md#-round-trip-property-tests) | โœ… |
35
+
36
+ ## ๐Ÿ—๏ธ Engineering targets
37
+
38
+ | # | ๐ŸŽฏ Target | Spec | Status |
39
+ | --- | --- | --- | --- |
40
+ | T-12 | **JSDoc everywhere** โ€” every exported function, type, constant, and class is documented (template + rules fixed) | [Standards โ†’ JSDoc standard](12-standards.md) | โœ… |
41
+ | T-13 | **Tests in all scenarios** โ€” Vitest suite covering the full scenario matrix (spec versions, ref graphs, modes, option combinations, zod features, edge cases), run with Bun | [Testing](11-testing.md) | โœ… |
42
+ | T-14 | **Bun runs the project** โ€” install, typecheck, test, coverage, CLI, and generated-TypeScript imports all work through one pinned-Bun gate | [Standards โ†’ Bun gate](12-standards.md#-bun-gate) | โœ… |
43
+ | T-15 | **Standard documentation** โ€” `docs/` directory with targets, roadmap, architecture, conventions; README links into it; beautiful, icon-based markdown | this document set ยท [Standards โ†’ Docs convention](12-standards.md#-docs-convention) | โœ… |
44
+ | T-16 | **Quality bar** โ€” pure, safe, clean code with descriptions; deterministic output; typed errors; no silent lossy conversions | [Standards](12-standards.md) | โœ… |
45
+ | T-17 | **Changelog after commits** โ€” `CHANGELOG.md` updated by every user-facing commit under `Unreleased` | [Standards โ†’ Changelog convention](12-standards.md#-changelog-convention) | โœ… |
46
+
47
+ ## ๐Ÿ—บ๏ธ Out of scope for the first phase
48
+
49
+ > ๐Ÿ“Œ The reverse-conversion *capability* (T-4/T-10/T-11) **is** in the first
50
+ > phase โ€” it is part of the four targets above. What is deferred:
51
+
52
+ - ~~๐Ÿ“ YAML spec input~~ โ†’ shipped in v0.2.x (D-16; `.yaml`/`.yml` files and inline YAML text reach the same normalized model as JSON)
53
+ - ๐Ÿ”— External (multi-file) `$ref`s โ†’ [Roadmap Phase 2](03-roadmap.md)
54
+ - ๐Ÿงฉ Reusable **parameters / responses** as emitted components (Phase 1 emits `components.schemas` only) โ†’ [Roadmap Phase 2](03-roadmap.md)
55
+ - ~~๐Ÿ–ฅ๏ธ `zopia validate` (spec linting)~~ โ†’ shipped in v0.3.x (S-89; [Roadmap Phase 3](03-roadmap.md)); incremental regeneration remains deferred
@@ -0,0 +1,205 @@
1
+ # ๐Ÿ—บ๏ธ Roadmap
2
+
3
+ zopia ships in phases. **Phase 0 is this documentation set** โ€” the contracts
4
+ are fixed before a line of code is written, so implementation never re-decides
5
+ anything.
6
+
7
+ ## ๐Ÿšฆ Phase 0 โ€” Documentation & standards โœ…
8
+
9
+ The standard documentation of the project:
10
+
11
+ - ๐Ÿ“š `docs/` โ€” overview, targets, roadmap, architecture, concepts, conversions,
12
+ api-docs format, components, configuration, usage, testing, standards
13
+ - ๐Ÿ  `README.md` โ€” project home with the documentation map
14
+ - ๐Ÿ“œ `CHANGELOG.md` โ€” Keep-a-Changelog format + the "changelog after commits" rule
15
+ - ๐Ÿ” `LICENSE` (MIT) ยท ๐Ÿงน `.gitignore`
16
+ - ๐Ÿ”‘ Key decisions **D-01 โ€ฆ D-15** recorded in [Standards](12-standards.md#-key-decisions)
17
+
18
+ **Completed:** the documentation fixed the Phase 1 contracts before
19
+ implementation; it now describes the implemented v0.1.0 behavior and deferred scope.
20
+
21
+ ## ๐Ÿš€ Phase 1 โ€” The four engines (v0.1.0) โœ…
22
+
23
+ **Released:** 2026-09-28. Everything in [Targets](02-targets.md) is marked โœ…:
24
+
25
+ - [x] โš™๏ธ Package scaffold โ€” ESM `package.json` (Bun-first, zero direct runtime
26
+ dependencies; `zod` + `km-api ^0.4.1` peers from npm โ€” D-15), strict `tsconfig`,
27
+ Vitest/V8, pinned Bun, and checked-in `bun.lock`
28
+ - [x] โ‘  **Engine 1** โ€” `zodToJsonSchema()` on top of `z.toJSONSchema()`
29
+ ([rules](06-conversions.md))
30
+ - [x] โ‘ก **Engine 2** โ€” `jsonSchemaToZod()` recursive emitter
31
+ ([rules](06-conversions.md))
32
+ - [x] โ‘ข **Engine 3** โ€” `openApiToApiDocs()` โ€” normalize v2/v3 โ†’ operation IR
33
+ โ†’ render `directory` / `flat` trees of `index.ts` files
34
+ ([rules](06-conversions.md),
35
+ [format](07-api-docs.md))
36
+ - [x] โ‘ฃ **Engine 4** โ€” `apiDocsToOpenApi()` โ€” manifest-driven reverse
37
+ conversion to OpenAPI 3.0/3.1
38
+ ([rules](06-conversions.md))
39
+ - [x] ๐Ÿงฑ Component options โ€” `insertComponents`, `useComponentAsReference`,
40
+ nested references, and direct/mutual cycles ([rules](08-components.md))
41
+ - [x] ๐Ÿ“ **YAML input** โ€” owned deterministic YAML 1.2 core-schema parser,
42
+ `.yaml`/`.yml` paths and inline YAML text, anchors/aliases/merge keys,
43
+ stable `ZOPIA_SPEC_INVALID_YAML` ([rules](06-conversions.md#engine-โ‘ข--openapi--api-docs), D-16)
44
+ - [x] ๐Ÿ”— **External `$ref`s** โ€” same-folder references bundled inline for
45
+ spec file paths, byte-identical to inline twins ([rules](06-conversions.md#engine-โ‘ข--openapi--api-docs), D-17)
46
+ - [x] ๐Ÿ“ฆ Manifest writer/reader โ€” `.zopia-manifest.json` (D-06)
47
+ - [x] โš ๏ธ **Warnings pipeline** โ€” stable typed codes, exact JSON Pointer locations,
48
+ deterministic collection/callbacks, generated-code markers, and CLI stderr
49
+ reporting across engines โ‘ โ€“โ‘ฃ (R-144/R-408/D-12)
50
+ - [x] โ™ป๏ธ **Manifest staleness** โ€” canonical source/config comparison, invalid and
51
+ incomplete-tree detection, source-located warnings, safe obsolete-artifact
52
+ pruning, and symlink-safe regeneration (R-741โ€ฆR-743)
53
+ - [x] ๐Ÿ” **Reverse security fallback** โ€” manifest-authoritative requirements,
54
+ validated metadata, collision-safe deterministic bearer synthesis,
55
+ OpenAPI/Swagger representations, and operation-located warnings (R-656)
56
+ - [x] ๐Ÿ›‘ **Typed errors** โ€” one immutable stable-code catalogue and `ZopiaError`
57
+ boundary across engines, manifests, generated-module imports, filesystem
58
+ operations, warnings, and CLI validation, with locations, hints, and causes
59
+ (R-141โ€ฆR-143/R-404)
60
+ - [x] ๐Ÿ” **Round-trip contract** โ€” fixture-backed source-dialect identity across
61
+ Swagger 2.0 and OpenAPI 3.0/3.1, every layout/component mode, refs/cycles,
62
+ lossy-keyword overlays, path-item metadata, and byte-identical regeneration;
63
+ supported Zod โ†” JSON Schema pipelines converge after canonicalization
64
+ (T-10/T-11/R-409)
65
+ - [x] โŒจ๏ธ **CLI contract** โ€” strict `generate` / `reverse` grammar, complete option
66
+ mapping and help, isolated stdout/stderr channels, stable exit statuses,
67
+ trusted-tree disclosure, and direct/package execution ([usage](10-usage.md#-cli))
68
+ - [x] ๐Ÿ“ธ **Golden generated-tree contract** โ€” deliberate reproducible updates,
69
+ complete byte-for-byte tree comparisons in all canonical layouts, and
70
+ strict compilation against installed published `km-api@0.4.1`, including
71
+ `trace`, custom/default statuses, and extension media types (R-112/R-126)
72
+ - [x] ๐Ÿ“ˆ **Coverage gates** โ€” V8 measures every source file; overall line/function
73
+ coverage is gated at 90%, branches at 85%, conversion engines at 95% lines,
74
+ and every source file at 80% lines, with omitted-file detection
75
+ - [x] ๐ŸŸฃ **Bun gate** โ€” pinned Bun 1.2.21, frozen `bun.lock` installation,
76
+ typecheck, Vitest, coverage, direct/package CLI smoke tests, and Bun-native
77
+ generated-TypeScript reverse imports run through one command (T-14/D-01)
78
+ - [x] ๐Ÿงช **Vitest suite** โ€” unit, integration, round-trip, golden-tree, JSDoc,
79
+ CLI, and package-release contracts run in the pinned Bun gate
80
+ ([testing](11-testing.md))
81
+ - [x] ๐Ÿ“– **JSDoc audit** โ€” every exported declaration and exposed interface/class
82
+ member has a useful summary; public callables document parameters and return
83
+ values; optional configuration fields state defaults; examples and links are
84
+ checked; and named-only exports are enforced by an AST contract suite (T-12,
85
+ R-131โ€ฆR-135/R-1003)
86
+ - [x] ๐Ÿ“ฆ **Package/release readiness** โ€” public npm metadata, an allowlisted
87
+ source archive, executable CLI, isolated packed-consumer import and CLI
88
+ smoke tests, and a mandatory prepublish gate (R-191โ€ฆR-193)
89
+ - [x] ๐Ÿ“š **Documentation status sync** โ€” current module/test layouts, generated
90
+ examples, Phase 1 completion labels, and deferred boundaries agree with
91
+ the implementation and are guarded by a documentation contract test
92
+ - [x] ๐Ÿ“œ First versioned entry in `CHANGELOG.md` โ†’ **v0.1.0**
93
+
94
+ ### โœ… Definition of done โ€” Phase 1 (met)
95
+
96
+ The v0.1.0 release satisfies all of the following:
97
+
98
+ 1. ๐Ÿ“„ `bun run test` is green โ€” unit + integration + round-trip suites
99
+ 2. ๐Ÿ“ˆ Coverage gates are met (see [Testing โ†’ Coverage gates](11-testing.md#-coverage-gates))
100
+ 3. ๐Ÿ” Round-trip: for every fixture spec, `openapi(docs(spec))` equals `spec` after canonicalization
101
+ 4. ๐Ÿงฉ All four engine docs sections are implemented exactly as specified (mapping tables are the contract)
102
+ 5. ๐Ÿ“– Every public symbol has JSDoc; `tsc --noEmit` (strict) passes
103
+ 6. ๐Ÿ“œ `CHANGELOG.md` v0.1.0 entry exists and `README` status banner is updated
104
+ 7. โœ… **km-api dependency gate** (D-15) โ€” `km-api@0.4.1` is published and zopia
105
+ uses `km-api: ^0.4.1` from npm; no Git submodule or unpublished commit remains.
106
+ The dependency remains installed and type-checkable in every release gate.
107
+
108
+ ## ๐Ÿงฐ Phase 2 โ€” Breadth (v0.2.x) โœ…
109
+
110
+ - ๐Ÿ“ **YAML input** โ€” โœ… accept `swagger.yaml` / `openapi.yaml` (D-13 lifts โ†’ D-16)
111
+ - ๐Ÿ”— **External `$ref`s** โ€” โœ… resolve references to other files in the same folder (D-17)
112
+ - ๐Ÿงฉ **Reusable parameters & responses** โ€” โœ… emitted as their own component
113
+ files `components/parameters/<Name>/index.ts` and
114
+ `components/responses/<Name>/index.ts` with `<Name>Parameter` / `<Name>Response`
115
+ exports, kind barrels, manifest `kind` entries, and a reverse conversion that
116
+ refreshes declarations from the modules while restoring every use-site `$ref`
117
+ verbatim (D-18; km-api has no standalone-parameter concept, so modules hold the
118
+ derived schema only โ€” name/location/`required` remain operation data)
119
+ - ๐Ÿงพ **`zopia.config.ts`** โ€” โœ… project-level config file with working-directory
120
+ discovery, explicit `--config` paths, validated `{ generate, reverse }` defaults,
121
+ and stable precedence CLI flag > config value > built-in default (D-19);
122
+ CLI flags stay available
123
+ - ๐Ÿ“ค **OpenAPI 2.0 output** โ€” โœ… engine โ‘ฃ accepts `version: '2.0'` (CLI
124
+ `--version 2.0`, config `reverse.version`) and downgrades 3.x-sourced
125
+ manifests into Swagger 2.0 documents: `nullable` becomes `x-nullable`,
126
+ `requestBody` becomes `body`/`formData` parameters, `components` becomes
127
+ top-level `definitions`/`parameters`/`responses`, `servers` decomposes into
128
+ `host`/`basePath`/`schemes`, and unrepresentable 3.x features (webhooks,
129
+ `jsonSchemaDialect`, cookie params, `links`, multi-flow OAuth2, โ€ฆ) drop with
130
+ deterministic `ZOPIA_WARN_DIALECT_DOWNGRADE` warnings (D-20)
131
+ - ๐Ÿงช **More JSON Schema keywords** โ€” โœ… `propertyNames` graduates from the D-12
132
+ approximation to native conversion: the exact
133
+ `{ type: 'object', propertyNames: { type: 'string', <pattern/length constraints> }, additionalProperties: <schema> }`
134
+ form now converts to `z.record(key, value)` (and back) with no warning or
135
+ frozen overlay (D-22); every other listed keyword keeps its runtime-refinement
136
+ + frozen-overlay round-trip (`patternProperties`, `if/then/else`,
137
+ `minProperties/maxProperties`, non-native `propertyNames` forms, `contains`) (Phase 1: documented approximation + warning, D-12)
138
+ - ๐Ÿช **3.1 webhook endpoint generation** โ€” โœ… `document.webhooks` operations now
139
+ generate real endpoint files under `webhooks/<name>/<method>/index.ts`
140
+ alongside path operations (D-23). The manifest records `webhooks[]` entries
141
+ with the same reference/overlay/security metadata as path endpoints plus
142
+ `webhookOrder` and a `webhooksOverlay` (item-level metadata, `x-` names, and
143
+ operation-less items stay verbatim), so engine โ‘ฃ reassembles webhooks in exact
144
+ source order for 3.1 output and omits them with source-located
145
+ `ZOPIA_WARN_WEBHOOKS` warnings for 3.0/2.0 output. Operation-less webhook maps
146
+ keep the Phase 1 manifest-only behavior (no endpoint files, forward warning)
147
+ - ๐Ÿ‘€ **Watch mode** โ€” โœ… `zopia generate --watch` regenerates whenever the spec
148
+ file changes (S-88): an immediate initial run, 50 ms-coalesced re-runs that
149
+ serialize against in-flight generation, run errors printed to stderr while
150
+ watching continues, and abort/cleanup on exit. Uses `fs.watch` with the
151
+ existing stale-tree/prune pipeline, so spec edits refresh owned files in place
152
+
153
+ ## ๐ŸŒŒ Phase 3 โ€” Ecosystem (v0.3+) โœ…
154
+
155
+ - ๐Ÿงน **`zopia validate`** โ€” โœ… CLI command + `validateZopia()` API lint specs
156
+ and generated trees (S-89): specs are checked for dialect validity, broken
157
+ local `$ref`s, endpoint-planning failures (name collisions, cross-namespace
158
+ duplicate operationIds), and components unreachable from any operation
159
+ (transitive; Swagger `definitions` included). Generated trees are checked for
160
+ manifest presence/validity, a successful reverse dry-run, and km-api peer
161
+ drift. Findings are deterministic sorted diagnostics with stable
162
+ `ZOPIA_VALIDATE_*` lint codes; the CLI prints them on stdout and exits `1`
163
+ when any error-severity finding exists
164
+ - โ™ป๏ธ **Incremental regeneration** โ€” โœ… unchanged generated files keep their
165
+ mtimes (byte-identical regeneration writes nothing); the opt-in merge-safe
166
+ custom layer (D-24, S-90) exports a `custom` companion namespace per
167
+ endpoint/webhook scaffolded once and never overwritten (`--custom`,
168
+ `generate.custom`, or the `custom` generate option)
169
+ - ๐Ÿ” **Diff tool** โ€” โœ… `zopia diff old.json new.json` + `diffOpenApiSpecs()`
170
+ API (S-91): semantic comparison of dialect, info, endpoints (with
171
+ parameter/request-body/response details), webhooks, schema components,
172
+ document fields, and `x-` extensions; key order is ignored; deterministic
173
+ `+`/`-`/`~` human-readable lines with a summary; differences are data on
174
+ stdout, so the CLI exits `0` for changed pairs
175
+ - ๐Ÿงฉ **Presets** โ€” โœ… split-generation layouts (S-92): `--preset multi-tag`
176
+ routes each operation by its primary tag, `--preset multi-server` by the
177
+ effective first server (repeatedly), producing one independently
178
+ reverse-convertible api-docs sub-tree per bucket; untagged/default-server
179
+ operations land in `untagged`/`https-default-server`-style buckets; nothing
180
+ to split โ†’ the normal single tree. Programmatic `preset` option plus
181
+ `generate.preset` configuration; `planPresetBuckets()` exposes the pure
182
+ deterministic planner (collision-safe slugs, `ZOPIA_WARN_PRESET_PRIMARY_TAG`
183
+ on multi-tagged operations) and results report `trees[]`
184
+ - ๐Ÿง‘โ€๐Ÿ’ป **VS Code extension** โ€” โœ… navigate spec โ†” generated code both ways
185
+ (S-93): manifest-driven navigation core (`loadNavigationIndex`,
186
+ `specToLocations`/`treeToSpecLocation`, one-pass JSON
187
+ `specPointersToLines`/`specPointerAtLine` cursor resolution, YAML
188
+ operationId fallback) plus the `zopia navigate` CLI (`--to-code` /
189
+ `--to-spec`) and a plain-JS extension package under `editors/vscode/`
190
+ resolving the workspace's own zopia install
191
+
192
+ ## ๐Ÿงฎ Versioning
193
+
194
+ SemVer, strictly:
195
+
196
+ | ๐Ÿ”– Bump | When |
197
+ | --- | --- |
198
+ | `MAJOR` | A generated-file format or manifest format breaks (`zopia:manifest@1` โ†’ `@2`) |
199
+ | `MINOR` | New option, new engine feature, new CLI flag โ€” backward compatible |
200
+ | `PATCH` | Bug fixes, doc corrections, mapping-table clarifications |
201
+
202
+ ## ๐Ÿ”— Next
203
+
204
+ - ๐ŸŽฏ The exact list of what Phase 1 builds โ†’ [Targets](02-targets.md)
205
+ - ๐Ÿ—๏ธ How the pieces fit โ†’ [Architecture](04-architecture.md)