@kubb/renderer-jsx 5.0.0-beta.2 → 5.0.0-beta.21

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
@@ -4,14 +4,17 @@ const require_jsx_runtime$1 = require("./jsx-runtime.cjs");
4
4
  let _kubb_ast = require("@kubb/ast");
5
5
  //#region ../../internals/utils/src/context.ts
6
6
  /**
7
- * Context stack for tracking the current context values
7
+ * Context stack for tracking the current context values.
8
+ *
9
+ * WeakMap keyed by symbol so entries are GC-eligible once no external code
10
+ * holds a reference to the context key — important for long-running agent
11
+ * builds where plugins create and discard context keys across repeated runs.
8
12
  *
9
- * Note: This uses a global Map for simplicity in code generation scenarios.
10
13
  * For concurrent runtime execution, consider using AsyncLocalStorage or
11
14
  * instance-based context management.
12
15
  */
13
- const contextStack = /* @__PURE__ */ new Map();
14
- const contextDefaults = /* @__PURE__ */ new Map();
16
+ const contextStack = /* @__PURE__ */ new WeakMap();
17
+ const contextDefaults = /* @__PURE__ */ new WeakMap();
15
18
  /**
16
19
  * Provides a value to descendant components (Vue 3 style)
17
20
  *
@@ -343,7 +346,7 @@ function Jsx({ children }) {
343
346
  Jsx.displayName = "Jsx";
344
347
  //#endregion
345
348
  //#region src/components/Root.tsx
346
- var import_react = require_jsx_runtime.require_react();
349
+ var import_react = /* @__PURE__ */ require_jsx_runtime.__toESM(require_jsx_runtime.require_react());
347
350
  var ErrorBoundary = class extends import_react.Component {
348
351
  state = { hasError: false };
349
352
  static displayName = "ErrorBoundary";
@@ -481,9 +484,9 @@ const nodeNames = new Set([
481
484
  const createNode = (nodeName) => {
482
485
  return {
483
486
  nodeName,
484
- attributes: /* @__PURE__ */ new Map(),
487
+ attributes: Object.create(null),
485
488
  childNodes: [],
486
- parentNode: void 0
489
+ parentNode: null
487
490
  };
488
491
  };
489
492
  /**
@@ -521,7 +524,7 @@ const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
521
524
  * Does nothing if `removeNode` is not a direct child of `node`.
522
525
  */
523
526
  const removeChildNode = (node, removeNode) => {
524
- removeNode.parentNode = void 0;
527
+ removeNode.parentNode = null;
525
528
  const index = node.childNodes.indexOf(removeNode);
526
529
  if (index >= 0) node.childNodes.splice(index, 1);
527
530
  };
@@ -529,26 +532,22 @@ const removeChildNode = (node, removeNode) => {
529
532
  * Set an attribute on `node`, storing it in the node's `attributes` map.
530
533
  */
531
534
  const setAttribute = (node, key, value) => {
532
- node.attributes.set(key, value);
535
+ node.attributes[key] = value;
533
536
  };
534
537
  /**
535
538
  * Create a new {@link TextNode} with the given text value.
536
539
  */
537
540
  const createTextNode = (text) => {
538
- const node = {
541
+ return {
539
542
  nodeName: TEXT_NODE_NAME,
540
543
  nodeValue: text,
541
- parentNode: void 0
544
+ parentNode: null
542
545
  };
543
- setTextNodeValue(node, text);
544
- return node;
545
546
  };
546
547
  /**
547
548
  * Update the `nodeValue` of an existing {@link TextNode}.
548
- * Non-string values are coerced to strings via `String(text)`.
549
549
  */
550
550
  const setTextNodeValue = (node, text) => {
551
- if (typeof text !== "string") text = String(text);
552
551
  node.nodeValue = text;
553
552
  };
554
553
  //#endregion
@@ -17820,7 +17819,7 @@ const Renderer = (0, import_react_reconciler.default)({
17820
17819
  return false;
17821
17820
  },
17822
17821
  supportsMutation: true,
17823
- isPrimaryRenderer: true,
17822
+ isPrimaryRenderer: false,
17824
17823
  supportsPersistence: false,
17825
17824
  supportsHydration: false,
17826
17825
  scheduleTimeout: setTimeout,
@@ -17886,20 +17885,24 @@ const Renderer = (0, import_react_reconciler.default)({
17886
17885
  });
17887
17886
  //#endregion
17888
17887
  //#region src/utils.ts
17888
+ function toBool$1(val) {
17889
+ return val ?? false;
17890
+ }
17891
+ require_jsx_runtime.__name(toBool$1, "toBool");
17889
17892
  /**
17890
17893
  * Collect the text and nested AST-node children of a single kubb-* element.
17891
17894
  *
17892
- * `#text` children become raw {@link TextNode}s; nested `kubb-function`, `kubb-const`,
17895
+ * `#text` children become raw text nodes; nested `kubb-function`, `kubb-const`,
17893
17896
  * `kubb-type`, and similar elements are converted into their respective {@link CodeNode}s.
17894
- * Any unrecognized DOM elements are silently skipped.
17897
+ * Any unrecognized element names are silently skipped.
17895
17898
  */
17896
- function collectChildNodes(element) {
17899
+ function collectCodeNodes$1(element) {
17897
17900
  const result = [];
17898
17901
  for (const child of element.childNodes) {
17899
17902
  if (!child) continue;
17900
17903
  if (child.nodeName === "#text") {
17901
17904
  const text = child.nodeValue;
17902
- if (text && text.trim().length > 0) result.push((0, _kubb_ast.createText)(text));
17905
+ if (text && text.trim()) result.push((0, _kubb_ast.createText)(text));
17903
17906
  continue;
17904
17907
  }
17905
17908
  if (child.nodeName === "br") {
@@ -17909,164 +17912,162 @@ function collectChildNodes(element) {
17909
17912
  if (child.nodeName === "kubb-function") {
17910
17913
  const attrs = child.attributes;
17911
17914
  result.push((0, _kubb_ast.createFunction)({
17912
- name: attrs.get("name"),
17913
- params: attrs.get("params"),
17914
- export: attrs.get("export"),
17915
- default: attrs.get("default"),
17916
- async: attrs.get("async"),
17917
- generics: attrs.get("generics"),
17918
- returnType: attrs.get("returnType"),
17919
- JSDoc: attrs.get("JSDoc"),
17920
- nodes: collectChildNodes(child)
17915
+ name: attrs["name"],
17916
+ params: attrs["params"],
17917
+ export: attrs["export"],
17918
+ default: attrs["default"],
17919
+ async: attrs["async"],
17920
+ generics: attrs["generics"],
17921
+ returnType: attrs["returnType"],
17922
+ JSDoc: attrs["JSDoc"],
17923
+ nodes: collectCodeNodes$1(child)
17921
17924
  }));
17922
- } else if (child.nodeName === "kubb-arrow-function") {
17925
+ continue;
17926
+ }
17927
+ if (child.nodeName === "kubb-arrow-function") {
17923
17928
  const attrs = child.attributes;
17924
17929
  result.push((0, _kubb_ast.createArrowFunction)({
17925
- name: attrs.get("name"),
17926
- params: attrs.get("params"),
17927
- export: attrs.get("export"),
17928
- default: attrs.get("default"),
17929
- async: attrs.get("async"),
17930
- generics: attrs.get("generics"),
17931
- returnType: attrs.get("returnType"),
17932
- singleLine: attrs.get("singleLine"),
17933
- JSDoc: attrs.get("JSDoc"),
17934
- nodes: collectChildNodes(child)
17930
+ name: attrs["name"],
17931
+ params: attrs["params"],
17932
+ export: attrs["export"],
17933
+ default: attrs["default"],
17934
+ async: attrs["async"],
17935
+ generics: attrs["generics"],
17936
+ returnType: attrs["returnType"],
17937
+ singleLine: attrs["singleLine"],
17938
+ JSDoc: attrs["JSDoc"],
17939
+ nodes: collectCodeNodes$1(child)
17935
17940
  }));
17936
- } else if (child.nodeName === "kubb-const") {
17941
+ continue;
17942
+ }
17943
+ if (child.nodeName === "kubb-const") {
17937
17944
  const attrs = child.attributes;
17938
17945
  result.push((0, _kubb_ast.createConst)({
17939
- name: attrs.get("name"),
17940
- type: attrs.get("type"),
17941
- export: attrs.get("export"),
17942
- asConst: attrs.get("asConst"),
17943
- JSDoc: attrs.get("JSDoc"),
17944
- nodes: collectChildNodes(child)
17946
+ name: attrs["name"],
17947
+ type: attrs["type"],
17948
+ export: attrs["export"],
17949
+ asConst: attrs["asConst"],
17950
+ JSDoc: attrs["JSDoc"],
17951
+ nodes: collectCodeNodes$1(child)
17945
17952
  }));
17946
- } else if (child.nodeName === "kubb-type") {
17953
+ continue;
17954
+ }
17955
+ if (child.nodeName === "kubb-type") {
17947
17956
  const attrs = child.attributes;
17948
17957
  result.push((0, _kubb_ast.createType)({
17949
- name: attrs.get("name"),
17950
- export: attrs.get("export"),
17951
- JSDoc: attrs.get("JSDoc"),
17952
- nodes: collectChildNodes(child)
17958
+ name: attrs["name"],
17959
+ export: attrs["export"],
17960
+ JSDoc: attrs["JSDoc"],
17961
+ nodes: collectCodeNodes$1(child)
17953
17962
  }));
17954
- } else if (child.nodeName === "kubb-jsx") {
17963
+ continue;
17964
+ }
17965
+ if (child.nodeName === "kubb-jsx") {
17955
17966
  const textChild = child.childNodes[0];
17956
17967
  const value = textChild?.nodeName === "#text" ? textChild.nodeValue : "";
17957
17968
  if (value) result.push((0, _kubb_ast.createJsx)(value));
17969
+ continue;
17958
17970
  }
17959
17971
  }
17960
17972
  return result;
17961
17973
  }
17974
+ require_jsx_runtime.__name(collectCodeNodes$1, "collectCodeNodes");
17962
17975
  /**
17963
- * Traverse `node` and collect all `<kubb-source>` elements into a `Set<SourceNode>`.
17964
- *
17965
- * Elements whose `nodeName` is in `ignores` are skipped entirely (including their subtrees).
17966
- * This is used to collect source blocks from a file node while excluding import/export subtrees.
17976
+ * Yields every {@link SourceNode}, {@link ExportNode}, and {@link ImportNode}
17977
+ * within a `<kubb-file>` subtree in a single tree walk.
17967
17978
  *
17968
- * @example Collect sources while ignoring export and import elements
17969
- * ```ts
17970
- * const sources = squashSourceNodes(fileElement, ['kubb-export', 'kubb-import'])
17971
- * ```
17979
+ * Import and export elements are leaf nodes. Once yielded, the walker does not
17980
+ * recurse into them, which also prevents source collection from descending into
17981
+ * their subtrees. Dispatch on `.kind` (`'Source'`, `'Export'`, `'Import'`) to
17982
+ * separate the results.
17972
17983
  */
17973
- function squashSourceNodes(node, ignores) {
17974
- const ignoreSet = new Set(ignores);
17975
- const sources = /* @__PURE__ */ new Set();
17976
- const walk = (current) => {
17977
- for (const child of current.childNodes) {
17978
- if (!child) continue;
17979
- if (child.nodeName !== "#text" && ignoreSet.has(child.nodeName)) continue;
17980
- if (child.nodeName === "kubb-source") {
17981
- const source = (0, _kubb_ast.createSource)({
17982
- name: child.attributes.get("name")?.toString(),
17983
- isTypeOnly: child.attributes.get("isTypeOnly") ?? false,
17984
- isExportable: child.attributes.get("isExportable") ?? false,
17985
- isIndexable: child.attributes.get("isIndexable") ?? false,
17986
- nodes: collectChildNodes(child)
17987
- });
17988
- sources.add(source);
17989
- continue;
17990
- }
17991
- if (child.nodeName !== "#text" && nodeNames.has(child.nodeName)) walk(child);
17984
+ function* collectFileEntries(node) {
17985
+ for (const child of node.childNodes) {
17986
+ if (!child || child.nodeName === "#text") continue;
17987
+ if (child.nodeName === "kubb-source") {
17988
+ yield (0, _kubb_ast.createSource)({
17989
+ name: child.attributes["name"]?.toString(),
17990
+ isTypeOnly: toBool$1(child.attributes["isTypeOnly"]),
17991
+ isExportable: toBool$1(child.attributes["isExportable"]),
17992
+ isIndexable: toBool$1(child.attributes["isIndexable"]),
17993
+ nodes: collectCodeNodes$1(child)
17994
+ });
17995
+ continue;
17992
17996
  }
17993
- };
17994
- walk(node);
17995
- return sources;
17997
+ if (child.nodeName === "kubb-export") {
17998
+ yield (0, _kubb_ast.createExport)({
17999
+ name: child.attributes["name"],
18000
+ path: child.attributes["path"],
18001
+ isTypeOnly: toBool$1(child.attributes["isTypeOnly"]),
18002
+ asAlias: toBool$1(child.attributes["asAlias"])
18003
+ });
18004
+ continue;
18005
+ }
18006
+ if (child.nodeName === "kubb-import") {
18007
+ yield (0, _kubb_ast.createImport)({
18008
+ name: child.attributes["name"],
18009
+ path: child.attributes["path"],
18010
+ root: child.attributes["root"],
18011
+ isTypeOnly: toBool$1(child.attributes["isTypeOnly"]),
18012
+ isNameSpace: toBool$1(child.attributes["isNameSpace"])
18013
+ });
18014
+ continue;
18015
+ }
18016
+ if (nodeNames.has(child.nodeName)) yield* collectFileEntries(child);
18017
+ }
17996
18018
  }
17997
18019
  /**
17998
- * Traverse `node` and collect all `<kubb-export>` elements into a `Set<ExportNode>`.
18020
+ * Runs a single {@link collectFileEntries} pass over a `<kubb-file>` DOM element
18021
+ * and assembles the result into a {@link FileNode}, bucketing each yielded
18022
+ * node by its `.kind`.
17999
18023
  */
18000
- function squashExportNodes(node) {
18001
- const exports = /* @__PURE__ */ new Set();
18002
- const walk = (current) => {
18003
- for (const child of current.childNodes) {
18004
- if (!child) continue;
18005
- if (child.nodeName !== "#text" && nodeNames.has(child.nodeName)) walk(child);
18006
- if (child.nodeName === "kubb-export") exports.add((0, _kubb_ast.createExport)({
18007
- name: child.attributes.get("name"),
18008
- path: child.attributes.get("path"),
18009
- isTypeOnly: child.attributes.get("isTypeOnly") ?? false,
18010
- asAlias: child.attributes.get("asAlias") ?? false
18011
- }));
18024
+ function createFileNode(child) {
18025
+ const sources = [];
18026
+ const exports = [];
18027
+ const imports = [];
18028
+ for (const node of collectFileEntries(child)) {
18029
+ if (node.kind === "Source") {
18030
+ sources.push(node);
18031
+ continue;
18012
18032
  }
18033
+ if (node.kind === "Export") {
18034
+ exports.push(node);
18035
+ continue;
18036
+ }
18037
+ imports.push(node);
18038
+ }
18039
+ return {
18040
+ baseName: child.attributes["baseName"],
18041
+ path: child.attributes["path"],
18042
+ meta: child.attributes["meta"] || {},
18043
+ footer: child.attributes["footer"],
18044
+ banner: child.attributes["banner"],
18045
+ sources,
18046
+ exports,
18047
+ imports
18013
18048
  };
18014
- walk(node);
18015
- return exports;
18016
18049
  }
18017
18050
  /**
18018
- * Traverse `node` and collect all `<kubb-import>` elements into a `Set<ImportNode>`.
18051
+ * Yields each {@link FileNode} as it is encountered during the tree walk,
18052
+ * without collecting into an intermediate array. Callers can begin processing
18053
+ * each file before the rest of the tree is traversed.
18019
18054
  */
18020
- function squashImportNodes(node) {
18021
- const imports = /* @__PURE__ */ new Set();
18022
- const walk = (current) => {
18023
- for (const child of current.childNodes) {
18024
- if (!child) continue;
18025
- if (child.nodeName !== "#text" && nodeNames.has(child.nodeName)) walk(child);
18026
- if (child.nodeName === "kubb-import") imports.add((0, _kubb_ast.createImport)({
18027
- name: child.attributes.get("name"),
18028
- path: child.attributes.get("path"),
18029
- root: child.attributes.get("root"),
18030
- isTypeOnly: child.attributes.get("isTypeOnly") ?? false,
18031
- isNameSpace: child.attributes.get("isNameSpace") ?? false
18032
- }));
18033
- }
18034
- };
18035
- walk(node);
18036
- return imports;
18055
+ function* streamFiles(node) {
18056
+ for (const child of node.childNodes) {
18057
+ if (!child) continue;
18058
+ if (child.nodeName !== "#text" && child.nodeName !== "kubb-file" && nodeNames.has(child.nodeName)) yield* streamFiles(child);
18059
+ if (child.nodeName === "kubb-file" && child.attributes["baseName"] !== void 0 && child.attributes["path"] !== void 0) yield createFileNode(child);
18060
+ }
18037
18061
  }
18038
18062
  /**
18039
18063
  * Walk the virtual DOM tree rooted at `node` and convert every `<kubb-file>` element
18040
18064
  * into a {@link FileNode}, collecting its source blocks, imports, and exports.
18041
18065
  *
18042
- * Returns the list of file nodes in document order. Nested files are supported
18066
+ * Returns the list of file nodes in document order. Nested files are supported;
18043
18067
  * the walker descends into non-file elements and recurses through them.
18044
18068
  */
18045
- function processFiles(node) {
18046
- const collected = [];
18047
- function walk(current) {
18048
- for (const child of current.childNodes) {
18049
- if (!child) continue;
18050
- if (child.nodeName !== "#text" && child.nodeName !== "kubb-file" && nodeNames.has(child.nodeName)) walk(child);
18051
- if (child.nodeName === "kubb-file") {
18052
- if (child.attributes.has("baseName") && child.attributes.has("path")) {
18053
- const sources = squashSourceNodes(child, ["kubb-export", "kubb-import"]);
18054
- collected.push({
18055
- baseName: child.attributes.get("baseName"),
18056
- path: child.attributes.get("path"),
18057
- meta: child.attributes.get("meta") || {},
18058
- footer: child.attributes.get("footer"),
18059
- banner: child.attributes.get("banner"),
18060
- sources: [...sources],
18061
- exports: [...squashExportNodes(child)],
18062
- imports: [...squashImportNodes(child)]
18063
- });
18064
- }
18065
- }
18066
- }
18067
- }
18068
- walk(node);
18069
- return collected;
18069
+ function collectFiles(node) {
18070
+ return [...streamFiles(node)];
18070
18071
  }
18071
18072
  //#endregion
18072
18073
  //#region src/Runtime.tsx
@@ -18078,7 +18079,7 @@ var Runtime = class {
18078
18079
  nodes = [];
18079
18080
  #container;
18080
18081
  #rootNode;
18081
- constructor(options) {
18082
+ constructor(options = {}) {
18082
18083
  this.#options = options;
18083
18084
  this.#rootNode = createNode("kubb-root");
18084
18085
  this.#rootNode.onRender = this.onRender;
@@ -18091,7 +18092,7 @@ var Runtime = class {
18091
18092
  console.log(data);
18092
18093
  };
18093
18094
  const logRecoverableError = typeof reportError === "function" ? reportError : console.error;
18094
- const rootTag = import_constants.ConcurrentRoot;
18095
+ const rootTag = import_constants.LegacyRoot;
18095
18096
  this.#container = Renderer.createContainer(this.#rootNode, rootTag, null, false, false, "id", logRecoverableError, logRecoverableError, logRecoverableError, null);
18096
18097
  this.unsubscribeExit = onProcessExit((code) => {
18097
18098
  this.unmount(code);
@@ -18104,7 +18105,7 @@ var Runtime = class {
18104
18105
  onRender = () => {
18105
18106
  const task = this.#renderPromise.catch(() => {}).then(() => {
18106
18107
  if (this.#isUnmounted) return;
18107
- const files = processFiles(this.#rootNode);
18108
+ const files = collectFiles(this.#rootNode);
18108
18109
  this.nodes.push(...files);
18109
18110
  if (!this.#options?.debug) return;
18110
18111
  });
@@ -18149,74 +18150,320 @@ var Runtime = class {
18149
18150
  }
18150
18151
  this.resolveExitPromise();
18151
18152
  }
18152
- async waitUntilExit() {
18153
- if (!this.exitPromise) this.exitPromise = new Promise((resolve, reject) => {
18154
- this.resolveExitPromise = resolve;
18155
- this.rejectExitPromise = reject;
18156
- });
18157
- return this.exitPromise;
18153
+ };
18154
+ //#endregion
18155
+ //#region src/SyncRuntime.tsx
18156
+ /**
18157
+ * Walks `element`, resolving arrays, Fragments, and function components
18158
+ * transparently, then calls `onText` for primitive values and `onHost` for
18159
+ * every host element encountered. Pure function components are called
18160
+ * synchronously; hooks and class components are not supported.
18161
+ */
18162
+ function walkElement(element, onText, onHost) {
18163
+ if (element == null || typeof element === "boolean") return;
18164
+ if (typeof element === "string" || typeof element === "number" || typeof element === "bigint") {
18165
+ onText(String(element));
18166
+ return;
18167
+ }
18168
+ if (Array.isArray(element)) {
18169
+ for (const child of element) walkElement(child, onText, onHost);
18170
+ return;
18171
+ }
18172
+ if (typeof element === "object" && "$$typeof" in element) {
18173
+ const el = element;
18174
+ const { type } = el;
18175
+ const props = el.props;
18176
+ if (type === import_react.Fragment) {
18177
+ walkElement(props["children"], onText, onHost);
18178
+ return;
18179
+ }
18180
+ if (typeof type === "function") {
18181
+ walkElement(type(props), onText, onHost);
18182
+ return;
18183
+ }
18184
+ if (typeof type === "string") onHost(type, props);
18185
+ }
18186
+ }
18187
+ function toBool(val) {
18188
+ return val ?? false;
18189
+ }
18190
+ function collectCodeNodes(props) {
18191
+ const nodes = [];
18192
+ collectCode(props["children"], nodes);
18193
+ return nodes;
18194
+ }
18195
+ function collectCode(element, nodes) {
18196
+ walkElement(element, (text) => {
18197
+ if (text.trim()) nodes.push((0, _kubb_ast.createText)(text));
18198
+ }, (type, props) => resolveCodeNode(type, props, nodes));
18199
+ }
18200
+ function resolveCodeNode(type, props, nodes) {
18201
+ if (type === "br") {
18202
+ nodes.push((0, _kubb_ast.createBreak)());
18203
+ return;
18204
+ }
18205
+ if (type === "kubb-jsx") {
18206
+ let value = "";
18207
+ walkElement(props["children"], (t) => {
18208
+ value += t;
18209
+ }, () => {});
18210
+ if (value) nodes.push((0, _kubb_ast.createJsx)(value));
18211
+ return;
18212
+ }
18213
+ if (type === "kubb-function") {
18214
+ nodes.push((0, _kubb_ast.createFunction)({
18215
+ name: props["name"],
18216
+ params: props["params"],
18217
+ export: props["export"],
18218
+ default: props["default"],
18219
+ async: props["async"],
18220
+ generics: props["generics"],
18221
+ returnType: props["returnType"],
18222
+ JSDoc: props["JSDoc"],
18223
+ nodes: collectCodeNodes(props)
18224
+ }));
18225
+ return;
18226
+ }
18227
+ if (type === "kubb-arrow-function") {
18228
+ nodes.push((0, _kubb_ast.createArrowFunction)({
18229
+ name: props["name"],
18230
+ params: props["params"],
18231
+ export: props["export"],
18232
+ default: props["default"],
18233
+ async: props["async"],
18234
+ generics: props["generics"],
18235
+ returnType: props["returnType"],
18236
+ singleLine: props["singleLine"],
18237
+ JSDoc: props["JSDoc"],
18238
+ nodes: collectCodeNodes(props)
18239
+ }));
18240
+ return;
18241
+ }
18242
+ if (type === "kubb-const") {
18243
+ nodes.push((0, _kubb_ast.createConst)({
18244
+ name: props["name"],
18245
+ type: props["type"],
18246
+ export: props["export"],
18247
+ asConst: props["asConst"],
18248
+ JSDoc: props["JSDoc"],
18249
+ nodes: collectCodeNodes(props)
18250
+ }));
18251
+ return;
18252
+ }
18253
+ if (type === "kubb-type") {
18254
+ nodes.push((0, _kubb_ast.createType)({
18255
+ name: props["name"],
18256
+ export: props["export"],
18257
+ JSDoc: props["JSDoc"],
18258
+ nodes: collectCodeNodes(props)
18259
+ }));
18260
+ return;
18261
+ }
18262
+ }
18263
+ function collectFileChildren(element) {
18264
+ const sources = [];
18265
+ const exports = [];
18266
+ const imports = [];
18267
+ walkElement(element, (text) => {
18268
+ if (text.trim()) throw new Error(`[react] '${text}' should be part of <File.Source> component when using the <File/> component`);
18269
+ }, (type, props) => {
18270
+ if (type === "kubb-source") {
18271
+ sources.push((0, _kubb_ast.createSource)({
18272
+ name: props["name"]?.toString(),
18273
+ isTypeOnly: toBool(props["isTypeOnly"]),
18274
+ isExportable: toBool(props["isExportable"]),
18275
+ isIndexable: toBool(props["isIndexable"]),
18276
+ nodes: collectCodeNodes(props)
18277
+ }));
18278
+ return;
18279
+ }
18280
+ if (type === "kubb-export") {
18281
+ exports.push((0, _kubb_ast.createExport)({
18282
+ name: props["name"],
18283
+ path: props["path"],
18284
+ isTypeOnly: toBool(props["isTypeOnly"]),
18285
+ asAlias: toBool(props["asAlias"])
18286
+ }));
18287
+ return;
18288
+ }
18289
+ if (type === "kubb-import") {
18290
+ imports.push((0, _kubb_ast.createImport)({
18291
+ name: props["name"],
18292
+ path: props["path"],
18293
+ root: props["root"],
18294
+ isTypeOnly: toBool(props["isTypeOnly"]),
18295
+ isNameSpace: toBool(props["isNameSpace"])
18296
+ }));
18297
+ return;
18298
+ }
18299
+ const nested = collectFileChildren(props["children"]);
18300
+ sources.push(...nested.sources);
18301
+ exports.push(...nested.exports);
18302
+ imports.push(...nested.imports);
18303
+ });
18304
+ return {
18305
+ sources,
18306
+ exports,
18307
+ imports
18308
+ };
18309
+ }
18310
+ function* walkFiles(element) {
18311
+ if (element == null || typeof element === "boolean") return;
18312
+ if (typeof element === "string" || typeof element === "number" || typeof element === "bigint") return;
18313
+ if (Array.isArray(element)) {
18314
+ for (const child of element) yield* walkFiles(child);
18315
+ return;
18316
+ }
18317
+ if (typeof element === "object" && "$$typeof" in element) {
18318
+ const el = element;
18319
+ const { type } = el;
18320
+ const props = el.props;
18321
+ if (type === import_react.Fragment) {
18322
+ yield* walkFiles(props["children"]);
18323
+ return;
18324
+ }
18325
+ if (typeof type === "function") {
18326
+ yield* walkFiles(type(props));
18327
+ return;
18328
+ }
18329
+ if (typeof type === "string") if (type === "kubb-file" && props["baseName"] !== void 0 && props["path"] !== void 0) {
18330
+ const { sources, exports, imports } = collectFileChildren(props["children"]);
18331
+ yield {
18332
+ baseName: props["baseName"],
18333
+ path: props["path"],
18334
+ meta: props["meta"] || {},
18335
+ footer: props["footer"],
18336
+ banner: props["banner"],
18337
+ sources,
18338
+ exports,
18339
+ imports
18340
+ };
18341
+ } else yield* walkFiles(props["children"]);
18342
+ }
18343
+ }
18344
+ /**
18345
+ * Synchronous JSX renderer that walks the element tree in a single pass,
18346
+ * producing {@link FileNode} objects directly without an intermediate virtual
18347
+ * DOM. No React fiber, scheduler, or work loop is involved.
18348
+ *
18349
+ * All components must be pure functions; hooks and class components are not
18350
+ * supported. Produces identical output to the React-backed {@link Runtime} at
18351
+ * approximately 2–4× the speed and a fraction of the allocations.
18352
+ */
18353
+ var SyncRuntime = class {
18354
+ /**
18355
+ * Accumulated {@link FileNode} results from every {@link render} call.
18356
+ */
18357
+ nodes = [];
18358
+ /**
18359
+ * Walks `element` synchronously, converts every `<kubb-file>` subtree into
18360
+ * a {@link FileNode} with no intermediate virtual DOM, and appends the results
18361
+ * to {@link nodes}.
18362
+ */
18363
+ render(element) {
18364
+ for (const file of walkFiles(element)) this.nodes.push(file);
18365
+ }
18366
+ /**
18367
+ * Walks `element` synchronously and yields each {@link FileNode} as it is
18368
+ * produced, without buffering into an intermediate array first. Callers can
18369
+ * begin processing each file before the rest of the element tree is traversed.
18370
+ *
18371
+ * @example
18372
+ * ```ts
18373
+ * for (const file of runtime.stream(element)) {
18374
+ * await writeFile(file)
18375
+ * }
18376
+ * ```
18377
+ */
18378
+ *stream(element) {
18379
+ yield* walkFiles(element);
18158
18380
  }
18159
18381
  };
18160
18382
  //#endregion
18161
18383
  //#region src/createRenderer.tsx
18162
18384
  /**
18163
- * Create a Kubb JSX renderer.
18385
+ * Renderer factory for generators that produce JSX output.
18164
18386
  *
18165
- * The renderer converts a React JSX element tree built from the components in this
18166
- * package into an array of {@link FileNode} entries representing the generated files.
18387
+ * Pass as the `renderer` property of `defineGenerator`. Core drives rendering
18388
+ * without a hard dependency on `@kubb/renderer-jsx`.
18167
18389
  *
18168
- * @example Basic usage
18390
+ * @example
18169
18391
  * ```ts
18170
- * import { createRenderer, File } from '@kubb/renderer-jsx'
18392
+ * import { jsxRenderer } from '@kubb/renderer-jsx'
18171
18393
  *
18172
- * const renderer = createRenderer()
18173
- * await renderer.render(
18174
- * <File baseName="pet.ts" path="src/models/pet.ts">
18175
- * <File.Source name="Pet" isExportable isIndexable>
18176
- * {`export type Pet = { id: number; name: string }`}
18177
- * </File.Source>
18178
- * </File>
18179
- * )
18180
- * console.log(renderer.files) // [FileNode]
18181
- * renderer.unmount()
18394
+ * export const myGenerator = defineGenerator<PluginTs>({
18395
+ * renderer: jsxRenderer,
18396
+ * schema(node, options) {
18397
+ * return <File baseName="output.ts" path="src/output.ts">...</File>
18398
+ * },
18399
+ * })
18182
18400
  * ```
18183
18401
  */
18184
- function createRenderer(options = {}) {
18185
- const runtime = new Runtime(options);
18402
+ const jsxRenderer = () => {
18403
+ const runtime = new Runtime();
18186
18404
  return {
18187
- async render(Element) {
18188
- await runtime.render(Element);
18405
+ async render(element) {
18406
+ await runtime.render(element);
18189
18407
  },
18190
18408
  get files() {
18191
18409
  return runtime.nodes;
18192
18410
  },
18411
+ dispose() {
18412
+ runtime.unmount();
18413
+ },
18193
18414
  unmount(error) {
18194
18415
  runtime.unmount(error);
18416
+ },
18417
+ [Symbol.dispose]() {
18418
+ this.dispose();
18195
18419
  }
18196
18420
  };
18197
- }
18421
+ };
18198
18422
  /**
18199
- * A renderer factory for generators that produce JSX output.
18423
+ * Lightweight renderer factory with no React fiber, scheduler, or work loop.
18200
18424
  *
18201
- * Pass this as the `renderer` property of a `defineGenerator` call so that
18202
- * core can render the JSX element tree returned by your generator methods
18203
- * without a hard dependency on `@kubb/renderer-jsx`.
18425
+ * Walks the JSX element tree in a single recursive pass. All components must be
18426
+ * pure functions; hooks and class components are not supported. Drop-in
18427
+ * replacement for {@link jsxRenderer} at approximately 2–4× the speed.
18204
18428
  *
18205
- * @example
18429
+ * @example Drop-in replacement
18206
18430
  * ```ts
18207
- * import { jsxRenderer } from '@kubb/renderer-jsx'
18208
- * import { defineGenerator } from '@kubb/core'
18431
+ * import { jsxRendererSync } from '@kubb/renderer-jsx'
18209
18432
  *
18210
18433
  * export const myGenerator = defineGenerator<PluginTs>({
18211
- * name: 'my-generator',
18212
- * renderer: jsxRenderer,
18434
+ * renderer: jsxRendererSync,
18213
18435
  * schema(node, options) {
18214
18436
  * return <File baseName="output.ts" path="src/output.ts">...</File>
18215
18437
  * },
18216
18438
  * })
18217
18439
  * ```
18440
+ *
18441
+ * @example Stream files as they are produced
18442
+ * ```ts
18443
+ * for await (const file of jsxRendererSync().stream(element)) {
18444
+ * await writeFile(file)
18445
+ * }
18446
+ * ```
18218
18447
  */
18219
- const jsxRenderer = () => createRenderer();
18448
+ const jsxRendererSync = () => {
18449
+ const runtime = new SyncRuntime();
18450
+ return {
18451
+ async render(element) {
18452
+ runtime.render(element);
18453
+ },
18454
+ get files() {
18455
+ return runtime.nodes;
18456
+ },
18457
+ stream(element) {
18458
+ return runtime.stream(element);
18459
+ },
18460
+ dispose() {},
18461
+ unmount(_error) {},
18462
+ [Symbol.dispose]() {
18463
+ this.dispose();
18464
+ }
18465
+ };
18466
+ };
18220
18467
  //#endregion
18221
18468
  exports.Const = Const;
18222
18469
  exports.File = File;
@@ -18225,9 +18472,9 @@ exports.Jsx = Jsx;
18225
18472
  exports.Root = Root;
18226
18473
  exports.Type = Type;
18227
18474
  exports.createContext = createContext;
18228
- exports.createRenderer = createRenderer;
18229
18475
  exports.inject = inject;
18230
18476
  exports.jsxRenderer = jsxRenderer;
18477
+ exports.jsxRendererSync = jsxRendererSync;
18231
18478
  exports.provide = provide;
18232
18479
  exports.unprovide = unprovide;
18233
18480