@kubb/ast 5.0.0-beta.31 → 5.0.0-beta.33

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,4 +1,4 @@
1
- import "./chunk--u3MIqq1.js";
1
+ import "./chunk-C0LytTxp.js";
2
2
  import { createHash } from "node:crypto";
3
3
  import path from "node:path";
4
4
  //#region src/constants.ts
@@ -6,25 +6,6 @@ const visitorDepths = {
6
6
  shallow: "shallow",
7
7
  deep: "deep"
8
8
  };
9
- const nodeKinds = {
10
- input: "Input",
11
- output: "Output",
12
- operation: "Operation",
13
- schema: "Schema",
14
- property: "Property",
15
- parameter: "Parameter",
16
- response: "Response",
17
- functionParameter: "FunctionParameter",
18
- parameterGroup: "ParameterGroup",
19
- functionParameters: "FunctionParameters",
20
- type: "Type",
21
- file: "File",
22
- import: "Import",
23
- export: "Export",
24
- source: "Source",
25
- text: "Text",
26
- break: "Break"
27
- };
28
9
  /**
29
10
  * Schema type discriminators used by all AST schema nodes.
30
11
  *
@@ -173,33 +154,6 @@ const httpMethods = {
173
154
  options: "OPTIONS",
174
155
  trace: "TRACE"
175
156
  };
176
- /**
177
- * Common MIME types used in request/response content negotiation.
178
- *
179
- * Covers JSON, XML, form data, PDFs, images, audio, and video formats.
180
- * Use these as keys when serializing request/response bodies.
181
- */
182
- const mediaTypes = {
183
- applicationJson: "application/json",
184
- applicationXml: "application/xml",
185
- applicationFormUrlEncoded: "application/x-www-form-urlencoded",
186
- applicationOctetStream: "application/octet-stream",
187
- applicationPdf: "application/pdf",
188
- applicationZip: "application/zip",
189
- applicationGraphql: "application/graphql",
190
- multipartFormData: "multipart/form-data",
191
- textPlain: "text/plain",
192
- textHtml: "text/html",
193
- textCsv: "text/csv",
194
- textXml: "text/xml",
195
- imagePng: "image/png",
196
- imageJpeg: "image/jpeg",
197
- imageGif: "image/gif",
198
- imageWebp: "image/webp",
199
- imageSvgXml: "image/svg+xml",
200
- audioMpeg: "audio/mpeg",
201
- videoMp4: "video/mp4"
202
- };
203
157
  //#endregion
204
158
  //#region ../../internals/utils/src/casing.ts
205
159
  /**
@@ -442,28 +396,6 @@ function isKind(kind) {
442
396
  return (node) => node.kind === kind;
443
397
  }
444
398
  /**
445
- * Returns `true` when the input is an `InputNode`.
446
- *
447
- * @example
448
- * ```ts
449
- * if (isInputNode(node)) {
450
- * console.log(node.schemas.length)
451
- * }
452
- * ```
453
- */
454
- const isInputNode = isKind("Input");
455
- /**
456
- * Returns `true` when the input is an `OutputNode`.
457
- *
458
- * @example
459
- * ```ts
460
- * if (isOutputNode(node)) {
461
- * console.log(node.files.length)
462
- * }
463
- * ```
464
- */
465
- const isOutputNode = isKind("Output");
466
- /**
467
399
  * Returns `true` when the input is an `OperationNode`.
468
400
  *
469
401
  * @example
@@ -654,8 +586,9 @@ async function walk(node, options) {
654
586
  }
655
587
  async function _walk(node, visitor, recurse, limit, parent) {
656
588
  await limit(() => applyVisitor(node, visitor, parent));
657
- const children = getChildren(node, recurse);
658
- for (const child of children) await _walk(child, visitor, recurse, limit, node);
589
+ const children = Array.from(getChildren(node, recurse));
590
+ if (children.length === 0) return;
591
+ await Promise.all(children.map((child) => _walk(child, visitor, recurse, limit, node)));
659
592
  }
660
593
  function transform(node, options) {
661
594
  const { depth, parent, ...visitor } = options;
@@ -2074,66 +2007,245 @@ function refTargetName(node) {
2074
2007
  if (node.ref) return extractRefName(node.ref);
2075
2008
  return node.name ?? "";
2076
2009
  }
2077
- /**
2078
- * Builds the local, shape-only descriptor for a node: its kind, flags, constraints, and its
2079
- * children's signatures. {@link signatureOf} hashes this string; children contribute their
2080
- * fixed-length signature rather than their own full descriptor, which keeps the result bounded.
2081
- */
2082
- function describeShape(node, signatures) {
2083
- const flags = flagsDescriptor(node);
2084
- switch (node.type) {
2085
- case "object": {
2086
- const props = (node.properties ?? []).map((prop) => `${prop.name}${prop.required ? "!" : "?"}${signatureOf(prop.schema, signatures)}`).join(",");
2087
- let additional = "";
2088
- if (typeof node.additionalProperties === "boolean") additional = `ab:${node.additionalProperties}`;
2089
- else if (node.additionalProperties) additional = `as:${signatureOf(node.additionalProperties, signatures)}`;
2090
- const pattern = node.patternProperties ? Object.keys(node.patternProperties).sort().map((key) => `${key}=${signatureOf(node.patternProperties[key], signatures)}`).join(",") : "";
2091
- return `object|${flags}|p[${props}]|${additional}|pp[${pattern}]|mn:${node.minProperties ?? ""}|mx:${node.maxProperties ?? ""}`;
2010
+ const arrayTupleFields = [
2011
+ {
2012
+ kind: "children",
2013
+ key: "items",
2014
+ prefix: "i"
2015
+ },
2016
+ {
2017
+ kind: "child",
2018
+ key: "rest",
2019
+ prefix: "r"
2020
+ },
2021
+ {
2022
+ kind: "scalar",
2023
+ key: "min",
2024
+ prefix: "mn"
2025
+ },
2026
+ {
2027
+ kind: "scalar",
2028
+ key: "max",
2029
+ prefix: "mx"
2030
+ },
2031
+ {
2032
+ kind: "bool",
2033
+ key: "unique",
2034
+ prefix: "u"
2035
+ }
2036
+ ];
2037
+ const numericFields = [
2038
+ {
2039
+ kind: "scalar",
2040
+ key: "min",
2041
+ prefix: "mn"
2042
+ },
2043
+ {
2044
+ kind: "scalar",
2045
+ key: "max",
2046
+ prefix: "mx"
2047
+ },
2048
+ {
2049
+ kind: "scalar",
2050
+ key: "exclusiveMinimum",
2051
+ prefix: "emn"
2052
+ },
2053
+ {
2054
+ kind: "scalar",
2055
+ key: "exclusiveMaximum",
2056
+ prefix: "emx"
2057
+ },
2058
+ {
2059
+ kind: "scalar",
2060
+ key: "multipleOf",
2061
+ prefix: "mo"
2062
+ }
2063
+ ];
2064
+ const rangeFields = [{
2065
+ kind: "scalar",
2066
+ key: "min",
2067
+ prefix: "mn"
2068
+ }, {
2069
+ kind: "scalar",
2070
+ key: "max",
2071
+ prefix: "mx"
2072
+ }];
2073
+ /**
2074
+ * Maps each schema node `type` to the ordered list of shape-contributing fields.
2075
+ * Node types absent from this map (scalar types like boolean, null, any, etc.) fall
2076
+ * back to `${type}|${flags}` with no additional fields.
2077
+ */
2078
+ const SHAPE_KEYS = {
2079
+ object: [
2080
+ { kind: "objectProps" },
2081
+ { kind: "additionalProps" },
2082
+ { kind: "patternProps" },
2083
+ {
2084
+ kind: "scalar",
2085
+ key: "minProperties",
2086
+ prefix: "mn"
2087
+ },
2088
+ {
2089
+ kind: "scalar",
2090
+ key: "maxProperties",
2091
+ prefix: "mx"
2092
2092
  }
2093
- case "array":
2094
- case "tuple": {
2095
- const items = (node.items ?? []).map((item) => signatureOf(item, signatures)).join(",");
2096
- const rest = node.rest ? signatureOf(node.rest, signatures) : "";
2097
- return `${node.type}|${flags}|i[${items}]|r:${rest}|mn:${node.min ?? ""}|mx:${node.max ?? ""}|u:${node.unique ? 1 : 0}`;
2093
+ ],
2094
+ array: arrayTupleFields,
2095
+ tuple: arrayTupleFields,
2096
+ union: [
2097
+ {
2098
+ kind: "scalar",
2099
+ key: "strategy",
2100
+ prefix: "s"
2101
+ },
2102
+ {
2103
+ kind: "scalar",
2104
+ key: "discriminatorPropertyName",
2105
+ prefix: "d"
2106
+ },
2107
+ {
2108
+ kind: "children",
2109
+ key: "members",
2110
+ prefix: "m"
2098
2111
  }
2099
- case "union": {
2100
- const members = (node.members ?? []).map((member) => signatureOf(member, signatures)).join(",");
2101
- return `union|${flags}|s:${node.strategy ?? ""}|d:${node.discriminatorPropertyName ?? ""}|m[${members}]`;
2112
+ ],
2113
+ intersection: [{
2114
+ kind: "children",
2115
+ key: "members",
2116
+ prefix: "m"
2117
+ }],
2118
+ enum: [{ kind: "enumValues" }],
2119
+ ref: [{ kind: "refTarget" }],
2120
+ string: [
2121
+ {
2122
+ kind: "scalar",
2123
+ key: "min",
2124
+ prefix: "mn"
2125
+ },
2126
+ {
2127
+ kind: "scalar",
2128
+ key: "max",
2129
+ prefix: "mx"
2130
+ },
2131
+ {
2132
+ kind: "scalar",
2133
+ key: "pattern",
2134
+ prefix: "pt"
2135
+ }
2136
+ ],
2137
+ number: numericFields,
2138
+ integer: numericFields,
2139
+ bigint: numericFields,
2140
+ url: [
2141
+ {
2142
+ kind: "scalar",
2143
+ key: "path",
2144
+ prefix: "path"
2145
+ },
2146
+ {
2147
+ kind: "scalar",
2148
+ key: "min",
2149
+ prefix: "mn"
2150
+ },
2151
+ {
2152
+ kind: "scalar",
2153
+ key: "max",
2154
+ prefix: "mx"
2155
+ }
2156
+ ],
2157
+ uuid: rangeFields,
2158
+ email: rangeFields,
2159
+ datetime: [{
2160
+ kind: "bool",
2161
+ key: "offset",
2162
+ prefix: "o"
2163
+ }, {
2164
+ kind: "bool",
2165
+ key: "local",
2166
+ prefix: "l"
2167
+ }],
2168
+ date: [{
2169
+ kind: "scalar",
2170
+ key: "representation",
2171
+ prefix: "rep"
2172
+ }],
2173
+ time: [{
2174
+ kind: "scalar",
2175
+ key: "representation",
2176
+ prefix: "rep"
2177
+ }]
2178
+ };
2179
+ function serializeShapeField(field, node, record) {
2180
+ switch (field.kind) {
2181
+ case "scalar": return `${field.prefix}:${record[field.key] ?? ""}`;
2182
+ case "bool": return `${field.prefix}:${record[field.key] ? 1 : 0}`;
2183
+ case "child": {
2184
+ const child = record[field.key];
2185
+ return `${field.prefix}:${child ? signatureOf(child) : ""}`;
2102
2186
  }
2103
- case "intersection": return `intersection|${flags}|m[${(node.members ?? []).map((member) => signatureOf(member, signatures)).join(",")}]`;
2104
- case "enum": {
2187
+ case "children": {
2188
+ const children = record[field.key] ?? [];
2189
+ return `${field.prefix}[${children.map((c) => signatureOf(c)).join(",")}]`;
2190
+ }
2191
+ case "objectProps": return `p[${(node.properties ?? []).map((prop) => `${prop.name}${prop.required ? "!" : "?"}${signatureOf(prop.schema)}`).join(",")}]`;
2192
+ case "additionalProps": {
2193
+ const obj = node;
2194
+ if (typeof obj.additionalProperties === "boolean") return `ab:${obj.additionalProperties}`;
2195
+ if (obj.additionalProperties) return `as:${signatureOf(obj.additionalProperties)}`;
2196
+ return "";
2197
+ }
2198
+ case "patternProps": {
2199
+ const obj = node;
2200
+ return `pp[${obj.patternProperties ? Object.keys(obj.patternProperties).sort().map((key) => `${key}=${signatureOf(obj.patternProperties[key])}`).join(",") : ""}]`;
2201
+ }
2202
+ case "enumValues": {
2203
+ const en = node;
2105
2204
  let values = "";
2106
- if (node.namedEnumValues?.length) values = node.namedEnumValues.map((entry) => `${entry.name}=${entry.primitive}:${String(entry.value)}`).join(",");
2107
- else if (node.enumValues?.length) values = node.enumValues.map((value) => `${value === null ? "null" : typeof value}:${String(value)}`).join(",");
2108
- return `enum|${flags}|v[${values}]`;
2205
+ if (en.namedEnumValues?.length) values = en.namedEnumValues.map((entry) => `${entry.name}=${entry.primitive}:${String(entry.value)}`).join(",");
2206
+ else if (en.enumValues?.length) values = en.enumValues.map((value) => `${value === null ? "null" : typeof value}:${String(value)}`).join(",");
2207
+ return `v[${values}]`;
2109
2208
  }
2110
- case "ref": return `ref|${flags}|->${refTargetName(node)}`;
2111
- case "string": return `string|${flags}|mn:${node.min ?? ""}|mx:${node.max ?? ""}|pt:${node.pattern ?? ""}`;
2112
- case "number":
2113
- case "integer":
2114
- case "bigint": return `${node.type}|${flags}|mn:${node.min ?? ""}|mx:${node.max ?? ""}|emn:${node.exclusiveMinimum ?? ""}|emx:${node.exclusiveMaximum ?? ""}|mo:${node.multipleOf ?? ""}`;
2115
- case "url": return `url|${flags}|path:${node.path ?? ""}|mn:${node.min ?? ""}|mx:${node.max ?? ""}`;
2116
- case "uuid":
2117
- case "email": return `${node.type}|${flags}|mn:${node.min ?? ""}|mx:${node.max ?? ""}`;
2118
- case "datetime": return `datetime|${flags}|o:${node.offset ? 1 : 0}|l:${node.local ? 1 : 0}`;
2119
- case "date":
2120
- case "time": return `${node.type}|${flags}|rep:${node.representation}`;
2121
- default: return `${node.type}|${flags}`;
2209
+ case "refTarget": return `->${refTargetName(node)}`;
2122
2210
  }
2123
2211
  }
2124
2212
  /**
2213
+ * Builds the local, shape-only descriptor for a node: its kind, flags, constraints, and its
2214
+ * children's signatures. {@link signatureOf} hashes this string; children contribute their
2215
+ * fixed-length signature rather than their own full descriptor, which keeps the result bounded.
2216
+ */
2217
+ function describeShape(node) {
2218
+ const flags = flagsDescriptor(node);
2219
+ const fields = SHAPE_KEYS[node.type];
2220
+ if (!fields) return `${node.type}|${flags}`;
2221
+ const record = node;
2222
+ const parts = [`${node.type}|${flags}`];
2223
+ for (const field of fields) parts.push(serializeShapeField(field, node, record));
2224
+ return parts.join("|");
2225
+ }
2226
+ /**
2227
+ * Persistent hash-consing cache: `SchemaNode` → signature digest, keyed by node identity.
2228
+ *
2229
+ * A `WeakMap` so entries are released once the node is garbage-collected, and so a node hashed
2230
+ * during dedupe planning is not re-hashed when the same tree is rewritten during streaming
2231
+ * (where `schemaSignature` and `applyDedupe` would otherwise each walk it from scratch). Reuse
2232
+ * across calls is sound because a signature depends only on a node's content, and schema nodes
2233
+ * are immutable once created — transforms allocate new objects rather than mutating in place.
2234
+ */
2235
+ const signatureCache = /* @__PURE__ */ new WeakMap();
2236
+ /**
2125
2237
  * Hash-consing: each node's signature is a fixed-length digest of its local shape plus its
2126
2238
  * children's digests (a Merkle hash). Children contribute their 64-char hash instead of their
2127
2239
  * full nested descriptor, so a signature stays bounded regardless of subtree depth, and the
2128
2240
  * digest is identical across calls because it depends only on content — never on traversal
2129
2241
  * order. This keeps the keys built during planning consistent with the ones recomputed later
2130
- * during streaming. `signatures` memoizes node → digest within a single computation.
2242
+ * during streaming. {@link signatureCache} memoizes node → digest across every computation.
2131
2243
  */
2132
- function signatureOf(node, signatures) {
2133
- const cached = signatures.get(node);
2244
+ function signatureOf(node) {
2245
+ const cached = signatureCache.get(node);
2134
2246
  if (cached !== void 0) return cached;
2135
- const signature = createHash("sha256").update(describeShape(node, signatures)).digest("hex");
2136
- signatures.set(node, signature);
2247
+ const signature = createHash("sha256").update(describeShape(node)).digest("hex");
2248
+ signatureCache.set(node, signature);
2137
2249
  return signature;
2138
2250
  }
2139
2251
  /**
@@ -2152,18 +2264,7 @@ function signatureOf(node, signatures) {
2152
2264
  * ```
2153
2265
  */
2154
2266
  function schemaSignature(node) {
2155
- return signatureOf(node, /* @__PURE__ */ new Map());
2156
- }
2157
- /**
2158
- * Returns `true` when two schema nodes are structurally identical under shape-only equality.
2159
- *
2160
- * @example
2161
- * ```ts
2162
- * isSchemaEqual(a, b) // a and b produce the same TypeScript type
2163
- * ```
2164
- */
2165
- function isSchemaEqual(a, b) {
2166
- return schemaSignature(a) === schemaSignature(b);
2267
+ return signatureOf(node);
2167
2268
  }
2168
2269
  //#endregion
2169
2270
  //#region src/dedupe.ts
@@ -2188,10 +2289,9 @@ function createRefNode(node, canonical) {
2188
2289
  }
2189
2290
  function applyDedupe(node, canonicalBySignature, skipRootMatch = false) {
2190
2291
  if (canonicalBySignature.size === 0) return node;
2191
- const signatures = /* @__PURE__ */ new Map();
2192
2292
  const root = node;
2193
2293
  return transform(node, { schema(schemaNode) {
2194
- const signature = signatureOf(schemaNode, signatures);
2294
+ const signature = signatureOf(schemaNode);
2195
2295
  if (skipRootMatch && schemaNode === root) return void 0;
2196
2296
  const canonical = canonicalBySignature.get(signature);
2197
2297
  if (!canonical) return void 0;
@@ -2229,11 +2329,10 @@ function cleanDefinition(node, name) {
2229
2329
  */
2230
2330
  function buildDedupePlan(roots, options) {
2231
2331
  const { isCandidate, nameFor, refFor, minOccurrences = 2 } = options;
2232
- const signatures = /* @__PURE__ */ new Map();
2233
2332
  const topLevelNodes = /* @__PURE__ */ new Set();
2234
2333
  const groups = /* @__PURE__ */ new Map();
2235
2334
  function record(schemaNode) {
2236
- const signature = signatureOf(schemaNode, signatures);
2335
+ const signature = signatureOf(schemaNode);
2237
2336
  if (!isCandidate(schemaNode)) return;
2238
2337
  const isTopLevel = topLevelNodes.has(schemaNode) && !!schemaNode.name;
2239
2338
  const group = groups.get(signature);
@@ -2506,9 +2605,6 @@ function* mergeAdjacentObjectsLazy(members) {
2506
2605
  }
2507
2606
  if (acc !== void 0) yield acc;
2508
2607
  }
2509
- function mergeAdjacentObjects(members) {
2510
- return [...mergeAdjacentObjectsLazy(members)];
2511
- }
2512
2608
  /**
2513
2609
  * Removes enum members that are covered by broader scalar primitives in the same union.
2514
2610
  *
@@ -2548,6 +2644,6 @@ function setEnumName(propNode, parentName, propName, enumSuffix) {
2548
2644
  return propNode;
2549
2645
  }
2550
2646
  //#endregion
2551
- export { applyDedupe, buildDedupePlan, caseParams, childName, collect, collectImports, collectLazy, collectReferencedSchemaNames, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createContent, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createRequestBody, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, dispatch, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isHttpOperationNode, isInputNode, isOperationNode, isOutputNode, isScalarPrimitive, isSchemaEqual, isSchemaNode, isStringType, mediaTypes, mergeAdjacentObjects, mergeAdjacentObjectsLazy, narrowSchema, nodeKinds, resolveRefName, schemaSignature, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk };
2647
+ export { applyDedupe, buildDedupePlan, caseParams, childName, collect, collectImports, collectUsedSchemaNames, containsCircularRef, createArrowFunction, createBreak, createConst, createDiscriminantNode, createExport, createFile, createFunction, createFunctionParameter, createFunctionParameters, createImport, createInput, createJsx, createOperation, createOperationParams, createOutput, createParameter, createParameterGroup, createParamsType, createPrinterFactory, createProperty, createResponse, createSchema, createSource, createStreamInput, createText, createType, definePrinter, defineSchemaDialect, dispatch, enumPropName, extractRefName, extractStringsFromNodes, findCircularSchemas, findDiscriminator, httpMethods, isHttpOperationNode, isOperationNode, isSchemaNode, isStringType, mergeAdjacentObjectsLazy, narrowSchema, schemaSignature, schemaTypes, setDiscriminatorEnum, setEnumName, simplifyUnion, syncOptionality, syncSchemaRef, transform, update, walk };
2552
2648
 
2553
2649
  //# sourceMappingURL=index.js.map