@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
@@ -1,101 +1,83 @@
1
- import crypto from 'node:crypto'
2
- import { extname, resolve } from 'node:path'
1
+ import { extname, join, relative } from 'node:path'
3
2
 
4
3
  import { orderBy } from 'natural-orderby'
5
- import PQueue from 'p-queue'
6
4
  import { isDeepEqual } from 'remeda'
7
5
 
8
- import { getRelativePath, read, write } from '@kubb/fs'
6
+ import { read, write } from '@kubb/fs'
9
7
  import { BarrelManager } from './BarrelManager.ts'
10
- import { searchAndReplace } from './transformers/searchAndReplace.ts'
11
- import { trimExtName } from './transformers/trim.ts'
12
8
 
13
9
  import type * as KubbFile from '@kubb/fs/types'
14
10
 
15
- import type { BaseName, File, UUID } from '@kubb/fs/src/types.ts'
11
+ import { trimExtName } from '@kubb/fs'
12
+ import type { ResolvedFile } from '@kubb/fs/types'
16
13
  import type { GreaterThan } from '@kubb/types'
17
- import type { BarrelManagerOptions } from './BarrelManager.ts'
14
+ import PQueue from 'p-queue'
18
15
  import type { Logger } from './logger.ts'
19
- import transformers from './transformers/index.ts'
20
- import type { Plugin } from './types.ts'
21
- import { getParser } from './utils'
22
-
23
- export type ResolvedFile<TMeta extends FileMetaBase = FileMetaBase, TBaseName extends BaseName = BaseName> = File<TMeta, TBaseName> & {
24
- /**
25
- * @default crypto.randomUUID()
26
- */
27
- id: UUID
28
- /**
29
- * Contains the first part of the baseName, generated based on baseName
30
- * @link https://nodejs.org/api/path.html#pathformatpathobject
31
- */
32
-
33
- name: string
34
- }
16
+ import type { BarrelType, Config, Plugin } from './types.ts'
17
+ import { createFile, getFileParser } from './utils'
18
+ import { type DirectoryTree, TreeNode, buildDirectoryTree } from './utils/TreeNode.ts'
35
19
 
36
20
  export type FileMetaBase = {
37
21
  pluginKey?: Plugin['key']
38
22
  }
39
23
 
40
- type FileWithMeta<TMeta extends FileMetaBase = FileMetaBase> = KubbFile.File<TMeta>
41
-
42
- type CacheItem = ResolvedFile & {
43
- cancel?: () => void
44
- }
45
-
46
- type AddResult<T extends Array<FileWithMeta>> = Promise<Awaited<GreaterThan<T['length'], 1> extends true ? Promise<ResolvedFile[]> : Promise<ResolvedFile>>>
24
+ type AddResult<T extends Array<KubbFile.File>> = Promise<Awaited<GreaterThan<T['length'], 1> extends true ? Promise<ResolvedFile[]> : Promise<ResolvedFile>>>
47
25
 
48
26
  type AddIndexesProps = {
27
+ type: BarrelType | false | undefined
49
28
  /**
50
29
  * Root based on root and output.path specified in the config
51
30
  */
52
31
  root: string
32
+ files: KubbFile.File[]
53
33
  /**
54
34
  * Output for plugin
55
35
  */
56
36
  output: {
57
37
  path: string
58
- exportAs?: string
59
- extName?: KubbFile.Extname
60
- exportType?: 'barrel' | 'barrelNamed' | false
61
38
  }
62
- logger: Logger
63
- options?: BarrelManagerOptions
64
- meta?: FileWithMeta['meta']
65
- }
39
+ group?: {
40
+ output: string
41
+ exportAs: string
42
+ }
43
+ logger?: Logger
66
44
 
67
- type Options = {
68
- queue?: PQueue
69
- task?: (file: ResolvedFile) => Promise<ResolvedFile>
45
+ meta?: FileMetaBase
70
46
  }
71
47
 
72
48
  export class FileManager {
73
- #cache: Map<KubbFile.Path, CacheItem[]> = new Map()
74
-
75
- #task: Options['task']
76
- #queue: PQueue
77
-
78
- constructor({ task = async (file) => file, queue = new PQueue() }: Options = {}) {
79
- this.#task = task
80
- this.#queue = queue
81
-
49
+ #filesByPath: Map<KubbFile.Path, KubbFile.ResolvedFile> = new Map()
50
+ constructor() {
82
51
  return this
83
52
  }
84
53
 
85
- get files(): Array<FileWithMeta> {
86
- const files: Array<FileWithMeta> = []
87
- this.#cache.forEach((item) => {
88
- files.push(...item.flat(1))
89
- })
54
+ get files(): Array<KubbFile.ResolvedFile> {
55
+ return [...this.#filesByPath.values()]
56
+ }
57
+
58
+ get orderedFiles(): Array<KubbFile.ResolvedFile> {
59
+ return orderBy(
60
+ [...this.#filesByPath.values()],
61
+ [
62
+ (v) => v?.meta && 'pluginKey' in v.meta && !v.meta.pluginKey,
63
+ (v) => v.path.length,
64
+ (v) => trimExtName(v.path).endsWith('index'),
65
+ (v) => trimExtName(v.baseName),
66
+ (v) => v.path.split('.').pop(),
67
+ ],
68
+ )
69
+ }
90
70
 
91
- return files
71
+ get groupedFiles(): DirectoryTree | null {
72
+ return buildDirectoryTree([...this.#filesByPath.values()])
92
73
  }
93
- get isExecuting(): boolean {
94
- return this.#queue.size !== 0 && this.#queue.pending !== 0
74
+
75
+ get treeNode(): TreeNode | null {
76
+ return TreeNode.build([...this.#filesByPath.values()])
95
77
  }
96
78
 
97
- async add<T extends Array<FileWithMeta> = Array<FileWithMeta>>(...files: T): AddResult<T> {
98
- const promises = combineFiles(files).map((file) => {
79
+ async add<T extends Array<KubbFile.File> = Array<KubbFile.File>>(...files: T): AddResult<T> {
80
+ const promises = files.map((file) => {
99
81
  if (file.override) {
100
82
  return this.#add(file)
101
83
  }
@@ -112,270 +94,160 @@ export class FileManager {
112
94
  return resolvedFiles[0] as unknown as AddResult<T>
113
95
  }
114
96
 
115
- async #add(file: FileWithMeta): Promise<ResolvedFile> {
116
- const controller = new AbortController()
117
- const resolvedFile: ResolvedFile = {
118
- id: crypto.randomUUID(),
119
- name: trimExtName(file.baseName),
120
- ...file,
121
- }
122
-
123
- if (resolvedFile.exports?.length) {
124
- const folder = resolvedFile.path.replace(resolvedFile.baseName, '')
125
-
126
- resolvedFile.exports = resolvedFile.exports.filter((exportItem) => {
127
- const exportedFile = this.files.find((file) => file.path.includes(resolve(folder, exportItem.path)))
97
+ async #add(file: KubbFile.File): Promise<ResolvedFile> {
98
+ const resolvedFile = createFile(file)
128
99
 
129
- if (exportedFile) {
130
- return exportedFile.exportable
131
- }
132
-
133
- return true
134
- })
135
- }
100
+ this.#filesByPath.set(resolvedFile.path, resolvedFile)
136
101
 
137
- this.#cache.set(resolvedFile.path, [{ cancel: () => controller.abort(), ...resolvedFile }])
102
+ return resolvedFile
103
+ }
138
104
 
139
- return this.#queue.add(
140
- async () => {
141
- return this.#task?.(resolvedFile)
142
- },
143
- { signal: controller.signal },
144
- ) as Promise<ResolvedFile>
105
+ clear() {
106
+ this.#filesByPath.clear()
145
107
  }
146
108
 
147
- async #addOrAppend(file: FileWithMeta): Promise<ResolvedFile> {
148
- const previousCaches = this.#cache.get(file.path)
149
- const previousCache = previousCaches ? previousCaches.at(previousCaches.length - 1) : undefined
109
+ async #addOrAppend(file: KubbFile.File): Promise<ResolvedFile> {
110
+ const previousFile = this.#filesByPath.get(file.path)
150
111
 
151
- if (previousCache) {
152
- this.#cache.delete(previousCache.path)
112
+ if (previousFile) {
113
+ this.#filesByPath.delete(previousFile.path)
153
114
 
154
- return this.#add({
155
- ...file,
156
- source: previousCache.source && file.source ? `${previousCache.source}\n${file.source}` : '',
157
- imports: [...(previousCache.imports || []), ...(file.imports || [])],
158
- exports: [...(previousCache.exports || []), ...(file.exports || [])],
159
- env: { ...(previousCache.env || {}), ...(file.env || {}) },
160
- })
115
+ return this.#add(mergeFile(previousFile, file))
161
116
  }
162
117
  return this.#add(file)
163
118
  }
164
119
 
165
- async addIndexes({ root, output, meta, logger, options = {} }: AddIndexesProps): Promise<void> {
166
- const { exportType = 'barrel' } = output
167
- // ^?
168
- if (exportType === false) {
169
- return undefined
170
- }
120
+ getCacheById(id: string): KubbFile.File | undefined {
121
+ return [...this.#filesByPath.values()].find((file) => file.id === id)
122
+ }
171
123
 
172
- const pathToBuildFrom = resolve(root, output.path)
124
+ getByPath(path: KubbFile.Path): KubbFile.ResolvedFile | undefined {
125
+ return this.#filesByPath.get(path)
126
+ }
173
127
 
174
- if (transformers.trimExtName(pathToBuildFrom).endsWith('index')) {
175
- logger.emit('warning', 'Output has the same fileName as the barrelFiles, please disable barrel generation')
128
+ deleteByPath(path: KubbFile.Path): void {
129
+ const cacheItem = this.getByPath(path)
130
+ if (!cacheItem) {
176
131
  return
177
132
  }
178
133
 
179
- const exportPath = output.path.startsWith('./') ? trimExtName(output.path) : `./${trimExtName(output.path)}`
180
- const mode = FileManager.getMode(output.path)
181
- const barrelManager = new BarrelManager({
182
- extName: output.extName,
183
- ...options,
184
- })
185
- let files = barrelManager.getIndexes(pathToBuildFrom)
134
+ this.#filesByPath.delete(path)
135
+ }
186
136
 
187
- if (!files) {
188
- return undefined
137
+ async getBarrelFiles({ type, files, meta = {}, root, output, logger }: AddIndexesProps): Promise<KubbFile.File[]> {
138
+ if (!type) {
139
+ return []
189
140
  }
190
141
 
191
- if (exportType === 'barrelNamed') {
192
- files = files.map((file) => {
193
- if (file.exports) {
194
- return {
195
- ...file,
196
- exports: barrelManager.getNamedExports(pathToBuildFrom, file.exports),
197
- }
198
- }
199
- return file
200
- })
201
- }
142
+ const barrelManager = new BarrelManager({ logger })
202
143
 
203
- await Promise.all(
204
- files.map((file) => {
205
- return this.#addOrAppend({
206
- ...file,
207
- meta: meta ? meta : file.meta,
208
- })
209
- }),
210
- )
144
+ const pathToBuildFrom = join(root, output.path)
211
145
 
212
- const rootPath = mode === 'split' ? `${exportPath}/index${output.extName || ''}` : `${exportPath}${output.extName || ''}`
213
- const rootFile: FileWithMeta = {
214
- path: resolve(root, 'index.ts'),
215
- baseName: 'index.ts',
216
- source: '',
217
- exports: [
218
- output.exportAs
219
- ? {
220
- name: output.exportAs,
221
- asAlias: true,
222
- path: rootPath,
223
- isTypeOnly: options.isTypeOnly,
224
- }
225
- : {
226
- path: rootPath,
227
- isTypeOnly: options.isTypeOnly,
228
- },
229
- ],
230
- exportable: true,
231
- }
146
+ if (trimExtName(pathToBuildFrom).endsWith('index')) {
147
+ logger?.emit('warning', 'Output has the same fileName as the barrelFiles, please disable barrel generation')
232
148
 
233
- if (exportType === 'barrelNamed' && !output.exportAs && rootFile.exports?.[0]) {
234
- rootFile.exports = barrelManager.getNamedExport(root, rootFile.exports[0])
149
+ return []
235
150
  }
236
151
 
237
- await this.#addOrAppend({
238
- ...rootFile,
239
- meta: meta ? meta : rootFile.meta,
240
- })
241
- }
242
-
243
- getCacheByUUID(UUID: KubbFile.UUID): FileWithMeta | undefined {
244
- let cache: FileWithMeta | undefined
245
-
246
- this.#cache.forEach((files) => {
247
- cache = files.find((item) => item.id === UUID)
248
- })
249
- return cache
250
- }
251
-
252
- get(path: KubbFile.Path): Array<FileWithMeta> | undefined {
253
- return this.#cache.get(path)
254
- }
152
+ const barrelFiles = barrelManager.getFiles({ files, root: pathToBuildFrom, meta })
255
153
 
256
- remove(path: KubbFile.Path): void {
257
- const cacheItem = this.get(path)
258
- if (!cacheItem) {
259
- return
154
+ if (type === 'all') {
155
+ return barrelFiles.map((file) => {
156
+ return {
157
+ ...file,
158
+ exports: file.exports?.map((exportItem) => {
159
+ return {
160
+ ...exportItem,
161
+ name: undefined,
162
+ }
163
+ }),
164
+ }
165
+ })
260
166
  }
261
167
 
262
- this.#cache.delete(path)
168
+ return barrelFiles.map((indexFile) => {
169
+ return {
170
+ ...indexFile,
171
+ meta,
172
+ }
173
+ })
263
174
  }
264
175
 
265
- async write(...params: Parameters<typeof write>): Promise<string | undefined> {
176
+ async write(...params: Parameters<typeof write>): ReturnType<typeof write> {
266
177
  return write(...params)
267
178
  }
268
179
 
269
- async read(...params: Parameters<typeof read>): Promise<string> {
180
+ async read(...params: Parameters<typeof read>): ReturnType<typeof read> {
270
181
  return read(...params)
271
182
  }
272
183
 
273
184
  // statics
274
-
275
- static async getSource<TMeta extends FileMetaBase = FileMetaBase>(file: FileWithMeta<TMeta>): Promise<string> {
276
- return getSource<TMeta>(file)
277
- }
278
-
279
- static combineFiles<TMeta extends FileMetaBase = FileMetaBase>(files: Array<FileWithMeta<TMeta> | null>): Array<FileWithMeta<TMeta>> {
280
- return combineFiles<TMeta>(files)
281
- }
282
185
  static getMode(path: string | undefined | null): KubbFile.Mode {
283
186
  if (!path) {
284
187
  return 'split'
285
188
  }
286
189
  return extname(path) ? 'single' : 'split'
287
190
  }
191
+ }
288
192
 
289
- static get extensions(): Array<KubbFile.Extname> {
290
- return ['.js', '.ts', '.tsx']
291
- }
193
+ type GetSourceOptions = {
194
+ extname?: KubbFile.Extname
195
+ logger?: Logger
196
+ }
197
+
198
+ export async function getSource<TMeta extends FileMetaBase = FileMetaBase>(
199
+ file: ResolvedFile<TMeta>,
200
+ { logger, extname }: GetSourceOptions = {},
201
+ ): Promise<string> {
202
+ const parser = await getFileParser(file.extname)
203
+ const source = await parser.print(file, { logger, extname })
204
+
205
+ return parser.format(source)
206
+ }
292
207
 
293
- static isJavascript(baseName: string): boolean {
294
- return FileManager.extensions.some((extension) => baseName.endsWith(extension))
208
+ function mergeFile<TMeta extends FileMetaBase = FileMetaBase>(a: KubbFile.File<TMeta>, b: KubbFile.File<TMeta>): KubbFile.File<TMeta> {
209
+ return {
210
+ ...a,
211
+ sources: [...(a.sources || []), ...(b.sources || [])],
212
+ imports: [...(a.imports || []), ...(b.imports || [])],
213
+ exports: [...(a.exports || []), ...(b.exports || [])],
295
214
  }
296
215
  }
297
216
 
298
- function combineFiles<TMeta extends FileMetaBase = FileMetaBase>(files: Array<FileWithMeta<TMeta> | null>): Array<FileWithMeta<TMeta>> {
299
- return files.filter(Boolean).reduce(
300
- (acc, file: FileWithMeta<TMeta>) => {
301
- const prevIndex = acc.findIndex((item) => item.path === file.path)
217
+ export function combineSources(sources: Array<KubbFile.Source>): Array<KubbFile.Source> {
218
+ return sources.reduce(
219
+ (prev, curr) => {
220
+ const prevByName = prev.findLast((imp) => imp.name && imp.name === curr.name)
221
+ const prevByPathAndIsExportable = prev.findLast((imp) => imp.name === curr.name && imp.isExportable)
302
222
 
303
- if (prevIndex === -1) {
304
- return [...acc, file]
223
+ if (prevByPathAndIsExportable) {
224
+ // we already have an export that has the same name but uses `isExportable` (export type ...)
225
+ return [...prev, curr]
305
226
  }
306
227
 
307
- const prev = acc[prevIndex]
308
-
309
- if (prev && file.override) {
310
- acc[prevIndex] = {
311
- imports: [],
312
- exports: [],
313
- ...file,
314
- }
315
- return acc
316
- }
228
+ if (prevByName) {
229
+ prevByName.value = curr.value
230
+ prevByName.isExportable = curr.isExportable
231
+ prevByName.isTypeOnly = curr.isTypeOnly
232
+ prevByName.isIndexable = curr.isIndexable
317
233
 
318
- if (prev) {
319
- acc[prevIndex] = {
320
- ...file,
321
- source: prev.source && file.source ? `${prev.source}\n${file.source}` : '',
322
- imports: [...(prev.imports || []), ...(file.imports || [])],
323
- exports: [...(prev.exports || []), ...(file.exports || [])],
324
- env: { ...(prev.env || {}), ...(file.env || {}) },
325
- }
234
+ return prev
326
235
  }
327
236
 
328
- return acc
237
+ return [...prev, curr]
329
238
  },
330
- [] as Array<FileWithMeta<TMeta>>,
331
- )
332
- }
333
-
334
- export async function getSource<TMeta extends FileMetaBase = FileMetaBase>(file: FileWithMeta<TMeta>): Promise<string> {
335
- // only use .js, .ts or .tsx files for ESM imports
336
-
337
- if (file.language ? !['typescript', 'javascript'].includes(file.language) : !FileManager.isJavascript(file.baseName)) {
338
- return file.source
339
- }
340
-
341
- const parser = await getParser(file.language)
342
-
343
- const exports = file.exports ? combineExports(file.exports) : []
344
- // imports should be defined and source should contain code or we have imports without them being used
345
- const imports = file.imports && file.source ? combineImports(file.imports, exports, file.source) : []
346
-
347
- const importNodes = imports
348
- .filter((item) => {
349
- const path = item.root ? getRelativePath(item.root, item.path) : item.path
350
- // trim extName
351
- return path !== trimExtName(file.path)
352
- })
353
- .map((item) => {
354
- const path = item.root ? getRelativePath(item.root, item.path) : item.path
355
-
356
- return parser.factory.createImportDeclaration({
357
- name: item.name,
358
- path: item.extName ? `${path}${item.extName}` : path,
359
- isTypeOnly: item.isTypeOnly,
360
- })
361
- })
362
- const exportNodes = exports.map((item) =>
363
- parser.factory.createExportDeclaration({
364
- name: item.name,
365
- path: item.extName ? `${item.path}${item.extName}` : item.path,
366
- isTypeOnly: item.isTypeOnly,
367
- asAlias: item.asAlias,
368
- }),
239
+ [] as Array<KubbFile.Source>,
369
240
  )
370
-
371
- const source = [parser.print([...importNodes, ...exportNodes]), getEnvSource(file.source, file.env)].join('\n')
372
-
373
- // do some basic linting with the ts compiler
374
- return parser.print([], { source, noEmitHelpers: false })
375
241
  }
376
242
 
377
243
  export function combineExports(exports: Array<KubbFile.Export>): Array<KubbFile.Export> {
378
- const combinedExports = orderBy(exports, [(v) => !v.isTypeOnly], ['asc']).reduce(
244
+ return orderBy(exports, [
245
+ (v) => !!Array.isArray(v.name),
246
+ (v) => !v.isTypeOnly,
247
+ (v) => v.path,
248
+ (v) => !!v.name,
249
+ (v) => (Array.isArray(v.name) ? orderBy(v.name) : v.name),
250
+ ]).reduce(
379
251
  (prev, curr) => {
380
252
  const name = curr.name
381
253
  const prevByPath = prev.findLast((imp) => imp.path === curr.path)
@@ -390,6 +262,7 @@ export function combineExports(exports: Array<KubbFile.Export>): Array<KubbFile.
390
262
  (imp) => imp.path === curr.path && isDeepEqual(imp.name, name) && imp.isTypeOnly === curr.isTypeOnly && imp.asAlias === curr.asAlias,
391
263
  )
392
264
 
265
+ // we already have an item that was unique enough or name field is empty or prev asAlias is set but current has no changes
393
266
  if (uniquePrev || (Array.isArray(name) && !name.length) || (prevByPath?.asAlias && !curr.asAlias)) {
394
267
  return prev
395
268
  }
@@ -404,6 +277,7 @@ export function combineExports(exports: Array<KubbFile.Export>): Array<KubbFile.
404
277
  ]
405
278
  }
406
279
 
280
+ // merge all names when prev and current both have the same isTypeOnly set
407
281
  if (prevByPath && Array.isArray(prevByPath.name) && Array.isArray(curr.name) && prevByPath.isTypeOnly === curr.isTypeOnly) {
408
282
  prevByPath.name = [...new Set([...prevByPath.name, ...curr.name])]
409
283
 
@@ -414,12 +288,16 @@ export function combineExports(exports: Array<KubbFile.Export>): Array<KubbFile.
414
288
  },
415
289
  [] as Array<KubbFile.Export>,
416
290
  )
417
-
418
- return orderBy(combinedExports, [(v) => !v.isTypeOnly, (v) => v.asAlias], ['desc', 'desc'])
419
291
  }
420
292
 
421
293
  export function combineImports(imports: Array<KubbFile.Import>, exports: Array<KubbFile.Export>, source?: string): Array<KubbFile.Import> {
422
- const combinedImports = orderBy(imports, [(v) => !v.isTypeOnly], ['asc']).reduce(
294
+ return orderBy(imports, [
295
+ (v) => !!Array.isArray(v.name),
296
+ (v) => !v.isTypeOnly,
297
+ (v) => v.path,
298
+ (v) => !!v.name,
299
+ (v) => (Array.isArray(v.name) ? orderBy(v.name) : v.name),
300
+ ]).reduce(
423
301
  (prev, curr) => {
424
302
  let name = Array.isArray(curr.name) ? [...new Set(curr.name)] : curr.name
425
303
 
@@ -428,7 +306,9 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
428
306
  return true
429
307
  }
430
308
 
431
- const checker = (name?: string) => name && !!source.includes(name)
309
+ const checker = (name?: string) => {
310
+ return name && !!source.includes(name)
311
+ }
432
312
 
433
313
  return checker(importName) || exports.some(({ name }) => (Array.isArray(name) ? name.some(checker) : checker(name)))
434
314
  }
@@ -438,6 +318,7 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
438
318
  return prev
439
319
  }
440
320
 
321
+ // merge all names and check if the importName is being used in the generated source and if not filter those imports out
441
322
  if (Array.isArray(name)) {
442
323
  name = name.filter((item) => (typeof item === 'string' ? hasImportInSource(item) : hasImportInSource(item.propertyName)))
443
324
  }
@@ -451,10 +332,12 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
451
332
  return prev
452
333
  }
453
334
 
335
+ // already unique enough or name is empty
454
336
  if (uniquePrev || (Array.isArray(name) && !name.length)) {
455
337
  return prev
456
338
  }
457
339
 
340
+ // new item, append name
458
341
  if (!prevByPath) {
459
342
  return [
460
343
  ...prev,
@@ -465,12 +348,14 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
465
348
  ]
466
349
  }
467
350
 
351
+ // merge all names when prev and current both have the same isTypeOnly set
468
352
  if (prevByPath && Array.isArray(prevByPath.name) && Array.isArray(name) && prevByPath.isTypeOnly === curr.isTypeOnly) {
469
353
  prevByPath.name = [...new Set([...prevByPath.name, ...name])]
470
354
 
471
355
  return prev
472
356
  }
473
357
 
358
+ // no import was found in the source, ignore import
474
359
  if (!Array.isArray(name) && name && !hasImportInSource(name)) {
475
360
  return prev
476
361
  }
@@ -479,44 +364,54 @@ export function combineImports(imports: Array<KubbFile.Import>, exports: Array<K
479
364
  },
480
365
  [] as Array<KubbFile.Import>,
481
366
  )
482
-
483
- return orderBy(combinedImports, [(v) => !v.isTypeOnly], ['desc'])
484
367
  }
485
368
 
486
- function getEnvSource(source: string, env: NodeJS.ProcessEnv | undefined): string {
487
- if (!env) {
488
- return source
489
- }
369
+ type WriteFilesProps = {
370
+ config: Config
371
+ files: Array<KubbFile.ResolvedFile>
372
+ logger: Logger
373
+ dryRun?: boolean
374
+ }
375
+ /**
376
+ * Global queue
377
+ */
378
+ const queue = new PQueue({ concurrency: 100 })
379
+
380
+ export async function processFiles({ dryRun, config, logger, files }: WriteFilesProps) {
381
+ const orderedFiles = orderBy(files, [
382
+ (v) => v?.meta && 'pluginKey' in v.meta && !v.meta.pluginKey,
383
+ (v) => v.path.length,
384
+ (v) => trimExtName(v.path).endsWith('index'),
385
+ ])
386
+
387
+ logger.emit('debug', {
388
+ date: new Date(),
389
+ logs: [JSON.stringify({ files: orderedFiles }, null, 2)],
390
+ fileName: 'kubb-files.log',
391
+ })
392
+
393
+ if (!dryRun) {
394
+ const size = orderedFiles.length
395
+
396
+ logger.emit('progress_start', { id: 'files', size, message: 'Writing files ...' })
397
+ const promises = orderedFiles.map(async (file) => {
398
+ await queue.add(async () => {
399
+ const message = file ? `Writing ${relative(config.root, file.path)}` : ''
400
+ const extnames = config.output.extension?.({})
401
+ const extname = extnames?.[file.extname]
402
+
403
+ const source = await getSource(file, { logger, extname })
404
+
405
+ await write(file.path, source, { sanity: false })
406
+
407
+ logger.emit('progressed', { id: 'files', message })
408
+ })
409
+ })
490
410
 
491
- const keys = Object.keys(env)
411
+ await Promise.all(promises)
492
412
 
493
- if (!keys.length) {
494
- return source
413
+ logger.emit('progress_stop', { id: 'files' })
495
414
  }
496
415
 
497
- return keys.reduce((prev, key: string) => {
498
- const environmentValue = env[key]
499
- const replaceBy = environmentValue ? `'${environmentValue.replaceAll('"', '')?.replaceAll("'", '')}'` : 'undefined'
500
-
501
- if (key.toUpperCase() !== key) {
502
- throw new TypeError(`Environment should be in upperCase for ${key}`)
503
- }
504
-
505
- if (typeof replaceBy === 'string') {
506
- prev = searchAndReplace({
507
- text: prev.replaceAll(`process.env.${key}`, replaceBy),
508
- replaceBy,
509
- prefix: 'process.env',
510
- key,
511
- })
512
- // removes `declare const ...`
513
- prev = searchAndReplace({
514
- text: prev.replaceAll(/(declare const).*\n/gi, ''),
515
- replaceBy,
516
- key,
517
- })
518
- }
519
-
520
- return prev
521
- }, source)
416
+ return files
522
417
  }
@@ -68,7 +68,7 @@ export class PackageManager {
68
68
 
69
69
  return module?.default ?? module
70
70
  } catch (e) {
71
- console.log(e)
71
+ console.error(e)
72
72
  return undefined
73
73
  }
74
74
  }