@kubb/core 3.0.0-alpha.3 → 3.0.0-alpha.31

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.
Files changed (112) hide show
  1. package/README.md +13 -4
  2. package/dist/{FileManager-BW--rO8q.d.ts → FileManager-Dnafk2I5.d.ts} +146 -92
  3. package/dist/{FileManager-Bw-FNS3q.d.cts → FileManager-U5yCmg00.d.cts} +146 -92
  4. package/dist/chunk-2EU7DMPM.js +96 -0
  5. package/dist/chunk-2EU7DMPM.js.map +1 -0
  6. package/dist/{chunk-34BPAXR2.cjs → chunk-2UQARE2O.cjs} +54 -37
  7. package/dist/chunk-2UQARE2O.cjs.map +1 -0
  8. package/dist/chunk-4X5FFJPJ.js +8 -13
  9. package/dist/chunk-4X5FFJPJ.js.map +1 -1
  10. package/dist/{chunk-3OXCZ5DJ.js → chunk-E6CN2CZC.js} +63 -54
  11. package/dist/chunk-E6CN2CZC.js.map +1 -0
  12. package/dist/{chunk-25NKJ3DV.js → chunk-HBQM723K.js} +13 -27
  13. package/dist/chunk-HBQM723K.js.map +1 -0
  14. package/dist/{chunk-LM2YQC3T.cjs → chunk-LLKRRIBF.cjs} +81 -51
  15. package/dist/chunk-LLKRRIBF.cjs.map +1 -0
  16. package/dist/chunk-MD2LDZ3Z.js +889 -0
  17. package/dist/chunk-MD2LDZ3Z.js.map +1 -0
  18. package/dist/chunk-OX2X7B4Z.cjs +101 -0
  19. package/dist/chunk-OX2X7B4Z.cjs.map +1 -0
  20. package/dist/{chunk-67C6RBGQ.cjs → chunk-RIW2LFFQ.cjs} +28 -29
  21. package/dist/chunk-RIW2LFFQ.cjs.map +1 -0
  22. package/dist/chunk-SX5FHSVT.cjs +1532 -0
  23. package/dist/chunk-SX5FHSVT.cjs.map +1 -0
  24. package/dist/chunk-VBGWLAET.cjs +42 -0
  25. package/dist/chunk-VBGWLAET.cjs.map +1 -0
  26. package/dist/index.cjs +553 -619
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +7 -22
  29. package/dist/index.d.ts +7 -22
  30. package/dist/index.js +444 -525
  31. package/dist/index.js.map +1 -1
  32. package/dist/{logger-DChjnJMn.d.cts → logger-DvbHXjIO.d.cts} +29 -19
  33. package/dist/{logger-DChjnJMn.d.ts → logger-DvbHXjIO.d.ts} +29 -19
  34. package/dist/logger.cjs +25 -15
  35. package/dist/logger.cjs.map +1 -1
  36. package/dist/logger.d.cts +1 -2
  37. package/dist/logger.d.ts +1 -2
  38. package/dist/logger.js +3 -15
  39. package/dist/logger.js.map +1 -1
  40. package/dist/mocks.cjs +42 -31
  41. package/dist/mocks.cjs.map +1 -1
  42. package/dist/mocks.d.cts +7 -9
  43. package/dist/mocks.d.ts +7 -9
  44. package/dist/mocks.js +35 -33
  45. package/dist/mocks.js.map +1 -1
  46. package/dist/{prompt-6FWP747F.cjs → prompt-2PN2F25D.cjs} +89 -89
  47. package/dist/prompt-2PN2F25D.cjs.map +1 -0
  48. package/dist/{prompt-HK3MWREM.js → prompt-WQQUN22Z.js} +9 -15
  49. package/dist/prompt-WQQUN22Z.js.map +1 -0
  50. package/dist/transformers.cjs +216 -49
  51. package/dist/transformers.cjs.map +1 -1
  52. package/dist/transformers.d.cts +2 -4
  53. package/dist/transformers.d.ts +2 -4
  54. package/dist/transformers.js +149 -35
  55. package/dist/transformers.js.map +1 -1
  56. package/dist/utils.cjs +65 -26
  57. package/dist/utils.cjs.map +1 -1
  58. package/dist/utils.d.cts +29 -3
  59. package/dist/utils.d.ts +29 -3
  60. package/dist/utils.js +3 -26
  61. package/dist/utils.js.map +1 -1
  62. package/package.json +11 -14
  63. package/src/BarrelManager.ts +95 -109
  64. package/src/{Generator.ts → BaseGenerator.ts} +1 -1
  65. package/src/FileManager.ts +199 -304
  66. package/src/PackageManager.ts +1 -1
  67. package/src/PluginManager.ts +152 -93
  68. package/src/PromiseManager.ts +1 -1
  69. package/src/__snapshots__/barrel.json +73 -0
  70. package/src/__snapshots__/grouped.json +120 -0
  71. package/src/__snapshots__/ordered.json +68 -0
  72. package/src/build.ts +86 -131
  73. package/src/config.ts +2 -4
  74. package/src/errors.ts +0 -11
  75. package/src/index.ts +2 -3
  76. package/src/logger.ts +76 -34
  77. package/src/plugin.ts +2 -5
  78. package/src/transformers/escape.ts +0 -10
  79. package/src/transformers/index.ts +2 -3
  80. package/src/transformers/stringify.ts +1 -1
  81. package/src/transformers/trim.ts +0 -4
  82. package/src/types.ts +77 -22
  83. package/src/utils/TreeNode.ts +132 -50
  84. package/src/utils/executeStrategies.ts +3 -3
  85. package/src/utils/index.ts +2 -1
  86. package/src/utils/parser.ts +156 -0
  87. package/dist/chunk-25NKJ3DV.js.map +0 -1
  88. package/dist/chunk-34BPAXR2.cjs.map +0 -1
  89. package/dist/chunk-3OXCZ5DJ.js.map +0 -1
  90. package/dist/chunk-5JZNFPUP.js +0 -309
  91. package/dist/chunk-5JZNFPUP.js.map +0 -1
  92. package/dist/chunk-67C6RBGQ.cjs.map +0 -1
  93. package/dist/chunk-ADC5UNZ5.cjs +0 -1227
  94. package/dist/chunk-ADC5UNZ5.cjs.map +0 -1
  95. package/dist/chunk-HMLY7DHA.js +0 -16
  96. package/dist/chunk-HMLY7DHA.js.map +0 -1
  97. package/dist/chunk-JKZG2IJR.js +0 -283
  98. package/dist/chunk-JKZG2IJR.js.map +0 -1
  99. package/dist/chunk-LM2YQC3T.cjs.map +0 -1
  100. package/dist/chunk-PZT4CTBV.cjs +0 -299
  101. package/dist/chunk-PZT4CTBV.cjs.map +0 -1
  102. package/dist/chunk-SA2GZKXS.js +0 -596
  103. package/dist/chunk-SA2GZKXS.js.map +0 -1
  104. package/dist/chunk-XCPFG6DO.cjs +0 -66
  105. package/dist/chunk-XCPFG6DO.cjs.map +0 -1
  106. package/dist/chunk-YTSNYMHW.cjs +0 -320
  107. package/dist/chunk-YTSNYMHW.cjs.map +0 -1
  108. package/dist/prompt-6FWP747F.cjs.map +0 -1
  109. package/dist/prompt-HK3MWREM.js.map +0 -1
  110. package/schema.json +0 -86
  111. package/src/utils/cache.ts +0 -35
  112. package/src/utils/getParser.ts +0 -17
package/src/plugin.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import path from 'node:path'
2
2
 
3
- import { createPluginCache } from './utils/cache.ts'
4
-
5
3
  import type { FileManager } from './FileManager.ts'
6
4
  import type { PluginManager } from './PluginManager.ts'
7
5
  import type { Plugin, PluginContext, PluginFactoryOptions, UserPluginWithLifeCycle } from './types.ts'
@@ -46,7 +44,7 @@ export const pluginCore = createPlugin<PluginCore>((options) => {
46
44
  return options.getPlugins()
47
45
  },
48
46
  get plugin() {
49
- // see pluginManger.#execute where we override with `.call` the this with the correct plugin
47
+ // see pluginManger.#execute where we override with `.call` the context with the correct plugin
50
48
  return options.plugin as NonNullable<Options['plugin']>
51
49
  },
52
50
  logger,
@@ -63,11 +61,10 @@ export const pluginCore = createPlugin<PluginCore>((options) => {
63
61
  },
64
62
  resolvePath,
65
63
  resolveName,
66
- cache: createPluginCache(),
67
64
  }
68
65
  },
69
66
  resolvePath(baseName) {
70
- const root = path.resolve(this.config.root, this.config.output.path)
67
+ const root = path.resolve(options.config.root, options.config.output.path)
71
68
 
72
69
  return path.resolve(root, baseName)
73
70
  },
@@ -29,13 +29,3 @@ export function jsStringEscape(input: any): string {
29
29
  }
30
30
  })
31
31
  }
32
-
33
- export function escapeStringRegexp(string: string) {
34
- if (typeof string !== 'string') {
35
- throw new TypeError('Expected a string')
36
- }
37
-
38
- // Escape characters with special meaning either inside or outside character sets.
39
- // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
40
- return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
41
- }
@@ -11,7 +11,7 @@ import { searchAndReplace } from './searchAndReplace.ts'
11
11
  import { stringify, stringifyObject } from './stringify.ts'
12
12
  import { toRegExp, toRegExpString } from './toRegExp.ts'
13
13
  import { transformReservedWord } from './transformReservedWord.ts'
14
- import { trim, trimExtName, trimQuotes } from './trim.ts'
14
+ import { trim, trimQuotes } from './trim.ts'
15
15
 
16
16
  export { camelCase, pascalCase, pathCase } from './casing.ts'
17
17
  export { combineCodes } from './combineCodes.ts'
@@ -23,7 +23,7 @@ export { searchAndReplace } from './searchAndReplace.ts'
23
23
  export { stringify, stringifyObject } from './stringify.ts'
24
24
  export { toRegExp, toRegExpString } from './toRegExp.ts'
25
25
  export { transformReservedWord } from './transformReservedWord.ts'
26
- export { trim, trimExtName, trimQuotes } from './trim.ts'
26
+ export { trim, trimQuotes } from './trim.ts'
27
27
  export { merge } from 'remeda'
28
28
  export { orderBy } from 'natural-orderby'
29
29
 
@@ -41,7 +41,6 @@ export default {
41
41
  toRegExpString,
42
42
  trim,
43
43
  trimQuotes,
44
- trimExtName,
45
44
  JSDoc: {
46
45
  createJSDocBlockText,
47
46
  },
@@ -1,6 +1,6 @@
1
1
  import { trimQuotes } from './trim'
2
2
 
3
- export function stringify(value: string | number | undefined): string {
3
+ export function stringify(value: string | number | boolean | undefined): string {
4
4
  if (value === undefined || value === null) {
5
5
  return '""'
6
6
  }
@@ -16,7 +16,3 @@ export function trimQuotes(text: string): string {
16
16
 
17
17
  return text
18
18
  }
19
-
20
- export function trimExtName(text: string): string {
21
- return text.replace(/\.[^/.]+$/, '')
22
- }
package/src/types.ts CHANGED
@@ -3,7 +3,6 @@ import type { PossiblePromise } from '@kubb/types'
3
3
  import type { FileManager } from './FileManager.ts'
4
4
  import type { PluginManager } from './PluginManager.ts'
5
5
  import type { Logger } from './logger.ts'
6
- import type { Cache } from './utils/cache.ts'
7
6
 
8
7
  // config
9
8
 
@@ -30,20 +29,25 @@ export type UserConfig = Omit<Config, 'root' | 'plugins'> & {
30
29
 
31
30
  export type InputPath = {
32
31
  /**
33
- * Path to be used as the input. This can be an absolute path or a path relative to the `root`.
32
+ * Define your Swagger/OpenAPI file. This can be an absolute path or a path relative to the `root`.
34
33
  */
35
34
  path: string
36
35
  }
37
36
 
38
37
  export type InputData = {
39
38
  /**
40
- * `string` or `object` containing the data.
39
+ * `string` or `object` containing your Swagger/OpenAPI data.
41
40
  */
42
41
  data: string | unknown
43
42
  }
44
43
 
45
44
  type Input = InputPath | InputData
46
45
 
46
+ type OutContext = {}
47
+ type OutExtension = (context: OutContext) => Record<KubbFile.Extname, KubbFile.Extname>
48
+
49
+ export type BarrelType = 'all' | 'named'
50
+
47
51
  /**
48
52
  * @private
49
53
  */
@@ -53,33 +57,44 @@ export type Config<TInput = Input> = {
53
57
  */
54
58
  name?: string
55
59
  /**
56
- * Project root directory. Can be an absolute path, or a path relative from
57
- * the location of the config file itself.
60
+ * Project root directory. This can be an absolute path or a path relative to the location of your `kubb.config.ts` file.
58
61
  * @default process.cwd()
59
62
  */
60
63
  root: string
64
+ /**
65
+ * You can use `input.path` or `input.data` depending on the needs you have.
66
+ */
61
67
  input: TInput
62
68
  output: {
63
69
  /**
64
- * Path to be used to export all generated files.
65
- * This can be an absolute path, or a path relative based of the defined `root` option.
70
+ * The path where all generated files will be exported. This can be an absolute path or a path relative to the specified root option.
66
71
  */
67
72
  path: string
68
73
  /**
69
- * Clean output directory before each build.
74
+ * Clean the output directory before each build.
70
75
  */
71
76
  clean?: boolean
72
77
  /**
73
- * Write files to the fileSystem
74
- * This is being used for the playground.
78
+ * Save files to the file system.
75
79
  * @default true
76
80
  */
77
81
  write?: boolean
82
+
83
+ /**
84
+ * Override the extension to the generated imports and exports, default the plugin will add an extension
85
+ * @default `() => ({ '.ts': '.ts'})`
86
+ */
87
+ extension?: OutExtension
88
+ /**
89
+ * Define what needs to exported, here you can also disable the export of barrel files.
90
+ * @default `'named'`
91
+ */
92
+ barrelType?: BarrelType | false
78
93
  }
79
94
  /**
80
- * Array of Kubb plugins to use.
81
- * The plugin/package can forsee some options that you need to pass through.
82
- * Sometimes a plugin is depended on another plugin, if that's the case you will get an error back from the plugin you installed.
95
+ * An array of Kubb plugins that will be used in the generation.
96
+ * Each plugin may include additional configurable options(defined in the plugin itself).
97
+ * If a plugin depends on another plugin, an error will be returned if the required dependency is missing. See pre for more details.
83
98
  */
84
99
  plugins?: Array<Plugin>
85
100
  /**
@@ -146,7 +161,7 @@ export type UserPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOpti
146
161
  options: TOptions['resolvedOptions']
147
162
  /**
148
163
  * Specifies the preceding plugins for the current plugin. You can pass an array of preceding plugin names, and the current plugin will be executed after these plugins.
149
- * Can be used to validate depended plugins.
164
+ * Can be used to validate dependent plugins.
150
165
  */
151
166
  pre?: Array<string>
152
167
  /**
@@ -178,7 +193,7 @@ export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
178
193
  key: TOptions['key']
179
194
  /**
180
195
  * Specifies the preceding plugins for the current plugin. You can pass an array of preceding plugin names, and the current plugin will be executed after these plugins.
181
- * Can be used to validate depended plugins.
196
+ * Can be used to validate dependent plugins.
182
197
  */
183
198
  pre?: Array<string>
184
199
  /**
@@ -214,7 +229,12 @@ export type PluginLifecycle<TOptions extends PluginFactoryOptions = PluginFactor
214
229
  * @type hookFirst
215
230
  * @example ('./Pet.ts', './src/gen/') => '/src/gen/Pet.ts'
216
231
  */
217
- resolvePath?: (this: PluginContext<TOptions>, baseName: string, mode?: KubbFile.Mode, options?: TOptions['resolvePathOptions']) => KubbFile.OptionalPath
232
+ resolvePath?: (
233
+ this: PluginContext<TOptions>,
234
+ baseName: KubbFile.BaseName,
235
+ mode?: KubbFile.Mode,
236
+ options?: TOptions['resolvePathOptions'],
237
+ ) => KubbFile.OptionalPath
218
238
  /**
219
239
  * Resolve to a name based on a string.
220
240
  * Useful when converting to PascalCase or camelCase.
@@ -233,11 +253,9 @@ export type PluginLifecycleHooks = keyof PluginLifecycle
233
253
 
234
254
  export type PluginParameter<H extends PluginLifecycleHooks> = Parameters<Required<PluginLifecycle>[H]>
235
255
 
236
- export type PluginCache = Record<string, [number, unknown]>
237
-
238
256
  export type ResolvePathParams<TOptions = object> = {
239
257
  pluginKey?: Plugin['key']
240
- baseName: string
258
+ baseName: KubbFile.BaseName
241
259
  mode?: KubbFile.Mode
242
260
  /**
243
261
  * Options to be passed to 'resolvePath' 3th parameter
@@ -253,15 +271,14 @@ export type ResolveNameParams = {
253
271
  * `function` can be used used to customize the exported functions(use of camelCase)
254
272
  * `type` is a special type for TypeScript(use of PascalCase)
255
273
  */
256
- type?: 'file' | 'function' | 'type'
274
+ type?: 'file' | 'function' | 'type' | 'const'
257
275
  }
258
276
 
259
277
  export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
260
278
  config: Config
261
- cache: Cache<PluginCache>
262
279
  fileManager: FileManager
263
280
  pluginManager: PluginManager
264
- addFile: (...file: Array<KubbFile.File>) => Promise<Array<KubbFile.File>>
281
+ addFile: (...file: Array<KubbFile.File>) => Promise<Array<KubbFile.ResolvedFile>>
265
282
  resolvePath: (params: ResolvePathParams<TOptions['resolvePathOptions']>) => KubbFile.OptionalPath
266
283
  resolveName: (params: ResolveNameParams) => string
267
284
  logger: Logger
@@ -274,3 +291,41 @@ export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryO
274
291
  */
275
292
  plugin: Plugin<TOptions>
276
293
  }
294
+
295
+ export type Output = {
296
+ /**
297
+ * Output to save the generated files.
298
+ */
299
+ path: string
300
+ /**
301
+ * Define what needs to exported, here you can also disable the export of barrel files.
302
+ * @default `'named'`
303
+ */
304
+ barrelType?: BarrelType | false
305
+ /**
306
+ * Add a banner text in the beginning of every file
307
+ */
308
+ banner?: string
309
+ /**
310
+ * Add a footer text in the beginning of every file
311
+ */
312
+ footer?: string
313
+ }
314
+
315
+ type GroupContext = {
316
+ group: string
317
+ }
318
+
319
+ export type Group = {
320
+ /**
321
+ * Tag will group based on the operation tag inside the Swagger file
322
+ */
323
+ type: 'tag'
324
+ /**
325
+ * Relative path to save the grouped clients.
326
+ *
327
+ * @example `${output}/{{tag}}Controller` => `clients/PetController`
328
+ * @default `({ group }) => `${group}Controller``
329
+ */
330
+ name?: (context: GroupContext) => string
331
+ }
@@ -1,28 +1,29 @@
1
- import dirTree from 'directory-tree'
2
-
3
- import { FileManager } from '../FileManager.ts'
4
-
5
1
  import type * as KubbFile from '@kubb/fs/types'
6
- import type { DirectoryTree, DirectoryTreeOptions } from 'directory-tree'
7
-
8
- export type TreeNodeOptions = DirectoryTreeOptions
9
-
10
- type BarrelData = { type: KubbFile.Mode; path: KubbFile.Path; name: string }
11
-
12
- export class TreeNode<T = BarrelData> {
13
- public data: T
2
+ import { FileManager } from '../FileManager.ts'
14
3
 
15
- public parent?: TreeNode<T>
4
+ type BarrelData = {
5
+ file?: KubbFile.File
6
+ /**
7
+ * @deprecated use file instead
8
+ */
9
+ type: KubbFile.Mode
10
+ path: string
11
+ name: string
12
+ }
16
13
 
17
- public children: Array<TreeNode<T>> = []
14
+ export class TreeNode {
15
+ data: BarrelData
16
+ parent?: TreeNode
17
+ children: Array<TreeNode> = []
18
+ #cachedLeaves?: Array<TreeNode> = undefined
18
19
 
19
- constructor(data: T, parent?: TreeNode<T>) {
20
+ constructor(data: BarrelData, parent?: TreeNode) {
20
21
  this.data = data
21
22
  this.parent = parent
22
23
  return this
23
24
  }
24
25
 
25
- addChild(data: T): TreeNode<T> {
26
+ addChild(data: BarrelData): TreeNode {
26
27
  const child = new TreeNode(data, this)
27
28
  if (!this.children) {
28
29
  this.children = []
@@ -31,51 +32,37 @@ export class TreeNode<T = BarrelData> {
31
32
  return child
32
33
  }
33
34
 
34
- find(data?: T): TreeNode<T> | null {
35
- if (!data) {
36
- return null
37
- }
38
-
39
- if (data === this.data) {
35
+ get root(): TreeNode {
36
+ if (!this.parent) {
40
37
  return this
41
38
  }
42
-
43
- if (this.children?.length) {
44
- for (let i = 0, { length } = this.children, target: TreeNode<T> | null = null; i < length; i++) {
45
- target = this.children[i]!.find(data)
46
- if (target) {
47
- return target
48
- }
49
- }
50
- }
51
-
52
- return null
39
+ return this.parent.root
53
40
  }
54
41
 
55
- get leaves(): TreeNode<T>[] {
42
+ get leaves(): Array<TreeNode> {
56
43
  if (!this.children || this.children.length === 0) {
57
44
  // this is a leaf
58
45
  return [this]
59
46
  }
60
47
 
48
+ if (this.#cachedLeaves) {
49
+ return this.#cachedLeaves
50
+ }
51
+
61
52
  // if not a leaf, return all children's leaves recursively
62
- const leaves: TreeNode<T>[] = []
53
+ const leaves: TreeNode[] = []
63
54
  if (this.children) {
64
55
  for (let i = 0, { length } = this.children; i < length; i++) {
65
56
  leaves.push.apply(leaves, this.children[i]!.leaves)
66
57
  }
67
58
  }
68
- return leaves
69
- }
70
59
 
71
- get root(): TreeNode<T> {
72
- if (!this.parent) {
73
- return this
74
- }
75
- return this.parent.root
60
+ this.#cachedLeaves = leaves
61
+
62
+ return leaves
76
63
  }
77
64
 
78
- forEach(callback: (treeNode: TreeNode<T>) => void): this {
65
+ forEach(callback: (treeNode: TreeNode) => void): this {
79
66
  if (typeof callback !== 'function') {
80
67
  throw new TypeError('forEach() callback must be a function')
81
68
  }
@@ -93,13 +80,41 @@ export class TreeNode<T = BarrelData> {
93
80
  return this
94
81
  }
95
82
 
96
- public static build(path: string, options: TreeNodeOptions = {}): TreeNode | null {
83
+ findDeep(predicate?: (value: TreeNode, index: number, obj: TreeNode[]) => boolean): TreeNode | undefined {
84
+ if (typeof predicate !== 'function') {
85
+ throw new TypeError('find() predicate must be a function')
86
+ }
87
+
88
+ return this.leaves.find(predicate)
89
+ }
90
+
91
+ forEachDeep(callback: (treeNode: TreeNode) => void): void {
92
+ if (typeof callback !== 'function') {
93
+ throw new TypeError('forEach() callback must be a function')
94
+ }
95
+
96
+ this.leaves.forEach(callback)
97
+ }
98
+
99
+ filterDeep(callback: (treeNode: TreeNode) => boolean): Array<TreeNode> {
100
+ if (typeof callback !== 'function') {
101
+ throw new TypeError('filter() callback must be a function')
102
+ }
103
+
104
+ return this.leaves.filter(callback)
105
+ }
106
+
107
+ mapDeep<T>(callback: (treeNode: TreeNode) => T): Array<T> {
108
+ if (typeof callback !== 'function') {
109
+ throw new TypeError('map() callback must be a function')
110
+ }
111
+
112
+ return this.leaves.map(callback)
113
+ }
114
+
115
+ public static build(files: KubbFile.File[], root?: string): TreeNode | null {
97
116
  try {
98
- const exclude = Array.isArray(options.exclude) ? options.exclude : [options.exclude].filter(Boolean)
99
- const filteredTree = dirTree(path, {
100
- extensions: options.extensions,
101
- exclude: [/node_modules/, ...exclude],
102
- })
117
+ const filteredTree = buildDirectoryTree(files, root)
103
118
 
104
119
  if (!filteredTree) {
105
120
  return null
@@ -108,6 +123,7 @@ export class TreeNode<T = BarrelData> {
108
123
  const treeNode = new TreeNode({
109
124
  name: filteredTree.name,
110
125
  path: filteredTree.path,
126
+ file: filteredTree.file,
111
127
  type: FileManager.getMode(filteredTree.path),
112
128
  })
113
129
 
@@ -115,6 +131,7 @@ export class TreeNode<T = BarrelData> {
115
131
  const subNode = node.addChild({
116
132
  name: item.name,
117
133
  path: item.path,
134
+ file: item.file,
118
135
  type: FileManager.getMode(item.path),
119
136
  })
120
137
 
@@ -129,7 +146,72 @@ export class TreeNode<T = BarrelData> {
129
146
 
130
147
  return treeNode
131
148
  } catch (e) {
132
- throw new Error('Something went wrong with creating index files with the TreehNode class', { cause: e })
149
+ throw new Error('Something went wrong with creating barrel files with the TreeNode class', { cause: e })
133
150
  }
134
151
  }
135
152
  }
153
+
154
+ export type DirectoryTree = {
155
+ name: string
156
+ path: string
157
+ file?: KubbFile.File
158
+ children: Array<DirectoryTree>
159
+ }
160
+
161
+ export function buildDirectoryTree(files: Array<KubbFile.File>, rootFolder = ''): DirectoryTree | null {
162
+ const rootPrefix = rootFolder.endsWith('/') ? rootFolder : `${rootFolder}/`
163
+ const filteredFiles = files.filter((file) => (rootFolder ? file.path.startsWith(rootPrefix) && !file.path.endsWith('.json') : !file.path.endsWith('.json')))
164
+
165
+ if (filteredFiles.length === 0) {
166
+ return null // No files match the root folder
167
+ }
168
+
169
+ const root: DirectoryTree = {
170
+ name: rootFolder || '',
171
+ path: rootFolder || '',
172
+ children: [],
173
+ }
174
+
175
+ filteredFiles.forEach((file) => {
176
+ const path = file.path.slice(rootFolder.length)
177
+ const parts = path.split('/')
178
+ let currentLevel: DirectoryTree[] = root.children
179
+ let currentPath = rootFolder
180
+
181
+ parts.forEach((part, index) => {
182
+ if (index !== 0) {
183
+ currentPath += `/${part}`
184
+ } else {
185
+ currentPath += `${part}`
186
+ }
187
+
188
+ let existingNode = currentLevel.find((node) => node.name === part)
189
+
190
+ if (!existingNode) {
191
+ if (index === parts.length - 1) {
192
+ // If it's the last part, it's a file
193
+ existingNode = {
194
+ name: part,
195
+ file,
196
+ path: currentPath,
197
+ } as DirectoryTree
198
+ } else {
199
+ // Otherwise, it's a folder
200
+ existingNode = {
201
+ name: part,
202
+ path: currentPath,
203
+ children: [],
204
+ } as DirectoryTree
205
+ }
206
+ currentLevel.push(existingNode)
207
+ }
208
+
209
+ // Move to the next level if it's a folder
210
+ if (!existingNode.file) {
211
+ currentLevel = existingNode.children
212
+ }
213
+ })
214
+ })
215
+
216
+ return root
217
+ }
@@ -1,10 +1,10 @@
1
1
  type PromiseFunc<T = unknown, T2 = never> = (state?: T) => T2 extends never ? Promise<T> : Promise<T> | T2
2
2
 
3
- export type ValueOfPromiseFuncArray<TInput extends Array<unknown>> = TInput extends Array<PromiseFunc<infer X, infer Y>> ? X | Y : never
3
+ type ValueOfPromiseFuncArray<TInput extends Array<unknown>> = TInput extends Array<PromiseFunc<infer X, infer Y>> ? X | Y : never
4
4
 
5
- export function noReturn(): void {}
5
+ function noReturn(): void {}
6
6
 
7
- type SeqOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue> = Array<Awaited<ValueOfPromiseFuncArray<TInput>>>
7
+ type SeqOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue> = Promise<Array<Awaited<ValueOfPromiseFuncArray<TInput>>>>
8
8
 
9
9
  /**
10
10
  * Chains promises
@@ -10,4 +10,5 @@ export { timeout } from './timeout.ts'
10
10
  export { getUniqueName, setUniqueName } from './uniqueName.ts'
11
11
  export type { URLObject } from './URLPath.ts'
12
12
  export { URLPath } from './URLPath.ts'
13
- export { getParser } from './getParser.ts'
13
+ export { getFileParser, createFileImport, createFileExport, createFile, createFileParser } from './parser.ts'
14
+ export type { ParserModule } from './parser.ts'