@kubb/ast 5.0.0-beta.17 → 5.0.0-beta.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/ast",
3
- "version": "5.0.0-beta.17",
3
+ "version": "5.0.0-beta.19",
4
4
  "description": "Spec-agnostic AST layer for Kubb. Defines the node tree, visitor pattern, factory functions, and type guards used across all code generation plugins.",
5
5
  "keywords": [
6
6
  "ast",
@@ -154,6 +154,10 @@ type SchemaNodeBase = BaseNode & {
154
154
  * For example, this is `'string'` for a `uuid` schema.
155
155
  */
156
156
  primitive?: PrimitiveSchemaType
157
+ /**
158
+ * Schema `format` value.
159
+ */
160
+ format?: string
157
161
  }
158
162
 
159
163
  /**
package/src/utils.ts CHANGED
@@ -74,16 +74,26 @@ export function isStringType(node: SchemaNode): boolean {
74
74
  * the desired casing while preserving `OperationNode.parameters` for other consumers.
75
75
  * The input array is not mutated. When `casing` is not set, the original array is returned unchanged.
76
76
  */
77
+ const caseParamsCache = new WeakMap<Array<ParameterNode>, Map<string, Array<ParameterNode>>>()
78
+
77
79
  export function caseParams(params: Array<ParameterNode>, casing: 'camelcase' | undefined): Array<ParameterNode> {
78
- if (!casing) {
79
- return params
80
+ if (!casing) return params
81
+
82
+ let byParams = caseParamsCache.get(params)
83
+ if (!byParams) {
84
+ byParams = new Map()
85
+ caseParamsCache.set(params, byParams)
80
86
  }
87
+ const cached = byParams.get(casing)
88
+ if (cached) return cached
81
89
 
82
- return params.map((param) => {
90
+ const result = params.map((param) => {
83
91
  const transformed = casing === 'camelcase' || !isValidVarName(param.name) ? camelCase(param.name) : param.name
84
-
85
92
  return { ...param, name: transformed }
86
93
  })
94
+
95
+ byParams.set(casing, result)
96
+ return result
87
97
  }
88
98
 
89
99
  /**
@@ -723,13 +733,18 @@ export function extractStringsFromNodes(nodes: Array<CodeNode> | undefined): str
723
733
  if (node.kind === 'Text') return node.value
724
734
  if (node.kind === 'Break') return ''
725
735
  if (node.kind === 'Jsx') return node.value
736
+
726
737
  const parts: string[] = []
738
+
727
739
  if ('params' in node && node.params) parts.push(node.params)
728
740
  if ('generics' in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(', ') : node.generics)
729
741
  if ('returnType' in node && node.returnType) parts.push(node.returnType)
730
742
  if ('type' in node && typeof node.type === 'string') parts.push(node.type)
743
+
731
744
  const nested = extractStringsFromNodes(node.nodes)
745
+
732
746
  if (nested) parts.push(nested)
747
+
733
748
  return parts.join('\n')
734
749
  })
735
750
  .filter(Boolean)
@@ -828,12 +843,20 @@ export function collectReferencedSchemaNames(node: SchemaNode | undefined, out:
828
843
  * allowed.has('OrderStatus') // false when no included operation references OrderStatus
829
844
  * ```
830
845
  */
846
+ const usedSchemaNamesCache = new WeakMap<ReadonlyArray<OperationNode>, WeakMap<ReadonlyArray<SchemaNode>, Set<string>>>()
847
+
831
848
  export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>, schemas: ReadonlyArray<SchemaNode>): Set<string> {
849
+ let byOps = usedSchemaNamesCache.get(operations)
850
+ if (!byOps) {
851
+ byOps = new WeakMap()
852
+ usedSchemaNamesCache.set(operations, byOps)
853
+ }
854
+ const cached = byOps.get(schemas)
855
+ if (cached) return cached
856
+
832
857
  const schemaMap = new Map<string, SchemaNode>()
833
858
  for (const schema of schemas) {
834
- if (schema.name) {
835
- schemaMap.set(schema.name, schema)
836
- }
859
+ if (schema.name) schemaMap.set(schema.name, schema)
837
860
  }
838
861
 
839
862
  const result = new Set<string>()
@@ -844,9 +867,7 @@ export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>,
844
867
  if (!result.has(name)) {
845
868
  result.add(name)
846
869
  const namedSchema = schemaMap.get(name)
847
- if (namedSchema) {
848
- visitSchema(namedSchema)
849
- }
870
+ if (namedSchema) visitSchema(namedSchema)
850
871
  }
851
872
  }
852
873
  }
@@ -857,9 +878,13 @@ export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>,
857
878
  }
858
879
  }
859
880
 
881
+ byOps.set(schemas, result)
860
882
  return result
861
883
  }
862
884
 
885
+ const EMPTY_CIRCULAR_SET = new Set<string>()
886
+ const circularSchemaCache = new WeakMap<ReadonlyArray<SchemaNode>, Set<string>>()
887
+
863
888
  /**
864
889
  * Identifies all schemas that participate in circular dependency chains, including direct self-loops.
865
890
  *
@@ -870,6 +895,11 @@ export function collectUsedSchemaNames(operations: ReadonlyArray<OperationNode>,
870
895
  * @note Call this once on the full schema graph, then use `containsCircularRef()` to check individual schemas.
871
896
  */
872
897
  export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<string> {
898
+ if (schemas.length === 0) return EMPTY_CIRCULAR_SET
899
+
900
+ const cached = circularSchemaCache.get(schemas)
901
+ if (cached) return cached
902
+
873
903
  const graph = new Map<string, Set<string>>()
874
904
 
875
905
  for (const schema of schemas) {
@@ -895,6 +925,7 @@ export function findCircularSchemas(schemas: ReadonlyArray<SchemaNode>): Set<str
895
925
  }
896
926
  }
897
927
 
928
+ circularSchemaCache.set(schemas, circular)
898
929
  return circular
899
930
  }
900
931
 
package/src/visitor.ts CHANGED
@@ -407,11 +407,7 @@ export function transform(node: Node, options: TransformOptions): Node {
407
407
 
408
408
  switch (node.kind) {
409
409
  case 'Input': {
410
- let input = node
411
- const replaced = visitor.input?.(input, {
412
- parent: parent as ParentOf<InputNode>,
413
- })
414
- if (replaced) input = replaced
410
+ const input = visitor.input?.(node, { parent: parent as ParentOf<InputNode> }) ?? node
415
411
 
416
412
  return {
417
413
  ...input,
@@ -420,20 +416,11 @@ export function transform(node: Node, options: TransformOptions): Node {
420
416
  }
421
417
  }
422
418
  case 'Output': {
423
- let output = node
424
- const replaced = visitor.output?.(output, {
425
- parent: parent as ParentOf<OutputNode>,
426
- })
427
- if (replaced) output = replaced
428
-
419
+ const output = visitor.output?.(node, { parent: parent as ParentOf<OutputNode> }) ?? node
429
420
  return output
430
421
  }
431
422
  case 'Operation': {
432
- let op = node
433
- const replaced = visitor.operation?.(op, {
434
- parent: parent as ParentOf<OperationNode>,
435
- })
436
- if (replaced) op = replaced
423
+ const op = visitor.operation?.(node, { parent: parent as ParentOf<OperationNode> }) ?? node
437
424
 
438
425
  return {
439
426
  ...op,
@@ -451,11 +438,7 @@ export function transform(node: Node, options: TransformOptions): Node {
451
438
  }
452
439
  }
453
440
  case 'Schema': {
454
- let schema = node
455
- const replaced = visitor.schema?.(schema, {
456
- parent: parent as ParentOf<SchemaNode>,
457
- })
458
- if (replaced) schema = replaced
441
+ const schema = visitor.schema?.(node, { parent: parent as ParentOf<SchemaNode> }) ?? node
459
442
 
460
443
  const childOptions = { ...options, parent: schema }
461
444
 
@@ -476,11 +459,7 @@ export function transform(node: Node, options: TransformOptions): Node {
476
459
  } as SchemaNode
477
460
  }
478
461
  case 'Property': {
479
- let prop = node
480
- const replaced = visitor.property?.(prop, {
481
- parent: parent as ParentOf<PropertyNode>,
482
- })
483
- if (replaced) prop = replaced
462
+ const prop = visitor.property?.(node, { parent: parent as ParentOf<PropertyNode> }) ?? node
484
463
 
485
464
  return createProperty({
486
465
  ...prop,
@@ -488,11 +467,7 @@ export function transform(node: Node, options: TransformOptions): Node {
488
467
  })
489
468
  }
490
469
  case 'Parameter': {
491
- let param = node
492
- const replaced = visitor.parameter?.(param, {
493
- parent: parent as ParentOf<ParameterNode>,
494
- })
495
- if (replaced) param = replaced
470
+ const param = visitor.parameter?.(node, { parent: parent as ParentOf<ParameterNode> }) ?? node
496
471
 
497
472
  return createParameter({
498
473
  ...param,
@@ -500,11 +475,7 @@ export function transform(node: Node, options: TransformOptions): Node {
500
475
  })
501
476
  }
502
477
  case 'Response': {
503
- let response = node
504
- const replaced = visitor.response?.(response, {
505
- parent: parent as ParentOf<ResponseNode>,
506
- })
507
- if (replaced) response = replaced
478
+ const response = visitor.response?.(node, { parent: parent as ParentOf<ResponseNode> }) ?? node
508
479
 
509
480
  return {
510
481
  ...response,