@kubb/core 5.0.0-alpha.2 → 5.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.
- package/dist/{types-B7eZvqwD.d.ts → PluginDriver-CEQPafXV.d.ts} +687 -298
- package/dist/hooks.cjs +15 -9
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +11 -5
- package/dist/hooks.js +16 -10
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +1131 -536
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +674 -89
- package/dist/index.js +1114 -532
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/Kubb.ts +37 -55
- package/src/{PluginManager.ts → PluginDriver.ts} +51 -40
- package/src/build.ts +74 -29
- package/src/config.ts +9 -8
- package/src/constants.ts +44 -1
- package/src/createAdapter.ts +25 -0
- package/src/createPlugin.ts +28 -0
- package/src/createStorage.ts +58 -0
- package/src/defineBuilder.ts +26 -0
- package/src/defineGenerator.ts +137 -0
- package/src/defineLogger.ts +13 -3
- package/src/definePreset.ts +27 -0
- package/src/definePresets.ts +16 -0
- package/src/defineResolver.ts +448 -0
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useDriver.ts +8 -0
- package/src/hooks/useMode.ts +5 -2
- package/src/hooks/usePlugin.ts +5 -2
- package/src/index.ts +21 -6
- package/src/renderNode.tsx +105 -0
- package/src/storages/fsStorage.ts +2 -2
- package/src/storages/memoryStorage.ts +2 -2
- package/src/types.ts +342 -42
- package/src/utils/FunctionParams.ts +2 -2
- package/src/utils/TreeNode.ts +24 -1
- package/src/utils/diagnostics.ts +4 -1
- package/src/utils/executeStrategies.ts +23 -10
- package/src/utils/formatters.ts +10 -21
- package/src/utils/getBarrelFiles.ts +79 -9
- package/src/utils/getConfigs.ts +8 -22
- package/src/utils/getPreset.ts +52 -0
- package/src/utils/linters.ts +23 -3
- package/src/utils/mergeResolvers.ts +8 -0
- package/src/utils/packageJSON.ts +76 -0
- package/src/BarrelManager.ts +0 -74
- package/src/PackageManager.ts +0 -180
- package/src/PromiseManager.ts +0 -40
- package/src/defineAdapter.ts +0 -22
- package/src/definePlugin.ts +0 -12
- package/src/defineStorage.ts +0 -56
- package/src/errors.ts +0 -1
- package/src/hooks/usePluginManager.ts +0 -8
- package/src/utils/getPlugins.ts +0 -23
package/src/utils/formatters.ts
CHANGED
|
@@ -4,18 +4,13 @@ import type { formatters } from '../constants.ts'
|
|
|
4
4
|
type Formatter = keyof typeof formatters
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Returns `true` when the given formatter is installed and callable.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @remarks
|
|
13
|
-
* This function checks availability by running `<formatter> --version` command.
|
|
14
|
-
* All supported formatters (biome, prettier, oxfmt) implement the --version flag.
|
|
9
|
+
* Availability is detected by running `<formatter> --version` and checking
|
|
10
|
+
* that the process exits without error.
|
|
15
11
|
*/
|
|
16
12
|
async function isFormatterAvailable(formatter: Formatter): Promise<boolean> {
|
|
17
13
|
try {
|
|
18
|
-
// Try to get the version of the formatter to check if it's installed
|
|
19
14
|
await x(formatter, ['--version'], { nodeOptions: { stdio: 'ignore' } })
|
|
20
15
|
return true
|
|
21
16
|
} catch {
|
|
@@ -24,27 +19,21 @@ async function isFormatterAvailable(formatter: Formatter): Promise<boolean> {
|
|
|
24
19
|
}
|
|
25
20
|
|
|
26
21
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* @returns Promise that resolves to the first available formatter or undefined if none are found
|
|
22
|
+
* Detects the first available code formatter on the current system.
|
|
30
23
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* Uses the `--version` flag to detect if each formatter command is available.
|
|
34
|
-
* This is a reliable method as all supported formatters implement this flag.
|
|
24
|
+
* - Checks in preference order: `biome`, `oxfmt`, `prettier`.
|
|
25
|
+
* - Returns `null` when none are found.
|
|
35
26
|
*
|
|
36
27
|
* @example
|
|
37
|
-
* ```
|
|
28
|
+
* ```ts
|
|
38
29
|
* const formatter = await detectFormatter()
|
|
39
30
|
* if (formatter) {
|
|
40
31
|
* console.log(`Using ${formatter} for formatting`)
|
|
41
|
-
* } else {
|
|
42
|
-
* console.log('No formatter found')
|
|
43
32
|
* }
|
|
44
33
|
* ```
|
|
45
34
|
*/
|
|
46
|
-
export async function detectFormatter(): Promise<Formatter |
|
|
47
|
-
const formatterNames
|
|
35
|
+
export async function detectFormatter(): Promise<Formatter | null> {
|
|
36
|
+
const formatterNames = new Set(['biome', 'oxfmt', 'prettier'] as const)
|
|
48
37
|
|
|
49
38
|
for (const formatter of formatterNames) {
|
|
50
39
|
if (await isFormatterAvailable(formatter)) {
|
|
@@ -52,5 +41,5 @@ export async function detectFormatter(): Promise<Formatter | undefined> {
|
|
|
52
41
|
}
|
|
53
42
|
}
|
|
54
43
|
|
|
55
|
-
return
|
|
44
|
+
return null
|
|
56
45
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */
|
|
1
2
|
import { join } from 'node:path'
|
|
3
|
+
import { getRelativePath } from '@internals/utils'
|
|
2
4
|
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
3
|
-
import { BarrelManager } from '../BarrelManager.ts'
|
|
4
5
|
import type { BarrelType } from '../types.ts'
|
|
6
|
+
import { TreeNode } from './TreeNode.ts'
|
|
5
7
|
|
|
6
8
|
export type FileMetaBase = {
|
|
7
9
|
pluginName?: string
|
|
@@ -27,6 +29,72 @@ type AddIndexesProps = {
|
|
|
27
29
|
meta?: FileMetaBase
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
function getBarrelFilesByRoot(root: string | undefined, files: Array<KubbFile.ResolvedFile>): Array<KubbFile.File> {
|
|
33
|
+
const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()
|
|
34
|
+
|
|
35
|
+
TreeNode.build(files, root)?.forEach((treeNode) => {
|
|
36
|
+
if (!treeNode?.children || !treeNode.parent?.data.path) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const barrelFilePath = join(treeNode.parent?.data.path, 'index.ts') as KubbFile.Path
|
|
41
|
+
const barrelFile: KubbFile.File = {
|
|
42
|
+
path: barrelFilePath,
|
|
43
|
+
baseName: 'index.ts',
|
|
44
|
+
exports: [],
|
|
45
|
+
imports: [],
|
|
46
|
+
sources: [],
|
|
47
|
+
}
|
|
48
|
+
const previousBarrelFile = cachedFiles.get(barrelFile.path)
|
|
49
|
+
const leaves = treeNode.leaves
|
|
50
|
+
|
|
51
|
+
leaves.forEach((item) => {
|
|
52
|
+
if (!item.data.name) {
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const sources = item.data.file?.sources || []
|
|
57
|
+
|
|
58
|
+
sources.forEach((source) => {
|
|
59
|
+
if (!item.data.file?.path || !source.isIndexable || !source.name) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
const alreadyContainInPreviousBarrelFile = previousBarrelFile?.sources.some(
|
|
63
|
+
(item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if (alreadyContainInPreviousBarrelFile) {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
barrelFile.exports!.push({
|
|
71
|
+
name: [source.name],
|
|
72
|
+
path: getRelativePath(treeNode.parent?.data.path, item.data.path),
|
|
73
|
+
isTypeOnly: source.isTypeOnly,
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
barrelFile.sources.push({
|
|
77
|
+
name: source.name,
|
|
78
|
+
isTypeOnly: source.isTypeOnly,
|
|
79
|
+
//TODO use parser to generate import
|
|
80
|
+
value: '',
|
|
81
|
+
isExportable: false,
|
|
82
|
+
isIndexable: false,
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
if (previousBarrelFile) {
|
|
88
|
+
previousBarrelFile.sources.push(...barrelFile.sources)
|
|
89
|
+
previousBarrelFile.exports?.push(...(barrelFile.exports || []))
|
|
90
|
+
} else {
|
|
91
|
+
cachedFiles.set(barrelFile.path, barrelFile)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
return [...cachedFiles.values()]
|
|
96
|
+
}
|
|
97
|
+
|
|
30
98
|
function trimExtName(text: string): string {
|
|
31
99
|
const dotIndex = text.lastIndexOf('.')
|
|
32
100
|
// Only strip when the dot is found and no path separator follows it
|
|
@@ -37,24 +105,26 @@ function trimExtName(text: string): string {
|
|
|
37
105
|
return text
|
|
38
106
|
}
|
|
39
107
|
|
|
40
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Generates `index.ts` barrel files for all directories under `root/output.path`.
|
|
110
|
+
*
|
|
111
|
+
* - Returns an empty array when `type` is falsy or `'propagate'`.
|
|
112
|
+
* - Skips generation when the output path itself ends with `index` (already a barrel).
|
|
113
|
+
* - When `type` is `'all'`, strips named exports so every re-export becomes a wildcard (`export * from`).
|
|
114
|
+
* - Attaches `meta` to each barrel file for downstream plugin identification.
|
|
115
|
+
*/
|
|
116
|
+
export async function getBarrelFiles(files: Array<KubbFile.ResolvedFile>, { type, meta = {}, root, output }: AddIndexesProps): Promise<Array<KubbFile.File>> {
|
|
41
117
|
if (!type || type === 'propagate') {
|
|
42
118
|
return []
|
|
43
119
|
}
|
|
44
120
|
|
|
45
|
-
const barrelManager = new BarrelManager()
|
|
46
|
-
|
|
47
121
|
const pathToBuildFrom = join(root, output.path)
|
|
48
122
|
|
|
49
123
|
if (trimExtName(pathToBuildFrom).endsWith('index')) {
|
|
50
124
|
return []
|
|
51
125
|
}
|
|
52
126
|
|
|
53
|
-
const barrelFiles =
|
|
54
|
-
files,
|
|
55
|
-
root: pathToBuildFrom,
|
|
56
|
-
meta,
|
|
57
|
-
})
|
|
127
|
+
const barrelFiles = getBarrelFilesByRoot(pathToBuildFrom, files)
|
|
58
128
|
|
|
59
129
|
if (type === 'all') {
|
|
60
130
|
return barrelFiles.map((file) => {
|
package/src/utils/getConfigs.ts
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import type { CLIOptions, ConfigInput } from '../config.ts'
|
|
2
2
|
import type { Config, UserConfig } from '../types.ts'
|
|
3
|
-
import { getPlugins } from './getPlugins.ts'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* Resolves a {@link ConfigInput} into a normalized array of {@link Config} objects.
|
|
6
|
+
*
|
|
7
|
+
* - Awaits the config when it is a `Promise`.
|
|
8
|
+
* - Calls the factory function with `args` when the config is a function.
|
|
9
|
+
* - Wraps a single config object in an array for uniform downstream handling.
|
|
7
10
|
*/
|
|
8
11
|
export async function getConfigs(config: ConfigInput | UserConfig, args: CLIOptions): Promise<Array<Config>> {
|
|
9
|
-
const
|
|
10
|
-
|
|
12
|
+
const resolved = await (typeof config === 'function' ? config(args as CLIOptions) : config)
|
|
13
|
+
const userConfigs = Array.isArray(resolved) ? resolved : [resolved]
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!Array.isArray(userConfigs)) {
|
|
15
|
-
userConfigs = [userConfigs]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const results: Array<Config> = []
|
|
19
|
-
|
|
20
|
-
for (const item of userConfigs) {
|
|
21
|
-
const plugins = item.plugins ? await getPlugins(item.plugins) : undefined
|
|
22
|
-
|
|
23
|
-
results.push({
|
|
24
|
-
...item,
|
|
25
|
-
plugins,
|
|
26
|
-
} as Config)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return results
|
|
15
|
+
return userConfigs.map((item) => ({ ...item }) as Config)
|
|
30
16
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Visitor } from '@kubb/ast/types'
|
|
2
|
+
import type { CompatibilityPreset, Generator, Preset, Presets, Resolver } from '../types.ts'
|
|
3
|
+
import { mergeResolvers } from './mergeResolvers.ts'
|
|
4
|
+
|
|
5
|
+
type GetPresetParams<TResolver extends Resolver> = {
|
|
6
|
+
preset: CompatibilityPreset
|
|
7
|
+
presets: Presets<TResolver>
|
|
8
|
+
resolvers: Array<TResolver>
|
|
9
|
+
/**
|
|
10
|
+
* User-supplied generators to append after the preset's generators.
|
|
11
|
+
*/
|
|
12
|
+
generators: Array<Generator<any>>
|
|
13
|
+
transformers?: Array<Visitor>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type GetPresetResult<TResolver extends Resolver> = {
|
|
17
|
+
resolver: TResolver
|
|
18
|
+
transformers: Array<Visitor>
|
|
19
|
+
generators: Array<Generator<any>>
|
|
20
|
+
preset: Preset<TResolver> | undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a named preset into merged resolvers, transformers, and generators.
|
|
25
|
+
*
|
|
26
|
+
* - Merges the preset's resolvers on top of the first (default)
|
|
27
|
+
* - Merges any additional user-supplied resolvers on top of that to produce the final `resolver`.
|
|
28
|
+
* - Concatenates preset transformers before user-supplied transformers.
|
|
29
|
+
* - Combines preset generators with user-supplied generators; falls back to the `default` preset's generators when neither provides any.
|
|
30
|
+
*/
|
|
31
|
+
export function getPreset<TResolver extends Resolver = Resolver>(params: GetPresetParams<TResolver>): GetPresetResult<TResolver> {
|
|
32
|
+
const { preset: presetName, presets, resolvers, transformers: userTransformers, generators: userGenerators } = params
|
|
33
|
+
const [defaultResolver, ...userResolvers] = resolvers
|
|
34
|
+
const preset = presets[presetName]
|
|
35
|
+
|
|
36
|
+
const baseResolver = mergeResolvers(defaultResolver!, ...(preset?.resolvers ?? []))
|
|
37
|
+
const resolver = mergeResolvers(baseResolver, ...(userResolvers ?? []))
|
|
38
|
+
const transformers = [...(preset?.transformers ?? []), ...(userTransformers ?? [])]
|
|
39
|
+
|
|
40
|
+
const presetGenerators = preset?.generators ?? []
|
|
41
|
+
const defaultPresetGenerators = presets['default']?.generators ?? []
|
|
42
|
+
const generators = (presetGenerators.length > 0 || userGenerators.length
|
|
43
|
+
? [...presetGenerators, ...userGenerators]
|
|
44
|
+
: defaultPresetGenerators) as unknown as Array<Generator<any>>
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
resolver,
|
|
48
|
+
transformers,
|
|
49
|
+
generators,
|
|
50
|
+
preset,
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/utils/linters.ts
CHANGED
|
@@ -3,6 +3,12 @@ import type { linters } from '../constants.ts'
|
|
|
3
3
|
|
|
4
4
|
type Linter = keyof typeof linters
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Returns `true` when the given linter is installed and callable.
|
|
8
|
+
*
|
|
9
|
+
* Availability is detected by running `<linter> --version` and checking
|
|
10
|
+
* that the process exits without error.
|
|
11
|
+
*/
|
|
6
12
|
async function isLinterAvailable(linter: Linter): Promise<boolean> {
|
|
7
13
|
try {
|
|
8
14
|
await x(linter, ['--version'], { nodeOptions: { stdio: 'ignore' } })
|
|
@@ -12,8 +18,22 @@ async function isLinterAvailable(linter: Linter): Promise<boolean> {
|
|
|
12
18
|
}
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Detects the first available linter on the current system.
|
|
23
|
+
*
|
|
24
|
+
* - Checks in preference order: `biome`, `oxlint`, `eslint`.
|
|
25
|
+
* - Returns `null` when none are found.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const linter = await detectLinter()
|
|
30
|
+
* if (linter) {
|
|
31
|
+
* console.log(`Using ${linter} for linting`)
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function detectLinter(): Promise<Linter | null> {
|
|
36
|
+
const linterNames = new Set(['biome', 'oxlint', 'eslint'] as const)
|
|
17
37
|
|
|
18
38
|
for (const linter of linterNames) {
|
|
19
39
|
if (await isLinterAvailable(linter)) {
|
|
@@ -21,5 +41,5 @@ export async function detectLinter(): Promise<Linter | undefined> {
|
|
|
21
41
|
}
|
|
22
42
|
}
|
|
23
43
|
|
|
24
|
-
return
|
|
44
|
+
return null
|
|
25
45
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Resolver } from '../types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Merges an array of resolvers into a single resolver. Later entries override earlier ones (last wins).
|
|
5
|
+
*/
|
|
6
|
+
export function mergeResolvers<T extends Resolver>(...resolvers: Array<T>): T {
|
|
7
|
+
return resolvers.reduce<T>((acc, curr) => ({ ...acc, ...curr }), resolvers[0]!)
|
|
8
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { readSync } from '@internals/utils'
|
|
2
|
+
import * as pkg from 'empathic/package'
|
|
3
|
+
import { coerce, satisfies } from 'semver'
|
|
4
|
+
|
|
5
|
+
type PackageJSON = {
|
|
6
|
+
dependencies?: Record<string, string>
|
|
7
|
+
devDependencies?: Record<string, string>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type DependencyName = string
|
|
11
|
+
type DependencyVersion = string
|
|
12
|
+
|
|
13
|
+
function getPackageJSONSync(cwd?: string): PackageJSON | null {
|
|
14
|
+
const pkgPath = pkg.up({ cwd })
|
|
15
|
+
if (!pkgPath) {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return JSON.parse(readSync(pkgPath)) as PackageJSON
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function match(packageJSON: PackageJSON, dependency: DependencyName | RegExp): string | null {
|
|
23
|
+
const dependencies = {
|
|
24
|
+
...(packageJSON.dependencies || {}),
|
|
25
|
+
...(packageJSON.devDependencies || {}),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof dependency === 'string' && dependencies[dependency]) {
|
|
29
|
+
return dependencies[dependency]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const matched = Object.keys(dependencies).find((dep) => dep.match(dependency))
|
|
33
|
+
|
|
34
|
+
return matched ? (dependencies[matched] ?? null) : null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getVersionSync(dependency: DependencyName | RegExp, cwd?: string): DependencyVersion | null {
|
|
38
|
+
const packageJSON = getPackageJSONSync(cwd)
|
|
39
|
+
|
|
40
|
+
return packageJSON ? match(packageJSON, dependency) : null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns `true` when the nearest `package.json` declares a dependency that
|
|
45
|
+
* satisfies the given semver range.
|
|
46
|
+
*
|
|
47
|
+
* - Searches both `dependencies` and `devDependencies`.
|
|
48
|
+
* - Accepts a string package name or a `RegExp` to match scoped/pattern packages.
|
|
49
|
+
* - Uses `semver.satisfies` for range comparison; returns `false` when the
|
|
50
|
+
* version string cannot be coerced into a valid semver.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* satisfiesDependency('react', '>=18') // true when react@18.x is installed
|
|
55
|
+
* satisfiesDependency(/^@tanstack\//, '>=5') // true when any @tanstack/* >=5 is found
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function satisfiesDependency(dependency: DependencyName | RegExp, version: DependencyVersion, cwd?: string): boolean {
|
|
59
|
+
const packageVersion = getVersionSync(dependency, cwd)
|
|
60
|
+
|
|
61
|
+
if (!packageVersion) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (packageVersion === version) {
|
|
66
|
+
return true
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const semVer = coerce(packageVersion)
|
|
70
|
+
|
|
71
|
+
if (!semVer) {
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return satisfies(semVer, version)
|
|
76
|
+
}
|
package/src/BarrelManager.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { getRelativePath } from '@internals/utils'
|
|
4
|
-
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
5
|
-
|
|
6
|
-
import type { FileMetaBase } from './utils/getBarrelFiles.ts'
|
|
7
|
-
import { TreeNode } from './utils/TreeNode.ts'
|
|
8
|
-
|
|
9
|
-
export class BarrelManager {
|
|
10
|
-
getFiles({ files: generatedFiles, root }: { files: KubbFile.File[]; root?: string; meta?: FileMetaBase | undefined }): Array<KubbFile.File> {
|
|
11
|
-
const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()
|
|
12
|
-
|
|
13
|
-
TreeNode.build(generatedFiles, root)?.forEach((treeNode) => {
|
|
14
|
-
if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) {
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const barrelFile: KubbFile.File = {
|
|
19
|
-
path: join(treeNode.parent?.data.path, 'index.ts') as KubbFile.Path,
|
|
20
|
-
baseName: 'index.ts',
|
|
21
|
-
exports: [],
|
|
22
|
-
imports: [],
|
|
23
|
-
sources: [],
|
|
24
|
-
}
|
|
25
|
-
const previousBarrelFile = cachedFiles.get(barrelFile.path)
|
|
26
|
-
const leaves = treeNode.leaves
|
|
27
|
-
|
|
28
|
-
leaves.forEach((item) => {
|
|
29
|
-
if (!item.data.name) {
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const sources = item.data.file?.sources || []
|
|
34
|
-
|
|
35
|
-
sources.forEach((source) => {
|
|
36
|
-
if (!item.data.file?.path || !source.isIndexable || !source.name) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
const alreadyContainInPreviousBarrelFile = previousBarrelFile?.sources.some(
|
|
40
|
-
(item) => item.name === source.name && item.isTypeOnly === source.isTypeOnly,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
if (alreadyContainInPreviousBarrelFile) {
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
barrelFile.exports!.push({
|
|
48
|
-
name: [source.name],
|
|
49
|
-
path: getRelativePath(treeNode.parent?.data.path, item.data.path),
|
|
50
|
-
isTypeOnly: source.isTypeOnly,
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
barrelFile.sources.push({
|
|
54
|
-
name: source.name,
|
|
55
|
-
isTypeOnly: source.isTypeOnly,
|
|
56
|
-
//TODO use parser to generate import
|
|
57
|
-
value: '',
|
|
58
|
-
isExportable: false,
|
|
59
|
-
isIndexable: false,
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
if (previousBarrelFile) {
|
|
65
|
-
previousBarrelFile.sources.push(...barrelFile.sources)
|
|
66
|
-
previousBarrelFile.exports?.push(...(barrelFile.exports || []))
|
|
67
|
-
} else {
|
|
68
|
-
cachedFiles.set(barrelFile.path, barrelFile)
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
return [...cachedFiles.values()]
|
|
73
|
-
}
|
|
74
|
-
}
|
package/src/PackageManager.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import mod from 'node:module'
|
|
2
|
-
import os from 'node:os'
|
|
3
|
-
import { pathToFileURL } from 'node:url'
|
|
4
|
-
import { read, readSync } from '@internals/utils'
|
|
5
|
-
import * as pkg from 'empathic/package'
|
|
6
|
-
import { coerce, satisfies } from 'semver'
|
|
7
|
-
import { PATH_SEPARATORS } from './constants.ts'
|
|
8
|
-
|
|
9
|
-
type PackageJSON = {
|
|
10
|
-
dependencies?: Record<string, string>
|
|
11
|
-
devDependencies?: Record<string, string>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type DependencyName = string
|
|
15
|
-
|
|
16
|
-
type DependencyVersion = string
|
|
17
|
-
|
|
18
|
-
export class PackageManager {
|
|
19
|
-
static #cache: Record<DependencyName, DependencyVersion> = {}
|
|
20
|
-
|
|
21
|
-
#cwd?: string
|
|
22
|
-
|
|
23
|
-
constructor(workspace?: string) {
|
|
24
|
-
if (workspace) {
|
|
25
|
-
this.#cwd = workspace
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
set workspace(workspace: string) {
|
|
30
|
-
this.#cwd = workspace
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
get workspace(): string | undefined {
|
|
34
|
-
return this.#cwd
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
normalizeDirectory(directory: string): string {
|
|
38
|
-
const lastChar = directory[directory.length - 1]
|
|
39
|
-
if (lastChar && !(PATH_SEPARATORS as readonly string[]).includes(lastChar)) {
|
|
40
|
-
return `${directory}/`
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return directory
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getLocation(path: string): string {
|
|
47
|
-
let location = path
|
|
48
|
-
|
|
49
|
-
if (this.#cwd) {
|
|
50
|
-
const require = mod.createRequire(this.normalizeDirectory(this.#cwd))
|
|
51
|
-
location = require.resolve(path)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return location
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async import(path: string): Promise<unknown> {
|
|
58
|
-
let location = this.getLocation(path)
|
|
59
|
-
|
|
60
|
-
if (os.platform() === 'win32') {
|
|
61
|
-
location = pathToFileURL(location).href
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const module = await import(location)
|
|
65
|
-
|
|
66
|
-
return module?.default ?? module
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async getPackageJSON(): Promise<PackageJSON | undefined> {
|
|
70
|
-
const pkgPath = pkg.up({
|
|
71
|
-
cwd: this.#cwd,
|
|
72
|
-
})
|
|
73
|
-
if (!pkgPath) {
|
|
74
|
-
return undefined
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const json = await read(pkgPath)
|
|
78
|
-
|
|
79
|
-
return JSON.parse(json) as PackageJSON
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getPackageJSONSync(): PackageJSON | undefined {
|
|
83
|
-
const pkgPath = pkg.up({
|
|
84
|
-
cwd: this.#cwd,
|
|
85
|
-
})
|
|
86
|
-
if (!pkgPath) {
|
|
87
|
-
return undefined
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const json = readSync(pkgPath)
|
|
91
|
-
|
|
92
|
-
return JSON.parse(json) as PackageJSON
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
static setVersion(dependency: DependencyName, version: DependencyVersion): void {
|
|
96
|
-
PackageManager.#cache[dependency] = version
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
#match(packageJSON: PackageJSON, dependency: DependencyName | RegExp): string | undefined {
|
|
100
|
-
const dependencies = {
|
|
101
|
-
...(packageJSON.dependencies || {}),
|
|
102
|
-
...(packageJSON.devDependencies || {}),
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (typeof dependency === 'string' && dependencies[dependency]) {
|
|
106
|
-
return dependencies[dependency]
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const matchedDependency = Object.keys(dependencies).find((dep) => dep.match(dependency))
|
|
110
|
-
|
|
111
|
-
return matchedDependency ? dependencies[matchedDependency] : undefined
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async getVersion(dependency: DependencyName | RegExp): Promise<DependencyVersion | undefined> {
|
|
115
|
-
if (typeof dependency === 'string' && PackageManager.#cache[dependency]) {
|
|
116
|
-
return PackageManager.#cache[dependency]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const packageJSON = await this.getPackageJSON()
|
|
120
|
-
|
|
121
|
-
if (!packageJSON) {
|
|
122
|
-
return undefined
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return this.#match(packageJSON, dependency)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
getVersionSync(dependency: DependencyName | RegExp): DependencyVersion | undefined {
|
|
129
|
-
if (typeof dependency === 'string' && PackageManager.#cache[dependency]) {
|
|
130
|
-
return PackageManager.#cache[dependency]
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const packageJSON = this.getPackageJSONSync()
|
|
134
|
-
|
|
135
|
-
if (!packageJSON) {
|
|
136
|
-
return undefined
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return this.#match(packageJSON, dependency)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async isValid(dependency: DependencyName | RegExp, version: DependencyVersion): Promise<boolean> {
|
|
143
|
-
const packageVersion = await this.getVersion(dependency)
|
|
144
|
-
|
|
145
|
-
if (!packageVersion) {
|
|
146
|
-
return false
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (packageVersion === version) {
|
|
150
|
-
return true
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const semVer = coerce(packageVersion)
|
|
154
|
-
|
|
155
|
-
if (!semVer) {
|
|
156
|
-
return false
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return satisfies(semVer, version)
|
|
160
|
-
}
|
|
161
|
-
isValidSync(dependency: DependencyName | RegExp, version: DependencyVersion): boolean {
|
|
162
|
-
const packageVersion = this.getVersionSync(dependency)
|
|
163
|
-
|
|
164
|
-
if (!packageVersion) {
|
|
165
|
-
return false
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (packageVersion === version) {
|
|
169
|
-
return true
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const semVer = coerce(packageVersion)
|
|
173
|
-
|
|
174
|
-
if (!semVer) {
|
|
175
|
-
return false
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return satisfies(semVer, version)
|
|
179
|
-
}
|
|
180
|
-
}
|