@kubb/ast 5.15.3 → 5.16.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/dist/index.cjs CHANGED
@@ -208,7 +208,7 @@ const VISITOR_KEYS = {
208
208
  "responses"
209
209
  ],
210
210
  RequestBody: ["content"],
211
- Content: ["schema"],
211
+ Content: ["schema", "stream"],
212
212
  Response: ["content"],
213
213
  Schema: [
214
214
  "properties",
@@ -272,24 +272,27 @@ function getChildren(node, recurse) {
272
272
  });
273
273
  return children;
274
274
  }
275
+ /** Calls `visit` for each direct child node and stops at the first call that returns `true`. */
275
276
  function visitChildNodes(node, visit) {
276
277
  const keys = VISITOR_KEYS[node.kind];
277
278
  if (!keys) return false;
278
279
  const record = node;
280
+ const seen = /* @__PURE__ */ new Set();
281
+ const visitOnce = (child) => !seen.has(child) && (seen.add(child), visit(child));
279
282
  for (const key of keys) {
280
283
  const value = record[key];
281
284
  if (Array.isArray(value)) {
282
- for (const item of value) if (isNode(item) && visit(item)) return true;
285
+ for (const item of value) if (isNode(item) && visitOnce(item)) return true;
283
286
  continue;
284
287
  }
285
288
  if (isNode(value)) {
286
- if (visit(value)) return true;
289
+ if (visitOnce(value)) return true;
287
290
  continue;
288
291
  }
289
292
  if (isNodeRecord(value)) for (const name in value) {
290
293
  if (!Object.hasOwn(value, name)) continue;
291
294
  const item = value[name];
292
- if (isNode(item) && visit(item)) return true;
295
+ if (isNode(item) && visitOnce(item)) return true;
293
296
  }
294
297
  }
295
298
  return false;
@@ -387,13 +390,19 @@ function transformChildren(node, visitor, recurse) {
387
390
  if (!keys) return node;
388
391
  const record = node;
389
392
  let updates;
393
+ const done = /* @__PURE__ */ new Map();
394
+ const transformOnce = (child) => {
395
+ const next = done.get(child) ?? transformNode(child, visitor, recurse, node);
396
+ done.set(child, next);
397
+ return next;
398
+ };
390
399
  for (const key of keys) {
391
400
  if (!(key in record)) continue;
392
401
  const value = record[key];
393
402
  if (Array.isArray(value)) {
394
403
  let mapped;
395
404
  for (const [i, item] of value.entries()) {
396
- const next = isNode(item) ? transformNode(item, visitor, recurse, node) : item;
405
+ const next = isNode(item) ? transformOnce(item) : item;
397
406
  if (mapped) {
398
407
  mapped.push(next);
399
408
  continue;
@@ -404,14 +413,14 @@ function transformChildren(node, visitor, recurse) {
404
413
  continue;
405
414
  }
406
415
  if (isNode(value)) {
407
- const next = transformNode(value, visitor, recurse, node);
416
+ const next = transformOnce(value);
408
417
  if (next !== value) (updates ??= {})[key] = next;
409
418
  continue;
410
419
  }
411
420
  if (isNodeRecord(value)) {
412
421
  let mapped;
413
422
  for (const [name, item] of Object.entries(value)) {
414
- const next = isNode(item) ? transformNode(item, visitor, recurse, node) : item;
423
+ const next = isNode(item) ? transformOnce(item) : item;
415
424
  if (next !== item) (mapped ??= { ...value })[name] = next;
416
425
  }
417
426
  if (mapped) (updates ??= {})[key] = mapped;