@kubb/core 4.33.0 → 4.33.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 (85) hide show
  1. package/dist/hooks.d.ts +1 -1
  2. package/dist/index.cjs +1695 -82
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +150 -20
  5. package/dist/index.js +1673 -65
  6. package/dist/index.js.map +1 -1
  7. package/dist/{types-f_no0d7G.d.ts → types-DfjjJb2r.d.ts} +70 -27
  8. package/package.json +3 -24
  9. package/src/BarrelManager.ts +10 -31
  10. package/src/PackageManager.ts +13 -21
  11. package/src/PluginManager.ts +65 -87
  12. package/src/PromiseManager.ts +3 -5
  13. package/src/build.ts +61 -47
  14. package/src/config.ts +1 -1
  15. package/src/constants.ts +60 -0
  16. package/src/errors.ts +1 -14
  17. package/src/index.ts +6 -3
  18. package/src/types.ts +5 -14
  19. package/src/utils/FunctionParams.ts +7 -8
  20. package/src/utils/TreeNode.ts +12 -23
  21. package/src/utils/executeStrategies.ts +5 -3
  22. package/src/utils/formatters.ts +3 -20
  23. package/src/utils/getBarrelFiles.ts +8 -2
  24. package/src/utils/getConfigs.ts +6 -15
  25. package/src/utils/getPlugins.ts +7 -7
  26. package/src/utils/linters.ts +3 -20
  27. package/dist/fs-D4eqq6bR.cjs +0 -103
  28. package/dist/fs-D4eqq6bR.cjs.map +0 -1
  29. package/dist/fs-TVBCPkE-.js +0 -67
  30. package/dist/fs-TVBCPkE-.js.map +0 -1
  31. package/dist/fs.cjs +0 -8
  32. package/dist/fs.d.ts +0 -23
  33. package/dist/fs.js +0 -2
  34. package/dist/packageManager-_7I0WFQU.d.ts +0 -82
  35. package/dist/packageManager-jzjuEj2U.cjs +0 -1103
  36. package/dist/packageManager-jzjuEj2U.cjs.map +0 -1
  37. package/dist/packageManager-wMCQlgd6.js +0 -1024
  38. package/dist/packageManager-wMCQlgd6.js.map +0 -1
  39. package/dist/transformers-BwSpAhvT.js +0 -267
  40. package/dist/transformers-BwSpAhvT.js.map +0 -1
  41. package/dist/transformers-BweFhqh-.cjs +0 -380
  42. package/dist/transformers-BweFhqh-.cjs.map +0 -1
  43. package/dist/transformers.cjs +0 -24
  44. package/dist/transformers.d.ts +0 -108
  45. package/dist/transformers.js +0 -2
  46. package/dist/utils.cjs +0 -430
  47. package/dist/utils.cjs.map +0 -1
  48. package/dist/utils.d.ts +0 -290
  49. package/dist/utils.js +0 -402
  50. package/dist/utils.js.map +0 -1
  51. package/src/BaseGenerator.ts +0 -34
  52. package/src/fs/clean.ts +0 -5
  53. package/src/fs/exists.ts +0 -16
  54. package/src/fs/index.ts +0 -5
  55. package/src/fs/read.ts +0 -13
  56. package/src/fs/utils.ts +0 -32
  57. package/src/fs/write.ts +0 -46
  58. package/src/transformers/casing.ts +0 -62
  59. package/src/transformers/combineCodes.ts +0 -3
  60. package/src/transformers/createJSDocBlockText.ts +0 -9
  61. package/src/transformers/escape.ts +0 -31
  62. package/src/transformers/indent.ts +0 -3
  63. package/src/transformers/index.ts +0 -46
  64. package/src/transformers/nameSorter.ts +0 -9
  65. package/src/transformers/searchAndReplace.ts +0 -25
  66. package/src/transformers/stringify.ts +0 -25
  67. package/src/transformers/toRegExp.ts +0 -22
  68. package/src/transformers/transformReservedWord.ts +0 -106
  69. package/src/transformers/trim.ts +0 -18
  70. package/src/utils/AsyncEventEmitter.ts +0 -48
  71. package/src/utils/Cache.ts +0 -31
  72. package/src/utils/URLPath.ts +0 -146
  73. package/src/utils/buildJSDoc.ts +0 -34
  74. package/src/utils/checkOnlineStatus.ts +0 -40
  75. package/src/utils/formatHrtime.ts +0 -33
  76. package/src/utils/getNestedAccessor.ts +0 -25
  77. package/src/utils/index.ts +0 -26
  78. package/src/utils/packageManager.ts +0 -58
  79. package/src/utils/promise.ts +0 -13
  80. package/src/utils/renderTemplate.ts +0 -31
  81. package/src/utils/serializePluginOptions.ts +0 -29
  82. package/src/utils/timeout.ts +0 -11
  83. package/src/utils/tokenize.ts +0 -23
  84. package/src/utils/types.ts +0 -1
  85. package/src/utils/uniqueName.ts +0 -20
package/src/build.ts CHANGED
@@ -1,18 +1,17 @@
1
- import { resolve } from 'node:path'
1
+ import { dirname, resolve } from 'node:path'
2
+ import { AsyncEventEmitter, clean, exists, formatMs, getElapsedMs, getRelativePath, URLPath, write } from '@internals/utils'
2
3
  import type { KubbFile } from '@kubb/fabric-core/types'
3
4
  import type { Fabric } from '@kubb/react-fabric'
4
5
  import { createFabric } from '@kubb/react-fabric'
5
6
  import { typescriptParser } from '@kubb/react-fabric/parsers'
6
7
  import { fsPlugin } from '@kubb/react-fabric/plugins'
7
8
  import { isInputPath } from './config.ts'
9
+ import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION } from './constants.ts'
8
10
  import { BuildError } from './errors.ts'
9
- import { clean, exists, getRelativePath, write } from './fs/index.ts'
10
11
  import { PluginManager } from './PluginManager.ts'
11
12
  import type { Config, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
12
- import { AsyncEventEmitter } from './utils/AsyncEventEmitter.ts'
13
13
  import { getDiagnosticInfo } from './utils/diagnostics.ts'
14
- import { formatMs, getElapsedMs } from './utils/formatHrtime.ts'
15
- import { URLPath } from './utils/URLPath.ts'
14
+ import type { FileMetaBase } from './utils/getBarrelFiles.ts'
16
15
 
17
16
  type BuildOptions = {
18
17
  config: UserConfig
@@ -93,10 +92,8 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
93
92
  output: {
94
93
  write: true,
95
94
  barrelType: 'named',
96
- extension: {
97
- '.ts': '.ts',
98
- },
99
- defaultBanner: 'simple',
95
+ extension: DEFAULT_EXTENSION,
96
+ defaultBanner: DEFAULT_BANNER,
100
97
  ...userConfig.output,
101
98
  },
102
99
  plugins: userConfig.plugins as Config['plugins'],
@@ -159,7 +156,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
159
156
  const pluginManager = new PluginManager(definedConfig, {
160
157
  fabric,
161
158
  events,
162
- concurrency: 15, // Increased from 5 to 15 for better parallel plugin execution
159
+ concurrency: DEFAULT_CONCURRENCY,
163
160
  })
164
161
 
165
162
  return {
@@ -258,7 +255,8 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
258
255
 
259
256
  if (config.output.barrelType) {
260
257
  const root = resolve(config.root)
261
- const rootPath = resolve(root, config.output.path, 'index.ts')
258
+ const rootPath = resolve(root, config.output.path, BARREL_FILENAME)
259
+ const rootDir = dirname(rootPath)
262
260
 
263
261
  await events.emit('debug', {
264
262
  date: new Date(),
@@ -274,45 +272,15 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
274
272
  logs: [`Found ${barrelFiles.length} indexable files for barrel export`],
275
273
  })
276
274
 
277
- // Build a Map of plugin keys to plugins for efficient lookups
278
- const pluginKeyMap = new Map<string, Plugin>()
279
- for (const plugin of pluginManager.plugins) {
280
- pluginKeyMap.set(JSON.stringify(plugin.key), plugin)
281
- }
275
+ const existingBarrel = fabric.files.find((f) => f.path === rootPath)
276
+ const existingExports = new Set(
277
+ existingBarrel?.exports?.flatMap((e) => (Array.isArray(e.name) ? e.name : [e.name])).filter((n): n is string => Boolean(n)) ?? [],
278
+ )
282
279
 
283
280
  const rootFile: KubbFile.File = {
284
281
  path: rootPath,
285
- baseName: 'index.ts',
286
- exports: barrelFiles
287
- .flatMap((file) => {
288
- const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly)
289
-
290
- return file.sources
291
- ?.map((source) => {
292
- if (!file.path || !source.isIndexable) {
293
- return undefined
294
- }
295
-
296
- // validate of the file is coming from plugin x, needs pluginKey on every file TODO update typing
297
- const meta = file.meta as any
298
- const plugin = meta?.pluginKey ? pluginKeyMap.get(JSON.stringify(meta.pluginKey)) : undefined
299
- const pluginOptions = plugin?.options as {
300
- output?: Output<any>
301
- }
302
-
303
- if (!pluginOptions || pluginOptions?.output?.barrelType === false) {
304
- return undefined
305
- }
306
-
307
- return {
308
- name: config.output.barrelType === 'all' ? undefined : [source.name],
309
- path: getRelativePath(rootPath, file.path),
310
- isTypeOnly: config.output.barrelType === 'all' ? containsOnlyTypes : source.isTypeOnly,
311
- } as KubbFile.Export
312
- })
313
- .filter(Boolean)
314
- })
315
- .filter(Boolean),
282
+ baseName: BARREL_FILENAME,
283
+ exports: buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }),
316
284
  sources: [],
317
285
  imports: [],
318
286
  meta: {},
@@ -350,3 +318,49 @@ export async function safeBuild(options: BuildOptions, overrides?: SetupResult):
350
318
  }
351
319
  }
352
320
  }
321
+
322
+ type BuildBarrelExportsParams = {
323
+ barrelFiles: KubbFile.ResolvedFile[]
324
+ rootDir: string
325
+ existingExports: Set<string>
326
+ config: Config
327
+ pluginManager: PluginManager
328
+ }
329
+
330
+ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, pluginManager }: BuildBarrelExportsParams): KubbFile.Export[] {
331
+ const pluginKeyMap = new Map<string, Plugin>()
332
+ for (const plugin of pluginManager.plugins) {
333
+ pluginKeyMap.set(JSON.stringify(plugin.key), plugin)
334
+ }
335
+
336
+ return barrelFiles.flatMap((file) => {
337
+ const containsOnlyTypes = file.sources?.every((source) => source.isTypeOnly)
338
+
339
+ return (file.sources ?? []).flatMap((source) => {
340
+ if (!file.path || !source.isIndexable) {
341
+ return []
342
+ }
343
+
344
+ const meta = file.meta as FileMetaBase | undefined
345
+ const plugin = meta?.pluginKey ? pluginKeyMap.get(JSON.stringify(meta.pluginKey)) : undefined
346
+ const pluginOptions = plugin?.options as { output?: Output<unknown> } | undefined
347
+
348
+ if (!pluginOptions || pluginOptions.output?.barrelType === false) {
349
+ return []
350
+ }
351
+
352
+ const exportName = config.output.barrelType === 'all' ? undefined : source.name ? [source.name] : undefined
353
+ if (exportName?.some((n) => existingExports.has(n))) {
354
+ return []
355
+ }
356
+
357
+ return [
358
+ {
359
+ name: exportName,
360
+ path: getRelativePath(rootDir, file.path),
361
+ isTypeOnly: config.output.barrelType === 'all' ? containsOnlyTypes : source.isTypeOnly,
362
+ } satisfies KubbFile.Export,
363
+ ]
364
+ })
365
+ })
366
+ }
package/src/config.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import type { PossiblePromise } from '@internals/utils'
1
2
  import type { InputPath, UserConfig } from './types.ts'
2
- import type { PossiblePromise } from './utils/types.ts'
3
3
 
4
4
  /**
5
5
  * CLI options derived from command-line flags.
@@ -0,0 +1,60 @@
1
+ import type { KubbFile } from '@kubb/fabric-core/types'
2
+
3
+ export const CORE_PLUGIN_NAME = 'core' as const
4
+
5
+ export const DEFAULT_MAX_LISTENERS = 100
6
+
7
+ export const DEFAULT_CONCURRENCY = 15
8
+
9
+ export const BARREL_FILENAME = 'index.ts' as const
10
+
11
+ export const DEFAULT_BANNER = 'simple' as const
12
+
13
+ export const DEFAULT_EXTENSION: Record<KubbFile.Extname, KubbFile.Extname | ''> = { '.ts': '.ts' }
14
+
15
+ export const PATH_SEPARATORS = ['/', '\\'] as const
16
+
17
+ export const logLevel = {
18
+ silent: Number.NEGATIVE_INFINITY,
19
+ error: 0,
20
+ warn: 1,
21
+ info: 3,
22
+ verbose: 4,
23
+ debug: 5,
24
+ } as const
25
+
26
+ export const linters = {
27
+ eslint: {
28
+ command: 'eslint',
29
+ args: (outputPath: string) => [outputPath, '--fix'],
30
+ errorMessage: 'Eslint not found',
31
+ },
32
+ biome: {
33
+ command: 'biome',
34
+ args: (outputPath: string) => ['lint', '--fix', outputPath],
35
+ errorMessage: 'Biome not found',
36
+ },
37
+ oxlint: {
38
+ command: 'oxlint',
39
+ args: (outputPath: string) => ['--fix', outputPath],
40
+ errorMessage: 'Oxlint not found',
41
+ },
42
+ } as const
43
+
44
+ export const formatters = {
45
+ prettier: {
46
+ command: 'prettier',
47
+ args: (outputPath: string) => ['--ignore-unknown', '--write', outputPath],
48
+ errorMessage: 'Prettier not found',
49
+ },
50
+ biome: {
51
+ command: 'biome',
52
+ args: (outputPath: string) => ['format', '--write', outputPath],
53
+ errorMessage: 'Biome not found',
54
+ },
55
+ oxfmt: {
56
+ command: 'oxfmt',
57
+ args: (outputPath: string) => [outputPath],
58
+ errorMessage: 'Oxfmt not found',
59
+ },
60
+ } as const
package/src/errors.ts CHANGED
@@ -1,14 +1 @@
1
- export class ValidationPluginError extends Error {}
2
-
3
- export class BuildError extends Error {
4
- cause: Error | undefined
5
- errors: Array<Error>
6
-
7
- constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {
8
- super(message, { cause: options.cause })
9
-
10
- this.name = 'BuildError'
11
- this.cause = options.cause
12
- this.errors = options.errors
13
- }
14
- }
1
+ export { BuildError, ValidationPluginError } from '@internals/utils'
package/src/index.ts CHANGED
@@ -1,13 +1,16 @@
1
- export { BaseGenerator } from './BaseGenerator.ts'
2
1
  export { build, build as default, safeBuild, setup } from './build.ts'
3
2
  export { type CLIOptions, defineConfig, isInputPath } from './config.ts'
3
+ export { formatters, linters, logLevel } from './constants.ts'
4
4
  export { defineLogger } from './defineLogger.ts'
5
5
  export { definePlugin } from './definePlugin.ts'
6
6
  export { PackageManager } from './PackageManager.ts'
7
7
  export { getMode, PluginManager } from './PluginManager.ts'
8
8
  export { PromiseManager } from './PromiseManager.ts'
9
9
  export * from './types.ts'
10
+ export type { FunctionParamsAST } from './utils/FunctionParams.ts'
11
+ export { FunctionParams } from './utils/FunctionParams.ts'
12
+ export { detectFormatter } from './utils/formatters.ts'
10
13
  export type { FileMetaBase } from './utils/getBarrelFiles.ts'
11
14
  export { getBarrelFiles } from './utils/getBarrelFiles.ts'
12
- export type { PackageManagerInfo, PackageManagerName } from './utils/packageManager.ts'
13
- export { detectPackageManager } from './utils/packageManager.ts'
15
+ export { getConfigs } from './utils/getConfigs.ts'
16
+ export { detectLinter } from './utils/linters.ts'
package/src/types.ts CHANGED
@@ -1,9 +1,9 @@
1
+ import type { AsyncEventEmitter, PossiblePromise } from '@internals/utils'
1
2
  import type { KubbFile } from '@kubb/fabric-core/types'
2
3
  import type { Fabric } from '@kubb/react-fabric'
4
+ import type { logLevel } from './constants.ts'
3
5
  import type { KubbEvents } from './Kubb.ts'
4
6
  import type { PluginManager } from './PluginManager.ts'
5
- import type { AsyncEventEmitter } from './utils/AsyncEventEmitter.ts'
6
- import type { PossiblePromise } from './utils/types.ts'
7
7
 
8
8
  declare global {
9
9
  namespace Kubb {
@@ -165,7 +165,7 @@ export type PluginFactoryOptions<
165
165
  /**
166
166
  * Context that you want to expose to other plugins.
167
167
  */
168
- TContext = any,
168
+ TContext = unknown,
169
169
  /**
170
170
  * When calling `resolvePath` you can specify better types.
171
171
  */
@@ -211,7 +211,7 @@ export type UserPlugin<TOptions extends PluginFactoryOptions = PluginFactoryOpti
211
211
 
212
212
  export type UserPluginWithLifeCycle<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = UserPlugin<TOptions> & PluginLifecycle<TOptions>
213
213
 
214
- type UnknownUserPlugin = UserPlugin<PluginFactoryOptions<any, any, any, any, any>>
214
+ export type UnknownUserPlugin = UserPlugin<PluginFactoryOptions<any, any, any, any, any>>
215
215
 
216
216
  export type Plugin<TOptions extends PluginFactoryOptions = PluginFactoryOptions> = {
217
217
  /**
@@ -362,20 +362,11 @@ export type Group = {
362
362
  name?: (context: GroupContext) => string
363
363
  }
364
364
 
365
- export const LogLevel = {
366
- silent: Number.NEGATIVE_INFINITY,
367
- error: 0,
368
- warn: 1,
369
- info: 3,
370
- verbose: 4,
371
- debug: 5,
372
- } as const
373
-
374
365
  export type LoggerOptions = {
375
366
  /**
376
367
  * @default 3
377
368
  */
378
- logLevel: (typeof LogLevel)[keyof typeof LogLevel]
369
+ logLevel: (typeof logLevel)[keyof typeof logLevel]
379
370
  }
380
371
 
381
372
  /**
@@ -1,5 +1,5 @@
1
+ import { camelCase } from '@internals/utils'
1
2
  import { sortBy } from 'remeda'
2
- import { camelCase } from '../transformers/casing.ts'
3
3
 
4
4
  type FunctionParamsASTWithoutType = {
5
5
  name?: string
@@ -38,9 +38,6 @@ export type FunctionParamsAST = FunctionParamsASTWithoutType | FunctionParamsAST
38
38
  */
39
39
  export class FunctionParams {
40
40
  #items: Array<FunctionParamsAST | FunctionParamsAST[]> = []
41
- constructor() {
42
- return this
43
- }
44
41
 
45
42
  get items(): FunctionParamsAST[] {
46
43
  return this.#items.flat()
@@ -52,9 +49,11 @@ export class FunctionParams {
52
49
  }
53
50
 
54
51
  if (Array.isArray(item)) {
55
- item.filter(Boolean).forEach((it) => {
56
- this.#items.push(it)
57
- })
52
+ item
53
+ .filter((x): x is FunctionParamsAST | FunctionParamsAST[] => x !== undefined)
54
+ .forEach((it) => {
55
+ this.#items.push(it)
56
+ })
58
57
  return this
59
58
  }
60
59
  this.#items.push(item)
@@ -83,7 +82,7 @@ export class FunctionParams {
83
82
 
84
83
  return acc
85
84
  }
86
- // TODO check whey we still need the camelcase here
85
+ // TODO check why we still need the camelcase here
87
86
  const parameterName = name.startsWith('{') ? name : camelCase(name)
88
87
 
89
88
  if (type) {
@@ -1,3 +1,4 @@
1
+ import path from 'node:path'
1
2
  import type { KubbFile } from '@kubb/fabric-core/types'
2
3
  import { getMode } from '../PluginManager.ts'
3
4
 
@@ -20,7 +21,6 @@ export class TreeNode {
20
21
  constructor(data: BarrelData, parent?: TreeNode) {
21
22
  this.data = data
22
23
  this.parent = parent
23
- return this
24
24
  }
25
25
 
26
26
  addChild(data: BarrelData): TreeNode {
@@ -49,12 +49,9 @@ export class TreeNode {
49
49
  return this.#cachedLeaves
50
50
  }
51
51
 
52
- // if not a leaf, return all children's leaves recursively
53
52
  const leaves: TreeNode[] = []
54
- if (this.children) {
55
- for (let childIndex = 0, { length } = this.children; childIndex < length; childIndex++) {
56
- leaves.push.apply(leaves, this.children[childIndex]!.leaves)
57
- }
53
+ for (const child of this.children) {
54
+ leaves.push(...child.leaves)
58
55
  }
59
56
 
60
57
  this.#cachedLeaves = leaves
@@ -67,14 +64,10 @@ export class TreeNode {
67
64
  throw new TypeError('forEach() callback must be a function')
68
65
  }
69
66
 
70
- // run this node through function
71
67
  callback(this)
72
68
 
73
- // do the same for all children
74
- if (this.children) {
75
- for (let childIndex = 0, { length } = this.children; childIndex < length; childIndex++) {
76
- this.children[childIndex]?.forEach(callback)
77
- }
69
+ for (const child of this.children) {
70
+ child.forEach(callback)
78
71
  }
79
72
 
80
73
  return this
@@ -153,16 +146,16 @@ export class TreeNode {
153
146
  }
154
147
  }
155
148
 
156
- export type DirectoryTree = {
149
+ type DirectoryTree = {
157
150
  name: string
158
151
  path: string
159
152
  file?: KubbFile.File
160
153
  children: Array<DirectoryTree>
161
154
  }
162
155
 
163
- const normalizePath = (p: string): string => p.replace(/\\/g, '/')
156
+ const normalizePath = (p: string): string => p.replaceAll('\\', '/')
164
157
 
165
- export function buildDirectoryTree(files: Array<KubbFile.File>, rootFolder = ''): DirectoryTree | null {
158
+ function buildDirectoryTree(files: Array<KubbFile.File>, rootFolder = ''): DirectoryTree | null {
166
159
  const normalizedRootFolder = normalizePath(rootFolder)
167
160
  const rootPrefix = normalizedRootFolder.endsWith('/') ? normalizedRootFolder : `${normalizedRootFolder}/`
168
161
 
@@ -182,17 +175,13 @@ export function buildDirectoryTree(files: Array<KubbFile.File>, rootFolder = '')
182
175
  }
183
176
 
184
177
  filteredFiles.forEach((file) => {
185
- const path = file.path.slice(rootFolder.length)
186
- const parts = path.split('/')
178
+ const relativePath = file.path.slice(rootFolder.length)
179
+ const parts = relativePath.split('/').filter(Boolean)
187
180
  let currentLevel: DirectoryTree[] = root.children
188
- let currentPath = rootFolder
181
+ let currentPath = normalizePath(rootFolder)
189
182
 
190
183
  parts.forEach((part, index) => {
191
- if (index !== 0) {
192
- currentPath += `/${part}`
193
- } else {
194
- currentPath += `${part}`
195
- }
184
+ currentPath = path.posix.join(currentPath, part)
196
185
 
197
186
  let existingNode = currentLevel.find((node) => node.name === part)
198
187
 
@@ -20,11 +20,13 @@ export function hookSeq<TInput extends Array<PromiseFunc<TValue, null>>, TValue,
20
20
  const calledFunc = func(state as TValue)
21
21
 
22
22
  if (calledFunc) {
23
- return calledFunc.then(Array.prototype.concat.bind(state))
23
+ return calledFunc.then(Array.prototype.concat.bind(state) as (result: TValue) => TValue[])
24
24
  }
25
+
26
+ return state
25
27
  })
26
28
  },
27
- Promise.resolve([] as unknown),
29
+ Promise.resolve([] as Array<TValue>),
28
30
  ) as TOutput
29
31
  }
30
32
 
@@ -35,7 +37,7 @@ type HookFirstOutput<TInput extends Array<PromiseFunc<TValue, null>>, TValue = u
35
37
  */
36
38
  export function hookFirst<TInput extends Array<PromiseFunc<TValue, null>>, TValue = unknown, TOutput = HookFirstOutput<TInput, TValue>>(
37
39
  promises: TInput,
38
- nullCheck = (state: any) => state !== null,
40
+ nullCheck: (state: unknown) => boolean = (state) => state !== null,
39
41
  ): TOutput {
40
42
  let promise: Promise<unknown> = Promise.resolve(null) as Promise<unknown>
41
43
 
@@ -1,22 +1,5 @@
1
1
  import { x } from 'tinyexec'
2
-
3
- export const formatters = {
4
- prettier: {
5
- command: 'prettier',
6
- args: (outputPath: string) => ['--ignore-unknown', '--write', outputPath],
7
- errorMessage: 'Prettier not found',
8
- },
9
- biome: {
10
- command: 'biome',
11
- args: (outputPath: string) => ['format', '--write', outputPath],
12
- errorMessage: 'Biome not found',
13
- },
14
- oxfmt: {
15
- command: 'oxfmt',
16
- args: (outputPath: string) => [outputPath],
17
- errorMessage: 'Oxfmt not found',
18
- },
19
- } as const
2
+ import type { formatters } from '../constants.ts'
20
3
 
21
4
  type Formatter = keyof typeof formatters
22
5
 
@@ -61,9 +44,9 @@ async function isFormatterAvailable(formatter: Formatter): Promise<boolean> {
61
44
  * ```
62
45
  */
63
46
  export async function detectFormatter(): Promise<Formatter | undefined> {
64
- const formatters: Formatter[] = ['biome', 'oxfmt', 'prettier']
47
+ const formatterNames: Formatter[] = ['biome', 'oxfmt', 'prettier']
65
48
 
66
- for (const formatter of formatters) {
49
+ for (const formatter of formatterNames) {
67
50
  if (await isFormatterAvailable(formatter)) {
68
51
  return formatter
69
52
  }
@@ -28,7 +28,13 @@ type AddIndexesProps = {
28
28
  }
29
29
 
30
30
  function trimExtName(text: string): string {
31
- return text.replace(/\.[^/.]+$/, '')
31
+ const dotIndex = text.lastIndexOf('.')
32
+ // Only strip when the dot is found and no path separator follows it
33
+ // (guards against stripping dots that are part of a directory name like /project.v2/gen)
34
+ if (dotIndex > 0 && !text.includes('/', dotIndex)) {
35
+ return text.slice(0, dotIndex)
36
+ }
37
+ return text
32
38
  }
33
39
 
34
40
  export async function getBarrelFiles(files: Array<KubbFile.ResolvedFile>, { type, meta = {}, root, output }: AddIndexesProps): Promise<KubbFile.File[]> {
@@ -36,7 +42,7 @@ export async function getBarrelFiles(files: Array<KubbFile.ResolvedFile>, { type
36
42
  return []
37
43
  }
38
44
 
39
- const barrelManager = new BarrelManager({})
45
+ const barrelManager = new BarrelManager()
40
46
 
41
47
  const pathToBuildFrom = join(root, output.path)
42
48
 
@@ -1,32 +1,23 @@
1
1
  import type { CLIOptions, defineConfig } from '../config.ts'
2
2
  import type { Config, UserConfig } from '../types.ts'
3
3
  import { getPlugins } from './getPlugins.ts'
4
- import { isPromise } from './promise.ts'
5
4
 
6
5
  /**
7
6
  * Converting UserConfig to Config Array without a change in the object beside the JSON convert.
8
7
  */
9
8
  export async function getConfigs(config: ReturnType<typeof defineConfig> | UserConfig, args: CLIOptions): Promise<Array<Config>> {
10
- let kubbUserConfig = Promise.resolve(config) as Promise<UserConfig | Array<UserConfig>>
9
+ const resolvedConfig: Promise<UserConfig | Array<UserConfig>> =
10
+ typeof config === 'function' ? Promise.resolve(config(args as CLIOptions)) : Promise.resolve(config)
11
11
 
12
- // for ts or js files
13
- if (typeof config === 'function') {
14
- const possiblePromise = config(args as CLIOptions)
15
- if (isPromise(possiblePromise)) {
16
- kubbUserConfig = possiblePromise
17
- }
18
- kubbUserConfig = Promise.resolve(possiblePromise)
19
- }
20
-
21
- let JSONConfig = await kubbUserConfig
12
+ let userConfigs = await resolvedConfig
22
13
 
23
- if (!Array.isArray(JSONConfig)) {
24
- JSONConfig = [JSONConfig]
14
+ if (!Array.isArray(userConfigs)) {
15
+ userConfigs = [userConfigs]
25
16
  }
26
17
 
27
18
  const results: Array<Config> = []
28
19
 
29
- for (const item of JSONConfig) {
20
+ for (const item of userConfigs) {
30
21
  const plugins = item.plugins ? await getPlugins(item.plugins) : undefined
31
22
 
32
23
  results.push({
@@ -1,16 +1,16 @@
1
- import type { UserConfig } from '../types.ts'
1
+ import type { UnknownUserPlugin, UserConfig } from '../types.ts'
2
2
 
3
- function isJSONPlugins(plugins: UserConfig['plugins']) {
4
- return !!(plugins as any)?.some((plugin: any) => {
5
- return Array.isArray(plugin) && typeof plugin?.at(0) === 'string'
6
- })
3
+ type PluginsArray = Array<Omit<UnknownUserPlugin, 'inject'>>
4
+
5
+ function isJSONPlugins(plugins: UserConfig['plugins']): boolean {
6
+ return Array.isArray(plugins) && plugins.some((plugin) => Array.isArray(plugin) && typeof (plugin as unknown[])[0] === 'string')
7
7
  }
8
8
 
9
- function isObjectPlugins(plugins: UserConfig['plugins']): plugins is any {
9
+ function isObjectPlugins(plugins: UserConfig['plugins']): boolean {
10
10
  return plugins instanceof Object && !Array.isArray(plugins)
11
11
  }
12
12
 
13
- export function getPlugins(plugins: UserConfig['plugins']): Promise<UserConfig['plugins']> {
13
+ export function getPlugins(plugins: UserConfig['plugins']): Promise<PluginsArray | undefined> {
14
14
  if (isObjectPlugins(plugins)) {
15
15
  throw new Error('Object plugins are not supported anymore, best to use http://kubb.dev/getting-started/configure#json')
16
16
  }
@@ -1,22 +1,5 @@
1
1
  import { x } from 'tinyexec'
2
-
3
- export const linters = {
4
- eslint: {
5
- command: 'eslint',
6
- args: (outputPath: string) => [outputPath, '--fix'],
7
- errorMessage: 'Eslint not found',
8
- },
9
- biome: {
10
- command: 'biome',
11
- args: (outputPath: string) => ['lint', '--fix', outputPath],
12
- errorMessage: 'Biome not found',
13
- },
14
- oxlint: {
15
- command: 'oxlint',
16
- args: (outputPath: string) => ['--fix', outputPath],
17
- errorMessage: 'Oxlint not found',
18
- },
19
- } as const
2
+ import type { linters } from '../constants.ts'
20
3
 
21
4
  type Linter = keyof typeof linters
22
5
 
@@ -30,9 +13,9 @@ async function isLinterAvailable(linter: Linter): Promise<boolean> {
30
13
  }
31
14
 
32
15
  export async function detectLinter(): Promise<Linter | undefined> {
33
- const linters: Linter[] = ['biome', 'oxlint', 'eslint']
16
+ const linterNames: Linter[] = ['biome', 'oxlint', 'eslint']
34
17
 
35
- for (const linter of linters) {
18
+ for (const linter of linterNames) {
36
19
  if (await isLinterAvailable(linter)) {
37
20
  return linter
38
21
  }