@kubb/core 3.0.0-alpha.9 → 3.0.0-beta.2

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 (91) hide show
  1. package/README.md +14 -5
  2. package/dist/{FileManager-B0GJlthB.d.cts → FileManager-C9aZTwst.d.ts} +94 -77
  3. package/dist/{FileManager-BFycBDqG.d.ts → FileManager-ibNoWwHN.d.cts} +94 -77
  4. package/dist/chunk-2EU7DMPM.js +2 -3
  5. package/dist/chunk-2EU7DMPM.js.map +1 -1
  6. package/dist/{chunk-DID47EQD.cjs → chunk-2TOEDZ2U.cjs} +6 -7
  7. package/dist/chunk-2TOEDZ2U.cjs.map +1 -0
  8. package/dist/{chunk-A6PCLWEY.cjs → chunk-4GJEWGQN.cjs} +30 -31
  9. package/dist/chunk-4GJEWGQN.cjs.map +1 -0
  10. package/dist/{chunk-SEH6NUCX.cjs → chunk-72BWXKV4.cjs} +10 -10
  11. package/dist/chunk-72BWXKV4.cjs.map +1 -0
  12. package/dist/{chunk-4X5FFJPJ.js → chunk-BQXM32UO.js} +11 -16
  13. package/dist/chunk-BQXM32UO.js.map +1 -0
  14. package/dist/{chunk-27CPVXAT.js → chunk-DXGMSPTW.js} +174 -231
  15. package/dist/chunk-DXGMSPTW.js.map +1 -0
  16. package/dist/{chunk-SCR3LUXT.js → chunk-E6CN2CZC.js} +38 -27
  17. package/dist/chunk-E6CN2CZC.js.map +1 -0
  18. package/dist/chunk-HBQM723K.js +12 -26
  19. package/dist/chunk-HBQM723K.js.map +1 -1
  20. package/dist/{chunk-5E2I6KH4.cjs → chunk-KXT7F2WS.cjs} +54 -37
  21. package/dist/chunk-KXT7F2WS.cjs.map +1 -0
  22. package/dist/{chunk-IPZQXBA2.cjs → chunk-MVWRVN66.cjs} +57 -34
  23. package/dist/chunk-MVWRVN66.cjs.map +1 -0
  24. package/dist/{chunk-5IGANEGE.cjs → chunk-SQBOUPF4.cjs} +268 -301
  25. package/dist/chunk-SQBOUPF4.cjs.map +1 -0
  26. package/dist/index.cjs +223 -241
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +4 -6
  29. package/dist/index.d.ts +4 -6
  30. package/dist/index.js +106 -148
  31. package/dist/index.js.map +1 -1
  32. package/dist/{logger-BWFeedRk.d.cts → logger-DvbHXjIO.d.cts} +10 -8
  33. package/dist/{logger-BWFeedRk.d.ts → logger-DvbHXjIO.d.ts} +10 -8
  34. package/dist/logger.cjs +25 -14
  35. package/dist/logger.cjs.map +1 -1
  36. package/dist/logger.d.cts +1 -1
  37. package/dist/logger.d.ts +1 -1
  38. package/dist/logger.js +3 -13
  39. package/dist/logger.js.map +1 -1
  40. package/dist/mocks.cjs +29 -24
  41. package/dist/mocks.cjs.map +1 -1
  42. package/dist/mocks.d.cts +4 -3
  43. package/dist/mocks.d.ts +4 -3
  44. package/dist/mocks.js +22 -25
  45. package/dist/mocks.js.map +1 -1
  46. package/dist/{prompt-DVQN7JTN.cjs → prompt-FODZPXQF.cjs} +89 -89
  47. package/dist/prompt-FODZPXQF.cjs.map +1 -0
  48. package/dist/prompt-WQQUN22Z.js +8 -13
  49. package/dist/prompt-WQQUN22Z.js.map +1 -1
  50. package/dist/transformers.cjs +63 -52
  51. package/dist/transformers.cjs.map +1 -1
  52. package/dist/transformers.d.cts +1 -1
  53. package/dist/transformers.d.ts +1 -1
  54. package/dist/transformers.js +10 -37
  55. package/dist/transformers.js.map +1 -1
  56. package/dist/utils.cjs +65 -34
  57. package/dist/utils.cjs.map +1 -1
  58. package/dist/utils.d.cts +6 -8
  59. package/dist/utils.d.ts +6 -8
  60. package/dist/utils.js +3 -33
  61. package/dist/utils.js.map +1 -1
  62. package/package.json +10 -13
  63. package/src/BarrelManager.ts +76 -74
  64. package/src/FileManager.ts +55 -60
  65. package/src/PluginManager.ts +61 -61
  66. package/src/PromiseManager.ts +1 -1
  67. package/src/__snapshots__/barrel.json +11 -29
  68. package/src/__snapshots__/grouped.json +18 -12
  69. package/src/__snapshots__/ordered.json +18 -12
  70. package/src/build.ts +24 -11
  71. package/src/config.ts +2 -4
  72. package/src/index.ts +1 -1
  73. package/src/logger.ts +41 -7
  74. package/src/plugin.ts +0 -3
  75. package/src/transformers/escape.ts +0 -10
  76. package/src/transformers/stringify.ts +1 -1
  77. package/src/types.ts +70 -38
  78. package/src/utils/TreeNode.ts +31 -56
  79. package/src/utils/executeStrategies.ts +2 -2
  80. package/src/utils/parser.ts +38 -39
  81. package/dist/chunk-27CPVXAT.js.map +0 -1
  82. package/dist/chunk-4X5FFJPJ.js.map +0 -1
  83. package/dist/chunk-5E2I6KH4.cjs.map +0 -1
  84. package/dist/chunk-5IGANEGE.cjs.map +0 -1
  85. package/dist/chunk-A6PCLWEY.cjs.map +0 -1
  86. package/dist/chunk-DID47EQD.cjs.map +0 -1
  87. package/dist/chunk-IPZQXBA2.cjs.map +0 -1
  88. package/dist/chunk-SCR3LUXT.js.map +0 -1
  89. package/dist/chunk-SEH6NUCX.cjs.map +0 -1
  90. package/dist/prompt-DVQN7JTN.cjs.map +0 -1
  91. package/src/utils/cache.ts +0 -35
package/src/build.ts CHANGED
@@ -6,10 +6,10 @@ import { isInputPath } from './config.ts'
6
6
  import { createLogger } from './logger.ts'
7
7
  import { URLPath } from './utils/URLPath.ts'
8
8
 
9
- import { resolve } from 'node:path'
9
+ import { join, resolve } from 'node:path'
10
10
  import { getRelativePath } from '@kubb/fs'
11
11
  import type { Logger } from './logger.ts'
12
- import type { PluginContext } from './types.ts'
12
+ import type { Output, PluginContext } from './types.ts'
13
13
 
14
14
  type BuildOptions = {
15
15
  config: PluginContext['config']
@@ -45,6 +45,7 @@ async function setup(options: BuildOptions): Promise<PluginManager> {
45
45
 
46
46
  if (config.output.clean) {
47
47
  await clean(config.output.path)
48
+ await clean(join(config.root, '.kubb'))
48
49
  }
49
50
 
50
51
  return new PluginManager(config, { logger })
@@ -63,13 +64,25 @@ export async function build(options: BuildOptions): Promise<BuildOutput> {
63
64
  }
64
65
 
65
66
  export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
66
- const pluginManager = await setup(options)
67
67
  let files = []
68
+ const pluginManager = await setup(options)
68
69
 
69
70
  try {
71
+ pluginManager.events.on('executing', ({ plugin, message }) => {
72
+ pluginManager.logger.emit('debug', { date: new Date(), logs: [`Executing pluginKey ${plugin.key?.join('.')} | ${message}`] })
73
+ })
74
+
75
+ pluginManager.events.on('executed', ({ plugin, message, output }) => {
76
+ pluginManager.logger.emit('debug', {
77
+ date: new Date(),
78
+ logs: [`Executed pluginKey ${plugin.key?.join('.')} | ${message} | ${JSON.stringify(output, undefined, 2)}`],
79
+ })
80
+ })
81
+
70
82
  await pluginManager.hookParallel({
71
83
  hookName: 'buildStart',
72
84
  parameters: [options.config],
85
+ message: 'buildStart',
73
86
  })
74
87
 
75
88
  // create root barrel file
@@ -91,20 +104,21 @@ export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
91
104
  }
92
105
 
93
106
  // validate of the file is coming from plugin x, needs pluginKey on every file TODO update typing
94
- const plugin = pluginManager.plugins.find((item) => {
107
+ const plugin = [...pluginManager.plugins].find((item) => {
95
108
  const meta = file.meta as any
96
- return item.name === meta?.pluginKey?.[0]
109
+ return item.key === meta?.pluginKey
97
110
  })
111
+ const pluginOptions = (plugin?.options as { output?: Output }) ?? {}
98
112
 
99
- if (plugin?.output?.exportType === false) {
113
+ if (pluginOptions.output?.barrelType === false) {
100
114
  return undefined
101
115
  }
102
116
 
103
- if (FileManager.getMode(plugin?.output?.path) === 'single') {
117
+ if (FileManager.getMode(pluginOptions.output?.path) === 'single') {
104
118
  return undefined
105
119
  }
106
120
  return {
107
- name: options.config.output.exportType === 'barrel' ? undefined : [source.name],
121
+ name: pluginOptions.output?.barrelType === 'all' ? undefined : [source.name],
108
122
  path: getRelativePath(rootPath, file.path),
109
123
  isTypeOnly: source.isTypeOnly,
110
124
  } as KubbFile.Export
@@ -116,11 +130,10 @@ export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
116
130
  meta: {},
117
131
  }
118
132
 
119
- if (options.config.output.exportType) {
133
+ if (options.config.output.barrelType) {
120
134
  await pluginManager.fileManager.add(rootFile)
121
135
  }
122
136
 
123
- //TODO set extName here instead of the files, extName is private. All exports will have extName, it's up the the process to hide.override the name
124
137
  files = await processFiles({
125
138
  config: options.config,
126
139
  dryRun: !options.config.output.write,
@@ -128,7 +141,7 @@ export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
128
141
  logger: pluginManager.logger,
129
142
  })
130
143
 
131
- await pluginManager.hookParallel({ hookName: 'buildEnd' })
144
+ await pluginManager.hookParallel({ hookName: 'buildEnd', message: `Build stopped for ${options.config.name}` })
132
145
 
133
146
  pluginManager.fileManager.clear()
134
147
  } catch (e) {
package/src/config.ts CHANGED
@@ -29,9 +29,7 @@ type Args = {
29
29
  }
30
30
 
31
31
  /**
32
- * Type helper to make it easier to use kubb.config.js
33
- * accepts a direct {@link Config} object, or a function that returns it.
34
- * The function receives a {@link ConfigEnv} object that exposes two properties:
32
+ * Type helper to make it easier to use vite.config.ts accepts a direct UserConfig object, or a function that returns it. The function receives a ConfigEnv object.
35
33
  */
36
34
  export function defineConfig(
37
35
  options:
@@ -45,5 +43,5 @@ export function defineConfig(
45
43
  }
46
44
 
47
45
  export function isInputPath(result: Config | undefined): result is Config<InputPath> {
48
- return !!result && 'path' in (result as any)
46
+ return !!result && 'path' in (result?.input as any)
49
47
  }
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { build, build as default, safeBuild } from './build.ts'
2
2
  export { defineConfig, isInputPath } from './config.ts'
3
- export { FileManager } from './FileManager.ts'
3
+ export { FileManager, getSource } from './FileManager.ts'
4
4
  export type { FileMetaBase } from './FileManager.ts'
5
5
  export { BaseGenerator } from './BaseGenerator.ts'
6
6
  export { PackageManager } from './PackageManager.ts'
package/src/logger.ts CHANGED
@@ -3,19 +3,22 @@ import c, { createColors } from 'tinyrainbow'
3
3
 
4
4
  import { EventEmitter } from './utils/EventEmitter.ts'
5
5
 
6
- import type * as KubbFile from '@kubb/fs/src/types.ts'
6
+ import { resolve } from 'node:path'
7
+ import { write } from '@kubb/fs'
7
8
  import { type ConsolaInstance, type LogLevel, createConsola } from 'consola'
8
9
  import type { Formatter } from 'tinyrainbow'
9
10
 
11
+ type DebugEvent = { date: Date; logs: string[]; fileName?: string }
12
+
10
13
  type Events = {
11
14
  start: [message: string]
12
15
  success: [message: string]
13
16
  error: [message: string, cause: Error]
14
17
  warning: [message: string]
15
- debug: [{ logs: string[]; override?: boolean; fileName?: string }]
18
+ debug: [DebugEvent]
16
19
  info: [message: string]
17
- progress_start: [{ id: string; size: number }]
18
- progress: [{ id: string; count?: number; data?: string }]
20
+ progress_start: [{ id: string; size: number; message?: string }]
21
+ progressed: [{ id: string; message?: string }]
19
22
  progress_stop: [{ id: string }]
20
23
  }
21
24
 
@@ -34,6 +37,7 @@ export type Logger = {
34
37
  consola?: ConsolaInstance
35
38
  on: EventEmitter<Events>['on']
36
39
  emit: EventEmitter<Events>['emit']
40
+ writeLogs: () => Promise<string[]>
37
41
  }
38
42
 
39
43
  type Props = {
@@ -44,6 +48,8 @@ type Props = {
44
48
 
45
49
  export function createLogger({ logLevel = 3, name, consola: _consola }: Props = {}): Logger {
46
50
  const events = new EventEmitter<Events>()
51
+ const startDate = Date.now()
52
+ const cachedLogs = new Set<DebugEvent>()
47
53
 
48
54
  const consola =
49
55
  _consola ||
@@ -52,7 +58,7 @@ export function createLogger({ logLevel = 3, name, consola: _consola }: Props =
52
58
  formatOptions: {
53
59
  colors: true,
54
60
  date: true,
55
- columns: 120,
61
+ columns: 80,
56
62
  compact: logLevel !== LogMapper.debug,
57
63
  },
58
64
  }).withTag(name ? randomCliColour(name) : '')
@@ -75,6 +81,14 @@ export function createLogger({ logLevel = 3, name, consola: _consola }: Props =
75
81
  consola.info(c.yellow(message))
76
82
  })
77
83
 
84
+ events.on('debug', (message) => {
85
+ if (message.logs.join('\n\n').length <= 100 && logLevel === LogMapper.debug) {
86
+ console.log(message.logs.join('\n\n'))
87
+ }
88
+
89
+ cachedLogs.add(message)
90
+ })
91
+
78
92
  events.on('error', (message, cause) => {
79
93
  const error = new Error(message || 'Something went wrong')
80
94
  error.cause = cause
@@ -90,12 +104,32 @@ export function createLogger({ logLevel = 3, name, consola: _consola }: Props =
90
104
  name,
91
105
  logLevel,
92
106
  consola,
93
- on: (...args) => {
107
+ on(...args) {
94
108
  return events.on(...args)
95
109
  },
96
- emit: (...args) => {
110
+ emit(...args) {
97
111
  return events.emit(...args)
98
112
  },
113
+ async writeLogs() {
114
+ const files: Record<string, string[]> = {}
115
+
116
+ cachedLogs.forEach((log) => {
117
+ const fileName = resolve(process.cwd(), '.kubb', log.fileName || `kubb-${startDate}.log`)
118
+
119
+ if (!files[fileName]) {
120
+ files[fileName] = []
121
+ }
122
+
123
+ files[fileName] = [...files[fileName], `[${log.date.toLocaleString()}]: ${log.logs.join('\n\n')}`]
124
+ })
125
+ await Promise.all(
126
+ Object.entries(files).map(async ([fileName, logs]) => {
127
+ return write(fileName, logs.join('\n'))
128
+ }),
129
+ )
130
+
131
+ return Object.keys(files)
132
+ },
99
133
  }
100
134
 
101
135
  return logger
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'
@@ -63,7 +61,6 @@ 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) {
@@ -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
- }
@@ -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
  }
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,22 @@ 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
+ export type BarrelType = 'all' | 'named'
47
+
47
48
  /**
48
49
  * @private
49
50
  */
@@ -53,38 +54,44 @@ export type Config<TInput = Input> = {
53
54
  */
54
55
  name?: string
55
56
  /**
56
- * Project root directory. Can be an absolute path, or a path relative from
57
- * the location of the config file itself.
57
+ * Project root directory. This can be an absolute path or a path relative to the location of your `kubb.config.ts` file.
58
58
  * @default process.cwd()
59
59
  */
60
60
  root: string
61
+ /**
62
+ * You can use `input.path` or `input.data` depending on the needs you have.
63
+ */
61
64
  input: TInput
62
65
  output: {
63
66
  /**
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.
67
+ * 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
68
  */
67
69
  path: string
68
70
  /**
69
- * Clean output directory before each build.
71
+ * Clean the output directory before each build.
70
72
  */
71
73
  clean?: boolean
72
74
  /**
73
- * Write files to the fileSystem
74
- * This is being used for the playground.
75
+ * Save files to the file system.
75
76
  * @default true
76
77
  */
77
78
  write?: boolean
79
+
80
+ /**
81
+ * Override the extension to the generated imports and exports, by default the plugin will add an extension
82
+ * @default `{ '.ts': '.ts'}`
83
+ */
84
+ extension?: Record<KubbFile.Extname, KubbFile.Extname>
78
85
  /**
79
- * Define what needs to exported, here you can also disable the export of barrel files
80
- * @default `'barrelNamed'`
86
+ * Define what needs to exported, here you can also disable the export of barrel files.
87
+ * @default `'named'`
81
88
  */
82
- exportType?: 'barrel' | 'barrelNamed' | false
89
+ barrelType?: BarrelType | false
83
90
  }
84
91
  /**
85
- * Array of Kubb plugins to use.
86
- * The plugin/package can forsee some options that you need to pass through.
87
- * Sometimes a plugin is depended on another plugin, if that's the case you will get an error back from the plugin you installed.
92
+ * An array of Kubb plugins that will be used in the generation.
93
+ * Each plugin may include additional configurable options(defined in the plugin itself).
94
+ * If a plugin depends on another plugin, an error will be returned if the required dependency is missing. See pre for more details.
88
95
  */
89
96
  plugins?: Array<Plugin>
90
97
  /**
@@ -181,21 +188,6 @@ export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
181
188
  * @private
182
189
  */
183
190
  key: TOptions['key']
184
- output?: {
185
- /**
186
- * Output to save the clients.
187
- */
188
- path: string
189
- /**
190
- * Add an extension to the generated imports and exports, default it will not use an extension
191
- */
192
- extName?: KubbFile.Extname
193
- /**
194
- * Define what needs to exported, here you can also disable the export of barrel files
195
- * @default `'barrelNamed'`
196
- */
197
- exportType?: 'barrel' | 'barrelNamed' | false
198
- }
199
191
  /**
200
192
  * 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.
201
193
  * Can be used to validate dependent plugins.
@@ -234,7 +226,12 @@ export type PluginLifecycle<TOptions extends PluginFactoryOptions = PluginFactor
234
226
  * @type hookFirst
235
227
  * @example ('./Pet.ts', './src/gen/') => '/src/gen/Pet.ts'
236
228
  */
237
- resolvePath?: (this: PluginContext<TOptions>, baseName: string, mode?: KubbFile.Mode, options?: TOptions['resolvePathOptions']) => KubbFile.OptionalPath
229
+ resolvePath?: (
230
+ this: PluginContext<TOptions>,
231
+ baseName: KubbFile.BaseName,
232
+ mode?: KubbFile.Mode,
233
+ options?: TOptions['resolvePathOptions'],
234
+ ) => KubbFile.OptionalPath
238
235
  /**
239
236
  * Resolve to a name based on a string.
240
237
  * Useful when converting to PascalCase or camelCase.
@@ -253,11 +250,9 @@ export type PluginLifecycleHooks = keyof PluginLifecycle
253
250
 
254
251
  export type PluginParameter<H extends PluginLifecycleHooks> = Parameters<Required<PluginLifecycle>[H]>
255
252
 
256
- export type PluginCache = Record<string, [number, unknown]>
257
-
258
253
  export type ResolvePathParams<TOptions = object> = {
259
254
  pluginKey?: Plugin['key']
260
- baseName: string
255
+ baseName: KubbFile.BaseName
261
256
  mode?: KubbFile.Mode
262
257
  /**
263
258
  * Options to be passed to 'resolvePath' 3th parameter
@@ -270,15 +265,15 @@ export type ResolveNameParams = {
270
265
  pluginKey?: Plugin['key']
271
266
  /**
272
267
  * `file` will be used to customize the name of the created file(use of camelCase)
273
- * `function` can be used used to customize the exported functions(use of camelCase)
268
+ * `function` can be used to customize the exported functions(use of camelCase)
274
269
  * `type` is a special type for TypeScript(use of PascalCase)
270
+ * `const` can be used for variables(use of camelCase)
275
271
  */
276
- type?: 'file' | 'function' | 'type'
272
+ type?: 'file' | 'function' | 'type' | 'const'
277
273
  }
278
274
 
279
275
  export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
280
276
  config: Config
281
- cache: Cache<PluginCache>
282
277
  fileManager: FileManager
283
278
  pluginManager: PluginManager
284
279
  addFile: (...file: Array<KubbFile.File>) => Promise<Array<KubbFile.ResolvedFile>>
@@ -294,3 +289,40 @@ export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryO
294
289
  */
295
290
  plugin: Plugin<TOptions>
296
291
  }
292
+ /**
293
+ * Specify the export location for the files and define the behavior of the output
294
+ */
295
+ export type Output = {
296
+ /**
297
+ * Path to the output folder or file that will contain the generated code
298
+ */
299
+ path: string
300
+ /**
301
+ * Define what needs to be 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
+ * Define a type where to group the files on
322
+ */
323
+ type: 'tag'
324
+ /**
325
+ * Return the name of a group based on the group name, this will be used for the file and name generation
326
+ */
327
+ name?: (context: GroupContext) => string
328
+ }
@@ -12,11 +12,10 @@ type BarrelData = {
12
12
  }
13
13
 
14
14
  export class TreeNode {
15
- public data: BarrelData
16
-
17
- public parent?: TreeNode
18
-
19
- public children: Array<TreeNode> = []
15
+ data: BarrelData
16
+ parent?: TreeNode
17
+ children: Array<TreeNode> = []
18
+ #cachedLeaves?: Array<TreeNode> = undefined
20
19
 
21
20
  constructor(data: BarrelData, parent?: TreeNode) {
22
21
  this.data = data
@@ -33,25 +32,11 @@ export class TreeNode {
33
32
  return child
34
33
  }
35
34
 
36
- find(data?: BarrelData): TreeNode | null {
37
- if (!data) {
38
- return null
39
- }
40
-
41
- if (data === this.data) {
35
+ get root(): TreeNode {
36
+ if (!this.parent) {
42
37
  return this
43
38
  }
44
-
45
- if (this.children?.length) {
46
- for (let i = 0, { length } = this.children, target: TreeNode | null = null; i < length; i++) {
47
- target = this.children[i]!.find(data)
48
- if (target) {
49
- return target
50
- }
51
- }
52
- }
53
-
54
- return null
39
+ return this.parent.root
55
40
  }
56
41
 
57
42
  get leaves(): Array<TreeNode> {
@@ -60,6 +45,10 @@ export class TreeNode {
60
45
  return [this]
61
46
  }
62
47
 
48
+ if (this.#cachedLeaves) {
49
+ return this.#cachedLeaves
50
+ }
51
+
63
52
  // if not a leaf, return all children's leaves recursively
64
53
  const leaves: TreeNode[] = []
65
54
  if (this.children) {
@@ -67,14 +56,10 @@ export class TreeNode {
67
56
  leaves.push.apply(leaves, this.children[i]!.leaves)
68
57
  }
69
58
  }
70
- return leaves
71
- }
72
59
 
73
- get root(): TreeNode {
74
- if (!this.parent) {
75
- return this
76
- }
77
- return this.parent.root
60
+ this.#cachedLeaves = leaves
61
+
62
+ return leaves
78
63
  }
79
64
 
80
65
  forEach(callback: (treeNode: TreeNode) => void): this {
@@ -95,46 +80,36 @@ export class TreeNode {
95
80
  return this
96
81
  }
97
82
 
98
- filter(callback: (treeNode: TreeNode) => boolean): Array<TreeNode> {
99
- let data: Array<TreeNode> = []
100
- if (typeof callback !== 'function') {
101
- throw new TypeError('forEach() callback must be a function')
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')
102
86
  }
103
87
 
104
- // run this node through function
105
- if (callback(this)) {
106
- data.push(this)
107
- }
88
+ return this.leaves.find(predicate)
89
+ }
108
90
 
109
- // do the same for all children
110
- if (this.children) {
111
- for (let i = 0, { length } = this.children; i < length; i++) {
112
- const childData = this.children[i]?.filter(callback).filter(Boolean) || []
113
- data = [...new Set([...data, ...childData])]
114
- }
91
+ forEachDeep(callback: (treeNode: TreeNode) => void): void {
92
+ if (typeof callback !== 'function') {
93
+ throw new TypeError('forEach() callback must be a function')
115
94
  }
116
95
 
117
- return data
96
+ this.leaves.forEach(callback)
118
97
  }
119
98
 
120
- map<T>(callback: (treeNode: TreeNode) => T): Array<T> {
121
- let data: Array<T> = []
99
+ filterDeep(callback: (treeNode: TreeNode) => boolean): Array<TreeNode> {
122
100
  if (typeof callback !== 'function') {
123
- throw new TypeError('forEach() callback must be a function')
101
+ throw new TypeError('filter() callback must be a function')
124
102
  }
125
103
 
126
- // run this node through function
127
- data.push(callback(this))
104
+ return this.leaves.filter(callback)
105
+ }
128
106
 
129
- // do the same for all children
130
- if (this.children) {
131
- for (let i = 0, { length } = this.children; i < length; i++) {
132
- const childData = this.children[i]?.map(callback).filter(Boolean) || []
133
- data = [...new Set([...data, ...childData])]
134
- }
107
+ mapDeep<T>(callback: (treeNode: TreeNode) => T): Array<T> {
108
+ if (typeof callback !== 'function') {
109
+ throw new TypeError('map() callback must be a function')
135
110
  }
136
111
 
137
- return data
112
+ return this.leaves.map(callback)
138
113
  }
139
114
 
140
115
  public static build(files: KubbFile.File[], root?: string): TreeNode | null {
@@ -1,8 +1,8 @@
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
7
  type SeqOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue> = Promise<Array<Awaited<ValueOfPromiseFuncArray<TInput>>>>
8
8