@shipworthy/openapi-overlay 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +270 -2
- package/dist/apply.d.ts +17 -0
- package/dist/apply.js +206 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prune.d.ts +3 -0
- package/dist/prune.js +239 -0
- package/dist/schemas/1.0.d.ts +28 -0
- package/dist/schemas/1.0.js +52 -0
- package/dist/schemas/1.1.d.ts +32 -0
- package/dist/schemas/1.1.js +57 -0
- package/dist/schemas.d.ts +53 -0
- package/dist/schemas.js +6 -0
- package/package.json +56 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shipworthy AI
|
|
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,3 +1,271 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @shipworthy/openapi-overlay
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Apply OpenAPI Overlay 1.0 and 1.1 documents with Effect v4. Validation schemas are generated
|
|
4
|
+
from the upstream YAML schemas, and action behavior follows the declared feature version. Supports RFC 9535 JSONPath, sequential `update`, `copy`, and `remove`
|
|
5
|
+
actions, recursive object merges, array concatenation/appending, and primitive replacement.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add @shipworthy/openapi-overlay effect@4.1.4
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Node.js 22.19.0 or later, or Bun. Ships ESM JavaScript and TypeScript declarations.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { applyOverlay } from "@shipworthy/openapi-overlay";
|
|
19
|
+
import { Effect } from "effect";
|
|
20
|
+
|
|
21
|
+
const document = {
|
|
22
|
+
openapi: "3.1.0",
|
|
23
|
+
info: { title: "Pets", version: "1.0.0" },
|
|
24
|
+
paths: {},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const overlay = {
|
|
28
|
+
overlay: "1.1.0",
|
|
29
|
+
info: { title: "Public documentation", version: "1.0.0" },
|
|
30
|
+
actions: [
|
|
31
|
+
{ target: "$.info.title", update: "Public Pets" },
|
|
32
|
+
{ target: "$", update: { "x-public": true } },
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const result = await Effect.runPromise(applyOverlay(document, overlay));
|
|
37
|
+
// result.info.title is "Public Pets"; document is unchanged.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`applyOverlay(document, overlay, options?)` accepts either a parsed object or JSON/YAML text for
|
|
41
|
+
the document and overlay. Options are schema-validated: `removeUnusedComponents` is an optional
|
|
42
|
+
boolean, and unknown options are rejected with `OverlayError`. The options type is inferred
|
|
43
|
+
from its Effect Schema. It returns `Effect.Effect<Schema.MutableJsonObject, OverlayError>` without requiring
|
|
44
|
+
services. Input documents must be JSON-compatible objects. Inputs are validated with Effect
|
|
45
|
+
schemas and copied before applying actions; neither input is mutated, including on failure.
|
|
46
|
+
|
|
47
|
+
`applyOverlayWithWarnings(document, overlay, options?)` accepts the same inputs and returns
|
|
48
|
+
`{ document, warnings }`. Each warning contains the one-based `action` number, `target`, and
|
|
49
|
+
`message`. Unmatched targets and malformed JSONPath target expressions are skipped and
|
|
50
|
+
collected in action order; subsequent actions still run against the preceding result.
|
|
51
|
+
`applyOverlay` returns only the document. Neither function logs warnings.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { applyOverlayWithWarnings } from "@shipworthy/openapi-overlay";
|
|
55
|
+
|
|
56
|
+
const { document: updated, warnings } = await Effect.runPromise(
|
|
57
|
+
applyOverlayWithWarnings(document, overlay),
|
|
58
|
+
);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
By default, the function applies overlays without validating the resulting OpenAPI structure.
|
|
62
|
+
It does not load files or fetch URLs. `extends` is descriptive
|
|
63
|
+
metadata; callers choose the document explicitly. To bundle and upgrade first, use
|
|
64
|
+
`bundleDocument` from `@shipworthy/openapi-parser`, then pass the result to `applyOverlay`.
|
|
65
|
+
|
|
66
|
+
### Filtering operations and removing unused components
|
|
67
|
+
|
|
68
|
+
Use an Overlay removal action to select operations by `operationId`, then opt into pruning:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const selected = {
|
|
72
|
+
overlay: "1.1.0",
|
|
73
|
+
info: { title: "Selected operations", version: "1.0.0" },
|
|
74
|
+
actions: [
|
|
75
|
+
{
|
|
76
|
+
target:
|
|
77
|
+
"$.paths.*[?(@.responses && !(@.operationId == 'listPets' || @.operationId == 'getPet'))]",
|
|
78
|
+
remove: true,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const result = await Effect.runPromise(
|
|
84
|
+
applyOverlay(document, selected, { removeUnusedComponents: true }),
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This selector identifies operations by their `responses` field. For operations without that
|
|
89
|
+
field, use method-specific selectors. Pruning runs after all actions, removes paths without
|
|
90
|
+
operations, and keeps the transitive component dependencies of remaining paths, webhooks,
|
|
91
|
+
document-level security, and retained root `$defs`. It handles all component categories, recursive schemas,
|
|
92
|
+
discriminator mappings and inheritance, and security scheme names. Example payloads,
|
|
93
|
+
schema defaults, and extension values do not count as references. Empty component groups
|
|
94
|
+
are removed; component extensions are preserved.
|
|
95
|
+
|
|
96
|
+
Pruning requires a bundled OpenAPI 3.1 document with local JSON Pointer references. Bundle
|
|
97
|
+
and upgrade with `bundleDocument` first; the CLI does this automatically. Reachable external
|
|
98
|
+
or anchor references and `$dynamicRef` are rejected. Broken references or links to removed
|
|
99
|
+
operation IDs fail with `OverlayError`. Neither input is mutated. Without the option,
|
|
100
|
+
unused components and paths are retained and no OpenAPI validation is performed.
|
|
101
|
+
|
|
102
|
+
## Actions
|
|
103
|
+
|
|
104
|
+
- Actions run in order against the result of the previous action. A target that selects no
|
|
105
|
+
nodes succeeds without creating anything. To create a property, target its existing parent
|
|
106
|
+
and merge the new property into it.
|
|
107
|
+
- Object updates merge recursively. Existing properties remain unless replaced or removed.
|
|
108
|
+
Corresponding arrays concatenate; corresponding primitives replace each other, including
|
|
109
|
+
`null`. Other corresponding property categories are incompatible and fail.
|
|
110
|
+
- In 1.1, array targets concatenate an array update or append an object or primitive update as
|
|
111
|
+
one element. Primitive targets require primitive updates.
|
|
112
|
+
- In 1.0, targets must select objects or arrays; primitive targets fail, including for removal.
|
|
113
|
+
A selected array receives the update as one appended entry, including when that entry is an
|
|
114
|
+
array. Update primitive properties through their containing object.
|
|
115
|
+
- In 1.1, `copy` selects exactly one source node from the current document and applies a snapshot of
|
|
116
|
+
its value using the same merge rules. Copies are independent of the source and other targets.
|
|
117
|
+
- In 1.1, multiple update/copy targets must all be objects, all arrays, or all primitives. Different
|
|
118
|
+
primitive types belong to the same category.
|
|
119
|
+
- `remove: true` takes precedence over `update` and `copy`. Array removals use the original
|
|
120
|
+
selected indexes. Removing the document root fails because it has no containing map or array.
|
|
121
|
+
- Supplying both `update` and `copy` on a matching action without `remove: true` fails as
|
|
122
|
+
ambiguous. An action with no modifier has no effect. Duplicate target locations are modified
|
|
123
|
+
once per action.
|
|
124
|
+
|
|
125
|
+
Versions `1.0.x` and `1.1.x` use their respective schemas and action behavior. Patch versions
|
|
126
|
+
do not change the feature set. `copy` and `info.description` are accepted only in 1.1. Both
|
|
127
|
+
versions require at least one action and reject structurally duplicate actions, as specified
|
|
128
|
+
by the upstream schemas. Unknown feature versions fail. YAML is parsed with
|
|
129
|
+
[Effect's YAML 1.2 parser](https://effect.website/docs/v4/api/effect/encoding/Yaml).
|
|
130
|
+
JSON-incompatible values and duplicate YAML mapping keys are rejected. The parser does not
|
|
131
|
+
support compact nested block sequences (`- - value`), multiline flow collections, explicit
|
|
132
|
+
complex keys, tag/directive processing, recursive aliases, or document streams. Use expanded
|
|
133
|
+
block collections for nested YAML; formatted JSON is accepted. Comments and source formatting
|
|
134
|
+
are not retained.
|
|
135
|
+
|
|
136
|
+
## Preparing a document for generation
|
|
137
|
+
|
|
138
|
+
Apply an overlay before running a generator so the same document changes are available to
|
|
139
|
+
TypeScript types, runtime validators, and clients:
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
openapi overlay openapi.yaml --overlay types.overlay.yaml -o types.openapi.json
|
|
143
|
+
openapi generate typescript -i types.openapi.json -o src/generated
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The examples below assume the named schemas and paths exist. Target an existing parent to add
|
|
147
|
+
a property; an unmatched target has no effect. Updates contain literal values, so list property
|
|
148
|
+
and parameter names explicitly.
|
|
149
|
+
|
|
150
|
+
### Require properties
|
|
151
|
+
|
|
152
|
+
Add property names to `required`. A property's `default` alone does not require its presence
|
|
153
|
+
in generated TypeScript types; the default remains available as documentation.
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
overlay: 1.1.0
|
|
157
|
+
info: { title: Required pet properties, version: "1" }
|
|
158
|
+
actions:
|
|
159
|
+
- target: $.components.schemas.Pet
|
|
160
|
+
update: { required: [id, name] }
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This appends to an existing `required` list. To replace the list, first remove
|
|
164
|
+
`$.components.schemas.Pet.required`, then update its parent with the new list.
|
|
165
|
+
|
|
166
|
+
### Allow additional keys
|
|
167
|
+
|
|
168
|
+
Set `additionalProperties: true` on the intended object schemas, including empty object
|
|
169
|
+
schemas. The TypeScript generator emits an index signature with `unknown` values.
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
overlay: 1.1.0
|
|
173
|
+
info: { title: Open object schemas, version: "1" }
|
|
174
|
+
actions:
|
|
175
|
+
- target: $.components.schemas.Pet
|
|
176
|
+
update: { additionalProperties: true }
|
|
177
|
+
- target: $.components.schemas.Metadata
|
|
178
|
+
update: { additionalProperties: true }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Preserve existing schema-valued `additionalProperties` constraints when they should still
|
|
182
|
+
apply. To replace a schema-valued constraint with `true`, remove the `additionalProperties`
|
|
183
|
+
property first, then update its parent; object and boolean values cannot merge.
|
|
184
|
+
|
|
185
|
+
### Remove deprecated members
|
|
186
|
+
|
|
187
|
+
Use a filter to remove properties or parameters marked `deprecated: true`, and remove
|
|
188
|
+
individual operations by their path and method:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
overlay: 1.1.0
|
|
192
|
+
info: { title: Public pet API, version: "1" }
|
|
193
|
+
actions:
|
|
194
|
+
- target: $.components.schemas.Pet.properties[?@.deprecated == true]
|
|
195
|
+
remove: true
|
|
196
|
+
- target: $.components.schemas.Pet.required[?@ == 'legacy']
|
|
197
|
+
remove: true
|
|
198
|
+
- target: $.paths['/pets/{id}'].get.parameters[?@.deprecated == true]
|
|
199
|
+
remove: true
|
|
200
|
+
- target: $.paths['/pets/{id}'].delete
|
|
201
|
+
remove: true
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Here `legacy` is a deprecated property listed in `Pet.required`. Remove each corresponding
|
|
205
|
+
`required` entry when removing a property. Filters inspect the selected object, not the target
|
|
206
|
+
of a `$ref`; handle referenced deprecated members explicitly. When removing a component,
|
|
207
|
+
repair or remove references to it as well.
|
|
208
|
+
|
|
209
|
+
### Declare path parameters
|
|
210
|
+
|
|
211
|
+
Add a required parameter declaration for each placeholder in a path template. This example
|
|
212
|
+
adds `id` to the path item's parameters, making it available to all operations on that path:
|
|
213
|
+
|
|
214
|
+
```yaml
|
|
215
|
+
overlay: 1.1.0
|
|
216
|
+
info: { title: Pet path parameters, version: "1" }
|
|
217
|
+
actions:
|
|
218
|
+
- target: $.paths['/pets/{id}']
|
|
219
|
+
update:
|
|
220
|
+
parameters:
|
|
221
|
+
- name: id
|
|
222
|
+
in: path
|
|
223
|
+
required: true
|
|
224
|
+
schema: { type: string }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Parameter arrays append on update, so add declarations only for parameters that are missing.
|
|
228
|
+
|
|
229
|
+
## Schemas and errors
|
|
230
|
+
|
|
231
|
+
The public API exports `applyOverlay`, `applyOverlayWithWarnings`, `OverlayError`, and the Effect schemas `Overlay`,
|
|
232
|
+
`OverlayInfo`, and `OverlayAction`, each with its schema-inferred TypeScript type of the same name.
|
|
233
|
+
Schema objects allow `x-` specification extensions and reject other undeclared fields. The root
|
|
234
|
+
schemas accept the union of supported versions. Import a particular version to validate or type
|
|
235
|
+
its documents directly:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { Overlay, type OverlayAction } from "@shipworthy/openapi-overlay/schemas/1.0";
|
|
239
|
+
// Also available at @shipworthy/openapi-overlay/schemas/1.1.
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { Overlay } from "@shipworthy/openapi-overlay";
|
|
244
|
+
import { Schema } from "effect";
|
|
245
|
+
|
|
246
|
+
const checked = Schema.decodeUnknownEffect(Overlay)({
|
|
247
|
+
overlay: "1.1.0",
|
|
248
|
+
info: { title: "Public documentation", version: "1.0.0" },
|
|
249
|
+
actions: [{ target: "$", update: {} }],
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`OverlayError` contains `message` and an optional `cause`. Action failures also contain a
|
|
254
|
+
one-based `action` index and the `target` expression. Catch it with
|
|
255
|
+
`Effect.catchTag("OverlayError", handler)`.
|
|
256
|
+
|
|
257
|
+
## CLI
|
|
258
|
+
|
|
259
|
+
Install `@shipworthy/openapi-cli` to bundle a local or remote OpenAPI document before overlaying:
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
openapi overlay openapi.yaml --overlay overlay.yaml -o bundled.openapi.json
|
|
263
|
+
openapi overlay openapi.yaml --overlay selected.overlay.yaml --remove-unused-components -o selected.openapi.json
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
The CLI resolves external references and upgrades OpenAPI 3.0 to 3.1, then applies the overlay
|
|
267
|
+
and writes formatted JSON. See the [CLI documentation](../openapi-cli/README.md).
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT. See [LICENSE](./LICENSE).
|
package/dist/apply.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { OverlayError } from "./errors.ts";
|
|
3
|
+
/** Apply actions and collect invalid or unmatched targets without mutating inputs. */
|
|
4
|
+
export declare const applyOverlayWithWarnings: (document: unknown, overlay: unknown, options?: {
|
|
5
|
+
readonly removeUnusedComponents?: boolean | undefined;
|
|
6
|
+
} | undefined) => Effect.Effect<{
|
|
7
|
+
document: Schema.MutableJsonObject;
|
|
8
|
+
warnings: {
|
|
9
|
+
readonly action: number;
|
|
10
|
+
readonly target: string;
|
|
11
|
+
readonly message: string;
|
|
12
|
+
}[];
|
|
13
|
+
}, OverlayError, never>;
|
|
14
|
+
/** Apply version-specific Overlay actions without mutating inputs. */
|
|
15
|
+
export declare const applyOverlay: (document: unknown, overlay: unknown, options?: {
|
|
16
|
+
readonly removeUnusedComponents?: boolean | undefined;
|
|
17
|
+
} | undefined) => Effect.Effect<Schema.MutableJsonObject, OverlayError, never>;
|
package/dist/apply.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Array as Arr, Effect, Formatter, Option, pipe, Predicate, Record, Result, Schema, String as Str, } from "effect";
|
|
2
|
+
import * as Yaml from "effect/encoding/Yaml";
|
|
3
|
+
import { exec } from "jsonpath-rfc9535";
|
|
4
|
+
import { OverlayError } from "./errors.js";
|
|
5
|
+
import { removeUnusedComponents } from "./prune.js";
|
|
6
|
+
import { Overlay } from "./schemas.js";
|
|
7
|
+
const applyOverlayOptions = Schema.Struct({
|
|
8
|
+
removeUnusedComponents: Schema.optionalKey(Schema.Boolean),
|
|
9
|
+
});
|
|
10
|
+
const overlayWarning = Schema.Struct({
|
|
11
|
+
action: Schema.Int,
|
|
12
|
+
target: Schema.String,
|
|
13
|
+
message: Schema.String,
|
|
14
|
+
});
|
|
15
|
+
function applyIfEnabled(enabled, transform) {
|
|
16
|
+
return Effect.flatMap((document) => Effect.suspend(() => transform(document)).pipe(Effect.when(Effect.succeed(enabled === true)), Effect.map(Option.getOrElse(() => document))));
|
|
17
|
+
}
|
|
18
|
+
const parseInput = Effect.fnUntraced(function* (input, label) {
|
|
19
|
+
if (typeof input !== "string")
|
|
20
|
+
return input;
|
|
21
|
+
return yield* Schema.decodeEffect(Schema.fromJsonString(Schema.Unknown))(input).pipe(Effect.catch(() => Effect.try({
|
|
22
|
+
try: () => Yaml.parse(input),
|
|
23
|
+
catch: (cause) => new OverlayError({ message: `Invalid ${label}: ${String(cause)}`, cause }),
|
|
24
|
+
})));
|
|
25
|
+
});
|
|
26
|
+
function cloneObject(value) {
|
|
27
|
+
return Record.fromEntries(Arr.map(Record.toEntries(value), ([key, item]) => [key, clone(item)]));
|
|
28
|
+
}
|
|
29
|
+
function clone(value) {
|
|
30
|
+
if (Arr.isArray(value))
|
|
31
|
+
return Arr.map(value, clone);
|
|
32
|
+
if (Predicate.isObject(value))
|
|
33
|
+
return cloneObject(value);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
function kind(value) {
|
|
37
|
+
if (Arr.isArray(value))
|
|
38
|
+
return "array";
|
|
39
|
+
return Predicate.isObject(value) ? "object" : "primitive";
|
|
40
|
+
}
|
|
41
|
+
function merge(target, update, append = false) {
|
|
42
|
+
if (Arr.isArray(target)) {
|
|
43
|
+
if (!Arr.isArray(update) && !append) {
|
|
44
|
+
throw new TypeError("Incompatible array property");
|
|
45
|
+
}
|
|
46
|
+
const items = Arr.isArray(update) ? update : [update];
|
|
47
|
+
for (const item of items)
|
|
48
|
+
target.push(clone(item));
|
|
49
|
+
return target;
|
|
50
|
+
}
|
|
51
|
+
if (Predicate.isObject(target)) {
|
|
52
|
+
if (kind(update) !== "object")
|
|
53
|
+
throw new TypeError("An object target requires an object update");
|
|
54
|
+
const object = target;
|
|
55
|
+
for (const [key, value] of Record.toEntries(update)) {
|
|
56
|
+
const next = Record.has(object, key)
|
|
57
|
+
? merge(object[key], value)
|
|
58
|
+
: clone(value);
|
|
59
|
+
Object.defineProperty(target, key, {
|
|
60
|
+
value: next,
|
|
61
|
+
writable: true,
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return target;
|
|
67
|
+
}
|
|
68
|
+
if (kind(update) !== "primitive")
|
|
69
|
+
throw new TypeError("A primitive target requires a primitive update");
|
|
70
|
+
return clone(update);
|
|
71
|
+
}
|
|
72
|
+
function select(document, expression) {
|
|
73
|
+
const nodes = [];
|
|
74
|
+
exec(document, expression, (value, path) => {
|
|
75
|
+
let parent = document;
|
|
76
|
+
for (const key of path.slice(0, -1)) {
|
|
77
|
+
parent = Arr.isArray(parent)
|
|
78
|
+
? parent[Number(key)]
|
|
79
|
+
: parent[key];
|
|
80
|
+
}
|
|
81
|
+
nodes.push({
|
|
82
|
+
value,
|
|
83
|
+
path: [...path],
|
|
84
|
+
parent: path.length === 0 ? undefined : parent,
|
|
85
|
+
key: path.at(-1),
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return nodes;
|
|
89
|
+
}
|
|
90
|
+
function uniqueNodes(nodes) {
|
|
91
|
+
return [
|
|
92
|
+
...new Map(Arr.map(nodes, (node) => [Formatter.formatJson(node.path), node])).values(),
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
function remove(nodes) {
|
|
96
|
+
if (Arr.some(nodes, (node) => node.parent === undefined)) {
|
|
97
|
+
throw new TypeError("Cannot remove the document root, which has no containing map or array");
|
|
98
|
+
}
|
|
99
|
+
// Descendants first; descending array indexes preserve the original selection.
|
|
100
|
+
const ordered = uniqueNodes(nodes).sort((left, right) => right.path.length - left.path.length ||
|
|
101
|
+
(typeof left.key === "number" && typeof right.key === "number"
|
|
102
|
+
? right.key - left.key
|
|
103
|
+
: typeof left.key === "number"
|
|
104
|
+
? -1
|
|
105
|
+
: typeof right.key === "number"
|
|
106
|
+
? 1
|
|
107
|
+
: 0));
|
|
108
|
+
for (const { parent, key } of ordered) {
|
|
109
|
+
if (Arr.isArray(parent))
|
|
110
|
+
parent.splice(Number(key), 1);
|
|
111
|
+
else if (parent !== undefined && key !== undefined)
|
|
112
|
+
delete parent[key];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function applyAction(document, action, version, nodes) {
|
|
116
|
+
if (version !== "1.0" && version !== "1.1") {
|
|
117
|
+
throw new TypeError(`Overlay ${version} action behavior is not implemented`);
|
|
118
|
+
}
|
|
119
|
+
if (version === "1.0" && Arr.some(nodes, (node) => kind(node.value) === "primitive")) {
|
|
120
|
+
throw new TypeError("Overlay 1.0 targets must select objects or arrays, not primitives");
|
|
121
|
+
}
|
|
122
|
+
if (action.remove === true) {
|
|
123
|
+
remove(nodes);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const hasUpdate = Record.has(action, "update");
|
|
127
|
+
const copy = version === "1.1" && typeof action.copy === "string" ? action.copy : undefined;
|
|
128
|
+
if (hasUpdate && copy !== undefined) {
|
|
129
|
+
throw new TypeError("An action cannot contain both update and copy");
|
|
130
|
+
}
|
|
131
|
+
if (!hasUpdate && copy === undefined)
|
|
132
|
+
return;
|
|
133
|
+
if (version === "1.1" && new Set(Arr.map(nodes, (node) => kind(node.value))).size > 1) {
|
|
134
|
+
throw new TypeError("All selected nodes must be objects, arrays, or primitives of the same category");
|
|
135
|
+
}
|
|
136
|
+
let update = action.update;
|
|
137
|
+
if (copy !== undefined) {
|
|
138
|
+
const sources = select(document, copy);
|
|
139
|
+
if (sources.length !== 1)
|
|
140
|
+
throw new TypeError("copy must select exactly one source node");
|
|
141
|
+
update = clone(sources[0].value);
|
|
142
|
+
}
|
|
143
|
+
for (const node of uniqueNodes(nodes)) {
|
|
144
|
+
if (version === "1.0" && Arr.isArray(node.value)) {
|
|
145
|
+
node.value.push(clone(update));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const value = merge(node.value, update, true);
|
|
149
|
+
if (Arr.isArray(node.parent))
|
|
150
|
+
node.parent[Number(node.key)] = value;
|
|
151
|
+
else if (node.parent !== undefined && node.key !== undefined) {
|
|
152
|
+
Object.defineProperty(node.parent, node.key, {
|
|
153
|
+
value,
|
|
154
|
+
writable: true,
|
|
155
|
+
enumerable: true,
|
|
156
|
+
configurable: true,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Apply actions and collect invalid or unmatched targets without mutating inputs. */
|
|
162
|
+
export const applyOverlayWithWarnings = Effect.fn("applyOverlayWithWarnings")(function* (document, overlay, options = {}) {
|
|
163
|
+
const checkedOptions = yield* Schema.decodeEffect(applyOverlayOptions)(options, {
|
|
164
|
+
onExcessProperty: "error",
|
|
165
|
+
}).pipe(Effect.mapError((cause) => new OverlayError({ message: `Invalid options: ${cause.message}`, cause })));
|
|
166
|
+
const source = yield* Schema.decodeUnknownEffect(Schema.JsonObject)(yield* parseInput(document, "document")).pipe(Effect.mapError((cause) => new OverlayError({ message: `Invalid document: ${cause.message}`, cause })));
|
|
167
|
+
const parsed = yield* Schema.decodeUnknownEffect(Overlay)(yield* parseInput(overlay, "overlay"), {
|
|
168
|
+
onExcessProperty: "error",
|
|
169
|
+
}).pipe(Effect.mapError((cause) => new OverlayError({ message: `Invalid overlay: ${cause.message}`, cause })));
|
|
170
|
+
const result = cloneObject(source);
|
|
171
|
+
const version = pipe(parsed.overlay, Str.split("."), Arr.take(2), Arr.join("."));
|
|
172
|
+
const warnings = yield* Effect.forEach(parsed.actions, Effect.fnUntraced(function* (action, index) {
|
|
173
|
+
const selected = yield* Effect.try({
|
|
174
|
+
try: () => select(result, action.target),
|
|
175
|
+
catch: (cause) => ({
|
|
176
|
+
action: index + 1,
|
|
177
|
+
target: action.target,
|
|
178
|
+
message: `Invalid target: ${String(cause)}`,
|
|
179
|
+
}),
|
|
180
|
+
}).pipe(Effect.result);
|
|
181
|
+
if (Result.isFailure(selected))
|
|
182
|
+
return [selected.failure];
|
|
183
|
+
if (selected.success.length === 0)
|
|
184
|
+
return [
|
|
185
|
+
{
|
|
186
|
+
action: index + 1,
|
|
187
|
+
target: action.target,
|
|
188
|
+
message: "Target matched no nodes",
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
yield* Effect.try({
|
|
192
|
+
try: () => applyAction(result, action, version, selected.success),
|
|
193
|
+
catch: (cause) => new OverlayError({
|
|
194
|
+
message: `Overlay action ${index + 1} (${action.target}): ${String(cause)}`,
|
|
195
|
+
action: index + 1,
|
|
196
|
+
target: action.target,
|
|
197
|
+
cause,
|
|
198
|
+
}),
|
|
199
|
+
});
|
|
200
|
+
return [];
|
|
201
|
+
}));
|
|
202
|
+
const output = yield* Effect.succeed(result).pipe(applyIfEnabled(checkedOptions.removeUnusedComponents, removeUnusedComponents));
|
|
203
|
+
return { document: output, warnings: Arr.flatten(warnings) };
|
|
204
|
+
});
|
|
205
|
+
/** Apply version-specific Overlay actions without mutating inputs. */
|
|
206
|
+
export const applyOverlay = Effect.fn("applyOverlay")((document, overlay, options = {}) => applyOverlayWithWarnings(document, overlay, options).pipe(Effect.map((result) => result.document)));
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
declare const OverlayError_base: Schema.Class<OverlayError, Schema.TaggedStruct<"OverlayError", {
|
|
3
|
+
readonly message: Schema.String;
|
|
4
|
+
readonly action: Schema.optionalKey<Schema.Int>;
|
|
5
|
+
readonly target: Schema.optionalKey<Schema.String>;
|
|
6
|
+
readonly cause: Schema.optionalKey<Schema.Defect>;
|
|
7
|
+
}>, import("effect/Cause").YieldableError & {
|
|
8
|
+
readonly brand: unique symbol;
|
|
9
|
+
}>;
|
|
10
|
+
export declare class OverlayError extends OverlayError_base {
|
|
11
|
+
}
|
|
12
|
+
export {};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export class OverlayError extends Schema.TaggedError()("OverlayError", {
|
|
3
|
+
message: Schema.String,
|
|
4
|
+
action: Schema.optionalKey(Schema.Int),
|
|
5
|
+
target: Schema.optionalKey(Schema.String),
|
|
6
|
+
cause: Schema.optionalKey(Schema.Defect()),
|
|
7
|
+
}) {
|
|
8
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/prune.d.ts
ADDED
package/dist/prune.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { OpenApiCallback, OpenApiExample, OpenApiHeader, OpenApiHttpMethod, OpenApiLink, OpenApiMediaType, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiRequestBody, OpenApiReference, OpenApiResponse, OpenApiSchema, OpenApiSecurityScheme, ParsedOpenApi, } from "@shipworthy/openapi-parser/schemas/3.1";
|
|
2
|
+
import { Array, Effect, JsonPointer, pipe, Predicate, Record, Schema, String } from "effect";
|
|
3
|
+
import { OverlayError } from "./errors.js";
|
|
4
|
+
const methods = OpenApiHttpMethod.literals;
|
|
5
|
+
const schemaWithAllOf = Schema.Struct({ allOf: Schema.Array(OpenApiSchema) });
|
|
6
|
+
const schemaMaps = ["properties", "patternProperties", "$defs", "dependentSchemas"];
|
|
7
|
+
const schemaLists = ["allOf", "anyOf", "oneOf", "prefixItems"];
|
|
8
|
+
const schemaSingles = [
|
|
9
|
+
"additionalProperties",
|
|
10
|
+
"unevaluatedProperties",
|
|
11
|
+
"items",
|
|
12
|
+
"contains",
|
|
13
|
+
"not",
|
|
14
|
+
"if",
|
|
15
|
+
"then",
|
|
16
|
+
"else",
|
|
17
|
+
"propertyNames",
|
|
18
|
+
"unevaluatedItems",
|
|
19
|
+
"contentSchema",
|
|
20
|
+
];
|
|
21
|
+
function extendsSchema(schema, pointer) {
|
|
22
|
+
return (Schema.is(schemaWithAllOf)(schema) &&
|
|
23
|
+
Array.some(schema.allOf, (child) => Schema.is(OpenApiReference)(child) && child.$ref === pointer));
|
|
24
|
+
}
|
|
25
|
+
function visitMap(values, visit, ignoreExtensions = false) {
|
|
26
|
+
return Effect.forEach(Record.toEntries(values ?? {}), ([key, value]) => ignoreExtensions && pipe(key, String.startsWith("x-")) ? Effect.void : visit(value), { discard: true });
|
|
27
|
+
}
|
|
28
|
+
export const removeUnusedComponents = Effect.fnUntraced(function* (document) {
|
|
29
|
+
const parsed = yield* Schema.decodeUnknownEffect(ParsedOpenApi)(document);
|
|
30
|
+
const used = new Set();
|
|
31
|
+
const followed = new Set();
|
|
32
|
+
const removedPaths = new Set();
|
|
33
|
+
const components = new Map();
|
|
34
|
+
const operationIds = new Set();
|
|
35
|
+
const linkedOperationIds = new Set();
|
|
36
|
+
const inherited = new Set();
|
|
37
|
+
const componentPointer = (category, name) => JsonPointer.formatUriFragment(["components", category, name]);
|
|
38
|
+
const mark = Effect.fnUntraced(function* (category, name) {
|
|
39
|
+
const pointer = componentPointer(category, name);
|
|
40
|
+
if (used.has(pointer))
|
|
41
|
+
return;
|
|
42
|
+
const visit = components.get(pointer);
|
|
43
|
+
if (visit === undefined)
|
|
44
|
+
return yield* new OverlayError({ message: `Missing component ${pointer}` });
|
|
45
|
+
used.add(pointer);
|
|
46
|
+
yield* visit();
|
|
47
|
+
});
|
|
48
|
+
const reference = Effect.fnUntraced(function* (ref, visit) {
|
|
49
|
+
const tokens = pipe(ref, String.startsWith("#/"))
|
|
50
|
+
? JsonPointer.parseUriFragment(ref)
|
|
51
|
+
: undefined;
|
|
52
|
+
if (tokens === undefined)
|
|
53
|
+
return yield* new OverlayError({
|
|
54
|
+
message: `Component pruning requires bundled local JSON Pointer references: ${ref}`,
|
|
55
|
+
});
|
|
56
|
+
if (tokens[0] === "paths" && tokens[1] !== undefined && removedPaths.has(tokens[1]))
|
|
57
|
+
return yield* new OverlayError({ message: `Reference targets a removed path: ${ref}` });
|
|
58
|
+
const root = parsed;
|
|
59
|
+
const target = Array.reduce(tokens, root, (value, token) => Predicate.isObject(value) && Record.has(value, token) ? value[token] : undefined);
|
|
60
|
+
if (target === undefined)
|
|
61
|
+
return yield* new OverlayError({ message: `Missing reference ${ref}` });
|
|
62
|
+
if (followed.has(ref))
|
|
63
|
+
return;
|
|
64
|
+
followed.add(ref);
|
|
65
|
+
if (tokens[0] === "components" && tokens[1] !== undefined && tokens[2] !== undefined)
|
|
66
|
+
yield* mark(tokens[1], tokens[2]);
|
|
67
|
+
yield* visit(target);
|
|
68
|
+
});
|
|
69
|
+
function referenced(schema, walk) {
|
|
70
|
+
const visit = Effect.fnUntraced(function* (value) {
|
|
71
|
+
if (Predicate.isObject(value) && Predicate.isString(value.$ref)) {
|
|
72
|
+
yield* reference(value.$ref, visit);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
yield* walk(yield* Schema.decodeUnknownEffect(schema)(value));
|
|
76
|
+
});
|
|
77
|
+
return visit;
|
|
78
|
+
}
|
|
79
|
+
const visitSchema = Effect.fnUntraced(function* (value, componentName) {
|
|
80
|
+
const schema = yield* Schema.decodeUnknownEffect(OpenApiSchema)(value);
|
|
81
|
+
if (typeof schema === "boolean")
|
|
82
|
+
return;
|
|
83
|
+
if (Predicate.isString(schema.$ref))
|
|
84
|
+
yield* reference(schema.$ref, visitSchema);
|
|
85
|
+
if (Predicate.isString(schema.$dynamicRef))
|
|
86
|
+
return yield* new OverlayError({
|
|
87
|
+
message: `Component pruning does not support $dynamicRef: ${schema.$dynamicRef}`,
|
|
88
|
+
});
|
|
89
|
+
yield* Effect.forEach(schemaSingles, (key) => (schema[key] === undefined ? Effect.void : visitSchema(schema[key])), { discard: true });
|
|
90
|
+
yield* Effect.forEach(schemaLists, (key) => {
|
|
91
|
+
const children = schema[key];
|
|
92
|
+
return Array.isArray(children)
|
|
93
|
+
? Effect.forEach(children, (child) => visitSchema(child), { discard: true })
|
|
94
|
+
: Effect.void;
|
|
95
|
+
}, { discard: true });
|
|
96
|
+
yield* Effect.forEach(schemaMaps, (key) => {
|
|
97
|
+
const children = schema[key];
|
|
98
|
+
return Predicate.isObject(children)
|
|
99
|
+
? Effect.forEach(Record.values(children), (child) => visitSchema(child), {
|
|
100
|
+
discard: true,
|
|
101
|
+
})
|
|
102
|
+
: Effect.void;
|
|
103
|
+
}, { discard: true });
|
|
104
|
+
const discriminator = schema.discriminator;
|
|
105
|
+
if (Predicate.isObject(discriminator) && componentName !== undefined)
|
|
106
|
+
yield* visitDerivedSchemas(componentName);
|
|
107
|
+
if (Predicate.isObject(discriminator) && Predicate.isObject(discriminator.mapping))
|
|
108
|
+
yield* Effect.forEach(Record.values(discriminator.mapping), (target) => {
|
|
109
|
+
if (!Predicate.isString(target))
|
|
110
|
+
return Effect.void;
|
|
111
|
+
return Record.has(parsed.components?.schemas ?? {}, target)
|
|
112
|
+
? mark("schemas", target)
|
|
113
|
+
: reference(target, visitSchema);
|
|
114
|
+
}, { discard: true });
|
|
115
|
+
});
|
|
116
|
+
function visitDerivedSchemas(parent) {
|
|
117
|
+
if (inherited.has(parent))
|
|
118
|
+
return Effect.void;
|
|
119
|
+
inherited.add(parent);
|
|
120
|
+
const pointer = componentPointer("schemas", parent);
|
|
121
|
+
return Effect.forEach(Record.toEntries(parsed.components?.schemas ?? {}), ([name, schema]) => {
|
|
122
|
+
if (!extendsSchema(schema, pointer))
|
|
123
|
+
return Effect.void;
|
|
124
|
+
return mark("schemas", name).pipe(Effect.andThen(() => visitDerivedSchemas(name)));
|
|
125
|
+
}, { discard: true });
|
|
126
|
+
}
|
|
127
|
+
const visitExample = referenced(OpenApiExample, () => Effect.void);
|
|
128
|
+
const visitSecurityScheme = referenced(OpenApiSecurityScheme, () => Effect.void);
|
|
129
|
+
const visitHeader = referenced(OpenApiHeader, Effect.fnUntraced(function* (header) {
|
|
130
|
+
if (header.schema !== undefined)
|
|
131
|
+
yield* visitSchema(header.schema);
|
|
132
|
+
yield* visitMap(header.content, visitMediaType);
|
|
133
|
+
yield* visitMap(header.examples, visitExample);
|
|
134
|
+
}));
|
|
135
|
+
const visitParameter = referenced(OpenApiParameter, Effect.fnUntraced(function* (parameter) {
|
|
136
|
+
if (parameter.schema !== undefined)
|
|
137
|
+
yield* visitSchema(parameter.schema);
|
|
138
|
+
yield* visitMap(parameter.content, visitMediaType);
|
|
139
|
+
yield* visitMap(parameter.examples, visitExample);
|
|
140
|
+
}));
|
|
141
|
+
const visitRequestBody = referenced(OpenApiRequestBody, (body) => visitMap(body.content, visitMediaType));
|
|
142
|
+
const visitLink = referenced(OpenApiLink, Effect.fnUntraced(function* (link) {
|
|
143
|
+
if (link.operationId !== undefined)
|
|
144
|
+
linkedOperationIds.add(link.operationId);
|
|
145
|
+
if (link.operationRef !== undefined && pipe(link.operationRef, String.startsWith("#")))
|
|
146
|
+
yield* reference(link.operationRef, visitOperation);
|
|
147
|
+
}));
|
|
148
|
+
const visitResponse = referenced(OpenApiResponse, Effect.fnUntraced(function* (response) {
|
|
149
|
+
yield* visitMap(response.content, visitMediaType);
|
|
150
|
+
yield* visitMap(response.headers, visitHeader);
|
|
151
|
+
yield* visitMap(response.links, visitLink);
|
|
152
|
+
}));
|
|
153
|
+
const visitCallback = referenced(OpenApiCallback, (callback) => visitMap(callback, visitPathItem, true));
|
|
154
|
+
function visitMediaType(value) {
|
|
155
|
+
return Schema.decodeUnknownEffect(OpenApiMediaType)(value).pipe(Effect.flatMap(Effect.fnUntraced(function* (media) {
|
|
156
|
+
if (media.schema !== undefined)
|
|
157
|
+
yield* visitSchema(media.schema);
|
|
158
|
+
yield* visitMap(media.examples, visitExample);
|
|
159
|
+
yield* Effect.forEach(Record.values(media.encoding ?? {}), (encoding) => visitMap(encoding.headers, visitHeader), { discard: true });
|
|
160
|
+
})));
|
|
161
|
+
}
|
|
162
|
+
function visitSecurity(security) {
|
|
163
|
+
return Effect.forEach(security ?? [], (requirement) => Effect.forEach(Record.keys(requirement), (name) => mark("securitySchemes", name), {
|
|
164
|
+
discard: true,
|
|
165
|
+
}), { discard: true });
|
|
166
|
+
}
|
|
167
|
+
function visitOperation(value) {
|
|
168
|
+
return Schema.decodeUnknownEffect(OpenApiOperation)(value).pipe(Effect.flatMap(Effect.fnUntraced(function* (operation) {
|
|
169
|
+
if (operation.operationId !== undefined)
|
|
170
|
+
operationIds.add(operation.operationId);
|
|
171
|
+
yield* Effect.forEach(operation.parameters ?? [], visitParameter, { discard: true });
|
|
172
|
+
if (operation.requestBody !== undefined)
|
|
173
|
+
yield* visitRequestBody(operation.requestBody);
|
|
174
|
+
yield* visitMap(operation.responses, visitResponse, true);
|
|
175
|
+
yield* visitMap(operation.callbacks, visitCallback);
|
|
176
|
+
yield* visitSecurity(operation.security);
|
|
177
|
+
})));
|
|
178
|
+
}
|
|
179
|
+
function visitPathItem(value) {
|
|
180
|
+
return Schema.decodeUnknownEffect(OpenApiPathItem)(value).pipe(Effect.flatMap(Effect.fnUntraced(function* (item) {
|
|
181
|
+
if (item.$ref !== undefined)
|
|
182
|
+
yield* reference(item.$ref, visitPathItem);
|
|
183
|
+
yield* Effect.forEach(item.parameters ?? [], visitParameter, { discard: true });
|
|
184
|
+
yield* Effect.forEach(methods, (method) => (item[method] === undefined ? Effect.void : visitOperation(item[method])), { discard: true });
|
|
185
|
+
})));
|
|
186
|
+
}
|
|
187
|
+
function register(category, values, visit) {
|
|
188
|
+
Array.forEach(Record.toEntries(values ?? {}), ([name, value]) => {
|
|
189
|
+
components.set(componentPointer(category, name), () => visit(value));
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
Array.forEach(Record.toEntries(parsed.components?.schemas ?? {}), ([name, schema]) => {
|
|
193
|
+
components.set(componentPointer("schemas", name), () => visitSchema(schema, name));
|
|
194
|
+
});
|
|
195
|
+
register("responses", parsed.components?.responses, visitResponse);
|
|
196
|
+
register("parameters", parsed.components?.parameters, visitParameter);
|
|
197
|
+
register("requestBodies", parsed.components?.requestBodies, visitRequestBody);
|
|
198
|
+
register("headers", parsed.components?.headers, visitHeader);
|
|
199
|
+
register("examples", parsed.components?.examples, visitExample);
|
|
200
|
+
register("links", parsed.components?.links, visitLink);
|
|
201
|
+
register("callbacks", parsed.components?.callbacks, visitCallback);
|
|
202
|
+
register("pathItems", parsed.components?.pathItems, visitPathItem);
|
|
203
|
+
register("securitySchemes", parsed.components?.securitySchemes, visitSecurityScheme);
|
|
204
|
+
const retainedPaths = yield* Effect.forEach(Record.toEntries(parsed.paths ?? {}), Effect.fnUntraced(function* ([path, value]) {
|
|
205
|
+
if (pipe(path, String.startsWith("x-")))
|
|
206
|
+
return;
|
|
207
|
+
const item = yield* Schema.decodeEffect(OpenApiPathItem)(value);
|
|
208
|
+
if (item.$ref !== undefined || Array.some(methods, (method) => item[method] !== undefined))
|
|
209
|
+
return item;
|
|
210
|
+
removedPaths.add(path);
|
|
211
|
+
}));
|
|
212
|
+
yield* Effect.forEach(retainedPaths, (item) => (item === undefined ? Effect.void : visitPathItem(item)), { discard: true });
|
|
213
|
+
yield* visitMap(parsed.webhooks, visitPathItem);
|
|
214
|
+
yield* visitMap(parsed.$defs, (value) => visitSchema(value));
|
|
215
|
+
yield* visitSecurity(parsed.security);
|
|
216
|
+
yield* Effect.forEach(linkedOperationIds, (id) => operationIds.has(id)
|
|
217
|
+
? Effect.void
|
|
218
|
+
: new OverlayError({ message: `Missing linked operationId ${id}` }), { discard: true });
|
|
219
|
+
const paths = document.paths;
|
|
220
|
+
if (Predicate.isObject(paths) && !Array.isArray(paths))
|
|
221
|
+
Array.forEach(removedPaths, (path) => {
|
|
222
|
+
delete paths[path];
|
|
223
|
+
});
|
|
224
|
+
const maps = document.components;
|
|
225
|
+
if (Predicate.isObject(maps) && !Array.isArray(maps))
|
|
226
|
+
Array.forEach(Record.toEntries(maps), ([category, entries]) => {
|
|
227
|
+
if (pipe(category, String.startsWith("x-")) ||
|
|
228
|
+
!Predicate.isObject(entries) ||
|
|
229
|
+
Array.isArray(entries))
|
|
230
|
+
return;
|
|
231
|
+
Array.forEach(Record.keys(entries), (name) => {
|
|
232
|
+
if (!used.has(componentPointer(category, name)))
|
|
233
|
+
delete entries[name];
|
|
234
|
+
});
|
|
235
|
+
if (Record.keys(entries).length === 0)
|
|
236
|
+
delete maps[category];
|
|
237
|
+
});
|
|
238
|
+
return document;
|
|
239
|
+
}, Effect.mapError((cause) => new OverlayError({ message: `Cannot prune components: ${cause.message}`, cause })));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const OverlayInfo: Schema.StructWithRest<Schema.Struct<{
|
|
3
|
+
readonly title: Schema.String;
|
|
4
|
+
readonly version: Schema.String;
|
|
5
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
6
|
+
export type OverlayInfo = typeof OverlayInfo.Type;
|
|
7
|
+
export declare const OverlayAction: Schema.StructWithRest<Schema.Struct<{
|
|
8
|
+
readonly target: Schema.String;
|
|
9
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
10
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
11
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
12
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
13
|
+
export type OverlayAction = typeof OverlayAction.Type;
|
|
14
|
+
export declare const Overlay: Schema.StructWithRest<Schema.Struct<{
|
|
15
|
+
readonly overlay: Schema.String;
|
|
16
|
+
readonly info: Schema.StructWithRest<Schema.Struct<{
|
|
17
|
+
readonly title: Schema.String;
|
|
18
|
+
readonly version: Schema.String;
|
|
19
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
20
|
+
readonly extends: Schema.optionalKey<Schema.String>;
|
|
21
|
+
readonly actions: Schema.$Array<Schema.StructWithRest<Schema.Struct<{
|
|
22
|
+
readonly target: Schema.String;
|
|
23
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
24
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
25
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
26
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>>;
|
|
27
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
28
|
+
export type Overlay = typeof Overlay.Type;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Generated from schemas/v1.0/schema.yaml (sha256: 209a9755d58f96b5d80bf5a3ed4f6f2b9e77550fa27849cd67bd50bc3eabfa83).
|
|
2
|
+
// Run bun run generate:schemas to regenerate. Do not edit by hand.
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
export const OverlayInfo = Schema.StructWithRest(Schema.Struct({ title: Schema.String, version: Schema.String }), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))]).check(Schema.isPropertyNames(Schema.Union([
|
|
5
|
+
Schema.Literals(["title", "version"]),
|
|
6
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
7
|
+
expected: "a string matching the RegExp ^x-",
|
|
8
|
+
})),
|
|
9
|
+
])).annotate({
|
|
10
|
+
expected: "an object with property names matching the schema",
|
|
11
|
+
identifier: "OverlayInfo",
|
|
12
|
+
}));
|
|
13
|
+
export const OverlayAction = Schema.StructWithRest(Schema.Struct({
|
|
14
|
+
target: Schema.String.check(Schema.isPattern(new globalThis.RegExp("^\\$", "u")).annotate({
|
|
15
|
+
expected: "a string matching the RegExp ^\\$",
|
|
16
|
+
})),
|
|
17
|
+
description: Schema.optionalKey(Schema.String),
|
|
18
|
+
update: Schema.optionalKey(Schema.Union([
|
|
19
|
+
Schema.String,
|
|
20
|
+
Schema.Boolean,
|
|
21
|
+
Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })),
|
|
22
|
+
Schema.Array(Schema.Json.annotate({ expected: "JSON value" })),
|
|
23
|
+
Schema.Finite,
|
|
24
|
+
Schema.Null,
|
|
25
|
+
])),
|
|
26
|
+
remove: Schema.optionalKey(Schema.Boolean.annotate({ default: false })),
|
|
27
|
+
}), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))]).check(Schema.isPropertyNames(Schema.Union([
|
|
28
|
+
Schema.Literals(["target", "description", "update", "remove"]),
|
|
29
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
30
|
+
expected: "a string matching the RegExp ^x-",
|
|
31
|
+
})),
|
|
32
|
+
])).annotate({
|
|
33
|
+
expected: "an object with property names matching the schema",
|
|
34
|
+
identifier: "OverlayAction",
|
|
35
|
+
}));
|
|
36
|
+
export const Overlay = Schema.StructWithRest(Schema.Struct({
|
|
37
|
+
overlay: Schema.String.check(Schema.isPattern(new globalThis.RegExp("^1\\.0\\.\\d+$", "u")).annotate({
|
|
38
|
+
expected: "a string matching the RegExp ^1\\.0\\.\\d+$",
|
|
39
|
+
})),
|
|
40
|
+
info: OverlayInfo,
|
|
41
|
+
extends: Schema.optionalKey(Schema.String.annotate({ format: "uri-reference" })),
|
|
42
|
+
actions: Schema.Array(OverlayAction)
|
|
43
|
+
.check(Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }))
|
|
44
|
+
.check(Schema.isUnique().annotate({ expected: "an array with unique items" })),
|
|
45
|
+
}), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))])
|
|
46
|
+
.annotate({ description: "The description of Overlay v1.0.x documents" })
|
|
47
|
+
.check(Schema.isPropertyNames(Schema.Union([
|
|
48
|
+
Schema.Literals(["overlay", "info", "extends", "actions"]),
|
|
49
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
50
|
+
expected: "a string matching the RegExp ^x-",
|
|
51
|
+
})),
|
|
52
|
+
])).annotate({ expected: "an object with property names matching the schema" }));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const OverlayInfo: Schema.StructWithRest<Schema.Struct<{
|
|
3
|
+
readonly title: Schema.String;
|
|
4
|
+
readonly version: Schema.String;
|
|
5
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
6
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
7
|
+
export type OverlayInfo = typeof OverlayInfo.Type;
|
|
8
|
+
export declare const OverlayAction: Schema.StructWithRest<Schema.Struct<{
|
|
9
|
+
readonly target: Schema.String;
|
|
10
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
11
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
12
|
+
readonly copy: Schema.optionalKey<Schema.String>;
|
|
13
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
14
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
15
|
+
export type OverlayAction = typeof OverlayAction.Type;
|
|
16
|
+
export declare const Overlay: Schema.StructWithRest<Schema.Struct<{
|
|
17
|
+
readonly overlay: Schema.String;
|
|
18
|
+
readonly info: Schema.StructWithRest<Schema.Struct<{
|
|
19
|
+
readonly title: Schema.String;
|
|
20
|
+
readonly version: Schema.String;
|
|
21
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
22
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
23
|
+
readonly extends: Schema.optionalKey<Schema.String>;
|
|
24
|
+
readonly actions: Schema.$Array<Schema.StructWithRest<Schema.Struct<{
|
|
25
|
+
readonly target: Schema.String;
|
|
26
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
27
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
28
|
+
readonly copy: Schema.optionalKey<Schema.String>;
|
|
29
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
30
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>>;
|
|
31
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
32
|
+
export type Overlay = typeof Overlay.Type;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Generated from schemas/v1.1/schema.yaml (sha256: c9988e3656d7f9de217654a3fc67b093c009668be357c86f07fd76b260863a51).
|
|
2
|
+
// Run bun run generate:schemas to regenerate. Do not edit by hand.
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
export const OverlayInfo = Schema.StructWithRest(Schema.Struct({
|
|
5
|
+
title: Schema.String,
|
|
6
|
+
version: Schema.String,
|
|
7
|
+
description: Schema.optionalKey(Schema.String),
|
|
8
|
+
}), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))]).check(Schema.isPropertyNames(Schema.Union([
|
|
9
|
+
Schema.Literals(["title", "version", "description"]),
|
|
10
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
11
|
+
expected: "a string matching the RegExp ^x-",
|
|
12
|
+
})),
|
|
13
|
+
])).annotate({
|
|
14
|
+
expected: "an object with property names matching the schema",
|
|
15
|
+
identifier: "OverlayInfo",
|
|
16
|
+
}));
|
|
17
|
+
export const OverlayAction = Schema.StructWithRest(Schema.Struct({
|
|
18
|
+
target: Schema.String.check(Schema.isPattern(new globalThis.RegExp("^\\$", "u")).annotate({
|
|
19
|
+
expected: "a string matching the RegExp ^\\$",
|
|
20
|
+
})),
|
|
21
|
+
description: Schema.optionalKey(Schema.String),
|
|
22
|
+
update: Schema.optionalKey(Schema.Union([
|
|
23
|
+
Schema.String,
|
|
24
|
+
Schema.Boolean,
|
|
25
|
+
Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" })),
|
|
26
|
+
Schema.Array(Schema.Json.annotate({ expected: "JSON value" })),
|
|
27
|
+
Schema.Finite,
|
|
28
|
+
Schema.Null,
|
|
29
|
+
])),
|
|
30
|
+
copy: Schema.optionalKey(Schema.String),
|
|
31
|
+
remove: Schema.optionalKey(Schema.Boolean.annotate({ default: false })),
|
|
32
|
+
}), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))]).check(Schema.isPropertyNames(Schema.Union([
|
|
33
|
+
Schema.Literals(["target", "description", "update", "copy", "remove"]),
|
|
34
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
35
|
+
expected: "a string matching the RegExp ^x-",
|
|
36
|
+
})),
|
|
37
|
+
])).annotate({
|
|
38
|
+
expected: "an object with property names matching the schema",
|
|
39
|
+
identifier: "OverlayAction",
|
|
40
|
+
}));
|
|
41
|
+
export const Overlay = Schema.StructWithRest(Schema.Struct({
|
|
42
|
+
overlay: Schema.String.check(Schema.isPattern(new globalThis.RegExp("^1\\.1\\.\\d+$", "u")).annotate({
|
|
43
|
+
expected: "a string matching the RegExp ^1\\.1\\.\\d+$",
|
|
44
|
+
})),
|
|
45
|
+
info: OverlayInfo,
|
|
46
|
+
extends: Schema.optionalKey(Schema.String.annotate({ format: "uri-reference" })),
|
|
47
|
+
actions: Schema.Array(OverlayAction)
|
|
48
|
+
.check(Schema.isMinLength(1).annotate({ expected: "a value with a length of at least 1" }))
|
|
49
|
+
.check(Schema.isUnique().annotate({ expected: "an array with unique items" })),
|
|
50
|
+
}), [Schema.Record(Schema.String, Schema.Json.annotate({ expected: "JSON value" }))])
|
|
51
|
+
.annotate({ description: "The description of Overlay v1.1.x documents" })
|
|
52
|
+
.check(Schema.isPropertyNames(Schema.Union([
|
|
53
|
+
Schema.Literals(["overlay", "info", "extends", "actions"]),
|
|
54
|
+
Schema.String.check(Schema.isPattern(new globalThis.RegExp("^x-", "u")).annotate({
|
|
55
|
+
expected: "a string matching the RegExp ^x-",
|
|
56
|
+
})),
|
|
57
|
+
])).annotate({ expected: "an object with property names matching the schema" }));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
export declare const OverlayInfo: Schema.Union<readonly [Schema.StructWithRest<Schema.Struct<{
|
|
3
|
+
readonly title: Schema.String;
|
|
4
|
+
readonly version: Schema.String;
|
|
5
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>, Schema.StructWithRest<Schema.Struct<{
|
|
6
|
+
readonly title: Schema.String;
|
|
7
|
+
readonly version: Schema.String;
|
|
8
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
9
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>]>;
|
|
10
|
+
export type OverlayInfo = typeof OverlayInfo.Type;
|
|
11
|
+
export declare const OverlayAction: Schema.Union<readonly [Schema.StructWithRest<Schema.Struct<{
|
|
12
|
+
readonly target: Schema.String;
|
|
13
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
14
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
15
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
16
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>, Schema.StructWithRest<Schema.Struct<{
|
|
17
|
+
readonly target: Schema.String;
|
|
18
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
19
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
20
|
+
readonly copy: Schema.optionalKey<Schema.String>;
|
|
21
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
22
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>]>;
|
|
23
|
+
export type OverlayAction = typeof OverlayAction.Type;
|
|
24
|
+
export declare const Overlay: Schema.Union<readonly [Schema.StructWithRest<Schema.Struct<{
|
|
25
|
+
readonly overlay: Schema.String;
|
|
26
|
+
readonly info: Schema.StructWithRest<Schema.Struct<{
|
|
27
|
+
readonly title: Schema.String;
|
|
28
|
+
readonly version: Schema.String;
|
|
29
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
30
|
+
readonly extends: Schema.optionalKey<Schema.String>;
|
|
31
|
+
readonly actions: Schema.$Array<Schema.StructWithRest<Schema.Struct<{
|
|
32
|
+
readonly target: Schema.String;
|
|
33
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
34
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
35
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
36
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>>;
|
|
37
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>, Schema.StructWithRest<Schema.Struct<{
|
|
38
|
+
readonly overlay: Schema.String;
|
|
39
|
+
readonly info: Schema.StructWithRest<Schema.Struct<{
|
|
40
|
+
readonly title: Schema.String;
|
|
41
|
+
readonly version: Schema.String;
|
|
42
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
43
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>;
|
|
44
|
+
readonly extends: Schema.optionalKey<Schema.String>;
|
|
45
|
+
readonly actions: Schema.$Array<Schema.StructWithRest<Schema.Struct<{
|
|
46
|
+
readonly target: Schema.String;
|
|
47
|
+
readonly description: Schema.optionalKey<Schema.String>;
|
|
48
|
+
readonly update: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Boolean, Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.$Array<Schema.Codec<Schema.Json, Schema.Json, never, never>>, Schema.Finite, Schema.Null]>>;
|
|
49
|
+
readonly copy: Schema.optionalKey<Schema.String>;
|
|
50
|
+
readonly remove: Schema.optionalKey<Schema.Boolean>;
|
|
51
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>>;
|
|
52
|
+
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>]>;
|
|
53
|
+
export type Overlay = typeof Overlay.Type;
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import * as V10 from "./schemas/1.0.js";
|
|
3
|
+
import * as V11 from "./schemas/1.1.js";
|
|
4
|
+
export const OverlayInfo = Schema.Union([V10.OverlayInfo, V11.OverlayInfo]);
|
|
5
|
+
export const OverlayAction = Schema.Union([V10.OverlayAction, V11.OverlayAction]);
|
|
6
|
+
export const Overlay = Schema.Union([V10.Overlay, V11.Overlay]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,58 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipworthy/openapi-overlay",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist"
|
|
6
|
+
],
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@shipworthy/openapi-parser": "1.0.0",
|
|
9
|
+
"effect": "4.1.4",
|
|
10
|
+
"jsonpath-rfc9535": "1.3.0"
|
|
11
|
+
},
|
|
12
|
+
"description": "Apply versioned OpenAPI Overlay documents with Effect.",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/ShipWorthyAI/openapi.git",
|
|
17
|
+
"directory": "packages/openapi-overlay"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./schemas/1.0": {
|
|
26
|
+
"types": "./dist/schemas/1.0.d.ts",
|
|
27
|
+
"default": "./dist/schemas/1.0.js"
|
|
28
|
+
},
|
|
29
|
+
"./schemas/1.1": {
|
|
30
|
+
"types": "./dist/schemas/1.1.d.ts",
|
|
31
|
+
"default": "./dist/schemas/1.1.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"generate:schemas": "bun scripts/generate-schemas.ts",
|
|
37
|
+
"check:schemas": "bun scripts/generate-schemas.ts --check",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@effect/platform-node": "4.1.4",
|
|
43
|
+
"@effect/vitest": "4.1.4",
|
|
44
|
+
"@shipworthy/typescript-config": "0.0.1",
|
|
45
|
+
"@types/node": "^26.6.6",
|
|
46
|
+
"oxfmt": "^0.78.0",
|
|
47
|
+
"typescript": "^7.0.2",
|
|
48
|
+
"vitest": "5.1.0"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=22.19.0"
|
|
52
|
+
},
|
|
53
|
+
"main": "./dist/index.js",
|
|
54
|
+
"types": "./dist/index.d.ts",
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
}
|
|
58
|
+
}
|