@speclynx/apidom-overlay 4.9.1 → 4.10.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 +6 -0
- package/README.md +108 -3
- package/dist/apidom-overlay.browser.js +60300 -59524
- package/dist/apidom-overlay.browser.min.js +1 -1
- package/package.json +8 -8
- package/src/diff/index.cjs +12 -0
- package/src/diff/index.mjs +3 -0
- package/src/diff/realms/apidom.cjs +177 -0
- package/src/diff/realms/apidom.mjs +170 -0
- package/src/diff/realms/pojo.cjs +15 -0
- package/src/diff/realms/pojo.mjs +10 -0
- package/src/diff/realms/uri.cjs +66 -0
- package/src/diff/realms/uri.mjs +60 -0
- package/src/index.cjs +6 -1
- package/src/index.mjs +1 -0
- package/types/apidom-overlay.d.ts +75 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.10.0](https://github.com/speclynx/apidom/compare/v4.9.1...v4.10.0) (2026-05-12)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **overlay:** add support for overlay generation by diffing API docs ([#278](https://github.com/speclynx/apidom/issues/278)) ([41fca34](https://github.com/speclynx/apidom/commit/41fca3455bce2e637b1e53f78f3f60afd93ef16c))
|
|
11
|
+
|
|
6
12
|
## [4.9.1](https://github.com/speclynx/apidom/compare/v4.9.0...v4.9.1) (2026-04-21)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @speclynx/apidom-overlay
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @speclynx/apidom-overlay
|
|
2
2
|
|
|
3
|
-
`@speclynx/apidom-overlay` applies [Overlay 1.x.y](https://spec.openapis.org/overlay/v1.1.0.html) documents to API definitions
|
|
3
|
+
`@speclynx/apidom-overlay` applies [Overlay 1.x.y](https://spec.openapis.org/overlay/v1.1.0.html) documents to API definitions
|
|
4
|
+
and can generate overlays by diffing two API documents.
|
|
4
5
|
The [Overlay Specification](https://spec.openapis.org/overlay/v1.1.0.html) defines a mechanism for modifying
|
|
5
6
|
existing API documents without directly editing the original, using [JSONPath (RFC 9535)](https://www.rfc-editor.org/rfc/rfc9535.html)
|
|
6
7
|
expressions to target specific nodes and apply updates, copies, or removals.
|
|
@@ -15,8 +16,6 @@ You can install this package via [npm CLI](https://docs.npmjs.com/cli) by runnin
|
|
|
15
16
|
|
|
16
17
|
## Usage
|
|
17
18
|
|
|
18
|
-
This package provides three levels of API for applying overlays:
|
|
19
|
-
|
|
20
19
|
### Applying from file/URL
|
|
21
20
|
|
|
22
21
|
`applyOverlay` parses an overlay document, resolves the target (from `targetURI` or the overlay's `extends` field),
|
|
@@ -109,6 +108,101 @@ const updated = applyActionPOJO(
|
|
|
109
108
|
);
|
|
110
109
|
```
|
|
111
110
|
|
|
111
|
+
### Generating an Overlay (diff)
|
|
112
|
+
|
|
113
|
+
`diffApiDOM` computes the diff between two ApiDOM elements and returns an `Overlay1Element` that,
|
|
114
|
+
when applied to the left document, yields the right document.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import { refract } from '@speclynx/apidom-datamodel';
|
|
118
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
119
|
+
import { diffApiDOM, applyOverlayApiDOM } from '@speclynx/apidom-overlay';
|
|
120
|
+
|
|
121
|
+
const left = refract({
|
|
122
|
+
openapi: '3.1.0',
|
|
123
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
124
|
+
servers: [{ url: 'https://staging.example.com' }],
|
|
125
|
+
});
|
|
126
|
+
const right = refract({
|
|
127
|
+
openapi: '3.1.0',
|
|
128
|
+
info: { title: 'My API', version: '2.0.0' },
|
|
129
|
+
servers: [{ url: 'https://prod.example.com' }, { url: 'https://dr.example.com' }],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const overlay = diffApiDOM(left, right, {
|
|
133
|
+
info: { title: 'v1 → v2 migration', version: '1.0.0' },
|
|
134
|
+
extends: 'https://example.com/openapi-v1.yaml',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// overlay is an Overlay1Element — serialize or apply it directly
|
|
138
|
+
const updated = applyOverlayApiDOM(overlay, left);
|
|
139
|
+
console.log(toValue(updated)); // equals toValue(right)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`diffPOJO` accepts and returns plain JavaScript objects:
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
import { diffPOJO } from '@speclynx/apidom-overlay';
|
|
146
|
+
|
|
147
|
+
const overlay = diffPOJO(
|
|
148
|
+
{ info: { title: 'Old', version: '1.0.0' } },
|
|
149
|
+
{ info: { title: 'New', version: '2.0.0' } },
|
|
150
|
+
);
|
|
151
|
+
// overlay is a plain object: { overlay: '1.1.0', info: {...}, actions: [...] }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`diffOverlay` parses two documents from file paths or URLs and returns an `Overlay1Element`.
|
|
155
|
+
The `extends` field is automatically set to `leftURI` when not provided, so the overlay
|
|
156
|
+
can be applied back to the original document without additional configuration.
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
import { diffOverlay } from '@speclynx/apidom-overlay';
|
|
160
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
161
|
+
|
|
162
|
+
// diff two local files
|
|
163
|
+
const overlay = await diffOverlay('/path/to/openapi-v1.yaml', '/path/to/openapi-v2.yaml');
|
|
164
|
+
|
|
165
|
+
// extends is auto-populated with leftURI
|
|
166
|
+
console.log(toValue(overlay).extends); // '/path/to/openapi-v1.yaml'
|
|
167
|
+
|
|
168
|
+
// provide a canonical URL instead
|
|
169
|
+
const overlay = await diffOverlay(
|
|
170
|
+
'/path/to/openapi-v1.yaml',
|
|
171
|
+
'/path/to/openapi-v2.yaml',
|
|
172
|
+
{ extends: 'https://example.com/openapi-v1.yaml' },
|
|
173
|
+
);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### DiffOptions
|
|
177
|
+
|
|
178
|
+
| Option | Type | Default | Description |
|
|
179
|
+
|---|---|---|---|
|
|
180
|
+
| `overlay` | `string` | `'1.1.0'` | Version string written to the `overlay` field. Configurable because 1.0.0 and 1.1.0 have slightly different semantics. |
|
|
181
|
+
| `info.title` | `string` | `'API diff'` | Title for the generated overlay's `info` object. |
|
|
182
|
+
| `info.version` | `string` | `'0.0.0'` | Version for the generated overlay's `info` object. |
|
|
183
|
+
| `info.description` | `string` | — | Optional description for the overlay's `info` object. |
|
|
184
|
+
| `extends` | `string` | — | When provided, sets the `extends` field on the overlay pointing to the base document. |
|
|
185
|
+
| `onEmptyDiff` | `'allow' \| 'throw'` | `'allow'` | Controls behavior when the documents are identical and the diff produces no actions. `'allow'` returns an overlay with an empty `actions` array; `'throw'` throws `OverlayError`. |
|
|
186
|
+
|
|
187
|
+
#### Diff algorithm
|
|
188
|
+
|
|
189
|
+
The diff walks both element trees recursively and generates [JSONPath (RFC 9535)](https://www.rfc-editor.org/rfc/rfc9535.html) targets using the normalized path format (e.g. `$['info']['title']`).
|
|
190
|
+
|
|
191
|
+
- **Objects**: per-field comparison. Removed fields produce `remove` actions. Newly added fields are batched into a single `update` on the parent object. Changed fields recurse deeper.
|
|
192
|
+
- **Arrays**: positional comparison. Changed items at the same index recurse deeper. New items at the end are appended via `update` on the array. Removed trailing items use `remove` in reverse-index order for index stability. Structural type changes at a given index trigger a tail-reconstruct (remove tail + re-append from right) to stay within Overlay's supported operations.
|
|
193
|
+
- **Primitives**: direct `update` with the new value.
|
|
194
|
+
|
|
195
|
+
#### Known limitations
|
|
196
|
+
|
|
197
|
+
| Limitation | Details |
|
|
198
|
+
|---|---|
|
|
199
|
+
| Empty actions on identical documents | By default, identical inputs produce an overlay with an empty `actions` array (Overlay 1.1.0 §3 requires non-empty). Use `onEmptyDiff: 'throw'` to turn this into an `OverlayError` instead. |
|
|
200
|
+
| Root structural type change | Throws `OverlayError`. Overlay has no mechanism to replace the root node. |
|
|
201
|
+
| Array insert-at-position | Overlay 1.x has no insert primitive. Positional diffing cascades replacements + appends, which is always correct but may be verbose for large array reorderings. |
|
|
202
|
+
| Array item structural type change | Handled via tail-reconstruct: items from the first type-mismatched index onward are removed and re-appended. Always correct, but produces more actions than a minimal diff. |
|
|
203
|
+
| Shared element references | Action `update` values reference elements from the right document directly. Mutating the right document after calling `diff` will affect the returned overlay. |
|
|
204
|
+
| Reverse diff | The overlay carries no "before" value. It cannot be reversed without the original document. |
|
|
205
|
+
|
|
112
206
|
## Overlay spec semantics
|
|
113
207
|
|
|
114
208
|
The implementation follows [Overlay 1.1.0](https://spec.openapis.org/overlay/v1.1.0.html) merge rules:
|
|
@@ -197,6 +291,17 @@ Passed to `applyActionApiDOM`, `applyOverlayApiDOM`, and `applyOverlay`:
|
|
|
197
291
|
Extends `ApplyOptions` with all [`@speclynx/apidom-reference` options](https://github.com/speclynx/apidom/blob/main/packages/apidom-reference/README.md)
|
|
198
292
|
for controlling parsing, resolving, and dereferencing of the overlay and target documents.
|
|
199
293
|
|
|
294
|
+
### DiffOverlayOptions
|
|
295
|
+
|
|
296
|
+
Passed to `diffOverlay`. Extends `DiffOptions` with a `reference` field:
|
|
297
|
+
|
|
298
|
+
| Option | Type | Default | Description |
|
|
299
|
+
|---|---|---|---|
|
|
300
|
+
| `overlay` | `string` | `'1.1.0'` | Inherited from `DiffOptions`. See [DiffOptions](#diffoptions). |
|
|
301
|
+
| `info` | `object` | — | Inherited from `DiffOptions`. |
|
|
302
|
+
| `extends` | `string` | `leftURI` | When omitted, automatically set to `leftURI` so the overlay points back to the base document. |
|
|
303
|
+
| `reference` | `PartialDeep<ReferenceOptions>` | — | [`@speclynx/apidom-reference` options](https://github.com/speclynx/apidom/blob/main/packages/apidom-reference/README.md) for parsing the left and right documents. |
|
|
304
|
+
|
|
200
305
|
## Validation
|
|
201
306
|
|
|
202
307
|
`validateAction` checks an `ActionElement` for spec conformance before applying:
|