@kubb/ast 5.0.0-beta.82 → 5.0.0-beta.85

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
@@ -609,7 +609,7 @@ function extractStringsFromNodes(nodes) {
609
609
  return collected.join("\n");
610
610
  }
611
611
  //#endregion
612
- //#region src/utils/fileMerge.ts
612
+ //#region src/utils/combineFileMembers.ts
613
613
  function sourceKey(source) {
614
614
  return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
615
615
  }
@@ -841,16 +841,23 @@ const createSource = sourceDef.create;
841
841
  * ```
842
842
  */
843
843
  function createFile(input) {
844
- const extname = path.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
844
+ const extname = path.extname(input.baseName);
845
845
  if (!extname) throw new Error(`No extname found for ${input.baseName}`);
846
846
  const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
847
- let resolvedImports = [];
848
- if (input.imports?.length) {
849
- const source = extractStringsFromNodes((input.sources ?? []).flatMap((item) => item.nodes ?? [])) || void 0;
847
+ const resolvedImports = (() => {
848
+ if (!input.imports?.length) return [];
849
+ const sourceParts = [];
850
+ const localNames = /* @__PURE__ */ new Set();
851
+ for (const item of input.sources ?? []) {
852
+ const extracted = item.nodes && extractStringsFromNodes(item.nodes);
853
+ if (extracted) sourceParts.push(extracted);
854
+ if (item.name) localNames.add(item.name);
855
+ }
856
+ const source = sourceParts.join("\n") || void 0;
850
857
  const combinedImports = combineImports(input.imports, resolvedExports, source);
851
- const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
852
858
  const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
853
- resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
859
+ return combinedImports.flatMap((imp) => {
860
+ if (imp.path === input.path) return [];
854
861
  if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
855
862
  const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
856
863
  if (!kept.length) return [];
@@ -859,7 +866,7 @@ function createFile(input) {
859
866
  name: kept
860
867
  }];
861
868
  });
862
- }
869
+ })();
863
870
  const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
864
871
  return {
865
872
  kind: "File",
@@ -892,31 +899,16 @@ const inputDef = defineNode({
892
899
  visitorKey: "input"
893
900
  });
894
901
  /**
895
- * Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
896
- * `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
897
- * `schemas`/`operations`. Both variants get the defaulted `meta`.
902
+ * Creates an `InputNode`, defaulting `schemas`/`operations` to empty arrays and `meta` per
903
+ * {@link inputDef}.
898
904
  *
899
- * @example Eager
905
+ * @example
900
906
  * ```ts
901
907
  * const input = createInput()
902
908
  * // { kind: 'Input', schemas: [], operations: [] }
903
909
  * ```
904
- *
905
- * @example Streaming
906
- * ```ts
907
- * const node = createInput({ stream: true, schemas: schemasIterable, operations: operationsIterable, meta: { title: 'My API' } })
908
- * ```
909
910
  */
910
- function createInput(options = {}) {
911
- const { stream, ...overrides } = options;
912
- if (stream) return {
913
- kind: "Input",
914
- meta: {
915
- circularNames: [],
916
- enumNames: []
917
- },
918
- ...overrides
919
- };
911
+ function createInput(overrides = {}) {
920
912
  return inputDef.create(overrides);
921
913
  }
922
914
  //#endregion
@@ -1629,6 +1621,51 @@ function buildList(items, brackets = ["[", "]"]) {
1629
1621
  if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
1630
1622
  return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`;
1631
1623
  }
1624
+ /**
1625
+ * Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
1626
+ * is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
1627
+ * of a recursive schema until first access.
1628
+ *
1629
+ * @example
1630
+ * ```ts
1631
+ * lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
1632
+ * // "get parent() { return z.lazy(() => Pet) }"
1633
+ * ```
1634
+ */
1635
+ function lazyGetter({ name, body }) {
1636
+ return `get ${objectKey(name)}() { return ${body} }`;
1637
+ }
1638
+ //#endregion
1639
+ //#region src/utils/mergeAdjacentSchemas.ts
1640
+ /**
1641
+ * Merges a run of adjacent anonymous object members into one. Named or non-object members break the
1642
+ * run and pass through unchanged. The merge follows member order, so callers control which members
1643
+ * combine by where they place them in the sequence.
1644
+ *
1645
+ * @example
1646
+ * ```ts
1647
+ * const merged = [...mergeAdjacentObjectsLazy([objectA, objectB])]
1648
+ * ```
1649
+ */
1650
+ function* mergeAdjacentObjectsLazy(members) {
1651
+ let acc;
1652
+ for (const member of members) {
1653
+ const objectMember = narrowSchema(member, "object");
1654
+ if (objectMember && !objectMember.name && acc !== void 0) {
1655
+ const accObject = narrowSchema(acc, "object");
1656
+ if (accObject && !accObject.name) {
1657
+ acc = createSchema({
1658
+ ...accObject,
1659
+ properties: [...accObject.properties ?? [], ...objectMember.properties ?? []]
1660
+ });
1661
+ continue;
1662
+ }
1663
+ }
1664
+ if (acc !== void 0) yield acc;
1665
+ acc = member;
1666
+ }
1667
+ if (acc !== void 0) yield acc;
1668
+ }
1632
1669
  //#endregion
1633
1670
  //#region src/utils/refs.ts
1634
1671
  const plainStringTypes = /* @__PURE__ */ new Set([
@@ -1726,151 +1763,6 @@ function isStringType(node) {
1726
1763
  return false;
1727
1764
  }
1728
1765
  //#endregion
1729
- //#region src/utils/schemaMerge.ts
1730
- /**
1731
- * Merges a run of adjacent anonymous object members into one. Named or non-object members break the
1732
- * run and pass through unchanged. The merge follows member order, so callers control which members
1733
- * combine by where they place them in the sequence.
1734
- *
1735
- * @example
1736
- * ```ts
1737
- * const merged = [...mergeAdjacentObjectsLazy([objectA, objectB])]
1738
- * ```
1739
- */
1740
- function* mergeAdjacentObjectsLazy(members) {
1741
- let acc;
1742
- for (const member of members) {
1743
- const objectMember = narrowSchema(member, "object");
1744
- if (objectMember && !objectMember.name && acc !== void 0) {
1745
- const accObject = narrowSchema(acc, "object");
1746
- if (accObject && !accObject.name) {
1747
- acc = createSchema({
1748
- ...accObject,
1749
- properties: [...accObject.properties ?? [], ...objectMember.properties ?? []]
1750
- });
1751
- continue;
1752
- }
1753
- }
1754
- if (acc !== void 0) yield acc;
1755
- acc = member;
1756
- }
1757
- if (acc !== void 0) yield acc;
1758
- }
1759
- //#endregion
1760
- //#region src/utils/strings.ts
1761
- /**
1762
- * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
1763
- * Returns the string unchanged when no balanced quote pair is found.
1764
- *
1765
- * @example
1766
- * ```ts
1767
- * trimQuotes('"hello"') // 'hello'
1768
- * trimQuotes('hello') // 'hello'
1769
- * ```
1770
- */
1771
- function trimQuotes(text) {
1772
- if (text.length >= 2) {
1773
- const first = text[0];
1774
- const last = text[text.length - 1];
1775
- if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
1776
- }
1777
- return text;
1778
- }
1779
- /**
1780
- * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
1781
- *
1782
- * Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
1783
- * code matches the repo style without a formatter.
1784
- *
1785
- * @example
1786
- * ```ts
1787
- * stringify('hello') // "'hello'"
1788
- * stringify('"hello"') // "'hello'"
1789
- * ```
1790
- */
1791
- function stringify(value) {
1792
- if (value === void 0 || value === null) return "''";
1793
- return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
1794
- }
1795
- /**
1796
- * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,
1797
- * and the Unicode line terminators U+2028 and U+2029.
1798
- *
1799
- * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
1800
- *
1801
- * @example
1802
- * ```ts
1803
- * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
1804
- * ```
1805
- */
1806
- function jsStringEscape(input) {
1807
- return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
1808
- switch (character) {
1809
- case "\"":
1810
- case "'":
1811
- case "\\": return `\\${character}`;
1812
- case "\n": return "\\n";
1813
- case "\r": return "\\r";
1814
- case "\u2028": return "\\u2028";
1815
- case "\u2029": return "\\u2029";
1816
- default: return "";
1817
- }
1818
- });
1819
- }
1820
- /**
1821
- * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
1822
- * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
1823
- * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
1824
- *
1825
- * @example
1826
- * ```ts
1827
- * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
1828
- * toRegExpString('^(?im)foo', null) // '/^foo/im'
1829
- * ```
1830
- */
1831
- function toRegExpString(text, func = "RegExp") {
1832
- const raw = trimQuotes(text);
1833
- const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
1834
- const replacementTarget = match?.[1] ?? "";
1835
- const matchedFlags = match?.[2];
1836
- const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
1837
- const { source, flags } = new RegExp(cleaned, matchedFlags);
1838
- if (func === null) return `/${source}/${flags}`;
1839
- return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
1840
- }
1841
- /**
1842
- * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested
1843
- * objects recurse with fixed indentation, so the result drops straight into an object literal
1844
- * without re-parsing.
1845
- *
1846
- * @example
1847
- * ```ts
1848
- * stringifyObject({ foo: 'bar', nested: { a: 1 } })
1849
- * // 'foo: bar,\nnested: {\n a: 1\n }'
1850
- * ```
1851
- */
1852
- function stringifyObject(value) {
1853
- return Object.entries(value).map(([key, val]) => {
1854
- if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`;
1855
- return `${key}: ${val}`;
1856
- }).filter(Boolean).join(",\n");
1857
- }
1858
- /**
1859
- * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
1860
- * `accessor`. Returns `null` for an empty path.
1861
- *
1862
- * @example
1863
- * ```ts
1864
- * getNestedAccessor('pagination.next.id', 'lastPage')
1865
- * // "lastPage?.['pagination']?.['next']?.['id']"
1866
- * ```
1867
- */
1868
- function getNestedAccessor(param, accessor) {
1869
- const parts = Array.isArray(param) ? param : param.split(".");
1870
- if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
1871
- return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
1872
- }
1873
- //#endregion
1874
1766
  //#region src/utils/schemaGraph.ts
1875
1767
  /**
1876
1768
  * Memoized inner pass that walks a single node and returns the names of every schema it references.
@@ -1943,7 +1835,7 @@ function computeUsedSchemaNames(operations, schemas) {
1943
1835
  *
1944
1836
  * @example Only generate schemas referenced by included operations
1945
1837
  * ```ts
1946
- * const includedOps = operations.filter((op) => resolver.resolveOptions(op, { options, include }) !== null)
1838
+ * const includedOps = operations.filter((op) => resolver.default.options(op, { options, include }) !== null)
1947
1839
  * const allowed = collectUsedSchemaNames(includedOps, schemas)
1948
1840
  *
1949
1841
  * for (const schema of schemas) {
@@ -2049,19 +1941,119 @@ function mapSchemaItems(node, transform) {
2049
1941
  output: transform(schema)
2050
1942
  }));
2051
1943
  }
1944
+ //#endregion
1945
+ //#region src/utils/strings.ts
2052
1946
  /**
2053
- * Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
2054
- * is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
2055
- * of a recursive schema until first access.
1947
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
1948
+ * Returns the string unchanged when no balanced quote pair is found.
2056
1949
  *
2057
1950
  * @example
2058
1951
  * ```ts
2059
- * lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
2060
- * // "get parent() { return z.lazy(() => Pet) }"
1952
+ * trimQuotes('"hello"') // 'hello'
1953
+ * trimQuotes('hello') // 'hello'
2061
1954
  * ```
2062
1955
  */
2063
- function lazyGetter({ name, body }) {
2064
- return `get ${objectKey(name)}() { return ${body} }`;
1956
+ function trimQuotes(text) {
1957
+ if (text.length >= 2) {
1958
+ const first = text[0];
1959
+ const last = text[text.length - 1];
1960
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
1961
+ }
1962
+ return text;
1963
+ }
1964
+ /**
1965
+ * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
1966
+ *
1967
+ * Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
1968
+ * code matches the repo style without a formatter.
1969
+ *
1970
+ * @example
1971
+ * ```ts
1972
+ * stringify('hello') // "'hello'"
1973
+ * stringify('"hello"') // "'hello'"
1974
+ * ```
1975
+ */
1976
+ function stringify(value) {
1977
+ if (value === void 0 || value === null) return "''";
1978
+ return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
1979
+ }
1980
+ /**
1981
+ * Escapes characters that are not allowed inside JS string literals, covering quotes, backslashes,
1982
+ * and the Unicode line terminators U+2028 and U+2029.
1983
+ *
1984
+ * @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
1985
+ *
1986
+ * @example
1987
+ * ```ts
1988
+ * jsStringEscape('say "hi"\nbye') // 'say \\"hi\\"\\nbye'
1989
+ * ```
1990
+ */
1991
+ function jsStringEscape(input) {
1992
+ return `${input}`.replace(/["'\\\n\r\u2028\u2029]/g, (character) => {
1993
+ switch (character) {
1994
+ case "\"":
1995
+ case "'":
1996
+ case "\\": return `\\${character}`;
1997
+ case "\n": return "\\n";
1998
+ case "\r": return "\\r";
1999
+ case "\u2028": return "\\u2028";
2000
+ case "\u2029": return "\\u2029";
2001
+ default: return "";
2002
+ }
2003
+ });
2004
+ }
2005
+ /**
2006
+ * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
2007
+ * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
2008
+ * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
2009
+ *
2010
+ * @example
2011
+ * ```ts
2012
+ * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
2013
+ * toRegExpString('^(?im)foo', null) // '/^foo/im'
2014
+ * ```
2015
+ */
2016
+ function toRegExpString(text, func = "RegExp") {
2017
+ const raw = trimQuotes(text);
2018
+ const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
2019
+ const replacementTarget = match?.[1] ?? "";
2020
+ const matchedFlags = match?.[2];
2021
+ const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
2022
+ const { source, flags } = new RegExp(cleaned, matchedFlags);
2023
+ if (func === null) return `/${source}/${flags}`;
2024
+ return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
2025
+ }
2026
+ /**
2027
+ * Renders a plain object as multi-line `key: value` source for embedding in generated code. Nested
2028
+ * objects recurse with fixed indentation, so the result drops straight into an object literal
2029
+ * without re-parsing.
2030
+ *
2031
+ * @example
2032
+ * ```ts
2033
+ * stringifyObject({ foo: 'bar', nested: { a: 1 } })
2034
+ * // 'foo: bar,\nnested: {\n a: 1\n }'
2035
+ * ```
2036
+ */
2037
+ function stringifyObject(value) {
2038
+ return Object.entries(value).map(([key, val]) => {
2039
+ if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`;
2040
+ return `${key}: ${val}`;
2041
+ }).filter(Boolean).join(",\n");
2042
+ }
2043
+ /**
2044
+ * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
2045
+ * `accessor`. Returns `null` for an empty path.
2046
+ *
2047
+ * @example
2048
+ * ```ts
2049
+ * getNestedAccessor('pagination.next.id', 'lastPage')
2050
+ * // "lastPage?.['pagination']?.['next']?.['id']"
2051
+ * ```
2052
+ */
2053
+ function getNestedAccessor(param, accessor) {
2054
+ const parts = Array.isArray(param) ? param : param.split(".");
2055
+ if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
2056
+ return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
2065
2057
  }
2066
2058
  //#endregion
2067
2059
  //#region src/macros/macroDiscriminatorEnum.ts
@@ -2244,6 +2236,9 @@ var exports_exports = /* @__PURE__ */ __exportAll({
2244
2236
  childName: () => childName,
2245
2237
  collect: () => collect,
2246
2238
  collectUsedSchemaNames: () => collectUsedSchemaNames,
2239
+ combineExports: () => combineExports,
2240
+ combineImports: () => combineImports,
2241
+ combineSources: () => combineSources,
2247
2242
  composeMacros: () => composeMacros,
2248
2243
  constDef: () => constDef,
2249
2244
  containsCircularRef: () => containsCircularRef,
@@ -2300,6 +2295,6 @@ var exports_exports = /* @__PURE__ */ __exportAll({
2300
2295
  walk: () => walk
2301
2296
  });
2302
2297
  //#endregion
2303
- export { applyMacros, arrowFunctionDef, exports_exports as ast, breakDef, buildJSDoc, buildList, buildObject, childName, collect, collectUsedSchemaNames, composeMacros, constDef, containsCircularRef, contentDef, createPrinter, defineDialect, defineMacro, defineNode, enumPropName, exportDef, extractRefName, extractStringsFromNodes, factory_exports as factory, fileDef, findCircularSchemas, functionDef, getNestedAccessor, importDef, inputDef, isHttpOperationNode, isStringType, isValidVarName, jsStringEscape, jsxDef, lazyGetter, macroDiscriminatorEnum, macroEnumName, macroSimplifyUnion, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, narrowSchema, nodeDefs, objectKey, operationDef, optionality, outputDef, parameterDef, propertyDef, requestBodyDef, responseDef, schemaDef, schemaTypes, sourceDef, stringify, stringifyObject, syncSchemaRef, textDef, toRegExpString, transform, trimQuotes, typeDef, walk };
2298
+ export { applyMacros, arrowFunctionDef, exports_exports as ast, breakDef, buildJSDoc, buildList, buildObject, childName, collect, collectUsedSchemaNames, combineExports, combineImports, combineSources, composeMacros, constDef, containsCircularRef, contentDef, createPrinter, defineDialect, defineMacro, defineNode, enumPropName, exportDef, extractRefName, extractStringsFromNodes, factory_exports as factory, fileDef, findCircularSchemas, functionDef, getNestedAccessor, importDef, inputDef, isHttpOperationNode, isStringType, isValidVarName, jsStringEscape, jsxDef, lazyGetter, macroDiscriminatorEnum, macroEnumName, macroSimplifyUnion, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, mergeAdjacentObjectsLazy, narrowSchema, nodeDefs, objectKey, operationDef, optionality, outputDef, parameterDef, propertyDef, requestBodyDef, responseDef, schemaDef, schemaTypes, sourceDef, stringify, stringifyObject, syncSchemaRef, textDef, toRegExpString, transform, trimQuotes, typeDef, walk };
2304
2299
 
2305
2300
  //# sourceMappingURL=index.js.map