@kubb/ast 5.13.1 → 5.14.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.js CHANGED
@@ -1,5 +1,5 @@
1
- import path from "node:path";
2
1
  import { hash } from "node:crypto";
2
+ import path from "node:path";
3
3
  //#region \0rolldown/runtime.js
4
4
  var __defProp = Object.defineProperty;
5
5
  var __exportAll = (all, no_symbols) => {
@@ -14,6 +14,30 @@ var __exportAll = (all, no_symbols) => {
14
14
  //#endregion
15
15
  //#region src/constants.ts
16
16
  /**
17
+ * Node kind discriminators used by every AST node (for example `node.kind === nodeKinds.text`).
18
+ */
19
+ const nodeKinds = {
20
+ input: "Input",
21
+ operation: "Operation",
22
+ schema: "Schema",
23
+ property: "Property",
24
+ parameter: "Parameter",
25
+ response: "Response",
26
+ requestBody: "RequestBody",
27
+ content: "Content",
28
+ type: "Type",
29
+ file: "File",
30
+ import: "Import",
31
+ export: "Export",
32
+ source: "Source",
33
+ const: "Const",
34
+ function: "Function",
35
+ arrowFunction: "ArrowFunction",
36
+ text: "Text",
37
+ break: "Break",
38
+ jsx: "Jsx"
39
+ };
40
+ /**
17
41
  * Schema type discriminators used by all AST schema nodes.
18
42
  *
19
43
  * Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
@@ -222,7 +246,7 @@ function isNodeRecord(value) {
222
246
  * ```
223
247
  */
224
248
  function getChildren(node, recurse) {
225
- if (node.kind === "Schema" && !recurse) return [];
249
+ if (node.kind === nodeKinds.schema && !recurse) return [];
226
250
  const children = [];
227
251
  visitChildNodes(node, (child) => {
228
252
  children.push(child);
@@ -280,7 +304,7 @@ function visitChildNodes(node, visit) {
280
304
  */
281
305
  function forEachSchema(node, visit) {
282
306
  const walk = (current) => {
283
- if (current.kind === "Schema") visit(current);
307
+ if (current.kind === nodeKinds.schema) visit(current);
284
308
  forEachChild(current, walk);
285
309
  };
286
310
  walk(node);
@@ -298,7 +322,7 @@ function forEachSchema(node, visit) {
298
322
  function findSchema(node, { predicate, followRefs = false }) {
299
323
  const seen = followRefs ? /* @__PURE__ */ new WeakSet() : void 0;
300
324
  const walk = (current) => {
301
- if (current.kind === "Schema") {
325
+ if (current.kind === nodeKinds.schema) {
302
326
  if (predicate(current)) return current;
303
327
  if (seen) {
304
328
  if (seen.has(current)) return void 0;
@@ -374,7 +398,7 @@ function transformNode(node, visitor, recurse, parent) {
374
398
  * (e.g. `additionalProperties: true`) intact.
375
399
  */
376
400
  function transformChildren(node, visitor, recurse) {
377
- const keys = node.kind === "Schema" && !recurse ? void 0 : VISITOR_KEYS[node.kind];
401
+ const keys = node.kind === nodeKinds.schema && !recurse ? void 0 : VISITOR_KEYS[node.kind];
378
402
  if (!keys) return node;
379
403
  const record = node;
380
404
  let updates;
@@ -659,11 +683,11 @@ function extractStringsFromNodes(nodes) {
659
683
  if (node) collected.push(node);
660
684
  continue;
661
685
  }
662
- if (node.kind === "Text" || node.kind === "Jsx") {
686
+ if (node.kind === nodeKinds.text || node.kind === nodeKinds.jsx) {
663
687
  if (node.value) collected.push(node.value);
664
688
  continue;
665
689
  }
666
- if (node.kind === "Break") continue;
690
+ if (node.kind === nodeKinds.break) continue;
667
691
  const parts = [];
668
692
  if ("params" in node && node.params) parts.push(node.params);
669
693
  if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
@@ -676,131 +700,539 @@ function extractStringsFromNodes(nodes) {
676
700
  return collected.join("\n");
677
701
  }
678
702
  //#endregion
679
- //#region src/utils/refs.ts
680
- /** Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`. */
681
- function refName(ref) {
682
- return ref.split("/").at(-1) ?? ref;
703
+ //#region src/utils/combineFileMembers.ts
704
+ const IDENTIFIER_RUN = /[\w$]+/g;
705
+ /**
706
+ * How many imports a file needs before indexing the source beats scanning it once per name.
707
+ */
708
+ const INDEX_ABOVE_IMPORTS = 128;
709
+ /**
710
+ * Returns the local binding an import name item introduces: the alias when there is one, else the
711
+ * imported name.
712
+ */
713
+ function importLocalName(item) {
714
+ return typeof item === "string" ? item : item.name ?? item.propertyName;
683
715
  }
684
716
  /**
685
- * Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
686
- * the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
687
- * then `name`, then the nested `schema.name`.
688
- *
689
- * Returns `null` for non-ref nodes or when no name resolves.
690
- *
691
- * @example
692
- * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
693
- *
694
- * @example Collision-renamed target
695
- * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
717
+ * Computes a multi-level sort key for exports and imports:
718
+ * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
696
719
  */
697
- function resolveRefName(node) {
698
- if (!node || node.type !== "ref") return null;
699
- if (node.targetName) return node.targetName;
700
- if (node.ref) return refName(node.ref);
701
- return node.name ?? node.schema?.name ?? null;
720
+ function sortKey(node) {
721
+ const isArray = Array.isArray(node.name) ? "1" : "0";
722
+ const typeOnly = node.isTypeOnly ? "0" : "1";
723
+ const hasName = node.name != null ? "1" : "0";
724
+ const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
725
+ return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
702
726
  }
703
727
  /**
704
- * Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
705
- *
706
- * @example
707
- * ```ts
708
- * const target = resolveRef(refSchema)
709
- * ```
728
+ * Sorts members by {@link sortKey}. Keys are computed once per node, not per comparison.
710
729
  */
711
- function resolveRef(node) {
712
- if (node.type !== "ref" || !node.schema) return node;
713
- const seen = /* @__PURE__ */ new WeakSet();
714
- let current = node;
715
- while (current.type === "ref" && current.schema) {
716
- if (seen.has(current)) return current;
717
- seen.add(current);
718
- current = current.schema;
719
- }
720
- return current;
730
+ function sortMembers(nodes) {
731
+ return nodes.map((node) => ({
732
+ node,
733
+ key: sortKey(node)
734
+ })).sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0).map(({ node }) => node);
721
735
  }
722
- /** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
723
- const REF_OWN_KEYS = /* @__PURE__ */ new Set([
724
- "kind",
725
- "type",
726
- "name",
727
- "ref",
728
- "schema"
729
- ]);
730
736
  /**
731
- * Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
732
- *
733
- * Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
734
- * of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
735
- * left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
736
- * is returned as is.
737
+ * Returns a collector for array-named members. A member whose path and `isTypeOnly` were already
738
+ * seen folds its names into that entry, otherwise it joins `result` as a new entry.
739
+ */
740
+ function mergeByPath(result) {
741
+ const byPath = /* @__PURE__ */ new Map();
742
+ return ({ node, names }) => {
743
+ const key = `${node.path}:${node.isTypeOnly ?? false}`;
744
+ const existing = byPath.get(key);
745
+ if (existing) {
746
+ for (const name of names) {
747
+ if (existing.seen.has(name)) continue;
748
+ existing.seen.add(name);
749
+ existing.names.push(name);
750
+ }
751
+ return;
752
+ }
753
+ const item = {
754
+ ...node,
755
+ name: [...names]
756
+ };
757
+ result.push(item);
758
+ byPath.set(key, {
759
+ names: item.name,
760
+ seen: new Set(names)
761
+ });
762
+ };
763
+ }
764
+ /**
765
+ * Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
766
+ * key. An unnamed source only drops when the same node appears twice, so markdown can repeat a
767
+ * paragraph or a table. Returns the deduplicated array in original order.
768
+ */
769
+ function combineSources(sources) {
770
+ const seen = /* @__PURE__ */ new Set();
771
+ return sources.filter((source) => {
772
+ const key = source.name != null ? `${source.name}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}` : source;
773
+ if (seen.has(key)) return false;
774
+ seen.add(key);
775
+ return true;
776
+ });
777
+ }
778
+ /**
779
+ * Deduplicates and merges `ExportNode` objects by path and type.
737
780
  *
738
- * @example
739
- * ```ts
740
- * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
741
- * mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
742
- * ```
781
+ * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
782
+ * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
743
783
  */
744
- function mergeRefWithSchema(node) {
745
- if (!node.schema) return node;
746
- const merged = { ...node.schema };
747
- for (const key of Object.keys(node)) {
748
- const value = node[key];
749
- if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
784
+ function combineExports(exports) {
785
+ const result = [];
786
+ const merge = mergeByPath(result);
787
+ const seen = /* @__PURE__ */ new Set();
788
+ for (const curr of sortMembers(exports)) {
789
+ const { name, path, isTypeOnly, asAlias } = curr;
790
+ if (Array.isArray(name)) {
791
+ if (name.length) merge({
792
+ node: curr,
793
+ names: [...new Set(name)]
794
+ });
795
+ continue;
796
+ }
797
+ const key = `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
798
+ if (!seen.has(key)) {
799
+ result.push(curr);
800
+ seen.add(key);
801
+ }
750
802
  }
751
- return merged;
803
+ return result;
752
804
  }
753
805
  /**
754
- * Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
806
+ * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
755
807
  *
756
- * Modifiers inherited from the resolved schema are included in the check because a ref emits the
757
- * referenced schema variable with those modifiers already applied.
808
+ * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
809
+ * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
758
810
  */
759
- function isBareRef(node, keysToOmit) {
760
- if (!node || node.type !== "ref") return false;
761
- const meta = mergeRefWithSchema(node);
762
- return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
811
+ function combineImports(imports, exports, source) {
812
+ const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
813
+ const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? new Set(source.match(IDENTIFIER_RUN)) : null;
814
+ const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
815
+ const importNameMemo = /* @__PURE__ */ new Map();
816
+ const canonicalizeName = (n) => {
817
+ if (typeof n === "string") return n;
818
+ const key = `${n.propertyName}:${n.name ?? ""}`;
819
+ if (!importNameMemo.has(key)) importNameMemo.set(key, n);
820
+ return importNameMemo.get(key);
821
+ };
822
+ const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
823
+ for (const node of imports) if (Array.isArray(node.name) && node.name.some((item) => isUsed(importLocalName(item)))) pathsWithUsedNamedImport.add(node.path);
824
+ const result = [];
825
+ const merge = mergeByPath(result);
826
+ const seen = /* @__PURE__ */ new Set();
827
+ for (const curr of sortMembers(imports)) {
828
+ if (curr.path === curr.root) continue;
829
+ const { name, path, isTypeOnly } = curr;
830
+ if (Array.isArray(name)) {
831
+ const names = [...new Set(name.map(canonicalizeName))].filter((item) => isUsed(importLocalName(item)));
832
+ if (names.length) merge({
833
+ node: curr,
834
+ names
835
+ });
836
+ continue;
837
+ }
838
+ if (!isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
839
+ const key = `${path}:${name}:${isTypeOnly ?? false}`;
840
+ if (!seen.has(key)) {
841
+ result.push(curr);
842
+ seen.add(key);
843
+ }
844
+ }
845
+ return result;
763
846
  }
764
847
  //#endregion
765
- //#region ../../internals/utils/src/promise.ts
848
+ //#region src/nodes/base.ts
849
+ /** Builds a `createX` factory for a node whose only computed field is `kind`. */
850
+ function nodeFactory(kind) {
851
+ return (input) => {
852
+ return {
853
+ ...input,
854
+ kind
855
+ };
856
+ };
857
+ }
858
+ //#endregion
859
+ //#region src/nodes/file.ts
766
860
  /**
767
- * Wraps `factory` with a keyed cache backed by the provided store.
768
- *
769
- * Pass a `WeakMap` for object keys (results are GC-eligible when the key is
770
- * collected) or a `Map` for primitive keys. For multi-argument functions,
771
- * nest two `memoize` calls — the outer keyed by the first argument, the
772
- * inner (created once per outer miss) keyed by the second.
773
- *
774
- * Because the cache is owned by the caller, it can be shared, inspected, or
775
- * cleared independently of the memoized function.
861
+ * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
776
862
  *
777
- * @example Single WeakMap key
863
+ * @example Named import
778
864
  * ```ts
779
- * const cache = new WeakMap<SchemaNode, Set<string>>()
780
- * const getRefs = memoize(cache, (node) => collectRefs(node))
865
+ * createImport({ name: ['useState'], path: 'react' })
866
+ * // import { useState } from 'react'
781
867
  * ```
868
+ */
869
+ const createImport = nodeFactory(nodeKinds.import);
870
+ /**
871
+ * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
782
872
  *
783
- * @example Single Map key (primitive)
873
+ * @example Named export
784
874
  * ```ts
785
- * const cache = new Map<string, Resolver>()
786
- * const getResolver = memoize(cache, (name) => buildResolver(name))
875
+ * createExport({ name: ['Pet'], path: './Pet' })
876
+ * // export { Pet } from './Pet'
787
877
  * ```
878
+ */
879
+ const createExport = nodeFactory(nodeKinds.export);
880
+ /**
881
+ * Creates a `SourceNode` representing a fragment of source code within a file.
788
882
  *
789
- * @example Two-level (object + primitive)
883
+ * @example
790
884
  * ```ts
791
- * const outer = new WeakMap<Params[], Map<string, Params[]>>()
792
- * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
793
- * fn(params)('camelcase')
885
+ * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
794
886
  * ```
795
887
  */
796
- function memoize(store, factory) {
797
- return (key) => {
798
- if (store.has(key)) return store.get(key);
799
- const value = factory(key);
800
- store.set(key, value);
801
- return value;
802
- };
803
- }
888
+ const createSource = nodeFactory(nodeKinds.source);
889
+ /**
890
+ * Creates a fully resolved `FileNode` from a file input descriptor.
891
+ *
892
+ * Computes:
893
+ * - `id` SHA256 hash of the file path
894
+ * - `name` `baseName` without extension
895
+ * - `extname` extension extracted from `baseName`
896
+ *
897
+ * Deduplicates:
898
+ * - `sources` via `combineSources`
899
+ * - `exports` via `combineExports`
900
+ * - `imports` via `combineImports` (also filters unused imports)
901
+ *
902
+ * @throws {Error} when `baseName` has no extension.
903
+ *
904
+ * @example
905
+ * ```ts
906
+ * const file = createFile({
907
+ * baseName: 'petStore.ts',
908
+ * path: 'src/models/petStore.ts',
909
+ * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
910
+ * imports: [createImport({ name: ['z'], path: 'zod' })],
911
+ * exports: [createExport({ name: ['Pet'], path: './petStore' })],
912
+ * })
913
+ * // file.id = SHA256 hash of 'src/models/petStore.ts'
914
+ * // file.name = 'petStore'
915
+ * // file.extname = '.ts'
916
+ * ```
917
+ *
918
+ * @example Copy a real file into the output
919
+ * ```ts
920
+ * const file = createFile({
921
+ * baseName: 'client.ts',
922
+ * path: 'src/gen/client.ts',
923
+ * copy: '/abs/path/to/templates/client.ts',
924
+ * })
925
+ * ```
926
+ */
927
+ function createFile(input) {
928
+ const extname = path.extname(input.baseName);
929
+ if (!extname) throw new Error(`No extname found for ${input.baseName}`);
930
+ const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
931
+ const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
932
+ const resolvedImports = (() => {
933
+ if (!input.imports?.length) return [];
934
+ const sourceParts = [];
935
+ const localNames = /* @__PURE__ */ new Set();
936
+ for (const item of resolvedSources) {
937
+ const extracted = item.nodes && extractStringsFromNodes(item.nodes);
938
+ if (extracted) sourceParts.push(extracted);
939
+ if (item.name) localNames.add(item.name);
940
+ }
941
+ const source = sourceParts.join("\n") || void 0;
942
+ return combineImports(input.imports, resolvedExports, source).flatMap((imp) => {
943
+ if (imp.path === input.path) return [];
944
+ if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
945
+ const kept = imp.name.filter((item) => !localNames.has(importLocalName(item)));
946
+ if (!kept.length) return [];
947
+ return [kept.length === imp.name.length ? imp : {
948
+ ...imp,
949
+ name: kept
950
+ }];
951
+ });
952
+ })();
953
+ return {
954
+ ...input,
955
+ kind: nodeKinds.file,
956
+ id: hash("sha256", input.path, "hex"),
957
+ name: path.basename(input.baseName, extname),
958
+ extname,
959
+ imports: resolvedImports,
960
+ exports: resolvedExports,
961
+ sources: resolvedSources,
962
+ meta: input.meta ?? {}
963
+ };
964
+ }
965
+ //#endregion
966
+ //#region src/utils/inline.ts
967
+ /**
968
+ * Whether every source of `file` is inline. Other files absorb such a file, so it is never written.
969
+ */
970
+ function isVirtualFile(file) {
971
+ return file.sources.length > 0 && file.sources.every((source) => source.inline);
972
+ }
973
+ /**
974
+ * Replaces every name a file imports from a virtual file (see {@link isVirtualFile}) with that name's
975
+ * `inline.expression`, until no inline names are left. The definitions' own imports move to the importing file.
976
+ */
977
+ function inlineFiles(files, { language }) {
978
+ const virtualFiles = new Map(files.filter(isVirtualFile).map((file) => [file.path, file]));
979
+ const result = {
980
+ files: [],
981
+ virtualPaths: [...virtualFiles.keys()],
982
+ problems: []
983
+ };
984
+ if (virtualFiles.size === 0) return result;
985
+ const definitions = /* @__PURE__ */ new Map();
986
+ function define(path, name, from, lang) {
987
+ const key = `${path}\0${name}`;
988
+ if (definitions.has(key)) {
989
+ const definition = definitions.get(key);
990
+ if (definition === null) result.problems.push({
991
+ path: from,
992
+ message: `"${name}" from "${path}" is defined in terms of itself.`
993
+ });
994
+ return definition ?? void 0;
995
+ }
996
+ const file = virtualFiles.get(path);
997
+ const inline = file.sources.find((source) => source.name === name)?.inline;
998
+ if (!inline) {
999
+ result.problems.push({
1000
+ path: from,
1001
+ message: `"${name}" is imported from "${path}", which never writes it and has no inline definition for it.`
1002
+ });
1003
+ return;
1004
+ }
1005
+ definitions.set(key, null);
1006
+ const imports = [];
1007
+ const { text, used } = replaceNames(inline.expression, file, lang, imports);
1008
+ imports.push(...file.imports.flatMap((imp) => virtualFiles.has(imp.path) ? [] : pickNames(imp, used)));
1009
+ const definition = {
1010
+ expression: text,
1011
+ imports
1012
+ };
1013
+ definitions.set(key, definition);
1014
+ return definition;
1015
+ }
1016
+ function replaceNames(input, file, lang, imports) {
1017
+ const used = /* @__PURE__ */ new Set();
1018
+ return {
1019
+ text: lang.replaceIdentifiers(input, (local) => {
1020
+ const target = findTarget(file, local);
1021
+ const definition = target && define(target.path, target.name, file.path, lang);
1022
+ if (!definition) {
1023
+ used.add(local);
1024
+ return;
1025
+ }
1026
+ imports.push(...definition.imports);
1027
+ return lang.wrap(definition.expression);
1028
+ }),
1029
+ used
1030
+ };
1031
+ }
1032
+ function findTarget(file, local) {
1033
+ if (virtualFiles.has(file.path) && file.sources.some((source) => source.name === local)) return {
1034
+ path: file.path,
1035
+ name: local
1036
+ };
1037
+ for (const imp of file.imports) {
1038
+ const item = virtualFiles.has(imp.path) && [imp.name].flat().find((item) => importLocalName(item) === local);
1039
+ if (item) return {
1040
+ path: imp.path,
1041
+ name: typeof item === "string" ? item : item.propertyName
1042
+ };
1043
+ }
1044
+ }
1045
+ for (const file of files) {
1046
+ if (virtualFiles.has(file.path) || !file.imports.some((imp) => virtualFiles.has(imp.path))) continue;
1047
+ const lang = language(file);
1048
+ if (!lang) {
1049
+ result.problems.push({
1050
+ path: file.path,
1051
+ message: `No parser for "${file.extname}" files supports inline sources.`
1052
+ });
1053
+ continue;
1054
+ }
1055
+ const carried = [];
1056
+ const sources = file.sources.map((source) => ({
1057
+ ...source,
1058
+ nodes: rewriteNodes(source.nodes, (text) => replaceNames(text, file, lang, carried).text)
1059
+ }));
1060
+ const imports = [...file.imports.filter((imp) => !virtualFiles.has(imp.path)), ...carried.map((imp) => imp.root ? {
1061
+ ...imp,
1062
+ root: file.path
1063
+ } : imp)];
1064
+ result.files.push(createFile({
1065
+ ...file,
1066
+ sources,
1067
+ imports
1068
+ }));
1069
+ }
1070
+ return result;
1071
+ }
1072
+ function pickNames(imp, used) {
1073
+ if (!Array.isArray(imp.name)) return used.has(imp.name) ? [imp] : [];
1074
+ const name = imp.name.filter((item) => used.has(importLocalName(item)));
1075
+ return name.length > 0 ? [{
1076
+ ...imp,
1077
+ name
1078
+ }] : [];
1079
+ }
1080
+ function rewriteNodes(nodes, rewrite) {
1081
+ return nodes?.map((node) => {
1082
+ if (typeof node === "string") return rewrite(node);
1083
+ switch (node.kind) {
1084
+ case nodeKinds.break: return node;
1085
+ case nodeKinds.text:
1086
+ case nodeKinds.jsx: return {
1087
+ ...node,
1088
+ value: rewrite(node.value)
1089
+ };
1090
+ case nodeKinds.function:
1091
+ case nodeKinds.arrowFunction: return {
1092
+ ...node,
1093
+ params: node.params && rewrite(node.params),
1094
+ generics: Array.isArray(node.generics) ? node.generics.map(rewrite) : node.generics && rewrite(node.generics),
1095
+ returnType: node.returnType && rewrite(node.returnType),
1096
+ nodes: rewriteNodes(node.nodes, rewrite)
1097
+ };
1098
+ case nodeKinds.const: return {
1099
+ ...node,
1100
+ type: node.type && rewrite(node.type),
1101
+ nodes: rewriteNodes(node.nodes, rewrite)
1102
+ };
1103
+ default: return {
1104
+ ...node,
1105
+ nodes: rewriteNodes(node.nodes, rewrite)
1106
+ };
1107
+ }
1108
+ });
1109
+ }
1110
+ //#endregion
1111
+ //#region src/utils/refs.ts
1112
+ /** Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`. */
1113
+ function refName(ref) {
1114
+ return ref.split("/").at(-1) ?? ref;
1115
+ }
1116
+ /**
1117
+ * Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
1118
+ * the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
1119
+ * then `name`, then the nested `schema.name`.
1120
+ *
1121
+ * Returns `null` for non-ref nodes or when no name resolves.
1122
+ *
1123
+ * @example
1124
+ * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
1125
+ *
1126
+ * @example Collision-renamed target
1127
+ * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
1128
+ */
1129
+ function resolveRefName(node) {
1130
+ if (!node || node.type !== "ref") return null;
1131
+ if (node.targetName) return node.targetName;
1132
+ if (node.ref) return refName(node.ref);
1133
+ return node.name ?? node.schema?.name ?? null;
1134
+ }
1135
+ /**
1136
+ * Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
1137
+ *
1138
+ * @example
1139
+ * ```ts
1140
+ * const target = resolveRef(refSchema)
1141
+ * ```
1142
+ */
1143
+ function resolveRef(node) {
1144
+ if (node.type !== "ref" || !node.schema) return node;
1145
+ const seen = /* @__PURE__ */ new WeakSet();
1146
+ let current = node;
1147
+ while (current.type === "ref" && current.schema) {
1148
+ if (seen.has(current)) return current;
1149
+ seen.add(current);
1150
+ current = current.schema;
1151
+ }
1152
+ return current;
1153
+ }
1154
+ /** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
1155
+ const REF_OWN_KEYS = /* @__PURE__ */ new Set([
1156
+ "kind",
1157
+ "type",
1158
+ "name",
1159
+ "ref",
1160
+ "schema"
1161
+ ]);
1162
+ /**
1163
+ * Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
1164
+ *
1165
+ * Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
1166
+ * of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
1167
+ * left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
1168
+ * is returned as is.
1169
+ *
1170
+ * @example
1171
+ * ```ts
1172
+ * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
1173
+ * mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
1174
+ * ```
1175
+ */
1176
+ function mergeRefWithSchema(node) {
1177
+ if (!node.schema) return node;
1178
+ const merged = { ...node.schema };
1179
+ for (const key of Object.keys(node)) {
1180
+ const value = node[key];
1181
+ if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
1182
+ }
1183
+ return merged;
1184
+ }
1185
+ /**
1186
+ * Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
1187
+ *
1188
+ * Modifiers inherited from the resolved schema are included in the check because a ref emits the
1189
+ * referenced schema variable with those modifiers already applied.
1190
+ */
1191
+ function isBareRef(node, keysToOmit) {
1192
+ if (!node || node.type !== "ref") return false;
1193
+ const meta = mergeRefWithSchema(node);
1194
+ return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
1195
+ }
1196
+ //#endregion
1197
+ //#region ../../internals/utils/src/promise.ts
1198
+ /**
1199
+ * Wraps `factory` with a keyed cache backed by the provided store.
1200
+ *
1201
+ * Pass a `WeakMap` for object keys (results are GC-eligible when the key is
1202
+ * collected) or a `Map` for primitive keys. For multi-argument functions,
1203
+ * nest two `memoize` calls — the outer keyed by the first argument, the
1204
+ * inner (created once per outer miss) keyed by the second.
1205
+ *
1206
+ * Because the cache is owned by the caller, it can be shared, inspected, or
1207
+ * cleared independently of the memoized function.
1208
+ *
1209
+ * @example Single WeakMap key
1210
+ * ```ts
1211
+ * const cache = new WeakMap<SchemaNode, Set<string>>()
1212
+ * const getRefs = memoize(cache, (node) => collectRefs(node))
1213
+ * ```
1214
+ *
1215
+ * @example Single Map key (primitive)
1216
+ * ```ts
1217
+ * const cache = new Map<string, Resolver>()
1218
+ * const getResolver = memoize(cache, (name) => buildResolver(name))
1219
+ * ```
1220
+ *
1221
+ * @example Two-level (object + primitive)
1222
+ * ```ts
1223
+ * const outer = new WeakMap<Params[], Map<string, Params[]>>()
1224
+ * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
1225
+ * fn(params)('camelcase')
1226
+ * ```
1227
+ */
1228
+ function memoize(store, factory) {
1229
+ return (key) => {
1230
+ if (store.has(key)) return store.get(key);
1231
+ const value = factory(key);
1232
+ store.set(key, value);
1233
+ return value;
1234
+ };
1235
+ }
804
1236
  //#endregion
805
1237
  //#region src/utils/schemaGraph.ts
806
1238
  /**
@@ -1059,17 +1491,6 @@ function inferDiscriminatorPropertyName(members) {
1059
1491
  }
1060
1492
  }
1061
1493
  //#endregion
1062
- //#region src/nodes/base.ts
1063
- /** Builds a `createX` factory for a node whose only computed field is `kind`. */
1064
- function nodeFactory(kind) {
1065
- return (input) => {
1066
- return {
1067
- ...input,
1068
- kind
1069
- };
1070
- };
1071
- }
1072
- //#endregion
1073
1494
  //#region src/nodes/code.ts
1074
1495
  /**
1075
1496
  * Creates a `ConstNode` representing a TypeScript `const` declaration.
@@ -1080,7 +1501,7 @@ function nodeFactory(kind) {
1080
1501
  * // export const pets: Pet[] = ... as const
1081
1502
  * ```
1082
1503
  */
1083
- const createConst = nodeFactory("Const");
1504
+ const createConst = nodeFactory(nodeKinds.const);
1084
1505
  /**
1085
1506
  * Creates a `TypeNode` representing a TypeScript `type` alias declaration.
1086
1507
  *
@@ -1090,7 +1511,7 @@ const createConst = nodeFactory("Const");
1090
1511
  * // export type Pet = ...
1091
1512
  * ```
1092
1513
  */
1093
- const createType = nodeFactory("Type");
1514
+ const createType = nodeFactory(nodeKinds.type);
1094
1515
  /**
1095
1516
  * Creates a `FunctionNode` representing a TypeScript `function` declaration.
1096
1517
  *
@@ -1100,7 +1521,7 @@ const createType = nodeFactory("Type");
1100
1521
  * // export async function fetchPet(): Promise<Pet> { ... }
1101
1522
  * ```
1102
1523
  */
1103
- const createFunction = nodeFactory("Function");
1524
+ const createFunction = nodeFactory(nodeKinds.function);
1104
1525
  /**
1105
1526
  * Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
1106
1527
  *
@@ -1110,7 +1531,7 @@ const createFunction = nodeFactory("Function");
1110
1531
  * // export const double = (n: number) => ...
1111
1532
  * ```
1112
1533
  */
1113
- const createArrowFunction = nodeFactory("ArrowFunction");
1534
+ const createArrowFunction = nodeFactory(nodeKinds.arrowFunction);
1114
1535
  /**
1115
1536
  * Creates a {@link TextNode} representing a raw string fragment in the source output.
1116
1537
  *
@@ -1122,7 +1543,7 @@ const createArrowFunction = nodeFactory("ArrowFunction");
1122
1543
  */
1123
1544
  function createText(value) {
1124
1545
  return {
1125
- kind: "Text",
1546
+ kind: nodeKinds.text,
1126
1547
  value
1127
1548
  };
1128
1549
  }
@@ -1136,7 +1557,7 @@ function createText(value) {
1136
1557
  * ```
1137
1558
  */
1138
1559
  function createBreak() {
1139
- return { kind: "Break" };
1560
+ return { kind: nodeKinds.break };
1140
1561
  }
1141
1562
  /**
1142
1563
  * Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
@@ -1149,7 +1570,7 @@ function createBreak() {
1149
1570
  */
1150
1571
  function createJsx(value) {
1151
1572
  return {
1152
- kind: "Jsx",
1573
+ kind: nodeKinds.jsx,
1153
1574
  value
1154
1575
  };
1155
1576
  }
@@ -1158,259 +1579,7 @@ function createJsx(value) {
1158
1579
  /**
1159
1580
  * Creates a `ContentNode` for a single request-body or response content type.
1160
1581
  */
1161
- const createContent = nodeFactory("Content");
1162
- //#endregion
1163
- //#region src/utils/combineFileMembers.ts
1164
- const IDENTIFIER_RUN = /[\w$]+/g;
1165
- /**
1166
- * How many imports a file needs before indexing the source beats scanning it once per name.
1167
- */
1168
- const INDEX_ABOVE_IMPORTS = 128;
1169
- /**
1170
- * Returns the local binding an import name item introduces: the alias when there is one, else the
1171
- * imported name.
1172
- */
1173
- function importLocalName(item) {
1174
- return typeof item === "string" ? item : item.name ?? item.propertyName;
1175
- }
1176
- /**
1177
- * Computes a multi-level sort key for exports and imports:
1178
- * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
1179
- */
1180
- function sortKey(node) {
1181
- const isArray = Array.isArray(node.name) ? "1" : "0";
1182
- const typeOnly = node.isTypeOnly ? "0" : "1";
1183
- const hasName = node.name != null ? "1" : "0";
1184
- const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
1185
- return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
1186
- }
1187
- /**
1188
- * Sorts members by {@link sortKey}. Keys are computed once per node, not per comparison.
1189
- */
1190
- function sortMembers(nodes) {
1191
- return nodes.map((node) => ({
1192
- node,
1193
- key: sortKey(node)
1194
- })).sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0).map(({ node }) => node);
1195
- }
1196
- /**
1197
- * Returns a collector for array-named members. A member whose path and `isTypeOnly` were already
1198
- * seen folds its names into that entry, otherwise it joins `result` as a new entry.
1199
- */
1200
- function mergeByPath(result) {
1201
- const byPath = /* @__PURE__ */ new Map();
1202
- return ({ node, names }) => {
1203
- const key = `${node.path}:${node.isTypeOnly ?? false}`;
1204
- const existing = byPath.get(key);
1205
- if (existing) {
1206
- for (const name of names) {
1207
- if (existing.seen.has(name)) continue;
1208
- existing.seen.add(name);
1209
- existing.names.push(name);
1210
- }
1211
- return;
1212
- }
1213
- const item = {
1214
- ...node,
1215
- name: [...names]
1216
- };
1217
- result.push(item);
1218
- byPath.set(key, {
1219
- names: item.name,
1220
- seen: new Set(names)
1221
- });
1222
- };
1223
- }
1224
- /**
1225
- * Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
1226
- * key. An unnamed source only drops when the same node appears twice, so markdown can repeat a
1227
- * paragraph or a table. Returns the deduplicated array in original order.
1228
- */
1229
- function combineSources(sources) {
1230
- const seen = /* @__PURE__ */ new Set();
1231
- return sources.filter((source) => {
1232
- const key = source.name != null ? `${source.name}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}` : source;
1233
- if (seen.has(key)) return false;
1234
- seen.add(key);
1235
- return true;
1236
- });
1237
- }
1238
- /**
1239
- * Deduplicates and merges `ExportNode` objects by path and type.
1240
- *
1241
- * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
1242
- * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
1243
- */
1244
- function combineExports(exports) {
1245
- const result = [];
1246
- const merge = mergeByPath(result);
1247
- const seen = /* @__PURE__ */ new Set();
1248
- for (const curr of sortMembers(exports)) {
1249
- const { name, path, isTypeOnly, asAlias } = curr;
1250
- if (Array.isArray(name)) {
1251
- if (name.length) merge({
1252
- node: curr,
1253
- names: [...new Set(name)]
1254
- });
1255
- continue;
1256
- }
1257
- const key = `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
1258
- if (!seen.has(key)) {
1259
- result.push(curr);
1260
- seen.add(key);
1261
- }
1262
- }
1263
- return result;
1264
- }
1265
- /**
1266
- * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
1267
- *
1268
- * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
1269
- * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
1270
- */
1271
- function combineImports(imports, exports, source) {
1272
- const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
1273
- const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? new Set(source.match(IDENTIFIER_RUN)) : null;
1274
- const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
1275
- const importNameMemo = /* @__PURE__ */ new Map();
1276
- const canonicalizeName = (n) => {
1277
- if (typeof n === "string") return n;
1278
- const key = `${n.propertyName}:${n.name ?? ""}`;
1279
- if (!importNameMemo.has(key)) importNameMemo.set(key, n);
1280
- return importNameMemo.get(key);
1281
- };
1282
- const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
1283
- for (const node of imports) if (Array.isArray(node.name) && node.name.some((item) => isUsed(importLocalName(item)))) pathsWithUsedNamedImport.add(node.path);
1284
- const result = [];
1285
- const merge = mergeByPath(result);
1286
- const seen = /* @__PURE__ */ new Set();
1287
- for (const curr of sortMembers(imports)) {
1288
- if (curr.path === curr.root) continue;
1289
- const { name, path, isTypeOnly } = curr;
1290
- if (Array.isArray(name)) {
1291
- const names = [...new Set(name.map(canonicalizeName))].filter((item) => isUsed(importLocalName(item)));
1292
- if (names.length) merge({
1293
- node: curr,
1294
- names
1295
- });
1296
- continue;
1297
- }
1298
- if (!isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
1299
- const key = `${path}:${name}:${isTypeOnly ?? false}`;
1300
- if (!seen.has(key)) {
1301
- result.push(curr);
1302
- seen.add(key);
1303
- }
1304
- }
1305
- return result;
1306
- }
1307
- //#endregion
1308
- //#region src/nodes/file.ts
1309
- /**
1310
- * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
1311
- *
1312
- * @example Named import
1313
- * ```ts
1314
- * createImport({ name: ['useState'], path: 'react' })
1315
- * // import { useState } from 'react'
1316
- * ```
1317
- */
1318
- const createImport = nodeFactory("Import");
1319
- /**
1320
- * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
1321
- *
1322
- * @example Named export
1323
- * ```ts
1324
- * createExport({ name: ['Pet'], path: './Pet' })
1325
- * // export { Pet } from './Pet'
1326
- * ```
1327
- */
1328
- const createExport = nodeFactory("Export");
1329
- /**
1330
- * Creates a `SourceNode` representing a fragment of source code within a file.
1331
- *
1332
- * @example
1333
- * ```ts
1334
- * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
1335
- * ```
1336
- */
1337
- const createSource = nodeFactory("Source");
1338
- /**
1339
- * Creates a fully resolved `FileNode` from a file input descriptor.
1340
- *
1341
- * Computes:
1342
- * - `id` SHA256 hash of the file path
1343
- * - `name` `baseName` without extension
1344
- * - `extname` extension extracted from `baseName`
1345
- *
1346
- * Deduplicates:
1347
- * - `sources` via `combineSources`
1348
- * - `exports` via `combineExports`
1349
- * - `imports` via `combineImports` (also filters unused imports)
1350
- *
1351
- * @throws {Error} when `baseName` has no extension.
1352
- *
1353
- * @example
1354
- * ```ts
1355
- * const file = createFile({
1356
- * baseName: 'petStore.ts',
1357
- * path: 'src/models/petStore.ts',
1358
- * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
1359
- * imports: [createImport({ name: ['z'], path: 'zod' })],
1360
- * exports: [createExport({ name: ['Pet'], path: './petStore' })],
1361
- * })
1362
- * // file.id = SHA256 hash of 'src/models/petStore.ts'
1363
- * // file.name = 'petStore'
1364
- * // file.extname = '.ts'
1365
- * ```
1366
- *
1367
- * @example Copy a real file into the output
1368
- * ```ts
1369
- * const file = createFile({
1370
- * baseName: 'client.ts',
1371
- * path: 'src/gen/client.ts',
1372
- * copy: '/abs/path/to/templates/client.ts',
1373
- * })
1374
- * ```
1375
- */
1376
- function createFile(input) {
1377
- const extname = path.extname(input.baseName);
1378
- if (!extname) throw new Error(`No extname found for ${input.baseName}`);
1379
- const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
1380
- const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
1381
- const resolvedImports = (() => {
1382
- if (!input.imports?.length) return [];
1383
- const sourceParts = [];
1384
- const localNames = /* @__PURE__ */ new Set();
1385
- for (const item of resolvedSources) {
1386
- const extracted = item.nodes && extractStringsFromNodes(item.nodes);
1387
- if (extracted) sourceParts.push(extracted);
1388
- if (item.name) localNames.add(item.name);
1389
- }
1390
- const source = sourceParts.join("\n") || void 0;
1391
- return combineImports(input.imports, resolvedExports, source).flatMap((imp) => {
1392
- if (imp.path === input.path) return [];
1393
- if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
1394
- const kept = imp.name.filter((item) => !localNames.has(importLocalName(item)));
1395
- if (!kept.length) return [];
1396
- return [kept.length === imp.name.length ? imp : {
1397
- ...imp,
1398
- name: kept
1399
- }];
1400
- });
1401
- })();
1402
- return {
1403
- ...input,
1404
- kind: "File",
1405
- id: hash("sha256", input.path, "hex"),
1406
- name: path.basename(input.baseName, extname),
1407
- extname,
1408
- imports: resolvedImports,
1409
- exports: resolvedExports,
1410
- sources: resolvedSources,
1411
- meta: input.meta ?? {}
1412
- };
1413
- }
1582
+ const createContent = nodeFactory(nodeKinds.content);
1414
1583
  //#endregion
1415
1584
  //#region src/nodes/input.ts
1416
1585
  /**
@@ -1432,7 +1601,7 @@ function createInput(overrides = {}) {
1432
1601
  enumNames: []
1433
1602
  },
1434
1603
  ...overrides,
1435
- kind: "Input"
1604
+ kind: nodeKinds.input
1436
1605
  };
1437
1606
  }
1438
1607
  //#endregion
@@ -1440,7 +1609,7 @@ function createInput(overrides = {}) {
1440
1609
  /**
1441
1610
  * Creates a `RequestBodyNode`.
1442
1611
  */
1443
- const createRequestBody = nodeFactory("RequestBody");
1612
+ const createRequestBody = nodeFactory(nodeKinds.requestBody);
1444
1613
  //#endregion
1445
1614
  //#region src/nodes/operation.ts
1446
1615
  function createOperation(props) {
@@ -1451,7 +1620,7 @@ function createOperation(props) {
1451
1620
  parameters: [],
1452
1621
  responses: [],
1453
1622
  ...rest,
1454
- kind: "Operation",
1623
+ kind: nodeKinds.operation,
1455
1624
  ...isHttp ? { protocol: "http" } : {},
1456
1625
  requestBody: requestBody ? createRequestBody(requestBody) : void 0
1457
1626
  };
@@ -1478,7 +1647,7 @@ function createParameter(input) {
1478
1647
  ...input,
1479
1648
  required,
1480
1649
  schema: optionality(input.schema, required),
1481
- kind: "Parameter"
1650
+ kind: nodeKinds.parameter
1482
1651
  };
1483
1652
  }
1484
1653
  //#endregion
@@ -1503,7 +1672,7 @@ function createProperty(input) {
1503
1672
  ...input,
1504
1673
  required,
1505
1674
  schema: optionality(input.schema, required),
1506
- kind: "Property"
1675
+ kind: nodeKinds.property
1507
1676
  };
1508
1677
  }
1509
1678
  //#endregion
@@ -1530,7 +1699,7 @@ function createResponse(props) {
1530
1699
  return {
1531
1700
  ...rest,
1532
1701
  content: entries,
1533
- kind: "Response"
1702
+ kind: nodeKinds.response
1534
1703
  };
1535
1704
  }
1536
1705
  //#endregion
@@ -1565,12 +1734,12 @@ function createSchema(props) {
1565
1734
  properties: [],
1566
1735
  primitive: "object",
1567
1736
  ...props,
1568
- kind: "Schema"
1737
+ kind: nodeKinds.schema
1569
1738
  };
1570
1739
  return {
1571
1740
  primitive: TYPE_TO_PRIMITIVE[props.type],
1572
1741
  ...props,
1573
- kind: "Schema"
1742
+ kind: nodeKinds.schema
1574
1743
  };
1575
1744
  }
1576
1745
  //#endregion
@@ -1618,10 +1787,13 @@ var src_exports = /* @__PURE__ */ __exportAll({
1618
1787
  forEachSchema: () => forEachSchema,
1619
1788
  getSchemaLiteralValues: () => getSchemaLiteralValues,
1620
1789
  inferDiscriminatorPropertyName: () => inferDiscriminatorPropertyName,
1790
+ inlineFiles: () => inlineFiles,
1621
1791
  isBareRef: () => isBareRef,
1622
1792
  isHttpOperationNode: () => isHttpOperationNode,
1793
+ isVirtualFile: () => isVirtualFile,
1623
1794
  mergeRefWithSchema: () => mergeRefWithSchema,
1624
1795
  narrowSchema: () => narrowSchema,
1796
+ nodeKinds: () => nodeKinds,
1625
1797
  optionality: () => optionality,
1626
1798
  refName: () => refName,
1627
1799
  resolveRef: () => resolveRef,
@@ -1631,6 +1803,6 @@ var src_exports = /* @__PURE__ */ __exportAll({
1631
1803
  transform: () => transform
1632
1804
  });
1633
1805
  //#endregion
1634
- export { applyMacros, src_exports as ast, collect, collectImportedRefNames, collectSchemaRefs, collectSync, collectUsedSchemaNames, composeMacros, createPrinter, defineMacro, extractStringsFromNodes, nodes_exports as factory, findCircularSchemas, findCircularSchemasFromGraph, findSchema, forEachChild, forEachSchema, getSchemaLiteralValues, inferDiscriminatorPropertyName, isBareRef, isHttpOperationNode, mergeRefWithSchema, narrowSchema, optionality, refName, resolveRef, resolveRefName, resolveSchemaProperties, schemaTypes, transform };
1806
+ export { applyMacros, src_exports as ast, collect, collectImportedRefNames, collectSchemaRefs, collectSync, collectUsedSchemaNames, composeMacros, createPrinter, defineMacro, extractStringsFromNodes, nodes_exports as factory, findCircularSchemas, findCircularSchemasFromGraph, findSchema, forEachChild, forEachSchema, getSchemaLiteralValues, inferDiscriminatorPropertyName, inlineFiles, isBareRef, isHttpOperationNode, isVirtualFile, mergeRefWithSchema, narrowSchema, nodeKinds, optionality, refName, resolveRef, resolveRefName, resolveSchemaProperties, schemaTypes, transform };
1635
1807
 
1636
1808
  //# sourceMappingURL=index.js.map