@kubb/core 3.0.0-alpha.2 → 3.0.0-alpha.21

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