@kubb/core 2.0.0-canary.20231030T124950 → 2.0.0
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.
- package/README.md +1 -1
- package/dist/chunk-4A7WG6IA.js +128 -0
- package/dist/chunk-4A7WG6IA.js.map +1 -0
- package/dist/chunk-54P4AWHI.js +71 -0
- package/dist/chunk-54P4AWHI.js.map +1 -0
- package/dist/chunk-5TK7TMV6.cjs +131 -0
- package/dist/chunk-5TK7TMV6.cjs.map +1 -0
- package/dist/chunk-7S67BJXQ.js +85 -0
- package/dist/chunk-7S67BJXQ.js.map +1 -0
- package/dist/chunk-E3ANGQ5N.cjs +2290 -0
- package/dist/chunk-E3ANGQ5N.cjs.map +1 -0
- package/dist/chunk-H47IKRXJ.cjs +129 -0
- package/dist/chunk-H47IKRXJ.cjs.map +1 -0
- package/dist/chunk-HIE46T3F.js +129 -0
- package/dist/chunk-HIE46T3F.js.map +1 -0
- package/dist/chunk-K2H7BYQB.js +155 -0
- package/dist/chunk-K2H7BYQB.js.map +1 -0
- package/dist/chunk-NAWI7UXW.js +67 -0
- package/dist/chunk-NAWI7UXW.js.map +1 -0
- package/dist/chunk-PLVKILIY.cjs +162 -0
- package/dist/chunk-PLVKILIY.cjs.map +1 -0
- package/dist/chunk-W2FP7ZWW.cjs +71 -0
- package/dist/chunk-W2FP7ZWW.cjs.map +1 -0
- package/dist/chunk-WZQO3EPM.cjs +91 -0
- package/dist/chunk-WZQO3EPM.cjs.map +1 -0
- package/dist/chunk-XDHI63G7.cjs +104 -0
- package/dist/chunk-XDHI63G7.cjs.map +1 -0
- package/dist/chunk-XPOF4D5N.js +18 -0
- package/dist/chunk-XPOF4D5N.js.map +1 -0
- package/dist/fs.cjs +31 -0
- package/dist/fs.cjs.map +1 -0
- package/dist/fs.d.cts +5 -0
- package/dist/fs.d.ts +5 -0
- package/dist/fs.js +11 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.cjs +1866 -977
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +302 -319
- package/dist/index.d.ts +302 -319
- package/dist/index.js +1071 -846
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +26 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +32 -0
- package/dist/logger.d.ts +32 -0
- package/dist/logger.js +8 -0
- package/dist/logger.js.map +1 -0
- package/dist/transformers.cjs +124 -0
- package/dist/transformers.cjs.map +1 -0
- package/dist/transformers.d.cts +55 -0
- package/dist/transformers.d.ts +55 -0
- package/dist/transformers.js +95 -0
- package/dist/transformers.js.map +1 -0
- package/dist/utils.cjs +23 -1163
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -143
- package/dist/utils.d.ts +2 -143
- package/dist/utils.js +15 -1118
- package/dist/utils.js.map +1 -1
- package/dist/write-A6VgHkYA.d.cts +10 -0
- package/dist/write-A6VgHkYA.d.ts +10 -0
- package/package.json +40 -23
- package/src/BarrelManager.ts +113 -0
- package/src/FileManager.ts +581 -0
- package/src/Generator.ts +34 -0
- package/src/PackageManager.ts +178 -0
- package/src/PluginManager.ts +645 -0
- package/src/PromiseManager.ts +51 -0
- package/src/build.ts +221 -0
- package/src/config.ts +22 -0
- package/src/errors.ts +12 -0
- package/src/fs/clean.ts +5 -0
- package/src/fs/index.ts +3 -0
- package/src/fs/read.ts +68 -0
- package/src/fs/write.ts +79 -0
- package/src/index.ts +27 -0
- package/src/logger.ts +121 -0
- package/src/plugin.ts +80 -0
- package/src/transformers/casing.ts +9 -0
- package/src/transformers/combineCodes.ts +3 -0
- package/src/transformers/createJSDocBlockText.ts +9 -0
- package/src/transformers/escape.ts +31 -0
- package/src/transformers/indent.ts +3 -0
- package/src/transformers/index.ts +36 -0
- package/src/transformers/nameSorter.ts +9 -0
- package/src/transformers/searchAndReplace.ts +25 -0
- package/src/transformers/transformReservedWord.ts +97 -0
- package/src/transformers/trim.ts +7 -0
- package/src/types.ts +334 -0
- package/src/utils/EventEmitter.ts +24 -0
- package/src/utils/FunctionParams.ts +86 -0
- package/src/utils/TreeNode.ts +125 -0
- package/src/utils/URLPath.ts +133 -0
- package/src/utils/cache.ts +35 -0
- package/src/utils/executeStrategies.ts +83 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/promise.ts +13 -0
- package/src/utils/renderTemplate.ts +31 -0
- package/src/utils/timeout.ts +7 -0
- package/src/utils/uniqueName.ts +20 -0
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-namespace */
|
|
2
|
+
import crypto from 'node:crypto'
|
|
3
|
+
import { extname, resolve } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { print } from '@kubb/parser'
|
|
6
|
+
import * as factory from '@kubb/parser/factory'
|
|
7
|
+
|
|
8
|
+
import isEqual from 'lodash.isequal'
|
|
9
|
+
import { orderBy } from 'natural-orderby'
|
|
10
|
+
import PQueue from 'p-queue'
|
|
11
|
+
|
|
12
|
+
import { getRelativePath, read } from './fs/read.ts'
|
|
13
|
+
import { write } from './fs/write.ts'
|
|
14
|
+
import { searchAndReplace } from './transformers/searchAndReplace.ts'
|
|
15
|
+
import { trimExtName } from './transformers/trim.ts'
|
|
16
|
+
import { BarrelManager } from './BarrelManager.ts'
|
|
17
|
+
|
|
18
|
+
import type { GreaterThan } from '@kubb/types'
|
|
19
|
+
import type { BarrelManagerOptions } from './BarrelManager.ts'
|
|
20
|
+
import type { KubbPlugin } from './types.ts'
|
|
21
|
+
|
|
22
|
+
type BasePath<T extends string = string> = `${T}/`
|
|
23
|
+
|
|
24
|
+
export namespace KubbFile {
|
|
25
|
+
export type Import = {
|
|
26
|
+
/**
|
|
27
|
+
* Import name to be used
|
|
28
|
+
* @example ["useState"]
|
|
29
|
+
* @example "React"
|
|
30
|
+
*/
|
|
31
|
+
name:
|
|
32
|
+
| string
|
|
33
|
+
| Array<
|
|
34
|
+
string | {
|
|
35
|
+
propertyName: string
|
|
36
|
+
name?: string
|
|
37
|
+
}
|
|
38
|
+
>
|
|
39
|
+
/**
|
|
40
|
+
* Path for the import
|
|
41
|
+
* @xample '@kubb/core'
|
|
42
|
+
*/
|
|
43
|
+
path: string
|
|
44
|
+
/**
|
|
45
|
+
* Add `type` prefix to the import, this will result in: `import type { Type } from './path'`.
|
|
46
|
+
*/
|
|
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
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type Export = {
|
|
59
|
+
/**
|
|
60
|
+
* Export name to be used.
|
|
61
|
+
* @example ["useState"]
|
|
62
|
+
* @example "React"
|
|
63
|
+
*/
|
|
64
|
+
name?: string | Array<string>
|
|
65
|
+
/**
|
|
66
|
+
* Path for the import.
|
|
67
|
+
* @xample '@kubb/core'
|
|
68
|
+
*/
|
|
69
|
+
path: string
|
|
70
|
+
/**
|
|
71
|
+
* Add `type` prefix to the export, this will result in: `export type { Type } from './path'`.
|
|
72
|
+
*/
|
|
73
|
+
isTypeOnly?: boolean
|
|
74
|
+
/**
|
|
75
|
+
* Make it possible to override the name, this will result in: `export * as aliasName from './path'`.
|
|
76
|
+
*/
|
|
77
|
+
asAlias?: boolean
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export declare const dataTagSymbol: unique symbol
|
|
81
|
+
export type DataTag<Type, Value> = Type & {
|
|
82
|
+
[dataTagSymbol]: Value
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type UUID = string
|
|
86
|
+
export type Source = string
|
|
87
|
+
|
|
88
|
+
export type Extname = '.ts' | '.js' | '.tsx' | '.json' | `.${string}`
|
|
89
|
+
|
|
90
|
+
export type Mode = 'file' | 'directory'
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Name to be used to dynamicly create the baseName(based on input.path)
|
|
94
|
+
* Based on UNIX basename
|
|
95
|
+
* @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
|
|
96
|
+
*/
|
|
97
|
+
export type BaseName = `${string}${Extname}`
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Path will be full qualified path to a specified file
|
|
101
|
+
*/
|
|
102
|
+
export type Path = string
|
|
103
|
+
|
|
104
|
+
export type AdvancedPath<T extends BaseName = BaseName> = `${BasePath}${T}`
|
|
105
|
+
|
|
106
|
+
export type OptionalPath = Path | undefined | null
|
|
107
|
+
|
|
108
|
+
export type FileMetaBase = {
|
|
109
|
+
pluginKey?: KubbPlugin['key']
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export type File<
|
|
113
|
+
TMeta extends FileMetaBase = FileMetaBase,
|
|
114
|
+
TBaseName extends BaseName = BaseName,
|
|
115
|
+
> = {
|
|
116
|
+
/**
|
|
117
|
+
* Unique identifier to reuse later
|
|
118
|
+
* @default crypto.randomUUID()
|
|
119
|
+
*/
|
|
120
|
+
id?: string
|
|
121
|
+
/**
|
|
122
|
+
* Name to be used to create the path
|
|
123
|
+
* Based on UNIX basename, `${name}.extName`
|
|
124
|
+
* @link https://nodejs.org/api/path.html#pathbasenamepath-suffix
|
|
125
|
+
*/
|
|
126
|
+
baseName: TBaseName
|
|
127
|
+
/**
|
|
128
|
+
* Path will be full qualified path to a specified file
|
|
129
|
+
*/
|
|
130
|
+
path: AdvancedPath<TBaseName> | Path
|
|
131
|
+
source: Source
|
|
132
|
+
imports?: Import[]
|
|
133
|
+
exports?: Export[]
|
|
134
|
+
/**
|
|
135
|
+
* This will call fileManager.add instead of fileManager.addOrAppend, adding the source when the files already exists
|
|
136
|
+
* This will also ignore the combinefiles utils
|
|
137
|
+
* @default `false`
|
|
138
|
+
*/
|
|
139
|
+
override?: boolean
|
|
140
|
+
/**
|
|
141
|
+
* Use extra meta, this is getting used to generate the barrel/index files.
|
|
142
|
+
*/
|
|
143
|
+
meta?: TMeta
|
|
144
|
+
/**
|
|
145
|
+
* This will override `process.env[key]` inside the `source`, see `getFileSource`.
|
|
146
|
+
*/
|
|
147
|
+
env?: NodeJS.ProcessEnv
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type ResolvedFile<
|
|
151
|
+
TMeta extends FileMetaBase = FileMetaBase,
|
|
152
|
+
TBaseName extends BaseName = BaseName,
|
|
153
|
+
> = KubbFile.File<TMeta, TBaseName> & {
|
|
154
|
+
/**
|
|
155
|
+
* @default crypto.randomUUID()
|
|
156
|
+
*/
|
|
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
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
type CacheItem = KubbFile.ResolvedFile & {
|
|
168
|
+
cancel?: () => void
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
type AddResult<T extends Array<KubbFile.File>> = Promise<
|
|
172
|
+
Awaited<GreaterThan<T['length'], 1> extends true ? Promise<KubbFile.ResolvedFile[]> : Promise<KubbFile.ResolvedFile>>
|
|
173
|
+
>
|
|
174
|
+
|
|
175
|
+
type AddIndexesProps = {
|
|
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
|
+
}
|
|
189
|
+
options?: BarrelManagerOptions
|
|
190
|
+
meta?: KubbFile.File['meta']
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
type Options = {
|
|
194
|
+
queue?: PQueue
|
|
195
|
+
task?: (file: KubbFile.ResolvedFile) => Promise<KubbFile.ResolvedFile>
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export class FileManager {
|
|
199
|
+
#cache: Map<KubbFile.Path, CacheItem[]> = new Map()
|
|
200
|
+
|
|
201
|
+
#task: Options['task']
|
|
202
|
+
#queue: PQueue
|
|
203
|
+
|
|
204
|
+
constructor({ task = async (file) => file, queue = new PQueue() }: Options = {}) {
|
|
205
|
+
this.#task = task
|
|
206
|
+
this.#queue = queue
|
|
207
|
+
|
|
208
|
+
return this
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
get files(): Array<KubbFile.File> {
|
|
212
|
+
const files: Array<KubbFile.File> = []
|
|
213
|
+
this.#cache.forEach((item) => {
|
|
214
|
+
files.push(...item.flat(1))
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
return files
|
|
218
|
+
}
|
|
219
|
+
get isExecuting(): boolean {
|
|
220
|
+
return this.#queue.size !== 0 && this.#queue.pending !== 0
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async add<T extends Array<KubbFile.File> = Array<KubbFile.File>>(
|
|
224
|
+
...files: T
|
|
225
|
+
): AddResult<T> {
|
|
226
|
+
const promises = combineFiles(files).map((file) => {
|
|
227
|
+
if (file.override) {
|
|
228
|
+
return this.#add(file)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return this.#addOrAppend(file)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const resolvedFiles = await Promise.all(promises)
|
|
235
|
+
|
|
236
|
+
if (files.length > 1) {
|
|
237
|
+
return resolvedFiles as unknown as AddResult<T>
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return resolvedFiles[0] as unknown as AddResult<T>
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async #add(file: KubbFile.File): Promise<KubbFile.ResolvedFile> {
|
|
244
|
+
const controller = new AbortController()
|
|
245
|
+
const resolvedFile: KubbFile.ResolvedFile = { id: crypto.randomUUID(), name: trimExtName(file.baseName), ...file }
|
|
246
|
+
|
|
247
|
+
this.#cache.set(resolvedFile.path, [{ cancel: () => controller.abort(), ...resolvedFile }])
|
|
248
|
+
|
|
249
|
+
return this.#queue.add(
|
|
250
|
+
async () => {
|
|
251
|
+
return this.#task?.(resolvedFile)
|
|
252
|
+
},
|
|
253
|
+
{ signal: controller.signal },
|
|
254
|
+
) as Promise<KubbFile.ResolvedFile>
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async #addOrAppend(file: KubbFile.File): Promise<KubbFile.ResolvedFile> {
|
|
258
|
+
const previousCaches = this.#cache.get(file.path)
|
|
259
|
+
const previousCache = previousCaches ? previousCaches.at(previousCaches.length - 1) : undefined
|
|
260
|
+
|
|
261
|
+
if (previousCache) {
|
|
262
|
+
this.#cache.delete(previousCache.path)
|
|
263
|
+
|
|
264
|
+
return this.#add({
|
|
265
|
+
...file,
|
|
266
|
+
source: previousCache.source && file.source ? `${previousCache.source}\n${file.source}` : '',
|
|
267
|
+
imports: [...(previousCache.imports || []), ...(file.imports || [])],
|
|
268
|
+
exports: [...(previousCache.exports || []), ...(file.exports || [])],
|
|
269
|
+
env: { ...(previousCache.env || {}), ...(file.env || {}) },
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
return this.#add(file)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async addIndexes({ root, output, meta, options = {} }: AddIndexesProps): Promise<Array<KubbFile.File> | undefined> {
|
|
276
|
+
const { exportType = 'barrel' } = output
|
|
277
|
+
|
|
278
|
+
if (!exportType) {
|
|
279
|
+
return undefined
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const exportPath = output.path.startsWith('./') ? trimExtName(output.path) : `./${trimExtName(output.path)}`
|
|
283
|
+
const mode = FileManager.getMode(output.path)
|
|
284
|
+
const barrelManager = new BarrelManager({ extName: output.extName, ...options })
|
|
285
|
+
const files = barrelManager.getIndexes(resolve(root, output.path))
|
|
286
|
+
|
|
287
|
+
function getPath() {
|
|
288
|
+
if (output.extName) {
|
|
289
|
+
if (mode === 'directory') {
|
|
290
|
+
return `${exportPath}/index${output.extName}`
|
|
291
|
+
}
|
|
292
|
+
return `${exportPath}${output.extName}`
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return exportPath
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (!files) {
|
|
299
|
+
return undefined
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const rootFile: KubbFile.File = {
|
|
303
|
+
path: resolve(root, 'index.ts'),
|
|
304
|
+
baseName: 'index.ts',
|
|
305
|
+
source: '',
|
|
306
|
+
exports: [
|
|
307
|
+
output.exportAs
|
|
308
|
+
? {
|
|
309
|
+
name: output.exportAs,
|
|
310
|
+
asAlias: true,
|
|
311
|
+
path: getPath(),
|
|
312
|
+
isTypeOnly: options.isTypeOnly,
|
|
313
|
+
}
|
|
314
|
+
: {
|
|
315
|
+
path: getPath(),
|
|
316
|
+
isTypeOnly: options.isTypeOnly,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
await this.#addOrAppend({
|
|
322
|
+
...rootFile,
|
|
323
|
+
meta: meta ? meta : rootFile.meta,
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
return await Promise.all(
|
|
327
|
+
files.map((file) => {
|
|
328
|
+
return this.#addOrAppend({
|
|
329
|
+
...file,
|
|
330
|
+
meta: meta ? meta : file.meta,
|
|
331
|
+
})
|
|
332
|
+
}),
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
getCacheByUUID(UUID: KubbFile.UUID): KubbFile.File | undefined {
|
|
337
|
+
let cache: KubbFile.File | undefined
|
|
338
|
+
|
|
339
|
+
this.#cache.forEach((files) => {
|
|
340
|
+
cache = files.find((item) => item.id === UUID)
|
|
341
|
+
})
|
|
342
|
+
return cache
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
get(path: KubbFile.Path): Array<KubbFile.File> | undefined {
|
|
346
|
+
return this.#cache.get(path)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
remove(path: KubbFile.Path): void {
|
|
350
|
+
const cacheItem = this.get(path)
|
|
351
|
+
if (!cacheItem) {
|
|
352
|
+
return
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
this.#cache.delete(path)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async write(...params: Parameters<typeof write>): Promise<string | undefined> {
|
|
359
|
+
return write(...params)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async read(...params: Parameters<typeof read>): Promise<string> {
|
|
363
|
+
return read(...params)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// statics
|
|
367
|
+
|
|
368
|
+
static getSource<TMeta extends KubbFile.FileMetaBase = KubbFile.FileMetaBase>(file: KubbFile.File<TMeta>): string {
|
|
369
|
+
return getSource<TMeta>(file)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
static combineFiles<TMeta extends KubbFile.FileMetaBase = KubbFile.FileMetaBase>(files: Array<KubbFile.File<TMeta> | null>): Array<KubbFile.File<TMeta>> {
|
|
373
|
+
return combineFiles<TMeta>(files)
|
|
374
|
+
}
|
|
375
|
+
static getMode(path: string | undefined | null): KubbFile.Mode {
|
|
376
|
+
if (!path) {
|
|
377
|
+
return 'directory'
|
|
378
|
+
}
|
|
379
|
+
return extname(path) ? 'file' : 'directory'
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
static get extensions(): Array<KubbFile.Extname> {
|
|
383
|
+
return ['.js', '.ts', '.tsx']
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
static isExtensionAllowed(baseName: string): boolean {
|
|
387
|
+
return FileManager.extensions.some((extension) => baseName.endsWith(extension))
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function combineFiles<TMeta extends KubbFile.FileMetaBase = KubbFile.FileMetaBase>(
|
|
392
|
+
files: Array<KubbFile.File<TMeta> | null>,
|
|
393
|
+
): Array<KubbFile.File<TMeta>> {
|
|
394
|
+
return files.filter(Boolean).reduce((acc, file: KubbFile.File<TMeta>) => {
|
|
395
|
+
const prevIndex = acc.findIndex((item) => item.path === file.path)
|
|
396
|
+
|
|
397
|
+
if (prevIndex === -1) {
|
|
398
|
+
return [...acc, file]
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const prev = acc[prevIndex]
|
|
402
|
+
|
|
403
|
+
if (prev && file.override) {
|
|
404
|
+
acc[prevIndex] = {
|
|
405
|
+
imports: [],
|
|
406
|
+
exports: [],
|
|
407
|
+
...file,
|
|
408
|
+
}
|
|
409
|
+
return acc
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (prev) {
|
|
413
|
+
acc[prevIndex] = {
|
|
414
|
+
...file,
|
|
415
|
+
source: prev.source && file.source ? `${prev.source}\n${file.source}` : '',
|
|
416
|
+
imports: [...(prev.imports || []), ...(file.imports || [])],
|
|
417
|
+
exports: [...(prev.exports || []), ...(file.exports || [])],
|
|
418
|
+
env: { ...(prev.env || {}), ...(file.env || {}) },
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return acc
|
|
423
|
+
}, [] as Array<KubbFile.File<TMeta>>)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export function getSource<TMeta extends KubbFile.FileMetaBase = KubbFile.FileMetaBase>(file: KubbFile.File<TMeta>): string {
|
|
427
|
+
if (!FileManager.isExtensionAllowed(file.baseName)) {
|
|
428
|
+
return file.source
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const exports = file.exports ? combineExports(file.exports) : []
|
|
432
|
+
const imports = file.imports ? combineImports(file.imports, exports, file.source) : []
|
|
433
|
+
|
|
434
|
+
const importNodes = imports.filter(item => {
|
|
435
|
+
// isImportNotNeeded
|
|
436
|
+
// trim extName
|
|
437
|
+
return item.path !== trimExtName(file.path)
|
|
438
|
+
}).map((item) => {
|
|
439
|
+
return factory.createImportDeclaration({
|
|
440
|
+
name: item.name,
|
|
441
|
+
path: item.root ? getRelativePath(item.root, item.path) : item.path,
|
|
442
|
+
isTypeOnly: item.isTypeOnly,
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
const exportNodes = exports.map((item) =>
|
|
446
|
+
factory.createExportDeclaration({
|
|
447
|
+
name: item.name,
|
|
448
|
+
path: item.path,
|
|
449
|
+
isTypeOnly: item.isTypeOnly,
|
|
450
|
+
asAlias: item.asAlias,
|
|
451
|
+
})
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
return [print([...importNodes, ...exportNodes]), getEnvSource(file.source, file.env)].join('\n')
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function combineExports(exports: Array<KubbFile.Export>): Array<KubbFile.Export> {
|
|
458
|
+
const combinedExports = orderBy(exports, [(v) => !v.isTypeOnly], ['asc']).reduce((prev, curr) => {
|
|
459
|
+
const name = curr.name
|
|
460
|
+
const prevByPath = prev.findLast((imp) => imp.path === curr.path)
|
|
461
|
+
const prevByPathAndIsTypeOnly = prev.findLast((imp) => imp.path === curr.path && isEqual(imp.name, name) && imp.isTypeOnly)
|
|
462
|
+
|
|
463
|
+
if (prevByPathAndIsTypeOnly) {
|
|
464
|
+
// we already have an export that has the same path but uses `isTypeOnly` (export type ...)
|
|
465
|
+
return prev
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const uniquePrev = prev.findLast(
|
|
469
|
+
(imp) => imp.path === curr.path && isEqual(imp.name, name) && imp.isTypeOnly === curr.isTypeOnly && imp.asAlias === curr.asAlias,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
if (uniquePrev || (Array.isArray(name) && !name.length) || (prevByPath?.asAlias && !curr.asAlias)) {
|
|
473
|
+
return prev
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (!prevByPath) {
|
|
477
|
+
return [
|
|
478
|
+
...prev,
|
|
479
|
+
{
|
|
480
|
+
...curr,
|
|
481
|
+
name: Array.isArray(name) ? [...new Set(name)] : name,
|
|
482
|
+
},
|
|
483
|
+
]
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (prevByPath && Array.isArray(prevByPath.name) && Array.isArray(curr.name) && prevByPath.isTypeOnly === curr.isTypeOnly) {
|
|
487
|
+
prevByPath.name = [...new Set([...prevByPath.name, ...curr.name])]
|
|
488
|
+
|
|
489
|
+
return prev
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return [...prev, curr]
|
|
493
|
+
}, [] as Array<KubbFile.Export>)
|
|
494
|
+
|
|
495
|
+
return orderBy(combinedExports, [(v) => !v.isTypeOnly, (v) => v.asAlias], ['desc', 'desc'])
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export function combineImports(imports: Array<KubbFile.Import>, exports: Array<KubbFile.Export>, source?: string): Array<KubbFile.Import> {
|
|
499
|
+
const combinedImports = orderBy(imports, [(v) => !v.isTypeOnly], ['asc']).reduce((prev, curr) => {
|
|
500
|
+
let name = Array.isArray(curr.name) ? [...new Set(curr.name)] : curr.name
|
|
501
|
+
|
|
502
|
+
const hasImportInSource = (importName: string) => {
|
|
503
|
+
if (!source) {
|
|
504
|
+
return true
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const checker = (name?: string) => name && !!source.includes(name)
|
|
508
|
+
return checker(importName) || exports.some(({ name }) => (Array.isArray(name) ? name.some(checker) : checker(name)))
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (Array.isArray(name)) {
|
|
512
|
+
name = name.filter((item) => typeof item === 'string' ? hasImportInSource(item) : hasImportInSource(item.propertyName))
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const prevByPath = prev.findLast((imp) => imp.path === curr.path && imp.isTypeOnly === curr.isTypeOnly)
|
|
516
|
+
const uniquePrev = prev.findLast((imp) => imp.path === curr.path && isEqual(imp.name, name) && imp.isTypeOnly === curr.isTypeOnly)
|
|
517
|
+
const prevByPathNameAndIsTypeOnly = prev.findLast((imp) => imp.path === curr.path && isEqual(imp.name, name) && imp.isTypeOnly)
|
|
518
|
+
|
|
519
|
+
if (prevByPathNameAndIsTypeOnly) {
|
|
520
|
+
// we already have an export that has the same path but uses `isTypeOnly` (import type ...)
|
|
521
|
+
return prev
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (uniquePrev || (Array.isArray(name) && !name.length)) {
|
|
525
|
+
return prev
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (!prevByPath) {
|
|
529
|
+
return [
|
|
530
|
+
...prev,
|
|
531
|
+
{
|
|
532
|
+
...curr,
|
|
533
|
+
name,
|
|
534
|
+
},
|
|
535
|
+
]
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (prevByPath && Array.isArray(prevByPath.name) && Array.isArray(name) && prevByPath.isTypeOnly === curr.isTypeOnly) {
|
|
539
|
+
prevByPath.name = [...new Set([...prevByPath.name, ...name])]
|
|
540
|
+
|
|
541
|
+
return prev
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (!Array.isArray(name) && name && !hasImportInSource(name)) {
|
|
545
|
+
return prev
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return [...prev, curr]
|
|
549
|
+
}, [] as Array<KubbFile.Import>)
|
|
550
|
+
|
|
551
|
+
return orderBy(combinedImports, [(v) => !v.isTypeOnly], ['desc'])
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function getEnvSource(source: string, env: NodeJS.ProcessEnv | undefined): string {
|
|
555
|
+
if (!env) {
|
|
556
|
+
return source
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const keys = Object.keys(env)
|
|
560
|
+
|
|
561
|
+
if (!keys.length) {
|
|
562
|
+
return source
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return keys.reduce((prev, key: string) => {
|
|
566
|
+
const environmentValue = env[key]
|
|
567
|
+
const replaceBy = environmentValue ? `'${environmentValue.replaceAll('"', '')?.replaceAll("'", '')}'` : 'undefined'
|
|
568
|
+
|
|
569
|
+
if (key.toUpperCase() !== key) {
|
|
570
|
+
throw new TypeError(`Environment should be in upperCase for ${key}`)
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (typeof replaceBy === 'string') {
|
|
574
|
+
prev = searchAndReplace({ text: prev.replaceAll(`process.env.${key}`, replaceBy), replaceBy, prefix: 'process.env', key })
|
|
575
|
+
// removes `declare const ...`
|
|
576
|
+
prev = searchAndReplace({ text: prev.replaceAll(new RegExp(`(declare const).*\n`, 'ig'), ''), replaceBy, key })
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return prev
|
|
580
|
+
}, source)
|
|
581
|
+
}
|
package/src/Generator.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract class that contains the building blocks for plugins to create their own Generator
|
|
3
|
+
* @link idea based on https://github.com/colinhacks/zod/blob/master/src/types.ts#L137
|
|
4
|
+
*/
|
|
5
|
+
export abstract class Generator<TOptions = unknown, TContext = unknown> {
|
|
6
|
+
#options: TOptions = {} as TOptions
|
|
7
|
+
#context: TContext = {} as TContext
|
|
8
|
+
|
|
9
|
+
constructor(options?: TOptions, context?: TContext) {
|
|
10
|
+
if (context) {
|
|
11
|
+
this.#context = context
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (options) {
|
|
15
|
+
this.#options = options
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return this
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get options(): TOptions {
|
|
22
|
+
return this.#options
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get context(): TContext {
|
|
26
|
+
return this.#context
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set options(options: TOptions) {
|
|
30
|
+
this.#options = { ...this.#options, ...options }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
abstract build(...params: unknown[]): unknown
|
|
34
|
+
}
|