zopia 0.3.0 โ 0.4.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.
- package/CHANGELOG.md +40 -0
- package/README.md +48 -16
- package/docs/07-api-docs.md +77 -2
- package/docs/09-configuration.md +2 -2
- package/docs/10-usage.md +26 -3
- package/package.json +10 -2
- package/src/conversions/api-docs-generate.ts +6 -12
- package/src/conversions/api-docs-names.ts +54 -0
- package/src/conversions/manifest-writer.ts +1 -1
- package/src/conversions/openapi-to-api-docs.ts +5 -10
- package/src/runtime/create-api-docs.ts +321 -0
- package/src/runtime.ts +10 -0
- package/docs/01-overview.md +0 -94
- package/docs/02-targets.md +0 -55
- package/docs/03-roadmap.md +0 -205
- package/docs/04-architecture.md +0 -345
- package/docs/05-concepts.md +0 -239
- package/docs/06-conversions.md +0 -493
- package/docs/08-components.md +0 -223
- package/docs/11-testing.md +0 -267
- package/docs/12-standards.md +0 -242
- package/docs/README.md +0 -42
- package/docs/publish-workflow.yml.example +0 -48
package/docs/05-concepts.md
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
# ๐งฉ Concepts & Glossary
|
|
2
|
-
|
|
3
|
-
The vocabulary of this project, pinned to exact versions. If a term is used in
|
|
4
|
-
any other zopia document, it means what it means here.
|
|
5
|
-
|
|
6
|
-
## ๐ The big picture
|
|
7
|
-
|
|
8
|
-
```mermaid
|
|
9
|
-
flowchart TB
|
|
10
|
-
S1["๐ Swagger 2.0<br/>(2016 spec)"] ---|dialect| JS1["๐ JSON Schema draft-04-ish"]
|
|
11
|
-
S2["๐ OpenAPI 3.0"] ---|dialect| JS2["๐ JSON Schema draft-07 subset<br/>+ nullable"]
|
|
12
|
-
S3["๐ OpenAPI 3.1"] ---|dialect| JS3["๐ JSON Schema 2020-12 (identical)"]
|
|
13
|
-
JS3 ---|same format| Z1["โ๏ธ Zod v4 schemas"]
|
|
14
|
-
S2 --> C["๐ api docs<br/>(.ts ยท km-api ยท zod v4)"]
|
|
15
|
-
S1 --> C
|
|
16
|
-
S3 --> C
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
> ๐ก **Key fact** โ OpenAPI 3.1's *Schema Object* **is** JSON Schema 2020-12
|
|
20
|
-
> ("the standards of openapi are the same as json schema"). That identity is
|
|
21
|
-
> what lets zopia treat 3.1 schemas and JSON Schema as one format.
|
|
22
|
-
|
|
23
|
-
## ๐ Terms
|
|
24
|
-
|
|
25
|
-
### ๐ Swagger 2.0
|
|
26
|
-
|
|
27
|
-
The 2016 API description format. Recognized by the top-level key
|
|
28
|
-
`"swagger": "2.0"`.
|
|
29
|
-
|
|
30
|
-
| ๐งฉ Piece | ๐ In Swagger 2.0 |
|
|
31
|
-
| --- | --- |
|
|
32
|
-
| ๐ Schemas | `definitions` (referenced as `#/definitions/X`) |
|
|
33
|
-
| ๐ Hosting | `host` + `basePath` + `schemes` |
|
|
34
|
-
| ๐ฆ Request bodies | a special parameter with `"in": "body"` (has `schema`) |
|
|
35
|
-
| ๐งพ Form data | parameters with `"in": "formData"` (media type from `consumes`) |
|
|
36
|
-
| ๐ช Cookie parameters | โ none (introduced in OpenAPI 3.0) |
|
|
37
|
-
| ๐ Security | `securityDefinitions` โ mapped to OpenAPI 3 `securitySchemes` |
|
|
38
|
-
| ๐ Schema dialect | draft-04-ish subset (no `nullable`, no `const`, โฆ) |
|
|
39
|
-
| ๐ฆ Responses | `responses` map โ each response may carry a single `schema` |
|
|
40
|
-
|
|
41
|
-
### ๐ OpenAPI 3.0
|
|
42
|
-
|
|
43
|
-
Recognized by `"openapi": "3.0.x"`.
|
|
44
|
-
|
|
45
|
-
| ๐งฉ Piece | ๐ In OpenAPI 3.0 |
|
|
46
|
-
| --- | --- |
|
|
47
|
-
| ๐ Schemas | `components.schemas` (referenced as `#/components/schemas/X`) |
|
|
48
|
-
| ๐ Hosting | `servers: [{ url, variables? }]` |
|
|
49
|
-
| ๐ฆ Request bodies | dedicated `requestBody` object with a `content` map (media type โ schema) |
|
|
50
|
-
| ๐ช Cookie parameters | โ
`"in": "cookie"` |
|
|
51
|
-
| ๐ Nullable | `nullable: true` keyword on schemas |
|
|
52
|
-
| ๐ Schema dialect | draft-07 **subset** + OpenAPI extensions (`nullable`, `discriminator`, `example`, `deprecated`, โฆ) |
|
|
53
|
-
|
|
54
|
-
### ๐ OpenAPI 3.1
|
|
55
|
-
|
|
56
|
-
Recognized by `"openapi": "3.1.x"`. Same shape as 3.0, but:
|
|
57
|
-
|
|
58
|
-
- ๐ Schema dialect = **JSON Schema 2020-12** (full equality)
|
|
59
|
-
- ๐ Nullability via `"type": ["string", "null"]` โ `nullable` is removed
|
|
60
|
-
- ๐ธ `examples` (array) replaces `example`; `const` is allowed
|
|
61
|
-
- ๐งฎ `exclusiveMinimum/Maximum` are **numbers** (were booleans in draft-04/07)
|
|
62
|
-
- ๐ช adds `webhooks` (not paths): v0.1.0 warns, preserves them in the manifest,
|
|
63
|
-
and restores them for 3.1 output but defers webhook endpoint files; valid local
|
|
64
|
-
path-item `$ref`s are supported and round-trip
|
|
65
|
-
- ๐ zopia treats 3.0 and 3.1 with the same normalizer + a small dialect shim
|
|
66
|
-
|
|
67
|
-
### ๐ JSON Schema
|
|
68
|
-
|
|
69
|
-
The vocabulary used to describe data shape (`type`, `properties`, `required`,
|
|
70
|
-
`enum`, `oneOf`, โฆ). zopia's engine โก accepts the union of keywords found in
|
|
71
|
-
the three dialects above and emits warnings for anything it cannot represent
|
|
72
|
-
in Zod (D-12). The canonical dialect of engine โ 's output is **2020-12**.
|
|
73
|
-
|
|
74
|
-
### ๐ $ref (reference)
|
|
75
|
-
|
|
76
|
-
A pointer like `"#/components/schemas/User"` that makes one schema *use*
|
|
77
|
-
another. Three shapes matter for zopia:
|
|
78
|
-
|
|
79
|
-
```jsonc
|
|
80
|
-
// 1๏ธโฃ operation โ component (responses, requestBody, parameters)
|
|
81
|
-
{ "schema": { "$ref": "#/components/schemas/User" } }
|
|
82
|
-
|
|
83
|
-
// 2๏ธโฃ component โ component (a part of another component)
|
|
84
|
-
{ "properties": { "address": { "$ref": "#/components/schemas/Address" } } }
|
|
85
|
-
|
|
86
|
-
// 3๏ธโฃ component โ itself (cycle โ always allowed, becomes z.lazy())
|
|
87
|
-
{ "properties": { "replies": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } } } }
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
> ๐ **Rule R-501** โ zopia resolves *internal* refs natively (refs stay
|
|
91
|
-
> inside the bundled document). Spec file paths additionally bundle
|
|
92
|
-
> **same-folder** external refs before processing (D-17); everything else โ
|
|
93
|
-
> URLs, other folders, external refs in non-file inputs โ stays a
|
|
94
|
-
> `ZOPIA_REF_EXTERNAL` error.
|
|
95
|
-
|
|
96
|
-
### โ๏ธ Zod v4
|
|
97
|
-
|
|
98
|
-
The schema library (validation at runtime + types at compile time). zopia
|
|
99
|
-
depends on Zod **v4** idioms โ *not* v3 โ throughout:
|
|
100
|
-
|
|
101
|
-
| ๐งฉ v4 feature | ๐ Used by zopia |
|
|
102
|
-
| --- | --- |
|
|
103
|
-
| `z.toJSONSchema(schema, { target })` | engine โ โ built-in, no third-party converter (D-03); targets: `draft-2020-12` (default), `draft-07`, `draft-04`, `openapi-3.0` |
|
|
104
|
-
| `z.fromJSONSchema(schema)` | โ ๏ธ experimental in Zod โ used **only** as a cross-check in tests, never in the output path (D-04) |
|
|
105
|
-
| top-level format schemas | `z.email()`, `z.uuid()`, `z.url()`, `z.hostname()`, `z.ipv4()`, `z.ipv6()` โ โ ๏ธ each emits `format` **plus a strict `pattern`** (engine โ strips the redundant pair โ R-618); `z.url()` emits `format: "uri"` |
|
|
106
|
-
| ISO builders | `z.iso.datetime()`, `z.iso.date()`, `z.iso.time()`, `z.iso.duration()` โ โ ๏ธ `z.iso.time()` emits a pattern but **no `format` key** (round-trip needs the manifest overlay โ R-635) |
|
|
107
|
-
| *(no v4 API for arbitrary formats)* | custom `format` values โ `z.string()` + warning + manifest overlay preserving the format verbatim (R-627) |
|
|
108
|
-
| `z.enum([...])`, `z.literal(v)` | `enum` / `const` keywords |
|
|
109
|
-
| `z.union([...])`, `z.discriminatedUnion(key, [...])` | `oneOf` / `anyOf` (with the `discriminator` heuristic) |
|
|
110
|
-
| `z.intersection(a, b)` | `allOf` |
|
|
111
|
-
| `z.tuple([...])` | `prefixItems` / tuple `items` |
|
|
112
|
-
| `z.lazy(() => โฆ)` | circular `$ref`s (R-402) |
|
|
113
|
-
| `.meta({ title, description, examples, โฆ })` / `z.globalRegistry` | **all** metadata fields are copied verbatim into the JSON Schema output (verified); โ ๏ธ never set the `id` key โ it triggers `$def` extraction |
|
|
114
|
-
| `z.object({โฆ})` + `.strict()` / `.catchall(s)` / `.optional()` / `.default(v)` | objects, `additionalProperties`, `required`, `default` |
|
|
115
|
-
| `.min()` / `.max()` / `.int()` / `.regex()` / `.multipleOf()` | string/number/array constraints |
|
|
116
|
-
|
|
117
|
-
### ๐งฑ km-api
|
|
118
|
-
|
|
119
|
-
The user's endpoint-definition package โ **the make function of this project's
|
|
120
|
-
generated code**. zopia targets **km-api `^0.4.1` (0.4.x)** and generates the
|
|
121
|
-
following conceptual shape (formatting abridged):
|
|
122
|
-
|
|
123
|
-
```ts
|
|
124
|
-
import { makeApiConfig } from 'km-api';
|
|
125
|
-
|
|
126
|
-
const getUser = makeApiConfig({
|
|
127
|
-
method: 'GET', // ๐งญ IMethod โ HTTP method
|
|
128
|
-
pathShape: '/admin/users/{id}', // ๐ฃ๏ธ IPath โ OpenAPI {param} syntax (D-05)
|
|
129
|
-
operationId: 'getUser', // ๐ preserved in config + export name
|
|
130
|
-
auth: 'YES', // ๐ 'YES' | 'NO'
|
|
131
|
-
responseContentType: 'application/json',
|
|
132
|
-
summary: 'Get user by ID', // ๐
|
|
133
|
-
description: 'Retrieves โฆ', // ๐ (Markdown)
|
|
134
|
-
tags: ['#admin', '#users'], // ๐ท๏ธ km-api convention: '#' prefix
|
|
135
|
-
request: {
|
|
136
|
-
body: z.any(), // ๐ฆ required field โ z.any() โ no body
|
|
137
|
-
params: z.object({ id: z.uuid() }), // ๐ฃ๏ธ path params
|
|
138
|
-
query: z.object({}), // โ
|
|
139
|
-
headers: z.object({}), // ๐ฉ
|
|
140
|
-
cookies: z.object({}), // ๐ช
|
|
141
|
-
},
|
|
142
|
-
response: { // ๐ฆ status code โ Zod schema
|
|
143
|
-
200: z.object({ id: z.uuid(), name: z.string() }),
|
|
144
|
-
404: z.object({ message: z.string() }),
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Helper methods on the result (`makeFullPath`, `makeOpenApiPathShape`,
|
|
150
|
-
`convertResponseType`, โฆ) are available to consumers for free โ zopia never
|
|
151
|
-
needs them at generation time, and engine โฃ uses `makeOpenApiPathShape()` to
|
|
152
|
-
normalize paths back to `{param}` form.
|
|
153
|
-
|
|
154
|
-
> ๐ **Rule R-502** โ generated files import **only** `zod` and `km-api`.
|
|
155
|
-
> No zopia runtime is imported by generated code. Component files are
|
|
156
|
-
> generated as standalone files, and exact endpoint component references can
|
|
157
|
-
> import through the barrel. Nested component references are recursively rendered, including nested objects, arrays, compositions, nullable schemas, enums, constants, and additional-property schemas. Direct and mutual cyclic component graphs use lazy Zod references.
|
|
158
|
-
|
|
159
|
-
### ๐ km-api's type surface (verified against published `0.4.1`)
|
|
160
|
-
|
|
161
|
-
`makeApiConfig` is a **type-level factory** โ it does no runtime validation, so
|
|
162
|
-
the generated tree's contract is that it **typechecks** against the installed
|
|
163
|
-
published package (D-14; the golden-tree contract test enforces this, R-126):
|
|
164
|
-
|
|
165
|
-
| ๐งฉ Field | ๐ Published km-api 0.4.1 / zopia contract |
|
|
166
|
-
| --- | --- |
|
|
167
|
-
| `method` (`IMethod`) | all **8** standard methods โ `get/post/put/delete/head/options/patch/trace` (each case-insensitive: `GET`, `Get`, โฆ) |
|
|
168
|
-
| `response` keys | standard statuses, **any valid custom `100`โ`599` code** (`419`, `499`, `512`, โฆ), OpenAPI `1XX`โ`5XX` ranges, and the **`default`** key; all are pinned by generated compilation and validated against the source/output dialect |
|
|
169
|
-
| `responseContentType` / `requestContentType` | km-api's declarations enumerate known MIME values, while OpenAPI media-type maps are open; zopia emits every exact string and applies a narrow type-only assertion at this package boundary, preserving the runtime value and reverse conversion |
|
|
170
|
-
| `operationId` | any string โ a real km-api field in 0.4.1; zopia emits it and reuses it as the export identifier (R-732) |
|
|
171
|
-
|
|
172
|
-
Other fixed shapes (source-verified): `ITags` = strings **prefixed with `#`**;
|
|
173
|
-
`IPath` = string starting with `/`; `auth`, `disable`, and the semantically
|
|
174
|
-
separate `deprecated` field use `'YES' | 'NO'`; `request.body` is required (any
|
|
175
|
-
Zod schema), and `params/query/headers/cookies` are required Zod objects. The
|
|
176
|
-
remaining km-api gaps โ **per-parameter metadata**
|
|
177
|
-
(`style`, `explode`, `allowEmptyValue`, `deprecated`, `example`) and **response
|
|
178
|
-
`headers`** โ have no home in km-api; zopia preserves them in the manifest
|
|
179
|
-
(overlay / `responseOverlay`, R-635/R-754).
|
|
180
|
-
|
|
181
|
-
> ๐ **Where km-api lives.** zopia consumes the published `km-api@^0.4.1`
|
|
182
|
-
> npm package. No Git submodule or unpublished commit is required (D-15).
|
|
183
|
-
|
|
184
|
-
### ๐ api docs
|
|
185
|
-
|
|
186
|
-
The generated artifact: an `api_docs/` directory containing one `index.ts` per
|
|
187
|
-
endpoint (plus optional `components/**` and the manifest). Defined fully in
|
|
188
|
-
[API docs format](07-api-docs.md).
|
|
189
|
-
|
|
190
|
-
### ๐ฆ .zopia-manifest.json
|
|
191
|
-
|
|
192
|
-
The hidden metadata file written into `api_docs/` (D-06). It is what makes
|
|
193
|
-
engine โฃ lossless: exact paths & methods per file, spec identity
|
|
194
|
-
(kind/title/version/sha256), servers, tags, security schemes, the **full
|
|
195
|
-
component schemas**, **`$ref` placement** (per-API ref pointers), and
|
|
196
|
-
**non-representable facts** (overlay entries: titles, examples, custom
|
|
197
|
-
formats, unsupported keywords). See
|
|
198
|
-
[API docs format โ The manifest](07-api-docs.md).
|
|
199
|
-
|
|
200
|
-
### ๐งฌ Stage-specific representations
|
|
201
|
-
|
|
202
|
-
Engine โข narrows a validated document into operation-level IR and normalized
|
|
203
|
-
request/response contracts. Engine โฃ combines imported runtime values with the
|
|
204
|
-
versioned manifest instead of sharing one repository-wide model with engine โข.
|
|
205
|
-
See [Architecture โ The internal representations](04-architecture.md#-the-internal-representations).
|
|
206
|
-
|
|
207
|
-
### ๐ Round-trip
|
|
208
|
-
|
|
209
|
-
For a spec `S`: `openApiToApiDocs(S) โ apiDocsToOpenApi(...) โ S` โ equal after
|
|
210
|
-
**canonicalization** (R-401 order, whitespace-independent JSON equality, and
|
|
211
|
-
documented metadata moves to the manifest). Round-trips are *tested as
|
|
212
|
-
properties*, not by eye (see [Testing](11-testing.md#-round-trip-property-tests)).
|
|
213
|
-
|
|
214
|
-
## โ๏ธ Dialect comparison (the table that answers most "why?" questions)
|
|
215
|
-
|
|
216
|
-
| ๐งฉ Concern | Swagger 2.0 | OpenAPI 3.0 | OpenAPI 3.1 |
|
|
217
|
-
| --- | --- | --- | --- |
|
|
218
|
-
| ๐ท๏ธ Version key | `swagger: "2.0"` | `openapi: "3.0.x"` | `openapi: "3.1.x"` |
|
|
219
|
-
| ๐ Schema home | `definitions` | `components.schemas` | `components.schemas` |
|
|
220
|
-
| ๐ Schema dialect | draft-04-ish | draft-07 subset + extensions | **JSON Schema 2020-12** |
|
|
221
|
-
| ๐ Servers | `host`+`basePath`+`schemes` | `servers[]` | `servers[]` |
|
|
222
|
-
| ๐ฆ Body | param `in: body` | `requestBody.content` | `requestBody.content` |
|
|
223
|
-
| ๐งพ FormData | param `in: formData` | `requestBody.content['multipart/โฆ' \| 'x-www-form-urlencoded']` | same as 3.0 |
|
|
224
|
-
| ๐ช Cookie params | โ | โ
| โ
|
|
|
225
|
-
| ๐ Nullable | โ no standard way (draft-04 allows type arrays, but 2.0 tooling rarely supports them) | `nullable: true` | `type: ["โฆ", "null"]` |
|
|
226
|
-
| ๐ธ Examples | `examples` (media-type map, legacy) | `example` (single) | `examples` (array) |
|
|
227
|
-
| ๐ Security | `securityDefinitions` | `components.securitySchemes` | same as 3.0 |
|
|
228
|
-
| ๐ฆ Response schema | response.schema (single) | per media type | per media type |
|
|
229
|
-
| ๐งฎ exclusiveMinimum | boolean | boolean | **number** |
|
|
230
|
-
|
|
231
|
-
> ๐ **Rule R-503** โ the normalizers convert *everything* into the IR using
|
|
232
|
-
> the **OpenAPI-3.1-flavoured** representation (2020-12 schemas, numeric
|
|
233
|
-
> exclusive bounds, `type: [t, "null"]` for nullables). Dialect differences
|
|
234
|
-
> die at the IR boundary; they never leak into generated code.
|
|
235
|
-
|
|
236
|
-
## ๐ Next
|
|
237
|
-
|
|
238
|
-
- ๐ How the IR is produced and consumed โ [Conversions](06-conversions.md)
|
|
239
|
-
- ๐๏ธ Where the IR lives in code โ [Architecture](04-architecture.md)
|