@shipworthy/openapi-parser 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.
- package/README.md +6 -3
- package/dist/pipeline.js +32 -45
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ Load an OpenAPI 3.0 or 3.1 document from a file path, a URL, a JSON or YAML stri
|
|
|
4
4
|
|
|
5
5
|
The API is Effect-native. Every entry point is an `Effect` or an Effect `Schema` codec, so you need [`effect`](https://www.npmjs.com/package/effect) v4 to run it.
|
|
6
6
|
|
|
7
|
+
Bundling preserves OpenAPI 3.1 schema keywords alongside `$ref`, including descriptions,
|
|
8
|
+
constraints, and extensions. It rewrites external references to internal references without
|
|
9
|
+
introducing `allOf` wrappers for their sibling keywords.
|
|
10
|
+
|
|
7
11
|
## Installation
|
|
8
12
|
|
|
9
13
|
```sh
|
|
@@ -14,10 +18,9 @@ bun add @shipworthy/openapi-parser effect @effect/platform-node
|
|
|
14
18
|
|
|
15
19
|
| Requirement | Details |
|
|
16
20
|
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
-
| `effect` | `^4.0.0`, a
|
|
21
|
+
| `effect` | `^4.0.0`, a regular dependency. Add a compatible version to your own `package.json` so your application and the parser resolve to one copy to run the returned effects and to use the schemas. |
|
|
18
22
|
| Platform | `@effect/platform-node` `^4.0.0` is a regular dependency. Install it yourself only if your code imports it, as the examples here do for `NodeServices`. The parser imports `node:stream`, `node:url`, `node:path`, `node:dns/promises`, `node:net`, and the `Buffer` global, so it needs Node.js `>=22.19.0` or Bun. It does not run in browsers. |
|
|
19
23
|
| Module format | ESM only (`"type": "module"`). Ships compiled JavaScript with `.d.ts` declarations; no TypeScript loader or bundler is needed. |
|
|
20
|
-
| Peer deps | `effect` `^4.0.0`. |
|
|
21
24
|
|
|
22
25
|
## Quick start
|
|
23
26
|
|
|
@@ -354,7 +357,7 @@ None of these settings can be configured through the public API.
|
|
|
354
357
|
- Load files with `URL` or `file://` strings. Bare strings are parsed as JSON or YAML text.
|
|
355
358
|
- Input can be OpenAPI 3.0 or 3.1. Output is always bundled and upgraded OpenAPI 3.1 (`openapi: "3.1.0"` when upgraded from 3.0), with external refs moved into `components`.
|
|
356
359
|
- Every error is a `Schema.SchemaError`. Read `error.message`.
|
|
357
|
-
-
|
|
360
|
+
- Depends on `effect` `^4.0.0`. ESM only, and Node.js `>=22.19.0` or Bun. Ships compiled JavaScript. It does not run in browsers.
|
|
358
361
|
- Next step in the toolchain: pass the result to `decode` from `@shipworthy/openapi-transformer` to get a `ParsedService` for code generators.
|
|
359
362
|
|
|
360
363
|
## License
|
package/dist/pipeline.js
CHANGED
|
@@ -94,7 +94,7 @@ function normalizeSchema(value) {
|
|
|
94
94
|
const record = asRecord(value);
|
|
95
95
|
if (!record)
|
|
96
96
|
throw bundleFailure("A schema position must contain an object or a boolean");
|
|
97
|
-
const normalized = JsonSchema.fromSchemaOpenApi3_1(
|
|
97
|
+
const normalized = JsonSchema.fromSchemaOpenApi3_1(record);
|
|
98
98
|
// A schema $id is its own resource, so its $defs join the shared pool.
|
|
99
99
|
// Nested $defs on a schema without $id stay on that schema.
|
|
100
100
|
if (typeof record.$id === "string")
|
|
@@ -156,31 +156,6 @@ function rewriteDefName(schema, from, to) {
|
|
|
156
156
|
for (const value of Object.values(record))
|
|
157
157
|
rewriteDefName(value, from, to);
|
|
158
158
|
}
|
|
159
|
-
function liftSiblings(value) {
|
|
160
|
-
if (Array.isArray(value))
|
|
161
|
-
return value.map((item) => liftSiblings(item));
|
|
162
|
-
const record = asRecord(value);
|
|
163
|
-
if (!record)
|
|
164
|
-
return value;
|
|
165
|
-
const lifted = {};
|
|
166
|
-
for (const [key, child] of Object.entries(record))
|
|
167
|
-
lifted[key] = liftSiblings(child);
|
|
168
|
-
if (typeof lifted.$ref !== "string")
|
|
169
|
-
return lifted;
|
|
170
|
-
const siblings = { ...lifted };
|
|
171
|
-
delete siblings.$ref;
|
|
172
|
-
// readOnly/writeOnly stay beside $ref so generators can wrap the reference itself.
|
|
173
|
-
const flags = {};
|
|
174
|
-
for (const key of ["readOnly", "writeOnly"]) {
|
|
175
|
-
if (siblings[key] === true) {
|
|
176
|
-
flags[key] = true;
|
|
177
|
-
delete siblings[key];
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
if (Object.keys(siblings).length === 0)
|
|
181
|
-
return { $ref: lifted.$ref, ...flags };
|
|
182
|
-
return { allOf: [{ $ref: lifted.$ref }, siblings], ...flags };
|
|
183
|
-
}
|
|
184
159
|
function recursiveNames(definitions) {
|
|
185
160
|
const names = Object.keys(definitions);
|
|
186
161
|
const dependencies = new Map(names.map((name) => [name, collectDefRefs(definitions[name])]));
|
|
@@ -246,30 +221,42 @@ function resolveValue(value, definitions, rootDefs, recursive, aliases, resolvin
|
|
|
246
221
|
return value;
|
|
247
222
|
if (typeof record.$ref === "string") {
|
|
248
223
|
const key = referenceKey(record.$ref);
|
|
249
|
-
if (!key)
|
|
250
|
-
return record;
|
|
251
|
-
if (!Object.hasOwn(definitions, key)) {
|
|
224
|
+
if (key && !Object.hasOwn(definitions, key)) {
|
|
252
225
|
if (rootDefs.has(key)) {
|
|
253
226
|
record.$ref = rootDefRef(key);
|
|
254
|
-
return record;
|
|
255
227
|
}
|
|
256
|
-
|
|
228
|
+
else {
|
|
229
|
+
throw missingPointerFailure(key, record.$ref, record.$ref);
|
|
230
|
+
}
|
|
257
231
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (recursive.has(final))
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
232
|
+
else if (key) {
|
|
233
|
+
const final = finalName(key, definitions, aliases);
|
|
234
|
+
const ref = joinPointer("#/$defs", final);
|
|
235
|
+
if (recursive.has(final) || mode === "bundle") {
|
|
236
|
+
if (recursive.has(final))
|
|
237
|
+
hooks?.onCircular?.(pointer);
|
|
238
|
+
record.$ref = ref;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
if (resolving.has(final))
|
|
242
|
+
throw circularAliasFailure(final);
|
|
243
|
+
resolving.add(final);
|
|
244
|
+
const resolved = resolveValue(structuredClone(definitions[final]), definitions, rootDefs, recursive, aliases, resolving, mode, hooks, ref);
|
|
245
|
+
resolving.delete(final);
|
|
246
|
+
const siblings = { ...record };
|
|
247
|
+
delete siblings.$ref;
|
|
248
|
+
const result = Object.keys(siblings).length === 0
|
|
249
|
+
? resolved
|
|
250
|
+
: {
|
|
251
|
+
allOf: [
|
|
252
|
+
resolved,
|
|
253
|
+
resolveValue(siblings, definitions, rootDefs, recursive, aliases, resolving, mode, hooks, pointer),
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
hooks?.onDereference?.(pointer, result, record, "$ref");
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
265
259
|
}
|
|
266
|
-
if (resolving.has(final))
|
|
267
|
-
throw circularAliasFailure(final);
|
|
268
|
-
resolving.add(final);
|
|
269
|
-
const resolved = resolveValue(structuredClone(definitions[final]), definitions, rootDefs, recursive, aliases, resolving, mode, hooks, ref);
|
|
270
|
-
resolving.delete(final);
|
|
271
|
-
hooks?.onDereference?.(pointer, resolved, record, "$ref");
|
|
272
|
-
return resolved;
|
|
273
260
|
}
|
|
274
261
|
for (const [key, child] of Object.entries(record)) {
|
|
275
262
|
record[key] = resolveValue(child, definitions, rootDefs, recursive, aliases, resolving, mode, hooks, joinPointer(pointer, key));
|
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipworthy/openapi-parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@effect/platform-node": "^4.0.0"
|
|
9
|
-
},
|
|
10
|
-
"peerDependencies": {
|
|
8
|
+
"@effect/platform-node": "^4.0.0",
|
|
11
9
|
"effect": "^4.0.0"
|
|
12
10
|
},
|
|
13
11
|
"description": "Parse, bundle, and upgrade OpenAPI documents with Effect schemas.",
|
|
@@ -37,7 +35,6 @@
|
|
|
37
35
|
"@effect/vitest": "4.0.0",
|
|
38
36
|
"@shipworthy/typescript-config": "0.0.1",
|
|
39
37
|
"@types/node": "^24.10.3",
|
|
40
|
-
"effect": "^4.0.0",
|
|
41
38
|
"typescript": "^7.0.2",
|
|
42
39
|
"vitest": "5.0.3"
|
|
43
40
|
},
|