@kubb/ast 5.13.1 → 5.14.1

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
@@ -30,11 +30,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
30
30
  enumerable: true
31
31
  }) : target, mod));
32
32
  //#endregion
33
+ let node_crypto = require("node:crypto");
33
34
  let node_path = require("node:path");
34
35
  node_path = __toESM(node_path, 1);
35
- let node_crypto = require("node:crypto");
36
36
  //#region src/constants.ts
37
37
  /**
38
+ * Node kind discriminators used by every AST node (for example `node.kind === nodeKinds.text`).
39
+ */
40
+ const nodeKinds = {
41
+ input: "Input",
42
+ operation: "Operation",
43
+ schema: "Schema",
44
+ property: "Property",
45
+ parameter: "Parameter",
46
+ response: "Response",
47
+ requestBody: "RequestBody",
48
+ content: "Content",
49
+ type: "Type",
50
+ file: "File",
51
+ import: "Import",
52
+ export: "Export",
53
+ source: "Source",
54
+ const: "Const",
55
+ function: "Function",
56
+ arrowFunction: "ArrowFunction",
57
+ text: "Text",
58
+ break: "Break",
59
+ jsx: "Jsx"
60
+ };
61
+ /**
38
62
  * Schema type discriminators used by all AST schema nodes.
39
63
  *
40
64
  * Each value is a stable discriminator across the AST (for example `schema.type === schemaTypes.object`).
@@ -243,7 +267,7 @@ function isNodeRecord(value) {
243
267
  * ```
244
268
  */
245
269
  function getChildren(node, recurse) {
246
- if (node.kind === "Schema" && !recurse) return [];
270
+ if (node.kind === nodeKinds.schema && !recurse) return [];
247
271
  const children = [];
248
272
  visitChildNodes(node, (child) => {
249
273
  children.push(child);
@@ -301,7 +325,7 @@ function visitChildNodes(node, visit) {
301
325
  */
302
326
  function forEachSchema(node, visit) {
303
327
  const walk = (current) => {
304
- if (current.kind === "Schema") visit(current);
328
+ if (current.kind === nodeKinds.schema) visit(current);
305
329
  forEachChild(current, walk);
306
330
  };
307
331
  walk(node);
@@ -319,7 +343,7 @@ function forEachSchema(node, visit) {
319
343
  function findSchema(node, { predicate, followRefs = false }) {
320
344
  const seen = followRefs ? /* @__PURE__ */ new WeakSet() : void 0;
321
345
  const walk = (current) => {
322
- if (current.kind === "Schema") {
346
+ if (current.kind === nodeKinds.schema) {
323
347
  if (predicate(current)) return current;
324
348
  if (seen) {
325
349
  if (seen.has(current)) return void 0;
@@ -395,7 +419,7 @@ function transformNode(node, visitor, recurse, parent) {
395
419
  * (e.g. `additionalProperties: true`) intact.
396
420
  */
397
421
  function transformChildren(node, visitor, recurse) {
398
- const keys = node.kind === "Schema" && !recurse ? void 0 : VISITOR_KEYS[node.kind];
422
+ const keys = node.kind === nodeKinds.schema && !recurse ? void 0 : VISITOR_KEYS[node.kind];
399
423
  if (!keys) return node;
400
424
  const record = node;
401
425
  let updates;
@@ -680,11 +704,11 @@ function extractStringsFromNodes(nodes) {
680
704
  if (node) collected.push(node);
681
705
  continue;
682
706
  }
683
- if (node.kind === "Text" || node.kind === "Jsx") {
707
+ if (node.kind === nodeKinds.text || node.kind === nodeKinds.jsx) {
684
708
  if (node.value) collected.push(node.value);
685
709
  continue;
686
710
  }
687
- if (node.kind === "Break") continue;
711
+ if (node.kind === nodeKinds.break) continue;
688
712
  const parts = [];
689
713
  if ("params" in node && node.params) parts.push(node.params);
690
714
  if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
@@ -697,133 +721,550 @@ function extractStringsFromNodes(nodes) {
697
721
  return collected.join("\n");
698
722
  }
699
723
  //#endregion
700
- //#region src/utils/refs.ts
701
- /** Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`. */
702
- function refName(ref) {
703
- return ref.split("/").at(-1) ?? ref;
724
+ //#region src/utils/combineFileMembers.ts
725
+ const IDENTIFIER_RUN = /[\w$]+/g;
726
+ /**
727
+ * How many imports a file needs before indexing the source beats scanning it once per name.
728
+ */
729
+ const INDEX_ABOVE_IMPORTS = 128;
730
+ /**
731
+ * Returns the local binding an import name item introduces: the alias when there is one, else the
732
+ * imported name.
733
+ */
734
+ function importLocalName(item) {
735
+ return typeof item === "string" ? item : item.name ?? item.propertyName;
704
736
  }
705
737
  /**
706
- * Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
707
- * the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
708
- * then `name`, then the nested `schema.name`.
709
- *
710
- * Returns `null` for non-ref nodes or when no name resolves.
711
- *
712
- * @example
713
- * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
714
- *
715
- * @example Collision-renamed target
716
- * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
738
+ * Computes a multi-level sort key for exports and imports:
739
+ * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
717
740
  */
718
- function resolveRefName(node) {
719
- if (!node || node.type !== "ref") return null;
720
- if (node.targetName) return node.targetName;
721
- if (node.ref) return refName(node.ref);
722
- return node.name ?? node.schema?.name ?? null;
741
+ function sortKey(node) {
742
+ const isArray = Array.isArray(node.name) ? "1" : "0";
743
+ const typeOnly = node.isTypeOnly ? "0" : "1";
744
+ const hasName = node.name != null ? "1" : "0";
745
+ const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
746
+ return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
723
747
  }
724
748
  /**
725
- * Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
726
- *
727
- * @example
728
- * ```ts
729
- * const target = resolveRef(refSchema)
730
- * ```
749
+ * Sorts members by {@link sortKey}. Keys are computed once per node, not per comparison.
731
750
  */
732
- function resolveRef(node) {
733
- if (node.type !== "ref" || !node.schema) return node;
734
- const seen = /* @__PURE__ */ new WeakSet();
735
- let current = node;
736
- while (current.type === "ref" && current.schema) {
737
- if (seen.has(current)) return current;
738
- seen.add(current);
739
- current = current.schema;
740
- }
741
- return current;
751
+ function sortMembers(nodes) {
752
+ return nodes.map((node) => ({
753
+ node,
754
+ key: sortKey(node)
755
+ })).sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0).map(({ node }) => node);
742
756
  }
743
- /** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
744
- const REF_OWN_KEYS = /* @__PURE__ */ new Set([
745
- "kind",
746
- "type",
747
- "name",
748
- "ref",
749
- "schema"
750
- ]);
751
757
  /**
752
- * Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
753
- *
754
- * Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
755
- * of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
756
- * left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
757
- * is returned as is.
758
+ * Returns a collector for array-named members. A member whose path and `isTypeOnly` were already
759
+ * seen folds its names into that entry, otherwise it joins `result` as a new entry.
760
+ */
761
+ function mergeByPath(result) {
762
+ const byPath = /* @__PURE__ */ new Map();
763
+ return ({ node, names }) => {
764
+ const key = `${node.path}:${node.isTypeOnly ?? false}`;
765
+ const existing = byPath.get(key);
766
+ if (existing) {
767
+ for (const name of names) {
768
+ if (existing.seen.has(name)) continue;
769
+ existing.seen.add(name);
770
+ existing.names.push(name);
771
+ }
772
+ return;
773
+ }
774
+ const item = {
775
+ ...node,
776
+ name: [...names]
777
+ };
778
+ result.push(item);
779
+ byPath.set(key, {
780
+ names: item.name,
781
+ seen: new Set(names)
782
+ });
783
+ };
784
+ }
785
+ /**
786
+ * Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
787
+ * key. An unnamed source only drops when the same node appears twice, so markdown can repeat a
788
+ * paragraph or a table. Returns the deduplicated array in original order.
789
+ */
790
+ function combineSources(sources) {
791
+ const seen = /* @__PURE__ */ new Set();
792
+ return sources.filter((source) => {
793
+ const key = source.name != null ? `${source.name}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}` : source;
794
+ if (seen.has(key)) return false;
795
+ seen.add(key);
796
+ return true;
797
+ });
798
+ }
799
+ /**
800
+ * Deduplicates and merges `ExportNode` objects by path and type.
758
801
  *
759
- * @example
760
- * ```ts
761
- * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
762
- * mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
763
- * ```
802
+ * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
803
+ * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
764
804
  */
765
- function mergeRefWithSchema(node) {
766
- if (!node.schema) return node;
767
- const merged = { ...node.schema };
768
- for (const key of Object.keys(node)) {
769
- const value = node[key];
770
- if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
805
+ function combineExports(exports) {
806
+ const result = [];
807
+ const merge = mergeByPath(result);
808
+ const seen = /* @__PURE__ */ new Set();
809
+ for (const curr of sortMembers(exports)) {
810
+ const { name, path, isTypeOnly, asAlias } = curr;
811
+ if (Array.isArray(name)) {
812
+ if (name.length) merge({
813
+ node: curr,
814
+ names: [...new Set(name)]
815
+ });
816
+ continue;
817
+ }
818
+ const key = `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
819
+ if (!seen.has(key)) {
820
+ result.push(curr);
821
+ seen.add(key);
822
+ }
771
823
  }
772
- return merged;
824
+ return result;
773
825
  }
774
826
  /**
775
- * Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
827
+ * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
776
828
  *
777
- * Modifiers inherited from the resolved schema are included in the check because a ref emits the
778
- * referenced schema variable with those modifiers already applied.
829
+ * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
830
+ * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
779
831
  */
780
- function isBareRef(node, keysToOmit) {
781
- if (!node || node.type !== "ref") return false;
782
- const meta = mergeRefWithSchema(node);
783
- return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
832
+ function combineImports(imports, exports, source) {
833
+ const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
834
+ const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? new Set(source.match(IDENTIFIER_RUN)) : null;
835
+ const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
836
+ const importNameMemo = /* @__PURE__ */ new Map();
837
+ const canonicalizeName = (n) => {
838
+ if (typeof n === "string") return n;
839
+ const key = `${n.propertyName}:${n.name ?? ""}`;
840
+ if (!importNameMemo.has(key)) importNameMemo.set(key, n);
841
+ return importNameMemo.get(key);
842
+ };
843
+ const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
844
+ for (const node of imports) if (Array.isArray(node.name) && node.name.some((item) => isUsed(importLocalName(item)))) pathsWithUsedNamedImport.add(node.path);
845
+ const result = [];
846
+ const merge = mergeByPath(result);
847
+ const seen = /* @__PURE__ */ new Set();
848
+ for (const curr of sortMembers(imports)) {
849
+ if (curr.path === curr.root) continue;
850
+ const { name, path, isTypeOnly } = curr;
851
+ if (Array.isArray(name)) {
852
+ const names = [...new Set(name.map(canonicalizeName))].filter((item) => isUsed(importLocalName(item)));
853
+ if (names.length) merge({
854
+ node: curr,
855
+ names
856
+ });
857
+ continue;
858
+ }
859
+ if (!isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
860
+ const key = `${path}:${name}:${isTypeOnly ?? false}`;
861
+ if (!seen.has(key)) {
862
+ result.push(curr);
863
+ seen.add(key);
864
+ }
865
+ }
866
+ return result;
784
867
  }
785
868
  //#endregion
786
- //#region ../../internals/utils/src/promise.ts
869
+ //#region src/nodes/base.ts
870
+ /** Builds a `createX` factory for a node whose only computed field is `kind`. */
871
+ function nodeFactory(kind) {
872
+ return (input) => {
873
+ return {
874
+ ...input,
875
+ kind
876
+ };
877
+ };
878
+ }
879
+ //#endregion
880
+ //#region src/nodes/file.ts
787
881
  /**
788
- * Wraps `factory` with a keyed cache backed by the provided store.
789
- *
790
- * Pass a `WeakMap` for object keys (results are GC-eligible when the key is
791
- * collected) or a `Map` for primitive keys. For multi-argument functions,
792
- * nest two `memoize` calls — the outer keyed by the first argument, the
793
- * inner (created once per outer miss) keyed by the second.
794
- *
795
- * Because the cache is owned by the caller, it can be shared, inspected, or
796
- * cleared independently of the memoized function.
882
+ * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
797
883
  *
798
- * @example Single WeakMap key
884
+ * @example Named import
799
885
  * ```ts
800
- * const cache = new WeakMap<SchemaNode, Set<string>>()
801
- * const getRefs = memoize(cache, (node) => collectRefs(node))
886
+ * createImport({ name: ['useState'], path: 'react' })
887
+ * // import { useState } from 'react'
802
888
  * ```
889
+ */
890
+ const createImport = nodeFactory(nodeKinds.import);
891
+ /**
892
+ * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
803
893
  *
804
- * @example Single Map key (primitive)
894
+ * @example Named export
805
895
  * ```ts
806
- * const cache = new Map<string, Resolver>()
807
- * const getResolver = memoize(cache, (name) => buildResolver(name))
896
+ * createExport({ name: ['Pet'], path: './Pet' })
897
+ * // export { Pet } from './Pet'
808
898
  * ```
899
+ */
900
+ const createExport = nodeFactory(nodeKinds.export);
901
+ /**
902
+ * Creates a `SourceNode` representing a fragment of source code within a file.
809
903
  *
810
- * @example Two-level (object + primitive)
904
+ * @example
811
905
  * ```ts
812
- * const outer = new WeakMap<Params[], Map<string, Params[]>>()
813
- * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
814
- * fn(params)('camelcase')
906
+ * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
815
907
  * ```
816
908
  */
817
- function memoize(store, factory) {
818
- return (key) => {
819
- if (store.has(key)) return store.get(key);
820
- const value = factory(key);
821
- store.set(key, value);
822
- return value;
823
- };
824
- }
825
- //#endregion
826
- //#region src/utils/schemaGraph.ts
909
+ const createSource = nodeFactory(nodeKinds.source);
910
+ /**
911
+ * Creates a fully resolved `FileNode` from a file input descriptor.
912
+ *
913
+ * Computes:
914
+ * - `id` SHA256 hash of the file path
915
+ * - `name` `baseName` without extension
916
+ * - `extname` extension extracted from `baseName`
917
+ *
918
+ * Deduplicates:
919
+ * - `sources` via `combineSources`
920
+ * - `exports` via `combineExports`
921
+ * - `imports` via `combineImports` (also filters unused imports)
922
+ *
923
+ * @throws {Error} when `baseName` has no extension.
924
+ *
925
+ * @example
926
+ * ```ts
927
+ * const file = createFile({
928
+ * baseName: 'petStore.ts',
929
+ * path: 'src/models/petStore.ts',
930
+ * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
931
+ * imports: [createImport({ name: ['z'], path: 'zod' })],
932
+ * exports: [createExport({ name: ['Pet'], path: './petStore' })],
933
+ * })
934
+ * // file.id = SHA256 hash of 'src/models/petStore.ts'
935
+ * // file.name = 'petStore'
936
+ * // file.extname = '.ts'
937
+ * ```
938
+ *
939
+ * @example Copy a real file into the output
940
+ * ```ts
941
+ * const file = createFile({
942
+ * baseName: 'client.ts',
943
+ * path: 'src/gen/client.ts',
944
+ * copy: '/abs/path/to/templates/client.ts',
945
+ * })
946
+ * ```
947
+ */
948
+ function createFile(input) {
949
+ const extname = node_path.default.extname(input.baseName);
950
+ if (!extname) throw new Error(`No extname found for ${input.baseName}`);
951
+ const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
952
+ const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
953
+ const resolvedImports = (() => {
954
+ if (!input.imports?.length) return [];
955
+ const sourceParts = [];
956
+ const localNames = /* @__PURE__ */ new Set();
957
+ for (const item of resolvedSources) {
958
+ const extracted = item.nodes && extractStringsFromNodes(item.nodes);
959
+ if (extracted) sourceParts.push(extracted);
960
+ if (item.name) localNames.add(item.name);
961
+ }
962
+ const source = sourceParts.join("\n") || void 0;
963
+ return combineImports(input.imports, resolvedExports, source).flatMap((imp) => {
964
+ if (imp.path === input.path) return [];
965
+ if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
966
+ const kept = imp.name.filter((item) => !localNames.has(importLocalName(item)));
967
+ if (!kept.length) return [];
968
+ return [kept.length === imp.name.length ? imp : {
969
+ ...imp,
970
+ name: kept
971
+ }];
972
+ });
973
+ })();
974
+ return {
975
+ ...input,
976
+ kind: nodeKinds.file,
977
+ id: (0, node_crypto.hash)("sha256", input.path, "hex"),
978
+ name: node_path.default.basename(input.baseName, extname),
979
+ extname,
980
+ imports: resolvedImports,
981
+ exports: resolvedExports,
982
+ sources: resolvedSources,
983
+ meta: input.meta ?? {}
984
+ };
985
+ }
986
+ //#endregion
987
+ //#region src/utils/inline.ts
988
+ /**
989
+ * Whether every source of `file` is inline. Other files absorb such a file, so it is never written.
990
+ */
991
+ function isVirtualFile(file) {
992
+ return file.sources.length > 0 && file.sources.every((source) => source.inline);
993
+ }
994
+ /**
995
+ * Replaces every name a file imports from a virtual file (see {@link isVirtualFile}) with that name's
996
+ * `inline.expression`, until no inline names are left. The definitions' own imports move to the importing file.
997
+ */
998
+ function inlineFiles(files, { language }) {
999
+ const virtualFiles = new Map(files.filter(isVirtualFile).map((file) => [file.path, file]));
1000
+ const result = {
1001
+ files: [],
1002
+ virtualPaths: [...virtualFiles.keys()],
1003
+ problems: []
1004
+ };
1005
+ if (virtualFiles.size === 0) return result;
1006
+ const definitions = /* @__PURE__ */ new Map();
1007
+ function define(path, name, from, lang) {
1008
+ const key = `${path}\0${name}`;
1009
+ if (definitions.has(key)) {
1010
+ const definition = definitions.get(key);
1011
+ if (definition === null) result.problems.push({
1012
+ path: from,
1013
+ message: `"${name}" from "${path}" is defined in terms of itself.`
1014
+ });
1015
+ return definition ?? void 0;
1016
+ }
1017
+ const file = virtualFiles.get(path);
1018
+ const inline = file.sources.find((source) => source.name === name)?.inline;
1019
+ if (!inline) {
1020
+ result.problems.push({
1021
+ path: from,
1022
+ message: `"${name}" is imported from "${path}", which never writes it and has no inline definition for it.`
1023
+ });
1024
+ return;
1025
+ }
1026
+ definitions.set(key, null);
1027
+ const imports = [];
1028
+ const { text, used } = replaceNames(inline.expression, file, lang, imports);
1029
+ imports.push(...file.imports.flatMap((imp) => virtualFiles.has(imp.path) ? [] : pickNames(imp, used)));
1030
+ const definition = {
1031
+ expression: text,
1032
+ imports
1033
+ };
1034
+ definitions.set(key, definition);
1035
+ return definition;
1036
+ }
1037
+ function replaceNames(input, file, lang, imports) {
1038
+ const used = /* @__PURE__ */ new Set();
1039
+ return {
1040
+ text: lang.replaceIdentifiers(input, (local) => {
1041
+ const target = findTarget(file, local);
1042
+ const definition = target && define(target.path, target.name, file.path, lang);
1043
+ if (!definition) {
1044
+ used.add(local);
1045
+ return;
1046
+ }
1047
+ imports.push(...definition.imports);
1048
+ return lang.wrap(definition.expression);
1049
+ }),
1050
+ used
1051
+ };
1052
+ }
1053
+ function findTarget(file, local) {
1054
+ if (virtualFiles.has(file.path) && file.sources.some((source) => source.name === local)) return {
1055
+ path: file.path,
1056
+ name: local
1057
+ };
1058
+ for (const imp of file.imports) {
1059
+ const item = virtualFiles.has(imp.path) && [imp.name].flat().find((item) => importLocalName(item) === local);
1060
+ if (item) return {
1061
+ path: imp.path,
1062
+ name: typeof item === "string" ? item : item.propertyName
1063
+ };
1064
+ }
1065
+ }
1066
+ for (const file of files) {
1067
+ if (virtualFiles.has(file.path) || !file.imports.some((imp) => virtualFiles.has(imp.path))) continue;
1068
+ const lang = language(file);
1069
+ if (!lang) {
1070
+ result.problems.push({
1071
+ path: file.path,
1072
+ message: `No parser for "${file.extname}" files supports inline sources.`
1073
+ });
1074
+ continue;
1075
+ }
1076
+ const carried = [];
1077
+ const sources = file.sources.map((source) => ({
1078
+ ...source,
1079
+ nodes: rewriteNodes(source.nodes, (text) => replaceNames(text, file, lang, carried).text)
1080
+ }));
1081
+ const imports = [...file.imports.filter((imp) => !virtualFiles.has(imp.path)), ...carried.map((imp) => imp.root ? {
1082
+ ...imp,
1083
+ root: file.path
1084
+ } : imp)];
1085
+ result.files.push(createFile({
1086
+ ...file,
1087
+ sources,
1088
+ imports
1089
+ }));
1090
+ }
1091
+ return result;
1092
+ }
1093
+ function pickNames(imp, used) {
1094
+ if (!Array.isArray(imp.name)) return used.has(imp.name) ? [imp] : [];
1095
+ const name = imp.name.filter((item) => used.has(importLocalName(item)));
1096
+ return name.length > 0 ? [{
1097
+ ...imp,
1098
+ name
1099
+ }] : [];
1100
+ }
1101
+ function rewriteNodes(nodes, rewrite) {
1102
+ return nodes?.map((node) => {
1103
+ if (typeof node === "string") return rewrite(node);
1104
+ switch (node.kind) {
1105
+ case nodeKinds.break: return node;
1106
+ case nodeKinds.text:
1107
+ case nodeKinds.jsx: return {
1108
+ ...node,
1109
+ value: rewrite(node.value)
1110
+ };
1111
+ case nodeKinds.function:
1112
+ case nodeKinds.arrowFunction: return {
1113
+ ...node,
1114
+ params: node.params && rewrite(node.params),
1115
+ generics: Array.isArray(node.generics) ? node.generics.map(rewrite) : node.generics && rewrite(node.generics),
1116
+ returnType: node.returnType && rewrite(node.returnType),
1117
+ nodes: rewriteNodes(node.nodes, rewrite)
1118
+ };
1119
+ case nodeKinds.const: return {
1120
+ ...node,
1121
+ type: node.type && rewrite(node.type),
1122
+ nodes: rewriteNodes(node.nodes, rewrite)
1123
+ };
1124
+ default: return {
1125
+ ...node,
1126
+ nodes: rewriteNodes(node.nodes, rewrite)
1127
+ };
1128
+ }
1129
+ });
1130
+ }
1131
+ //#endregion
1132
+ //#region src/utils/refs.ts
1133
+ /**
1134
+ * Returns the last segment of a `$ref` pointer, for example `'Pet'` for `#/components/schemas/Pet`.
1135
+ * The segment is decoded like the pointer resolver does: percent-escapes first, then `~1` and `~0`
1136
+ * (RFC 6901), so `a~1b~0c` names the component `a/b~c`.
1137
+ */
1138
+ function refName(ref) {
1139
+ const segment = ref.split("/").at(-1) ?? ref;
1140
+ let decoded = segment;
1141
+ try {
1142
+ decoded = decodeURIComponent(segment);
1143
+ } catch {}
1144
+ return decoded.replaceAll("~1", "/").replaceAll("~0", "~");
1145
+ }
1146
+ /**
1147
+ * Resolves the emitted name of the schema a ref node points at. Prefers `targetName` (set when
1148
+ * the referenced schema was renamed, e.g. to break a collision), then the last segment of `ref`,
1149
+ * then `name`, then the nested `schema.name`.
1150
+ *
1151
+ * Returns `null` for non-ref nodes or when no name resolves.
1152
+ *
1153
+ * @example
1154
+ * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Pet' }) // 'Pet'`
1155
+ *
1156
+ * @example Collision-renamed target
1157
+ * `resolveRefName({ kind: 'Schema', type: 'ref', ref: '#/components/schemas/Order', targetName: 'OrderSchema' }) // 'OrderSchema'`
1158
+ */
1159
+ function resolveRefName(node) {
1160
+ if (!node || node.type !== "ref") return null;
1161
+ if (node.targetName) return node.targetName;
1162
+ if (node.ref) return refName(node.ref);
1163
+ return node.name ?? node.schema?.name ?? null;
1164
+ }
1165
+ /**
1166
+ * Follows a resolved ref chain to its target schema. Returns an unresolved or cyclic ref as is.
1167
+ *
1168
+ * @example
1169
+ * ```ts
1170
+ * const target = resolveRef(refSchema)
1171
+ * ```
1172
+ */
1173
+ function resolveRef(node) {
1174
+ if (node.type !== "ref" || !node.schema) return node;
1175
+ const seen = /* @__PURE__ */ new WeakSet();
1176
+ let current = node;
1177
+ while (current.type === "ref" && current.schema) {
1178
+ if (seen.has(current)) return current;
1179
+ seen.add(current);
1180
+ current = current.schema;
1181
+ }
1182
+ return current;
1183
+ }
1184
+ /** Fields of a ref node that describe the ref itself, so they never override the resolved schema. */
1185
+ const REF_OWN_KEYS = /* @__PURE__ */ new Set([
1186
+ "kind",
1187
+ "type",
1188
+ "name",
1189
+ "ref",
1190
+ "schema"
1191
+ ]);
1192
+ /**
1193
+ * Merges a ref node with its resolved schema, giving the fields set at the usage site precedence.
1194
+ *
1195
+ * Every field on the ref except `kind`, `type`, `name`, `ref`, and `schema` overrides the same field
1196
+ * of the resolved `schema` (for example `description`, `nullable`, `readOnly`, `deprecated`). Fields
1197
+ * left `undefined` on the ref do not shadow the resolved schema. A ref without a resolved `schema`
1198
+ * is returned as is.
1199
+ *
1200
+ * @example
1201
+ * ```ts
1202
+ * const ref = createSchema({ type: 'ref', ref: '#/components/schemas/Pet', description: 'A pet', schema: petSchema })
1203
+ * mergeRefWithSchema(ref) // petSchema's fields with description 'A pet'
1204
+ * ```
1205
+ */
1206
+ function mergeRefWithSchema(node) {
1207
+ if (!node.schema) return node;
1208
+ const merged = { ...node.schema };
1209
+ for (const key of Object.keys(node)) {
1210
+ const value = node[key];
1211
+ if (value !== void 0 && !REF_OWN_KEYS.has(key)) merged[key] = value;
1212
+ }
1213
+ return merged;
1214
+ }
1215
+ /**
1216
+ * Returns `true` when a schema is a bare ref without modifiers, metadata, or omit keys.
1217
+ *
1218
+ * Modifiers inherited from the resolved schema are included in the check because a ref emits the
1219
+ * referenced schema variable with those modifiers already applied.
1220
+ */
1221
+ function isBareRef(node, keysToOmit) {
1222
+ if (!node || node.type !== "ref") return false;
1223
+ const meta = mergeRefWithSchema(node);
1224
+ return !meta.nullable && !meta.optional && !meta.nullish && meta.default === void 0 && !meta.description && !meta.examples?.length && !keysToOmit?.length;
1225
+ }
1226
+ //#endregion
1227
+ //#region ../../internals/utils/src/promise.ts
1228
+ /**
1229
+ * Wraps `factory` with a keyed cache backed by the provided store.
1230
+ *
1231
+ * Pass a `WeakMap` for object keys (results are GC-eligible when the key is
1232
+ * collected) or a `Map` for primitive keys. For multi-argument functions,
1233
+ * nest two `memoize` calls — the outer keyed by the first argument, the
1234
+ * inner (created once per outer miss) keyed by the second.
1235
+ *
1236
+ * Because the cache is owned by the caller, it can be shared, inspected, or
1237
+ * cleared independently of the memoized function.
1238
+ *
1239
+ * @example Single WeakMap key
1240
+ * ```ts
1241
+ * const cache = new WeakMap<SchemaNode, Set<string>>()
1242
+ * const getRefs = memoize(cache, (node) => collectRefs(node))
1243
+ * ```
1244
+ *
1245
+ * @example Single Map key (primitive)
1246
+ * ```ts
1247
+ * const cache = new Map<string, Resolver>()
1248
+ * const getResolver = memoize(cache, (name) => buildResolver(name))
1249
+ * ```
1250
+ *
1251
+ * @example Two-level (object + primitive)
1252
+ * ```ts
1253
+ * const outer = new WeakMap<Params[], Map<string, Params[]>>()
1254
+ * const fn = memoize(outer, (params) => memoize(new Map(), (key) => transform(params, key)))
1255
+ * fn(params)('camelcase')
1256
+ * ```
1257
+ */
1258
+ function memoize(store, factory) {
1259
+ return (key) => {
1260
+ if (store.has(key)) return store.get(key);
1261
+ const value = factory(key);
1262
+ store.set(key, value);
1263
+ return value;
1264
+ };
1265
+ }
1266
+ //#endregion
1267
+ //#region src/utils/schemaGraph.ts
827
1268
  /**
828
1269
  * Collects the names of every schema a node's subtree references, resolved with `resolveRefName`.
829
1270
  * Each ref contributes its name only, so the schema it points to is never traversed. The walk is
@@ -1080,17 +1521,6 @@ function inferDiscriminatorPropertyName(members) {
1080
1521
  }
1081
1522
  }
1082
1523
  //#endregion
1083
- //#region src/nodes/base.ts
1084
- /** Builds a `createX` factory for a node whose only computed field is `kind`. */
1085
- function nodeFactory(kind) {
1086
- return (input) => {
1087
- return {
1088
- ...input,
1089
- kind
1090
- };
1091
- };
1092
- }
1093
- //#endregion
1094
1524
  //#region src/nodes/code.ts
1095
1525
  /**
1096
1526
  * Creates a `ConstNode` representing a TypeScript `const` declaration.
@@ -1101,7 +1531,7 @@ function nodeFactory(kind) {
1101
1531
  * // export const pets: Pet[] = ... as const
1102
1532
  * ```
1103
1533
  */
1104
- const createConst = nodeFactory("Const");
1534
+ const createConst = nodeFactory(nodeKinds.const);
1105
1535
  /**
1106
1536
  * Creates a `TypeNode` representing a TypeScript `type` alias declaration.
1107
1537
  *
@@ -1111,7 +1541,7 @@ const createConst = nodeFactory("Const");
1111
1541
  * // export type Pet = ...
1112
1542
  * ```
1113
1543
  */
1114
- const createType = nodeFactory("Type");
1544
+ const createType = nodeFactory(nodeKinds.type);
1115
1545
  /**
1116
1546
  * Creates a `FunctionNode` representing a TypeScript `function` declaration.
1117
1547
  *
@@ -1121,7 +1551,7 @@ const createType = nodeFactory("Type");
1121
1551
  * // export async function fetchPet(): Promise<Pet> { ... }
1122
1552
  * ```
1123
1553
  */
1124
- const createFunction = nodeFactory("Function");
1554
+ const createFunction = nodeFactory(nodeKinds.function);
1125
1555
  /**
1126
1556
  * Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
1127
1557
  *
@@ -1131,7 +1561,7 @@ const createFunction = nodeFactory("Function");
1131
1561
  * // export const double = (n: number) => ...
1132
1562
  * ```
1133
1563
  */
1134
- const createArrowFunction = nodeFactory("ArrowFunction");
1564
+ const createArrowFunction = nodeFactory(nodeKinds.arrowFunction);
1135
1565
  /**
1136
1566
  * Creates a {@link TextNode} representing a raw string fragment in the source output.
1137
1567
  *
@@ -1143,7 +1573,7 @@ const createArrowFunction = nodeFactory("ArrowFunction");
1143
1573
  */
1144
1574
  function createText(value) {
1145
1575
  return {
1146
- kind: "Text",
1576
+ kind: nodeKinds.text,
1147
1577
  value
1148
1578
  };
1149
1579
  }
@@ -1157,7 +1587,7 @@ function createText(value) {
1157
1587
  * ```
1158
1588
  */
1159
1589
  function createBreak() {
1160
- return { kind: "Break" };
1590
+ return { kind: nodeKinds.break };
1161
1591
  }
1162
1592
  /**
1163
1593
  * Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
@@ -1170,7 +1600,7 @@ function createBreak() {
1170
1600
  */
1171
1601
  function createJsx(value) {
1172
1602
  return {
1173
- kind: "Jsx",
1603
+ kind: nodeKinds.jsx,
1174
1604
  value
1175
1605
  };
1176
1606
  }
@@ -1179,259 +1609,7 @@ function createJsx(value) {
1179
1609
  /**
1180
1610
  * Creates a `ContentNode` for a single request-body or response content type.
1181
1611
  */
1182
- const createContent = nodeFactory("Content");
1183
- //#endregion
1184
- //#region src/utils/combineFileMembers.ts
1185
- const IDENTIFIER_RUN = /[\w$]+/g;
1186
- /**
1187
- * How many imports a file needs before indexing the source beats scanning it once per name.
1188
- */
1189
- const INDEX_ABOVE_IMPORTS = 128;
1190
- /**
1191
- * Returns the local binding an import name item introduces: the alias when there is one, else the
1192
- * imported name.
1193
- */
1194
- function importLocalName(item) {
1195
- return typeof item === "string" ? item : item.name ?? item.propertyName;
1196
- }
1197
- /**
1198
- * Computes a multi-level sort key for exports and imports:
1199
- * non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
1200
- */
1201
- function sortKey(node) {
1202
- const isArray = Array.isArray(node.name) ? "1" : "0";
1203
- const typeOnly = node.isTypeOnly ? "0" : "1";
1204
- const hasName = node.name != null ? "1" : "0";
1205
- const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
1206
- return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
1207
- }
1208
- /**
1209
- * Sorts members by {@link sortKey}. Keys are computed once per node, not per comparison.
1210
- */
1211
- function sortMembers(nodes) {
1212
- return nodes.map((node) => ({
1213
- node,
1214
- key: sortKey(node)
1215
- })).sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0).map(({ node }) => node);
1216
- }
1217
- /**
1218
- * Returns a collector for array-named members. A member whose path and `isTypeOnly` were already
1219
- * seen folds its names into that entry, otherwise it joins `result` as a new entry.
1220
- */
1221
- function mergeByPath(result) {
1222
- const byPath = /* @__PURE__ */ new Map();
1223
- return ({ node, names }) => {
1224
- const key = `${node.path}:${node.isTypeOnly ?? false}`;
1225
- const existing = byPath.get(key);
1226
- if (existing) {
1227
- for (const name of names) {
1228
- if (existing.seen.has(name)) continue;
1229
- existing.seen.add(name);
1230
- existing.names.push(name);
1231
- }
1232
- return;
1233
- }
1234
- const item = {
1235
- ...node,
1236
- name: [...names]
1237
- };
1238
- result.push(item);
1239
- byPath.set(key, {
1240
- names: item.name,
1241
- seen: new Set(names)
1242
- });
1243
- };
1244
- }
1245
- /**
1246
- * Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
1247
- * key. An unnamed source only drops when the same node appears twice, so markdown can repeat a
1248
- * paragraph or a table. Returns the deduplicated array in original order.
1249
- */
1250
- function combineSources(sources) {
1251
- const seen = /* @__PURE__ */ new Set();
1252
- return sources.filter((source) => {
1253
- const key = source.name != null ? `${source.name}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}` : source;
1254
- if (seen.has(key)) return false;
1255
- seen.add(key);
1256
- return true;
1257
- });
1258
- }
1259
- /**
1260
- * Deduplicates and merges `ExportNode` objects by path and type.
1261
- *
1262
- * Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
1263
- * Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
1264
- */
1265
- function combineExports(exports) {
1266
- const result = [];
1267
- const merge = mergeByPath(result);
1268
- const seen = /* @__PURE__ */ new Set();
1269
- for (const curr of sortMembers(exports)) {
1270
- const { name, path, isTypeOnly, asAlias } = curr;
1271
- if (Array.isArray(name)) {
1272
- if (name.length) merge({
1273
- node: curr,
1274
- names: [...new Set(name)]
1275
- });
1276
- continue;
1277
- }
1278
- const key = `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
1279
- if (!seen.has(key)) {
1280
- result.push(curr);
1281
- seen.add(key);
1282
- }
1283
- }
1284
- return result;
1285
- }
1286
- /**
1287
- * Deduplicates and merges `ImportNode` objects, filtering out unused imports.
1288
- *
1289
- * Retains imports that are referenced in `source` or re-exported. Imports with the same path and
1290
- * `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
1291
- */
1292
- function combineImports(imports, exports, source) {
1293
- const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
1294
- const identifiers = source && imports.length > INDEX_ABOVE_IMPORTS ? new Set(source.match(IDENTIFIER_RUN)) : null;
1295
- const isUsed = (importName) => !source || identifiers?.has(importName) || source.includes(importName) || exportedNames.has(importName);
1296
- const importNameMemo = /* @__PURE__ */ new Map();
1297
- const canonicalizeName = (n) => {
1298
- if (typeof n === "string") return n;
1299
- const key = `${n.propertyName}:${n.name ?? ""}`;
1300
- if (!importNameMemo.has(key)) importNameMemo.set(key, n);
1301
- return importNameMemo.get(key);
1302
- };
1303
- const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
1304
- for (const node of imports) if (Array.isArray(node.name) && node.name.some((item) => isUsed(importLocalName(item)))) pathsWithUsedNamedImport.add(node.path);
1305
- const result = [];
1306
- const merge = mergeByPath(result);
1307
- const seen = /* @__PURE__ */ new Set();
1308
- for (const curr of sortMembers(imports)) {
1309
- if (curr.path === curr.root) continue;
1310
- const { name, path, isTypeOnly } = curr;
1311
- if (Array.isArray(name)) {
1312
- const names = [...new Set(name.map(canonicalizeName))].filter((item) => isUsed(importLocalName(item)));
1313
- if (names.length) merge({
1314
- node: curr,
1315
- names
1316
- });
1317
- continue;
1318
- }
1319
- if (!isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
1320
- const key = `${path}:${name}:${isTypeOnly ?? false}`;
1321
- if (!seen.has(key)) {
1322
- result.push(curr);
1323
- seen.add(key);
1324
- }
1325
- }
1326
- return result;
1327
- }
1328
- //#endregion
1329
- //#region src/nodes/file.ts
1330
- /**
1331
- * Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
1332
- *
1333
- * @example Named import
1334
- * ```ts
1335
- * createImport({ name: ['useState'], path: 'react' })
1336
- * // import { useState } from 'react'
1337
- * ```
1338
- */
1339
- const createImport = nodeFactory("Import");
1340
- /**
1341
- * Creates an `ExportNode` representing a language-agnostic export/public API declaration.
1342
- *
1343
- * @example Named export
1344
- * ```ts
1345
- * createExport({ name: ['Pet'], path: './Pet' })
1346
- * // export { Pet } from './Pet'
1347
- * ```
1348
- */
1349
- const createExport = nodeFactory("Export");
1350
- /**
1351
- * Creates a `SourceNode` representing a fragment of source code within a file.
1352
- *
1353
- * @example
1354
- * ```ts
1355
- * createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')], isExportable: true })
1356
- * ```
1357
- */
1358
- const createSource = nodeFactory("Source");
1359
- /**
1360
- * Creates a fully resolved `FileNode` from a file input descriptor.
1361
- *
1362
- * Computes:
1363
- * - `id` SHA256 hash of the file path
1364
- * - `name` `baseName` without extension
1365
- * - `extname` extension extracted from `baseName`
1366
- *
1367
- * Deduplicates:
1368
- * - `sources` via `combineSources`
1369
- * - `exports` via `combineExports`
1370
- * - `imports` via `combineImports` (also filters unused imports)
1371
- *
1372
- * @throws {Error} when `baseName` has no extension.
1373
- *
1374
- * @example
1375
- * ```ts
1376
- * const file = createFile({
1377
- * baseName: 'petStore.ts',
1378
- * path: 'src/models/petStore.ts',
1379
- * sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
1380
- * imports: [createImport({ name: ['z'], path: 'zod' })],
1381
- * exports: [createExport({ name: ['Pet'], path: './petStore' })],
1382
- * })
1383
- * // file.id = SHA256 hash of 'src/models/petStore.ts'
1384
- * // file.name = 'petStore'
1385
- * // file.extname = '.ts'
1386
- * ```
1387
- *
1388
- * @example Copy a real file into the output
1389
- * ```ts
1390
- * const file = createFile({
1391
- * baseName: 'client.ts',
1392
- * path: 'src/gen/client.ts',
1393
- * copy: '/abs/path/to/templates/client.ts',
1394
- * })
1395
- * ```
1396
- */
1397
- function createFile(input) {
1398
- const extname = node_path.default.extname(input.baseName);
1399
- if (!extname) throw new Error(`No extname found for ${input.baseName}`);
1400
- const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
1401
- const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
1402
- const resolvedImports = (() => {
1403
- if (!input.imports?.length) return [];
1404
- const sourceParts = [];
1405
- const localNames = /* @__PURE__ */ new Set();
1406
- for (const item of resolvedSources) {
1407
- const extracted = item.nodes && extractStringsFromNodes(item.nodes);
1408
- if (extracted) sourceParts.push(extracted);
1409
- if (item.name) localNames.add(item.name);
1410
- }
1411
- const source = sourceParts.join("\n") || void 0;
1412
- return combineImports(input.imports, resolvedExports, source).flatMap((imp) => {
1413
- if (imp.path === input.path) return [];
1414
- if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
1415
- const kept = imp.name.filter((item) => !localNames.has(importLocalName(item)));
1416
- if (!kept.length) return [];
1417
- return [kept.length === imp.name.length ? imp : {
1418
- ...imp,
1419
- name: kept
1420
- }];
1421
- });
1422
- })();
1423
- return {
1424
- ...input,
1425
- kind: "File",
1426
- id: (0, node_crypto.hash)("sha256", input.path, "hex"),
1427
- name: node_path.default.basename(input.baseName, extname),
1428
- extname,
1429
- imports: resolvedImports,
1430
- exports: resolvedExports,
1431
- sources: resolvedSources,
1432
- meta: input.meta ?? {}
1433
- };
1434
- }
1612
+ const createContent = nodeFactory(nodeKinds.content);
1435
1613
  //#endregion
1436
1614
  //#region src/nodes/input.ts
1437
1615
  /**
@@ -1453,7 +1631,7 @@ function createInput(overrides = {}) {
1453
1631
  enumNames: []
1454
1632
  },
1455
1633
  ...overrides,
1456
- kind: "Input"
1634
+ kind: nodeKinds.input
1457
1635
  };
1458
1636
  }
1459
1637
  //#endregion
@@ -1461,7 +1639,7 @@ function createInput(overrides = {}) {
1461
1639
  /**
1462
1640
  * Creates a `RequestBodyNode`.
1463
1641
  */
1464
- const createRequestBody = nodeFactory("RequestBody");
1642
+ const createRequestBody = nodeFactory(nodeKinds.requestBody);
1465
1643
  //#endregion
1466
1644
  //#region src/nodes/operation.ts
1467
1645
  function createOperation(props) {
@@ -1472,7 +1650,7 @@ function createOperation(props) {
1472
1650
  parameters: [],
1473
1651
  responses: [],
1474
1652
  ...rest,
1475
- kind: "Operation",
1653
+ kind: nodeKinds.operation,
1476
1654
  ...isHttp ? { protocol: "http" } : {},
1477
1655
  requestBody: requestBody ? createRequestBody(requestBody) : void 0
1478
1656
  };
@@ -1499,7 +1677,7 @@ function createParameter(input) {
1499
1677
  ...input,
1500
1678
  required,
1501
1679
  schema: optionality(input.schema, required),
1502
- kind: "Parameter"
1680
+ kind: nodeKinds.parameter
1503
1681
  };
1504
1682
  }
1505
1683
  //#endregion
@@ -1524,7 +1702,7 @@ function createProperty(input) {
1524
1702
  ...input,
1525
1703
  required,
1526
1704
  schema: optionality(input.schema, required),
1527
- kind: "Property"
1705
+ kind: nodeKinds.property
1528
1706
  };
1529
1707
  }
1530
1708
  //#endregion
@@ -1551,7 +1729,7 @@ function createResponse(props) {
1551
1729
  return {
1552
1730
  ...rest,
1553
1731
  content: entries,
1554
- kind: "Response"
1732
+ kind: nodeKinds.response
1555
1733
  };
1556
1734
  }
1557
1735
  //#endregion
@@ -1586,12 +1764,12 @@ function createSchema(props) {
1586
1764
  properties: [],
1587
1765
  primitive: "object",
1588
1766
  ...props,
1589
- kind: "Schema"
1767
+ kind: nodeKinds.schema
1590
1768
  };
1591
1769
  return {
1592
1770
  primitive: TYPE_TO_PRIMITIVE[props.type],
1593
1771
  ...props,
1594
- kind: "Schema"
1772
+ kind: nodeKinds.schema
1595
1773
  };
1596
1774
  }
1597
1775
  //#endregion
@@ -1639,10 +1817,13 @@ var src_exports = /* @__PURE__ */ __exportAll({
1639
1817
  forEachSchema: () => forEachSchema,
1640
1818
  getSchemaLiteralValues: () => getSchemaLiteralValues,
1641
1819
  inferDiscriminatorPropertyName: () => inferDiscriminatorPropertyName,
1820
+ inlineFiles: () => inlineFiles,
1642
1821
  isBareRef: () => isBareRef,
1643
1822
  isHttpOperationNode: () => isHttpOperationNode,
1823
+ isVirtualFile: () => isVirtualFile,
1644
1824
  mergeRefWithSchema: () => mergeRefWithSchema,
1645
1825
  narrowSchema: () => narrowSchema,
1826
+ nodeKinds: () => nodeKinds,
1646
1827
  optionality: () => optionality,
1647
1828
  refName: () => refName,
1648
1829
  resolveRef: () => resolveRef,
@@ -1681,10 +1862,13 @@ exports.forEachChild = forEachChild;
1681
1862
  exports.forEachSchema = forEachSchema;
1682
1863
  exports.getSchemaLiteralValues = getSchemaLiteralValues;
1683
1864
  exports.inferDiscriminatorPropertyName = inferDiscriminatorPropertyName;
1865
+ exports.inlineFiles = inlineFiles;
1684
1866
  exports.isBareRef = isBareRef;
1685
1867
  exports.isHttpOperationNode = isHttpOperationNode;
1868
+ exports.isVirtualFile = isVirtualFile;
1686
1869
  exports.mergeRefWithSchema = mergeRefWithSchema;
1687
1870
  exports.narrowSchema = narrowSchema;
1871
+ exports.nodeKinds = nodeKinds;
1688
1872
  exports.optionality = optionality;
1689
1873
  exports.refName = refName;
1690
1874
  exports.resolveRef = resolveRef;