@kubb/core 2.0.0-beta.1 → 2.0.0-beta.10

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 (44) hide show
  1. package/dist/index.cjs +292 -240
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +61 -61
  4. package/dist/index.d.ts +61 -61
  5. package/dist/index.js +289 -236
  6. package/dist/index.js.map +1 -1
  7. package/dist/transformers.cjs +222 -0
  8. package/dist/transformers.cjs.map +1 -0
  9. package/dist/transformers.d.cts +55 -0
  10. package/dist/transformers.d.ts +55 -0
  11. package/dist/transformers.js +207 -0
  12. package/dist/transformers.js.map +1 -0
  13. package/dist/utils.cjs +302 -274
  14. package/dist/utils.cjs.map +1 -1
  15. package/dist/utils.d.cts +515 -67
  16. package/dist/utils.d.ts +515 -67
  17. package/dist/utils.js +303 -274
  18. package/dist/utils.js.map +1 -1
  19. package/package.json +14 -9
  20. package/src/BarrelManager.ts +55 -65
  21. package/src/FileManager.ts +93 -24
  22. package/src/PluginManager.ts +35 -17
  23. package/src/build.ts +1 -11
  24. package/src/index.ts +0 -1
  25. package/src/plugin.ts +4 -4
  26. package/src/transformers/casing.ts +9 -0
  27. package/src/transformers/createJSDocBlockText.ts +9 -0
  28. package/src/transformers/index.ts +36 -0
  29. package/src/transformers/trim.ts +7 -0
  30. package/src/types.ts +22 -41
  31. package/src/utils/FunctionParams.ts +3 -2
  32. package/src/utils/TreeNode.ts +6 -3
  33. package/src/utils/URLPath.ts +5 -5
  34. package/src/utils/index.ts +0 -1
  35. package/src/SchemaGenerator.ts +0 -8
  36. package/src/utils/transformers/createJSDocBlockText.ts +0 -15
  37. package/src/utils/transformers/index.ts +0 -22
  38. package/src/utils/transformers/trim.ts +0 -3
  39. /package/src/{utils/transformers → transformers}/combineCodes.ts +0 -0
  40. /package/src/{utils/transformers → transformers}/escape.ts +0 -0
  41. /package/src/{utils/transformers → transformers}/indent.ts +0 -0
  42. /package/src/{utils/transformers → transformers}/nameSorter.ts +0 -0
  43. /package/src/{utils/transformers → transformers}/searchAndReplace.ts +0 -0
  44. /package/src/{utils/transformers → transformers}/transformReservedWord.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-namespace */
2
2
  import crypto from 'node:crypto'
3
- import { extname } from 'node:path'
3
+ import { extname, resolve } from 'node:path'
4
4
 
5
5
  import { print } from '@kubb/parser'
6
6
  import * as factory from '@kubb/parser/factory'
@@ -8,9 +8,9 @@ import * as factory from '@kubb/parser/factory'
8
8
  import isEqual from 'lodash.isequal'
9
9
  import { orderBy } from 'natural-orderby'
10
10
 
11
- import { read } from './utils/read.ts'
11
+ import transformers from './transformers/index.ts'
12
+ import { getRelativePath, read } from './utils/read.ts'
12
13
  import { timeout } from './utils/timeout.ts'
13
- import { transformers } from './utils/transformers/index.ts'
14
14
  import { write } from './utils/write.ts'
15
15
  import { BarrelManager } from './BarrelManager.ts'
16
16
 
@@ -28,7 +28,14 @@ export namespace KubbFile {
28
28
  * @example ["useState"]
29
29
  * @example "React"
30
30
  */
31
- name: string | Array<string>
31
+ name:
32
+ | string
33
+ | Array<
34
+ string | {
35
+ propertyName: string
36
+ name?: string
37
+ }
38
+ >
32
39
  /**
33
40
  * Path for the import
34
41
  * @xample '@kubb/core'
@@ -38,6 +45,14 @@ export namespace KubbFile {
38
45
  * Add `type` prefix to the import, this will result in: `import type { Type } from './path'`.
39
46
  */
40
47
  isTypeOnly?: boolean
48
+ /**
49
+ * Add `* as` prefix to the import, this will result in: `import * as path from './path'`.
50
+ */
51
+ isNameSpace?: boolean
52
+ /**
53
+ * When root is set it will get the path with relative getRelativePath(root, path).
54
+ */
55
+ root?: string
41
56
  }
42
57
 
43
58
  export type Export = {
@@ -104,8 +119,8 @@ export namespace KubbFile {
104
119
  */
105
120
  id?: string
106
121
  /**
107
- * Name to be used to dynamicly create the baseName(based on input.path)
108
- * Based on UNIX basename
122
+ * Name to be used to create the path
123
+ * Based on UNIX basename, `${name}.extName`
109
124
  * @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
110
125
  */
111
126
  baseName: TBaseName
@@ -130,10 +145,6 @@ export namespace KubbFile {
130
145
  * This will override `process.env[key]` inside the `source`, see `getFileSource`.
131
146
  */
132
147
  env?: NodeJS.ProcessEnv
133
- /**
134
- * @deprecated
135
- */
136
- validate?: boolean
137
148
  }
138
149
 
139
150
  export type ResolvedFile<
@@ -144,6 +155,12 @@ export namespace KubbFile {
144
155
  * @default crypto.randomUUID()
145
156
  */
146
157
  id: UUID
158
+ /**
159
+ * Contains the first part of the baseName, generated based on baseName
160
+ * @link https://nodejs.org/api/path.html#pathformatpathobject
161
+ */
162
+
163
+ name: string
147
164
  }
148
165
  }
149
166
 
@@ -156,8 +173,19 @@ type AddResult<T extends Array<KubbFile.File>> = Promise<
156
173
  >
157
174
 
158
175
  type AddIndexesProps = {
159
- root: KubbFile.Path
160
- extName?: KubbFile.Extname
176
+ /**
177
+ * Root based on root and output.path specified in the config
178
+ */
179
+ root: string
180
+ /**
181
+ * Output for plugin
182
+ */
183
+ output: {
184
+ path: string
185
+ exportAs?: string
186
+ extName?: KubbFile.Extname
187
+ exportType?: 'barrel' | false
188
+ }
161
189
  options?: BarrelManagerOptions
162
190
  meta?: KubbFile.File['meta']
163
191
  }
@@ -205,10 +233,6 @@ export class FileManager {
205
233
  }
206
234
 
207
235
  #validate(file: KubbFile.File): void {
208
- if (!file.validate) {
209
- return
210
- }
211
-
212
236
  if (!file.path.toLowerCase().endsWith(file.baseName.toLowerCase())) {
213
237
  throw new Error(`${file.path} should end with the baseName ${file.baseName}`)
214
238
  }
@@ -218,7 +242,7 @@ export class FileManager {
218
242
  ...files: T
219
243
  ): AddResult<T> {
220
244
  const promises = files.map((file) => {
221
- this.#validate(file)
245
+ // this.#validate(file)
222
246
 
223
247
  if (file.override) {
224
248
  return this.#add(file)
@@ -238,7 +262,7 @@ export class FileManager {
238
262
 
239
263
  async #add(file: KubbFile.File): Promise<KubbFile.ResolvedFile> {
240
264
  const controller = new AbortController()
241
- const resolvedFile: KubbFile.ResolvedFile = { id: crypto.randomUUID(), ...file }
265
+ const resolvedFile: KubbFile.ResolvedFile = { id: crypto.randomUUID(), name: transformers.trimExtName(file.baseName), ...file }
242
266
 
243
267
  this.#cache.set(resolvedFile.path, [{ cancel: () => controller.abort(), ...resolvedFile }])
244
268
 
@@ -272,15 +296,45 @@ export class FileManager {
272
296
  return this.#add(file)
273
297
  }
274
298
 
275
- async addIndexes({ root, extName = '.ts', meta, options = {} }: AddIndexesProps): Promise<Array<KubbFile.File> | undefined> {
276
- const barrelManager = new BarrelManager(options)
299
+ async addIndexes({ root, output, meta, options = {} }: AddIndexesProps): Promise<Array<KubbFile.File> | undefined> {
300
+ const { exportType = 'barrel' } = output
301
+
302
+ if (!exportType) {
303
+ return undefined
304
+ }
277
305
 
278
- const files = barrelManager.getIndexes(root, extName)
306
+ const exportPath = output.path.startsWith('./') ? output.path : `./${output.path}`
307
+ const barrelManager = new BarrelManager({ extName: output.extName, ...options })
308
+ const files = barrelManager.getIndexes(resolve(root, output.path))
279
309
 
280
310
  if (!files) {
281
311
  return undefined
282
312
  }
283
313
 
314
+ const rootFile: KubbFile.File = {
315
+ path: resolve(root, 'index.ts'),
316
+ baseName: 'index.ts',
317
+ source: '',
318
+ exports: [
319
+ output.exportAs
320
+ ? {
321
+ name: output.exportAs,
322
+ asAlias: true,
323
+ path: exportPath,
324
+ isTypeOnly: options.isTypeOnly,
325
+ }
326
+ : {
327
+ path: exportPath,
328
+ isTypeOnly: options.isTypeOnly,
329
+ },
330
+ ],
331
+ }
332
+
333
+ await this.#addOrAppend({
334
+ ...rootFile,
335
+ meta: meta ? meta : rootFile.meta,
336
+ })
337
+
284
338
  return await Promise.all(
285
339
  files.map((file) => {
286
340
  return this.#addOrAppend({
@@ -342,9 +396,24 @@ export class FileManager {
342
396
  const exports = file.exports ? combineExports(file.exports) : []
343
397
  const imports = file.imports ? combineImports(file.imports, exports, file.source) : []
344
398
 
345
- const importNodes = imports.map((item) => factory.createImportDeclaration({ name: item.name, path: item.path, isTypeOnly: item.isTypeOnly }))
399
+ const importNodes = imports.filter(item => {
400
+ // isImportNotNeeded
401
+ // trim extName
402
+ return item.path !== transformers.trimExtName(file.path)
403
+ }).map((item) => {
404
+ return factory.createImportDeclaration({
405
+ name: item.name,
406
+ path: item.root ? getRelativePath(item.root, item.path) : item.path,
407
+ isTypeOnly: item.isTypeOnly,
408
+ })
409
+ })
346
410
  const exportNodes = exports.map((item) =>
347
- factory.createExportDeclaration({ name: item.name, path: item.path, isTypeOnly: item.isTypeOnly, asAlias: item.asAlias })
411
+ factory.createExportDeclaration({
412
+ name: item.name,
413
+ path: item.path,
414
+ isTypeOnly: item.isTypeOnly,
415
+ asAlias: item.asAlias,
416
+ })
348
417
  )
349
418
 
350
419
  return [print([...importNodes, ...exportNodes]), getEnvSource(file.source, file.env)].join('\n')
@@ -452,7 +521,7 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
452
521
  }
453
522
 
454
523
  if (Array.isArray(name)) {
455
- name = name.filter((item) => hasImportInSource(item))
524
+ name = name.filter((item) => typeof item === 'string' ? hasImportInSource(item) : hasImportInSource(item.propertyName))
456
525
  }
457
526
 
458
527
  const prevByPath = prev.findLast((imp) => imp.path === curr.path && imp.isTypeOnly === curr.isTypeOnly)
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-unsafe-argument */
2
2
 
3
+ import { transformReservedWord } from './transformers/transformReservedWord.ts'
3
4
  import { EventEmitter } from './utils/EventEmitter.ts'
4
5
  import { LogLevel } from './utils/logger.ts'
5
6
  import { Queue } from './utils/Queue.ts'
6
- import { transformReservedWord } from './utils/transformers/transformReservedWord.ts'
7
7
  import { setUniqueName } from './utils/uniqueName.ts'
8
8
  import { ValidationPluginError } from './errors.ts'
9
9
  import { FileManager } from './FileManager.ts'
@@ -129,11 +129,11 @@ export class PluginManager {
129
129
  parameters: [params.baseName, params.directory, params.options as object],
130
130
  })
131
131
 
132
- if (paths && paths?.length > 1) {
133
- throw new Error(
132
+ if (paths && paths?.length > 1 && this.logger.logLevel === LogLevel.debug) {
133
+ this.logger.warn(
134
134
  `Cannot return a path where the 'pluginKey' ${params.pluginKey ? JSON.stringify(params.pluginKey) : '"'} is not unique enough\n\nPaths: ${
135
135
  JSON.stringify(paths, undefined, 2)
136
- }`,
136
+ }\n\nFalling back on the first item.\n`,
137
137
  )
138
138
  }
139
139
 
@@ -153,11 +153,11 @@ export class PluginManager {
153
153
  parameters: [params.name, params.type],
154
154
  })
155
155
 
156
- if (names && names?.length > 1) {
157
- throw new Error(
156
+ if (names && names?.length > 1 && this.logger.logLevel === LogLevel.debug) {
157
+ this.logger.warn(
158
158
  `Cannot return a name where the 'pluginKey' ${params.pluginKey ? JSON.stringify(params.pluginKey) : '"'} is not unique enough\n\nNames: ${
159
159
  JSON.stringify(names, undefined, 2)
160
- }`,
160
+ }\n\nFalling back on the first item.\n`,
161
161
  )
162
162
  }
163
163
 
@@ -379,7 +379,7 @@ export class PluginManager {
379
379
  const plugins = [...this.plugins].filter((plugin) => plugin.name !== 'core')
380
380
 
381
381
  if (hookName) {
382
- if (this.logger.logLevel === 'info') {
382
+ if (this.logger.logLevel === LogLevel.info) {
383
383
  const containsHookName = plugins.some((item) => item[hookName])
384
384
  if (!containsHookName) {
385
385
  this.logger.warn(`No hook ${hookName} found`)
@@ -388,28 +388,46 @@ export class PluginManager {
388
388
 
389
389
  return plugins.filter((item) => item[hookName])
390
390
  }
391
+ // TODO add test case for sorting with pre/post
391
392
 
392
- return plugins
393
+ return plugins.map(plugin => {
394
+ if (plugin.pre) {
395
+ const isValid = plugin.pre.every(pluginName => plugins.find(pluginToFind => pluginToFind.name === pluginName))
396
+
397
+ if (!isValid) {
398
+ throw new ValidationPluginError(`This plugin has a pre set that is not valid(${JSON.stringify(plugin.pre, undefined, 2)})`)
399
+ }
400
+ }
401
+
402
+ return plugin
403
+ }).sort((a, b) => {
404
+ if (b.pre?.includes(a.name)) {
405
+ return 1
406
+ }
407
+ if (b.post?.includes(a.name)) {
408
+ return -1
409
+ }
410
+ return 0
411
+ })
393
412
  }
394
413
 
395
414
  getPluginsByKey(hookName: keyof PluginLifecycle, pluginKey: KubbPlugin['key']): KubbPlugin[] {
396
415
  const plugins = [...this.plugins]
397
- const [searchKind, searchPluginName, searchIdentifier] = pluginKey
416
+ const [searchPluginName, searchIdentifier] = pluginKey
398
417
 
399
418
  const pluginByPluginName = plugins
400
419
  .filter((plugin) => plugin[hookName])
401
420
  .filter((item) => {
402
- const [kind, name, identifier] = item.key
421
+ const [name, identifier] = item.key
403
422
 
404
423
  const identifierCheck = identifier?.toString() === searchIdentifier?.toString()
405
- const kindCheck = kind === searchKind
406
424
  const nameCheck = name === searchPluginName
407
425
 
408
426
  if (searchIdentifier) {
409
- return identifierCheck && kindCheck && nameCheck
427
+ return identifierCheck && nameCheck
410
428
  }
411
429
 
412
- return kindCheck && nameCheck
430
+ return nameCheck
413
431
  })
414
432
 
415
433
  if (!pluginByPluginName?.length) {
@@ -417,7 +435,7 @@ export class PluginManager {
417
435
 
418
436
  const corePlugin = plugins.find((plugin) => plugin.name === 'core' && plugin[hookName])
419
437
 
420
- if (this.logger.logLevel === 'info') {
438
+ if (this.logger.logLevel === LogLevel.debug) {
421
439
  if (corePlugin) {
422
440
  this.logger.warn(`No hook '${hookName}' for pluginKey '${JSON.stringify(pluginKey)}' found, falling back on the '@kubb/core' plugin`)
423
441
  } else {
@@ -569,7 +587,7 @@ export class PluginManager {
569
587
 
570
588
  setUniqueName(plugin.name, usedPluginNames)
571
589
 
572
- const key = plugin.key || ([plugin.kind, plugin.name, usedPluginNames[plugin.name]].filter(Boolean) as [typeof plugin.kind, typeof plugin.name, string])
590
+ const key = [plugin.name, usedPluginNames[plugin.name]].filter(Boolean) as [typeof plugin.name, string]
573
591
 
574
592
  if (plugin.name !== 'core' && usedPluginNames[plugin.name]! >= 2) {
575
593
  pluginManager.logger.warn('Using multiple of the same plugin is an experimental feature')
@@ -624,6 +642,6 @@ export class PluginManager {
624
642
 
625
643
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
626
644
  static get hooks() {
627
- return ['validate', 'buildStart', 'resolvePath', 'resolveName', 'load', 'transform', 'writeFile', 'buildEnd'] as const
645
+ return ['buildStart', 'resolvePath', 'resolveName', 'load', 'transform', 'writeFile', 'buildEnd'] as const
628
646
  }
629
647
  }
package/src/build.ts CHANGED
@@ -116,7 +116,7 @@ async function setup(options: BuildOptions): Promise<PluginManager> {
116
116
  logger.spinner.start(`💾 Writing`)
117
117
  }
118
118
 
119
- if (logger.logLevel === 'debug') {
119
+ if (logger.logLevel === LogLevel.debug) {
120
120
  logger.info(`PluginKey ${pc.dim(JSON.stringify(plugin.key))} \nwith source\n\n${code}`)
121
121
  }
122
122
  }
@@ -157,11 +157,6 @@ export async function build(options: BuildOptions): Promise<BuildOutput> {
157
157
 
158
158
  const { fileManager, logger } = pluginManager
159
159
 
160
- await pluginManager.hookParallel<'validate', true>({
161
- hookName: 'validate',
162
- parameters: [pluginManager.plugins],
163
- })
164
-
165
160
  await pluginManager.hookParallel({
166
161
  hookName: 'buildStart',
167
162
  parameters: [options.config],
@@ -183,11 +178,6 @@ export async function safeBuild(options: BuildOptions): Promise<BuildOutput> {
183
178
  const { fileManager, logger } = pluginManager
184
179
 
185
180
  try {
186
- await pluginManager.hookParallel<'validate', true>({
187
- hookName: 'validate',
188
- parameters: [pluginManager.plugins],
189
- })
190
-
191
181
  await pluginManager.hookParallel({
192
182
  hookName: 'buildStart',
193
183
  parameters: [options.config],
package/src/index.ts CHANGED
@@ -12,7 +12,6 @@ export { PackageManager } from './PackageManager.ts'
12
12
  export { createPlugin, pluginName as name, pluginName } from './plugin.ts'
13
13
  export { PluginManager } from './PluginManager.ts'
14
14
  export { PromiseManager } from './PromiseManager.ts'
15
- export { SchemaGenerator } from './SchemaGenerator.ts'
16
15
  export * from './types.ts'
17
16
 
18
17
  export interface _Register {}
package/src/plugin.ts CHANGED
@@ -26,10 +26,10 @@ type Options = {
26
26
  }
27
27
 
28
28
  // not publicly exported
29
- export type CorePluginOptions = PluginFactoryOptions<'core', 'controller', Options, Options, PluginContext, never>
29
+ export type CorePluginOptions = PluginFactoryOptions<'core', Options, Options, PluginContext, never>
30
30
 
31
31
  export const pluginName = 'core' satisfies CorePluginOptions['name']
32
- export const pluginKey: CorePluginOptions['key'] = ['controller', pluginName] satisfies CorePluginOptions['key']
32
+ export const pluginKey: CorePluginOptions['key'] = [pluginName] satisfies CorePluginOptions['key']
33
33
 
34
34
  export const definePlugin = createPlugin<CorePluginOptions>((options) => {
35
35
  const { fileManager, pluginManager, resolvePath, resolveName, logger } = options
@@ -37,8 +37,8 @@ export const definePlugin = createPlugin<CorePluginOptions>((options) => {
37
37
  return {
38
38
  name: pluginName,
39
39
  options,
40
- key: ['controller', 'core'],
41
- kind: 'controller',
40
+ key: ['core'],
41
+
42
42
  api() {
43
43
  return {
44
44
  get config() {
@@ -0,0 +1,9 @@
1
+ import { camelCase as changeCaseCamel, camelCaseTransformMerge, pascalCase as changePascalCase, pascalCaseTransformMerge } from 'change-case'
2
+
3
+ export function camelCase(text: string): string {
4
+ return changeCaseCamel(text, { delimiter: '', stripRegexp: /[^A-Z0-9$]/gi, transform: camelCaseTransformMerge })
5
+ }
6
+
7
+ export function pascalCase(text: string): string {
8
+ return changePascalCase(text, { delimiter: '', stripRegexp: /[^A-Z0-9$]/gi, transform: pascalCaseTransformMerge })
9
+ }
@@ -0,0 +1,9 @@
1
+ export function createJSDocBlockText({ comments }: { comments: Array<string> }): string {
2
+ const filteredComments = comments.filter(Boolean)
3
+
4
+ if (!filteredComments.length) {
5
+ return ''
6
+ }
7
+
8
+ return `/**\n * ${filteredComments.join('\n * ')}\n */`
9
+ }
@@ -0,0 +1,36 @@
1
+ import { camelCase, pascalCase } from './casing.ts'
2
+ import { combineCodes } from './combineCodes.ts'
3
+ import { createJSDocBlockText } from './createJSDocBlockText.ts'
4
+ import { escape, jsStringEscape } from './escape.ts'
5
+ import { createIndent } from './indent.ts'
6
+ import { nameSorter } from './nameSorter.ts'
7
+ import { searchAndReplace } from './searchAndReplace.ts'
8
+ import { transformReservedWord } from './transformReservedWord.ts'
9
+ import { trim, trimExtName } from './trim.ts'
10
+
11
+ export { camelCase, pascalCase } from './casing.ts'
12
+ export { combineCodes } from './combineCodes.ts'
13
+ export { createJSDocBlockText } from './createJSDocBlockText.ts'
14
+ export { escape, jsStringEscape } from './escape.ts'
15
+ export { createIndent } from './indent.ts'
16
+ export { nameSorter } from './nameSorter.ts'
17
+ export { searchAndReplace } from './searchAndReplace.ts'
18
+ export { transformReservedWord } from './transformReservedWord.ts'
19
+ export { trim, trimExtName } from './trim.ts'
20
+
21
+ export default {
22
+ combineCodes,
23
+ escape,
24
+ jsStringEscape,
25
+ createIndent,
26
+ transformReservedWord,
27
+ nameSorter,
28
+ searchAndReplace,
29
+ trim,
30
+ trimExtName,
31
+ JSDoc: {
32
+ createJSDocBlockText,
33
+ },
34
+ camelCase,
35
+ pascalCase,
36
+ } as const
@@ -0,0 +1,7 @@
1
+ export function trim(text: string): string {
2
+ return text.replaceAll(/\n/g, '').trim()
3
+ }
4
+
5
+ export function trimExtName(text: string): string {
6
+ return text.replace(/\.[^/.]+$/, '')
7
+ }
package/src/types.ts CHANGED
@@ -123,8 +123,6 @@ export type CLIOptions = {
123
123
 
124
124
  // plugin
125
125
 
126
- export type KubbPluginKind = 'schema' | 'controller'
127
-
128
126
  export type KubbUnionPlugins = PluginUnion
129
127
 
130
128
  export type KubbObjectPlugin = keyof OptionsPlugins
@@ -134,10 +132,6 @@ export type PluginFactoryOptions<
134
132
  * Name to be used for the plugin, this will also be used for they key.
135
133
  */
136
134
  TName extends string = string,
137
- /**
138
- * @type "schema" | "controller"
139
- */
140
- TKind extends KubbPluginKind = KubbPluginKind,
141
135
  /**
142
136
  * Options of the plugin.
143
137
  */
@@ -161,18 +155,17 @@ export type PluginFactoryOptions<
161
155
  TAppMeta = unknown,
162
156
  > = {
163
157
  name: TName
164
- kind: TKind
165
158
  /**
166
159
  * Same behaviour like what has been done with `QueryKey` in `@tanstack/react-query`
167
160
  */
168
- key: [kind: TKind | undefined, name: TName | string, identifier?: string | number]
161
+ key: [name: TName | string, identifier?: string | number]
169
162
  options: TOptions
170
163
  resolvedOptions: TResolvedOptions
171
164
  api: TAPI
172
165
  resolvePathOptions: TResolvePathOptions
173
166
  appMeta: {
174
167
  pluginManager: PluginManager
175
- plugin: KubbPlugin<PluginFactoryOptions<TName, TKind, TOptions, TResolvedOptions, TAPI, TResolvePathOptions, TAppMeta>>
168
+ plugin: KubbPlugin<PluginFactoryOptions<TName, TOptions, TResolvedOptions, TAPI, TResolvePathOptions, TAppMeta>>
176
169
  } & TAppMeta
177
170
  }
178
171
 
@@ -182,18 +175,23 @@ export type KubbUserPlugin<TOptions extends PluginFactoryOptions = PluginFactory
182
175
  & {
183
176
  /**
184
177
  * Unique name used for the plugin
178
+ * The name of the plugin follows the format scope:foo-bar or foo-bar, adding scope: can avoid naming conflicts with other plugins.
185
179
  * @example @kubb/typescript
186
180
  */
187
181
  name: TOptions['name']
188
- /**
189
- * Internal key used when a developer uses more than one of the same plugin
190
- * @private
191
- */
192
- key?: TOptions['key']
193
182
  /**
194
183
  * Options set for a specific plugin(see kubb.config.js), passthrough of options.
195
184
  */
196
185
  options: TOptions['resolvedOptions']
186
+ /**
187
+ * 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.
188
+ * Can be used to validate depended plugins.
189
+ */
190
+ pre?: Array<string>
191
+ /**
192
+ * Specifies the succeeding plugins for the current plugin. You can pass an array of succeeding plugin names, and the current plugin will be executed before these plugins.
193
+ */
194
+ post?: Array<string>
197
195
  }
198
196
  & (TOptions['api'] extends never ? {
199
197
  api?: never
@@ -201,24 +199,10 @@ export type KubbUserPlugin<TOptions extends PluginFactoryOptions = PluginFactory
201
199
  : {
202
200
  api: (this: TOptions['name'] extends 'core' ? null : Omit<PluginContext<TOptions>, 'addFile'>) => TOptions['api']
203
201
  })
204
- & (TOptions['kind'] extends never ? {
205
- kind?: never
206
- }
207
- : {
208
- /**
209
- * Kind/type for the plugin
210
- *
211
- * Type 'schema' can be used for JSON schema's, TypeScript types, ...
212
- *
213
- * Type 'controller' can be used to create generate API calls, React-Query hooks, Axios controllers, ...
214
- * @default undefined
215
- */
216
- kind: TOptions['kind']
217
- })
218
202
 
219
203
  export type KubbUserPluginWithLifeCycle<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = KubbUserPlugin<TOptions> & PluginLifecycle<TOptions>
220
204
 
221
- type UnknownKubbUserPlugin = KubbUserPlugin<PluginFactoryOptions<any, any, any, any, any, any, any>>
205
+ type UnknownKubbUserPlugin = KubbUserPlugin<PluginFactoryOptions<any, any, any, any, any, any>>
222
206
 
223
207
  export type KubbPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions> =
224
208
  & {
@@ -233,16 +217,18 @@ export type KubbPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOpti
233
217
  */
234
218
  key: TOptions['key']
235
219
  /**
236
- * Options set for a specific plugin(see kubb.config.js), passthrough of options.
220
+ * 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.
221
+ * Can be used to validate depended plugins.
237
222
  */
238
- options: TOptions['resolvedOptions']
223
+ pre?: Array<string>
239
224
  /**
240
- * Kind/type for the plugin
241
- * Type 'schema' can be used for JSON schema's, TypeScript types, ...
242
- * Type 'controller' can be used to create generate API calls, React-Query hooks, Axios controllers, ...
243
- * @default undefined
225
+ * Specifies the succeeding plugins for the current plugin. You can pass an array of succeeding plugin names, and the current plugin will be executed before these plugins.
244
226
  */
245
- kind?: TOptions['kind']
227
+ post?: Array<string>
228
+ /**
229
+ * Options set for a specific plugin(see kubb.config.js), passthrough of options.
230
+ */
231
+ options: TOptions['resolvedOptions']
246
232
  /**
247
233
  * Define an api that can be used by other plugins, see `PluginManager' where we convert from `KubbUserPlugin` to `KubbPlugin`(used when calling `createPlugin`).
248
234
  */
@@ -257,11 +243,6 @@ export type KubbPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOpti
257
243
  export type KubbPluginWithLifeCycle<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = KubbPlugin<TOptions> & PluginLifecycle<TOptions>
258
244
 
259
245
  export type PluginLifecycle<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
260
- /**
261
- * Valdiate all plugins to see if their depended plugins are installed and configured.
262
- * @type hookParallel
263
- */
264
- validate?: (this: Omit<PluginContext<TOptions>, 'addFile'>, plugins: NonNullable<KubbConfig['plugins']>) => PossiblePromise<true>
265
246
  /**
266
247
  * Start of the lifecycle of a plugin.
267
248
  * @type hookParallel
@@ -1,6 +1,7 @@
1
- import { camelCase, camelCaseTransformMerge } from 'change-case'
2
1
  import { orderBy } from 'natural-orderby'
3
2
 
3
+ import transformers from '../transformers/index.ts'
4
+
4
5
  type FunctionParamsASTWithoutType = {
5
6
  name?: string
6
7
  type?: string
@@ -66,7 +67,7 @@ export class FunctionParams {
66
67
  return acc
67
68
  }
68
69
  // TODO check whey we still need the camelcase here
69
- const parameterName = name.startsWith('{') ? name : camelCase(name, { delimiter: '', transform: camelCaseTransformMerge })
70
+ const parameterName = name.startsWith('{') ? name : transformers.camelCase(name)
70
71
 
71
72
  if (type) {
72
73
  if (required) {
@@ -3,10 +3,13 @@ import dirTree from 'directory-tree'
3
3
  import { FileManager } from '../FileManager.ts'
4
4
 
5
5
  import type { DirectoryTree, DirectoryTreeOptions } from 'directory-tree'
6
+ import type { KubbFile } from '../FileManager.ts'
6
7
 
7
8
  export type TreeNodeOptions = DirectoryTreeOptions
8
9
 
9
- export class TreeNode<T = unknown> {
10
+ type BarrelData = { type: KubbFile.Mode; path: KubbFile.Path; name: string }
11
+
12
+ export class TreeNode<T = BarrelData> {
10
13
  public data: T
11
14
 
12
15
  public parent?: TreeNode<T>
@@ -91,7 +94,7 @@ export class TreeNode<T = unknown> {
91
94
  return this
92
95
  }
93
96
 
94
- public static build<T = unknown>(path: string, options: TreeNodeOptions = {}): TreeNode<T> | null {
97
+ public static build(path: string, options: TreeNodeOptions = {}): TreeNode | null {
95
98
  try {
96
99
  const exclude = Array.isArray(options.exclude) ? options.exclude : [options.exclude].filter(Boolean)
97
100
  const filteredTree = dirTree(path, { extensions: options.extensions, exclude: [/node_modules/, ...exclude] })
@@ -114,7 +117,7 @@ export class TreeNode<T = unknown> {
114
117
 
115
118
  filteredTree.children?.forEach((child) => recurse(treeNode, child))
116
119
 
117
- return treeNode as TreeNode<T>
120
+ return treeNode
118
121
  } catch (e) {
119
122
  throw new Error('Something went wrong with creating index files with the TreehNode class', { cause: e })
120
123
  }