@speclynx/apidom-overlay 4.5.0 → 4.6.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 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.6.0](https://github.com/speclynx/apidom/compare/v4.5.0...v4.6.0) (2026-04-12)
7
+
8
+ ### Features
9
+
10
+ - **overlay:** add tracing and restructure into realms ([#234](https://github.com/speclynx/apidom/issues/234)) ([3ae47c6](https://github.com/speclynx/apidom/commit/3ae47c6f8916b70db15704ade73af63210813c8c))
11
+
6
12
  # [4.5.0](https://github.com/speclynx/apidom/compare/v4.4.0...v4.5.0) (2026-04-12)
7
13
 
8
14
  ### Features
package/README.md CHANGED
@@ -124,6 +124,61 @@ The implementation follows [Overlay 1.1.0](https://spec.openapis.org/overlay/v1.
124
124
  | `remove: true` | Removes matched nodes; when combined with `update`, the update has no effect |
125
125
  | Action ordering | Applied sequentially — each action modifies the result of the previous |
126
126
 
127
+ ## Tracing
128
+
129
+ Overlay application supports tracing to inspect what each action did during application.
130
+ Pass a trace object via the `trace` option — it will be populated in place with step-by-step
131
+ information about every action applied.
132
+
133
+ ```js
134
+ import { applyOverlayApiDOM } from '@speclynx/apidom-overlay';
135
+
136
+ const trace = {};
137
+ const result = applyOverlayApiDOM(overlay, target, { trace });
138
+
139
+ console.log(trace.failed); // false
140
+ console.log(trace.message); // 'Overlay was successfully applied'
141
+
142
+ for (const action of trace.actions) {
143
+ console.log(action.target); // '$.info.title'
144
+ console.log(action.type); // 'update' | 'copy' | 'remove' | 'noop'
145
+ console.log(action.matchCount); // 1
146
+ console.log(action.normalizedPaths); // ["$['info']['title']"]
147
+ console.log(action.success); // true
148
+ }
149
+ ```
150
+
151
+ When an action fails, the trace captures the error before it is re-thrown:
152
+
153
+ ```js
154
+ const trace = {};
155
+ try {
156
+ applyOverlayApiDOM(overlay, target, { trace });
157
+ } catch (error) {
158
+ console.log(trace.failed); // true
159
+ console.log(trace.failedAt); // index of the failed action
160
+ console.log(trace.message); // error message
161
+ console.log(trace.actions[trace.failedAt].error); // the OverlayError instance
162
+ }
163
+ ```
164
+
165
+ Tracing works across all API levels — ApiDOM elements, file/URL, and POJO:
166
+
167
+ ```js
168
+ // single action (ApiDOM)
169
+ const trace = {};
170
+ applyActionApiDOM(action, target, { trace });
171
+ console.log(trace.actions[0].type); // 'update'
172
+
173
+ // file/URL
174
+ const trace = {};
175
+ await applyOverlay('/path/to/overlay.yaml', undefined, { trace });
176
+
177
+ // POJO
178
+ const trace = {};
179
+ applyOverlayPOJO(overlay, target, { trace });
180
+ ```
181
+
127
182
  ## Options
128
183
 
129
184
  ### ApplyOptions
@@ -135,6 +190,7 @@ Passed to `applyActionApiDOM`, `applyOverlayApiDOM`, and `applyOverlay`:
135
190
  | `deepmerge` | `DeepMergeUserOptions` | `{}` | Custom [deepmerge options](https://github.com/speclynx/apidom/blob/main/packages/apidom-core/src/merge/deepmerge.ts) from `@speclynx/apidom-core`. Default `customMerge` enforces Overlay spec type compatibility. |
136
191
  | `strict` | `boolean` | `false` | When `true`, throws `OverlayError` if any action's target JSONPath matches zero nodes. |
137
192
  | `immutable` | `boolean` | `true` | When `true` (default), returns a new element without mutating the input. Set to `false` for in-place mutation. |
193
+ | `trace` | `OverlayTrace` | — | When provided, populated in place with action-by-action trace data. See [Tracing](#tracing). |
138
194
 
139
195
  ### ApplyOverlayOptions
140
196
 
@@ -11,7 +11,7 @@
11
11
  return /******/ (() => { // webpackBootstrap
12
12
  /******/ var __webpack_modules__ = ({
13
13
 
14
- /***/ 4433
14
+ /***/ 28216
15
15
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
16
16
 
17
17
  "use strict";
@@ -33,6 +33,8 @@ __webpack_require__.r(__webpack_exports__);
33
33
  /* harmony import */ var _speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(26432);
34
34
  /* harmony import */ var _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(18436);
35
35
  /* harmony import */ var _validate_ts__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(24338);
36
+ /* harmony import */ var _trace_TraceBuilder_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(90563);
37
+
36
38
 
37
39
 
38
40
 
@@ -44,6 +46,10 @@ __webpack_require__.r(__webpack_exports__);
44
46
  * @public
45
47
  */
46
48
 
49
+ /**
50
+ * Internal options that carry the tracer instance.
51
+ */
52
+
47
53
  const defaultApplyOptions = {
48
54
  immutable: true,
49
55
  strict: false
@@ -185,6 +191,8 @@ const applyRemoveAction = (normalizedPaths, targetElement, options = defaultAppl
185
191
  * @public
186
192
  */
187
193
  const applyAction = (actionElement, targetElement, options = defaultApplyOptions) => {
194
+ const internalOpts = options;
195
+ const tracer = internalOpts.tracer ?? (options.trace ? new _trace_TraceBuilder_ts__WEBPACK_IMPORTED_MODULE_10__["default"](options.trace) : undefined);
188
196
  const actionValidation = (0,_validate_ts__WEBPACK_IMPORTED_MODULE_9__.validateAction)(actionElement);
189
197
  if (!actionValidation.valid) throw actionValidation.error;
190
198
  const targetExpression = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_3__["default"])(actionElement.target);
@@ -198,24 +206,53 @@ const applyAction = (actionElement, targetElement, options = defaultApplyOptions
198
206
  });
199
207
  if (matches.length === 0) {
200
208
  if (options.strict) {
201
- throw new _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_8__["default"](`Action target "${targetExpression}" matched zero nodes (strict mode)`, {
209
+ const error = new _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_8__["default"](`Action target "${targetExpression}" matched zero nodes (strict mode)`, {
202
210
  action: actionElement
203
211
  });
212
+ tracer?.action({
213
+ target: targetExpression,
214
+ type: 'noop',
215
+ matchCount: 0,
216
+ normalizedPaths: [],
217
+ success: false,
218
+ error
219
+ });
220
+ throw error;
204
221
  }
222
+ tracer?.action({
223
+ target: targetExpression,
224
+ type: 'noop',
225
+ matchCount: 0,
226
+ normalizedPaths: []
227
+ });
205
228
  return targetElement;
206
229
  }
207
230
  try {
208
231
  // remove action
209
232
  const removeValue = actionElement.removeField;
210
233
  if (removeValue !== undefined && (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_3__["default"])(removeValue) === true) {
211
- return applyRemoveAction(normalizedPaths, targetElement, options);
234
+ const result = applyRemoveAction(normalizedPaths, targetElement, options);
235
+ tracer?.action({
236
+ target: targetExpression,
237
+ type: 'remove',
238
+ matchCount: matches.length,
239
+ normalizedPaths
240
+ });
241
+ return result;
212
242
  }
213
243
 
214
244
  // update action
215
245
  if (actionElement.update !== undefined) {
216
246
  const nodesValidation = (0,_validate_ts__WEBPACK_IMPORTED_MODULE_9__.validateTargetNodes)(matches);
217
247
  if (!nodesValidation.valid) throw nodesValidation.error;
218
- return applyUpdateAction(normalizedPaths, actionElement.update, targetElement, options);
248
+ const result = applyUpdateAction(normalizedPaths, actionElement.update, targetElement, options);
249
+ tracer?.action({
250
+ target: targetExpression,
251
+ type: 'update',
252
+ matchCount: matches.length,
253
+ normalizedPaths
254
+ });
255
+ return result;
219
256
  }
220
257
 
221
258
  // copy action
@@ -223,14 +260,35 @@ const applyAction = (actionElement, targetElement, options = defaultApplyOptions
223
260
  const nodesValidation = (0,_validate_ts__WEBPACK_IMPORTED_MODULE_9__.validateTargetNodes)(matches);
224
261
  if (!nodesValidation.valid) throw nodesValidation.error;
225
262
  const copyExpression = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_3__["default"])(actionElement.copy);
226
- return applyCopyAction(normalizedPaths, copyExpression, targetElement, options);
263
+ const result = applyCopyAction(normalizedPaths, copyExpression, targetElement, options);
264
+ tracer?.action({
265
+ target: targetExpression,
266
+ type: 'copy',
267
+ matchCount: matches.length,
268
+ normalizedPaths
269
+ });
270
+ return result;
227
271
  }
272
+ tracer?.action({
273
+ target: targetExpression,
274
+ type: 'noop',
275
+ matchCount: matches.length,
276
+ normalizedPaths
277
+ });
228
278
  return targetElement;
229
279
  } catch (error) {
230
280
  // enrich OverlayError with action context, preserving original stack
231
281
  if (error instanceof _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_8__["default"] && !error.action) {
232
282
  error.action = actionElement;
233
283
  }
284
+ tracer?.action({
285
+ target: targetExpression,
286
+ type: 'noop',
287
+ matchCount: matches.length,
288
+ normalizedPaths,
289
+ success: false,
290
+ error: error instanceof _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_8__["default"] ? error : undefined
291
+ });
234
292
  throw error;
235
293
  }
236
294
  };
@@ -258,8 +316,13 @@ const applyOverlay = (overlayElement, targetElement, options = defaultApplyOptio
258
316
  if (!(0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isArrayElement)(overlay.actions)) {
259
317
  return targetElement;
260
318
  }
319
+ const tracer = options.trace ? new _trace_TraceBuilder_ts__WEBPACK_IMPORTED_MODULE_10__["default"](options.trace) : undefined;
320
+ const internalOptions = tracer ? {
321
+ ...options,
322
+ tracer
323
+ } : options;
261
324
  for (const action of overlay.actions) {
262
- target = applyAction(action, target, options);
325
+ target = applyAction(action, target, internalOptions);
263
326
  }
264
327
  if (targetElement instanceof _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"]) {
265
328
  targetElement.replaceResult(target);
@@ -270,7 +333,7 @@ const applyOverlay = (overlayElement, targetElement, options = defaultApplyOptio
270
333
 
271
334
  /***/ },
272
335
 
273
- /***/ 56019
336
+ /***/ 83942
274
337
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
275
338
 
276
339
  "use strict";
@@ -282,7 +345,7 @@ __webpack_require__.r(__webpack_exports__);
282
345
  /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10404);
283
346
  /* harmony import */ var _speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(44673);
284
347
  /* harmony import */ var _speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35957);
285
- /* harmony import */ var _apidom_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4433);
348
+ /* harmony import */ var _apidom_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(28216);
286
349
 
287
350
 
288
351
 
@@ -293,18 +356,18 @@ __webpack_require__.r(__webpack_exports__);
293
356
  *
294
357
  * @public
295
358
  */
296
- const applyAction = (action, target) => (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_1__["default"])((0,_apidom_ts__WEBPACK_IMPORTED_MODULE_3__.applyAction)((0,_speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_2__.refractAction)(action), (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.refract)(target)));
359
+ const applyAction = (action, target, options) => (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_1__["default"])((0,_apidom_ts__WEBPACK_IMPORTED_MODULE_3__.applyAction)((0,_speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_2__.refractAction)(action), (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.refract)(target), options));
297
360
 
298
361
  /**
299
362
  * Applies an entire overlay document (POJO) to a target (POJO).
300
363
  *
301
364
  * @public
302
365
  */
303
- const applyOverlay = (overlay, target) => (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_1__["default"])((0,_apidom_ts__WEBPACK_IMPORTED_MODULE_3__.applyOverlay)((0,_speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_2__.refractOverlay1)(overlay), (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.refract)(target)));
366
+ const applyOverlay = (overlay, target, options) => (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_1__["default"])((0,_apidom_ts__WEBPACK_IMPORTED_MODULE_3__.applyOverlay)((0,_speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_2__.refractOverlay1)(overlay), (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.refract)(target), options));
304
367
 
305
368
  /***/ },
306
369
 
307
- /***/ 54687
370
+ /***/ 42768
308
371
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
309
372
 
310
373
  "use strict";
@@ -315,7 +378,7 @@ __webpack_require__.r(__webpack_exports__);
315
378
  /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(96911);
316
379
  /* harmony import */ var _speclynx_apidom_ns_overlay_1__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(26432);
317
380
  /* harmony import */ var _speclynx_apidom_reference__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(29807);
318
- /* harmony import */ var _apidom_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4433);
381
+ /* harmony import */ var _apidom_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(28216);
319
382
  /* harmony import */ var _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(18436);
320
383
 
321
384
 
@@ -396,6 +459,58 @@ const applyOverlay = async (overlayURI, targetURI, options = {
396
459
 
397
460
  /***/ },
398
461
 
462
+ /***/ 90563
463
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
464
+
465
+ "use strict";
466
+ __webpack_require__.r(__webpack_exports__);
467
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
468
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
469
+ /* harmony export */ });
470
+ /**
471
+ * Collects trace entries during overlay application.
472
+ * Instantiated internally when `options.trace` is provided.
473
+ */
474
+ class TraceBuilder {
475
+ #trace;
476
+ constructor(trace) {
477
+ this.#trace = trace;
478
+ this.#trace.actions = [];
479
+ this.#trace.failed = false;
480
+ this.#trace.failedAt = -1;
481
+ this.#trace.message = 'Overlay was successfully applied';
482
+ }
483
+ action(step) {
484
+ const {
485
+ target,
486
+ type,
487
+ matchCount,
488
+ normalizedPaths,
489
+ success = true,
490
+ error
491
+ } = step;
492
+ const position = this.#trace.actions.length;
493
+ this.#trace.actions.push({
494
+ target,
495
+ type,
496
+ matchCount,
497
+ normalizedPaths,
498
+ success,
499
+ ...(error !== undefined ? {
500
+ error
501
+ } : {})
502
+ });
503
+ if (!success) {
504
+ this.#trace.failed = true;
505
+ this.#trace.failedAt = position;
506
+ this.#trace.message = error?.message ?? 'Action failed';
507
+ }
508
+ }
509
+ }
510
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TraceBuilder);
511
+
512
+ /***/ },
513
+
399
514
  /***/ 18436
400
515
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
401
516
 
@@ -100897,16 +101012,16 @@ var __webpack_exports__ = {};
100897
101012
  __webpack_require__.r(__webpack_exports__);
100898
101013
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
100899
101014
  /* harmony export */ OverlayError: () => (/* reexport safe */ _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_4__["default"]),
100900
- /* harmony export */ applyActionApiDOM: () => (/* reexport safe */ _apply_apidom_ts__WEBPACK_IMPORTED_MODULE_0__.applyAction),
100901
- /* harmony export */ applyActionPOJO: () => (/* reexport safe */ _apply_pojo_ts__WEBPACK_IMPORTED_MODULE_2__.applyAction),
100902
- /* harmony export */ applyOverlay: () => (/* reexport safe */ _apply_uri_ts__WEBPACK_IMPORTED_MODULE_1__["default"]),
100903
- /* harmony export */ applyOverlayApiDOM: () => (/* reexport safe */ _apply_apidom_ts__WEBPACK_IMPORTED_MODULE_0__.applyOverlay),
100904
- /* harmony export */ applyOverlayPOJO: () => (/* reexport safe */ _apply_pojo_ts__WEBPACK_IMPORTED_MODULE_2__.applyOverlay),
101015
+ /* harmony export */ applyActionApiDOM: () => (/* reexport safe */ _apply_realms_apidom_ts__WEBPACK_IMPORTED_MODULE_0__.applyAction),
101016
+ /* harmony export */ applyActionPOJO: () => (/* reexport safe */ _apply_realms_pojo_ts__WEBPACK_IMPORTED_MODULE_2__.applyAction),
101017
+ /* harmony export */ applyOverlay: () => (/* reexport safe */ _apply_realms_uri_ts__WEBPACK_IMPORTED_MODULE_1__["default"]),
101018
+ /* harmony export */ applyOverlayApiDOM: () => (/* reexport safe */ _apply_realms_apidom_ts__WEBPACK_IMPORTED_MODULE_0__.applyOverlay),
101019
+ /* harmony export */ applyOverlayPOJO: () => (/* reexport safe */ _apply_realms_pojo_ts__WEBPACK_IMPORTED_MODULE_2__.applyOverlay),
100905
101020
  /* harmony export */ validateAction: () => (/* reexport safe */ _validate_ts__WEBPACK_IMPORTED_MODULE_3__.validateAction)
100906
101021
  /* harmony export */ });
100907
- /* harmony import */ var _apply_apidom_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4433);
100908
- /* harmony import */ var _apply_uri_ts__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(54687);
100909
- /* harmony import */ var _apply_pojo_ts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(56019);
101022
+ /* harmony import */ var _apply_realms_apidom_ts__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(28216);
101023
+ /* harmony import */ var _apply_realms_uri_ts__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(42768);
101024
+ /* harmony import */ var _apply_realms_pojo_ts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(83942);
100910
101025
  /* harmony import */ var _validate_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(24338);
100911
101026
  /* harmony import */ var _errors_OverlayError_ts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(18436);
100912
101027