@reliverse/dler 2.0.6 → 2.0.7

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 (46) hide show
  1. package/package.json +16 -12
  2. package/src/cli.ts +0 -8
  3. package/src/cmds/build/cmd.ts +0 -568
  4. package/src/cmds/clean/cmd.ts +0 -166
  5. package/src/cmds/clean/impl.ts +0 -900
  6. package/src/cmds/clean/presets.ts +0 -158
  7. package/src/cmds/clean/types.ts +0 -71
  8. package/src/cmds/init/cmd.ts +0 -68
  9. package/src/cmds/init/impl/config.ts +0 -105
  10. package/src/cmds/init/impl/generators.ts +0 -220
  11. package/src/cmds/init/impl/prompts.ts +0 -137
  12. package/src/cmds/init/impl/types.ts +0 -25
  13. package/src/cmds/init/impl/utils.ts +0 -17
  14. package/src/cmds/init/impl/validators.ts +0 -55
  15. package/src/cmds/integrate/cmd.ts +0 -82
  16. package/src/cmds/integrate/impl.ts +0 -204
  17. package/src/cmds/integrate/integrations/base.ts +0 -69
  18. package/src/cmds/integrate/integrations/nextjs.ts +0 -227
  19. package/src/cmds/integrate/integrations/registry.ts +0 -45
  20. package/src/cmds/integrate/integrations/ultracite.ts +0 -53
  21. package/src/cmds/integrate/types.ts +0 -48
  22. package/src/cmds/integrate/utils/biome.ts +0 -173
  23. package/src/cmds/integrate/utils/context.ts +0 -148
  24. package/src/cmds/integrate/utils/temp.ts +0 -47
  25. package/src/cmds/perf/analysis/bundle.ts +0 -311
  26. package/src/cmds/perf/analysis/filesystem.ts +0 -324
  27. package/src/cmds/perf/analysis/monorepo.ts +0 -439
  28. package/src/cmds/perf/benchmarks/command.ts +0 -230
  29. package/src/cmds/perf/benchmarks/memory.ts +0 -249
  30. package/src/cmds/perf/benchmarks/runner.ts +0 -220
  31. package/src/cmds/perf/cmd.ts +0 -285
  32. package/src/cmds/perf/impl.ts +0 -411
  33. package/src/cmds/perf/reporters/console.ts +0 -331
  34. package/src/cmds/perf/reporters/html.ts +0 -984
  35. package/src/cmds/perf/reporters/json.ts +0 -42
  36. package/src/cmds/perf/types.ts +0 -220
  37. package/src/cmds/perf/utils/cache.ts +0 -234
  38. package/src/cmds/perf/utils/formatter.ts +0 -190
  39. package/src/cmds/perf/utils/stats.ts +0 -153
  40. package/src/cmds/publish/cmd.ts +0 -213
  41. package/src/cmds/shell/cmd.ts +0 -61
  42. package/src/cmds/tsc/cache.ts +0 -237
  43. package/src/cmds/tsc/cmd.ts +0 -139
  44. package/src/cmds/tsc/impl.ts +0 -855
  45. package/src/cmds/tsc/types.ts +0 -66
  46. package/tsconfig.json +0 -9
@@ -1,227 +0,0 @@
1
- // apps/dler/src/cmds/integrate/integrations/nextjs.ts
2
-
3
- import { existsSync, mkdirSync } from "node:fs";
4
- import { dirname, join } from "node:path";
5
- import { writeJsonFile, writeTextFile } from "@reliverse/dler-helpers";
6
- import { logger } from "@reliverse/dler-logger";
7
- import type { IntegrationContext, TempDirectory } from "../types";
8
- import { createIntegrationTempDir } from "../utils/temp";
9
- import { BaseIntegration } from "./base";
10
-
11
- export class NextJsIntegration extends BaseIntegration {
12
- name = "nextjs";
13
- description =
14
- "Next.js React framework with App Router, TypeScript, and Tailwind CSS";
15
- dependencies = ["next", "react", "react-dom"];
16
- devDependencies = ["@types/react", "@types/react-dom", "typescript"];
17
-
18
- private tempDir?: TempDirectory;
19
-
20
- async install(context: IntegrationContext): Promise<void> {
21
- logger.info("šŸ”§ Installing Next.js integration...");
22
-
23
- // Create temp directory for Next.js setup
24
- this.tempDir = context.tempDir;
25
- if (!this.tempDir) {
26
- throw new Error("Temp directory not provided for Next.js integration");
27
- }
28
-
29
- const nextjsTempPath = await createIntegrationTempDir(
30
- this.tempDir,
31
- "nextjs",
32
- );
33
-
34
- // Create Next.js app in temp directory
35
- logger.info("šŸ“¦ Creating Next.js app in temp directory...");
36
- await Bun.$`bunx create-next-app@latest . --yes`
37
- .cwd(nextjsTempPath)
38
- .quiet();
39
-
40
- // Modify tsconfig.json to use ~/ instead of @/
41
- await this.updateTsConfig(nextjsTempPath);
42
-
43
- // Copy files to target
44
- await this.copyFilesToTarget(nextjsTempPath, context);
45
-
46
- // Install dependencies
47
- await this.installDependencies(context);
48
-
49
- // Update package.json scripts
50
- await this.updatePackageJsonScripts(context);
51
- }
52
-
53
- async configure(context: IntegrationContext): Promise<void> {
54
- logger.info("āš™ļø Configuring Next.js...");
55
-
56
- // Create next.config.js if it doesn't exist
57
- const nextConfigPath = join(context.targetPath, "next.config.js");
58
- if (!existsSync(nextConfigPath)) {
59
- const nextConfig = `/** @type {import('next').NextConfig} */
60
- const nextConfig = {
61
- experimental: {
62
- turbo: {
63
- rules: {
64
- '*.svg': {
65
- loaders: ['@svgr/webpack'],
66
- as: '*.js',
67
- },
68
- },
69
- },
70
- },
71
- };
72
-
73
- module.exports = nextConfig;`;
74
-
75
- await writeTextFile(nextConfigPath, nextConfig);
76
- }
77
-
78
- // Create tailwind.config.ts if it doesn't exist
79
- const tailwindConfigPath = join(context.targetPath, "tailwind.config.ts");
80
- if (!existsSync(tailwindConfigPath)) {
81
- const tailwindConfig = `import type { Config } from "tailwindcss";
82
-
83
- const config: Config = {
84
- content: [
85
- "./pages/**/*.{js,ts,jsx,tsx,mdx}",
86
- "./components/**/*.{js,ts,jsx,tsx,mdx}",
87
- "./app/**/*.{js,ts,jsx,tsx,mdx}",
88
- ],
89
- theme: {
90
- extend: {
91
- backgroundImage: {
92
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
93
- "gradient-conic":
94
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
95
- },
96
- },
97
- },
98
- plugins: [],
99
- };
100
- export default config;`;
101
-
102
- await writeTextFile(tailwindConfigPath, tailwindConfig);
103
- }
104
-
105
- logger.success("āœ… Next.js configuration complete");
106
- }
107
-
108
- async postInstall(context: IntegrationContext): Promise<void> {
109
- logger.info("šŸ”§ Verifying Next.js installation...");
110
-
111
- try {
112
- // Check if Next.js is properly installed
113
- await Bun.$`bun next --version`.cwd(context.targetPath).quiet();
114
- logger.success("āœ… Next.js is ready to use");
115
- logger.info("šŸš€ Run 'bun dev' to start the development server");
116
- } catch (error) {
117
- logger.warn("āš ļø Next.js verification failed, but installation completed");
118
- if (context.verbose) {
119
- logger.debug(`Error: ${error}`);
120
- }
121
- }
122
- }
123
-
124
- private async updateTsConfig(tempPath: string): Promise<void> {
125
- const tsconfigPath = join(tempPath, "tsconfig.json");
126
-
127
- if (existsSync(tsconfigPath)) {
128
- const tsconfig = await Bun.file(tsconfigPath).json();
129
-
130
- // Replace @/* with ~/* in paths
131
- if (tsconfig.compilerOptions?.paths) {
132
- const newPaths: Record<string, string[]> = {};
133
- for (const [key, value] of Object.entries(
134
- tsconfig.compilerOptions.paths,
135
- )) {
136
- const newKey = key.replace("@/*", "~/*");
137
- newPaths[newKey] = Array.isArray(value) ? value : [value];
138
- }
139
- tsconfig.compilerOptions.paths = newPaths;
140
- }
141
-
142
- await writeJsonFile(tsconfigPath, tsconfig);
143
- }
144
- }
145
-
146
- private async copyFilesToTarget(
147
- tempPath: string,
148
- context: IntegrationContext,
149
- ): Promise<void> {
150
- const filesToCopy = [
151
- "app",
152
- "public",
153
- "next.config.js",
154
- "next.config.ts",
155
- "tailwind.config.ts",
156
- "postcss.config.js",
157
- "tsconfig.json",
158
- ];
159
-
160
- for (const file of filesToCopy) {
161
- const srcPath = join(tempPath, file);
162
- const destPath = join(context.targetPath, file);
163
-
164
- if (existsSync(srcPath)) {
165
- await this.copyFileOrDir(srcPath, destPath);
166
- logger.debug(`šŸ“„ Copied ${file}`);
167
- }
168
- }
169
- }
170
-
171
- private async copyFileOrDir(src: string, dest: string): Promise<void> {
172
- const stat = await Bun.file(src).stat();
173
-
174
- if (stat.isDirectory()) {
175
- // Copy directory recursively
176
- const glob = new Bun.Glob("**/*");
177
- const files = Array.from(glob.scanSync({ cwd: src, onlyFiles: true }));
178
-
179
- for (const file of files) {
180
- const srcFile = join(src, file);
181
- const destFile = join(dest, file);
182
-
183
- // Ensure destination directory exists
184
- mkdirSync(dirname(destFile), { recursive: true });
185
-
186
- // Copy file
187
- const content = await Bun.file(srcFile).arrayBuffer();
188
- await Bun.write(destFile, content);
189
- }
190
- } else {
191
- // Copy single file
192
- mkdirSync(dirname(dest), { recursive: true });
193
- const content = await Bun.file(src).arrayBuffer();
194
- await Bun.write(dest, content);
195
- }
196
- }
197
-
198
- private async updatePackageJsonScripts(
199
- context: IntegrationContext,
200
- ): Promise<void> {
201
- const packageJsonPath = join(context.targetPath, "package.json");
202
-
203
- try {
204
- const packageJson = await Bun.file(packageJsonPath).json();
205
-
206
- const nextjsScripts = {
207
- dev: "next dev",
208
- build: "next build",
209
- start: "next start",
210
- lint: "next lint",
211
- };
212
-
213
- packageJson.scripts = {
214
- ...packageJson.scripts,
215
- ...nextjsScripts,
216
- };
217
-
218
- await writeJsonFile(packageJsonPath, packageJson);
219
- logger.debug("šŸ“ Updated package.json scripts");
220
- } catch (error) {
221
- logger.warn("āš ļø Failed to update package.json scripts");
222
- if (context.verbose) {
223
- logger.debug(`Error: ${error}`);
224
- }
225
- }
226
- }
227
- }
@@ -1,45 +0,0 @@
1
- // apps/dler/src/cmds/integrate/integrations/registry.ts
2
-
3
- import { logger } from "@reliverse/dler-logger";
4
- import type { Integration } from "../types";
5
- import { NextJsIntegration } from "./nextjs";
6
- import { UltraciteIntegration } from "./ultracite";
7
-
8
- const INTEGRATIONS: Record<string, () => Integration> = {
9
- ultracite: () => new UltraciteIntegration(),
10
- nextjs: () => new NextJsIntegration(),
11
- };
12
-
13
- export function getIntegration(name: string): Integration | null {
14
- const integrationFactory = INTEGRATIONS[name.toLowerCase()];
15
-
16
- if (!integrationFactory) {
17
- logger.error(`āŒ Unknown integration: ${name}`);
18
- logger.info(`Available integrations: ${listIntegrations().join(", ")}`);
19
- return null;
20
- }
21
-
22
- return integrationFactory();
23
- }
24
-
25
- export function listIntegrations(): string[] {
26
- return Object.keys(INTEGRATIONS);
27
- }
28
-
29
- export function validateIntegrationNames(names: string[]): {
30
- valid: string[];
31
- invalid: string[];
32
- } {
33
- const valid: string[] = [];
34
- const invalid: string[] = [];
35
-
36
- for (const name of names) {
37
- if (INTEGRATIONS[name.toLowerCase()]) {
38
- valid.push(name);
39
- } else {
40
- invalid.push(name);
41
- }
42
- }
43
-
44
- return { valid, invalid };
45
- }
@@ -1,53 +0,0 @@
1
- // apps/dler/src/cmds/integrate/integrations/ultracite.ts
2
-
3
- import { logger } from "@reliverse/dler-logger";
4
- import type { IntegrationContext } from "../types";
5
- import {
6
- createBiomeConfig,
7
- findBiomeConfig,
8
- updateBiomeConfig,
9
- } from "../utils/biome";
10
- import { BaseIntegration } from "./base";
11
-
12
- export class UltraciteIntegration extends BaseIntegration {
13
- name = "ultracite";
14
- description =
15
- "Ultracite preset for Biome (highly opinionated linter and formatter)";
16
- dependencies: string[] = [];
17
- devDependencies = ["@biomejs/biome", "ultracite"];
18
-
19
- async install(context: IntegrationContext): Promise<void> {
20
- logger.info("šŸ”§ Installing Ultracite integration...");
21
- await this.installDependencies(context);
22
- }
23
-
24
- async configure(context: IntegrationContext): Promise<void> {
25
- logger.info("āš™ļø Configuring Biome with Ultracite preset...");
26
-
27
- const biomeConfig = await findBiomeConfig(context.targetPath);
28
-
29
- if (biomeConfig.exists && biomeConfig.content) {
30
- // Update existing biome.json
31
- await updateBiomeConfig(biomeConfig.path, biomeConfig.content);
32
- logger.success("āœ… Updated existing biome.json with Ultracite preset");
33
- } else {
34
- // Create new biome.json
35
- await createBiomeConfig(biomeConfig.path);
36
- logger.success("āœ… Created new biome.json with Ultracite preset");
37
- }
38
- }
39
-
40
- async postInstall(context: IntegrationContext): Promise<void> {
41
- logger.info("šŸ”§ Running Biome check to verify configuration...");
42
-
43
- try {
44
- await Bun.$`bun biome check --version`.cwd(context.targetPath).quiet();
45
- logger.success("āœ… Biome is properly configured and ready to use");
46
- } catch (error) {
47
- logger.warn("āš ļø Biome check failed, but configuration was created");
48
- if (context.verbose) {
49
- logger.debug(`Error: ${error}`);
50
- }
51
- }
52
- }
53
- }
@@ -1,48 +0,0 @@
1
- // apps/dler/src/cmds/integrate/types.ts
2
-
3
- export interface IntegrationContext {
4
- targetPath: string;
5
- isMonorepo: boolean;
6
- monorepoRoot?: string;
7
- packageName?: string;
8
- verbose: boolean;
9
- tempDir: TempDirectory;
10
- }
11
-
12
- export interface Integration {
13
- name: string;
14
- description: string;
15
- dependencies: string[];
16
- devDependencies: string[];
17
-
18
- // Lifecycle hooks
19
- validate(context: IntegrationContext): Promise<boolean>;
20
- install(context: IntegrationContext): Promise<void>;
21
- configure(context: IntegrationContext): Promise<void>;
22
- postInstall(context: IntegrationContext): Promise<void>;
23
- }
24
-
25
- export interface ProjectContext {
26
- type: "monorepo" | "single-repo";
27
- rootPath: string;
28
- targetPath: string;
29
- packages?: PackageInfo[];
30
- selectedPackage?: PackageInfo;
31
- }
32
-
33
- export interface PackageInfo {
34
- name: string;
35
- path: string;
36
- packageJson: any;
37
- }
38
-
39
- export interface BiomeConfig {
40
- path: string;
41
- exists: boolean;
42
- content?: any;
43
- }
44
-
45
- export interface TempDirectory {
46
- path: string;
47
- cleanup: () => Promise<void>;
48
- }
@@ -1,173 +0,0 @@
1
- // apps/dler/src/cmds/integrate/utils/biome.ts
2
-
3
- import { existsSync } from "node:fs";
4
- import { join, resolve } from "node:path";
5
- import { writeJsonFile } from "@reliverse/dler-helpers";
6
- import { logger } from "@reliverse/dler-logger";
7
- import { hasWorkspaces, readPackageJSON } from "@reliverse/dler-pkg-tsc";
8
- import type { BiomeConfig } from "../types";
9
-
10
- export const findBiomeConfig = async (
11
- startDir: string,
12
- ): Promise<BiomeConfig> => {
13
- let currentDir = resolve(startDir);
14
- let depth = 0;
15
- const maxDepth = 3;
16
-
17
- while (depth <= maxDepth) {
18
- const biomePath = join(currentDir, "biome.json");
19
-
20
- if (existsSync(biomePath)) {
21
- try {
22
- const content = await Bun.file(biomePath).json();
23
- return {
24
- path: biomePath,
25
- exists: true,
26
- content,
27
- };
28
- } catch {
29
- // If we can't read the file, continue searching
30
- }
31
- }
32
-
33
- const parentDir = resolve(currentDir, "..");
34
- if (parentDir === currentDir) break;
35
- currentDir = parentDir;
36
- depth++;
37
- }
38
-
39
- // No biome.json found, determine where to create it
40
- const monorepoRoot = await findMonorepoRoot(startDir);
41
- const targetPath = monorepoRoot || startDir;
42
-
43
- return {
44
- path: join(targetPath, "biome.json"),
45
- exists: false,
46
- };
47
- };
48
-
49
- const findMonorepoRoot = async (startDir: string): Promise<string | null> => {
50
- let currentDir = resolve(startDir);
51
-
52
- while (currentDir !== "/") {
53
- const pkgPath = join(currentDir, "package.json");
54
-
55
- if (existsSync(pkgPath)) {
56
- const pkg = await readPackageJSON(currentDir);
57
-
58
- if (pkg && hasWorkspaces(pkg)) {
59
- return currentDir;
60
- }
61
- }
62
-
63
- const parentDir = resolve(currentDir, "..");
64
- if (parentDir === currentDir) break;
65
- currentDir = parentDir;
66
- }
67
-
68
- return null;
69
- };
70
-
71
- export const createBiomeConfig = async (
72
- configPath: string,
73
- integrationType?: string,
74
- ): Promise<void> => {
75
- logger.info(`šŸ“ Creating biome.json at ${configPath}`);
76
-
77
- const baseConfig = {
78
- $schema: "./node_modules/@biomejs/biome/configuration_schema.json",
79
- extends: ["ultracite"],
80
- files: {
81
- includes: [
82
- "**",
83
- "!**/.js",
84
- "!**/.d.ts",
85
- "!**/_generated",
86
- "!**/.next",
87
- "!**/.react-email",
88
- "!**/.source",
89
- "!**/.turbo",
90
- "!**/.vercel",
91
- "!**/.wrangler",
92
- "!**/.zed",
93
- "!**/dev-dist",
94
- "!**/dist-*",
95
- "!**/dist",
96
- "!**/drizzle/migrations",
97
- "!**/node_modules",
98
- ],
99
- ignoreUnknown: false,
100
- },
101
- linter: {
102
- enabled: true,
103
- rules: {
104
- recommended: true,
105
- // Add integration-specific rules if needed
106
- ...(integrationType === "nextjs" && {
107
- a11y: {
108
- useHtmlLang: "warn",
109
- noHeaderScope: "warn",
110
- },
111
- }),
112
- },
113
- },
114
- formatter: {
115
- enabled: true,
116
- indentStyle: "space",
117
- indentWidth: 2,
118
- lineWidth: 80,
119
- },
120
- javascript: {
121
- globals: ["Bun"],
122
- formatter: {
123
- enabled: true,
124
- lineEnding: "lf",
125
- jsxQuoteStyle: "double",
126
- quoteProperties: "asNeeded",
127
- trailingCommas: "all",
128
- lineWidth: 80,
129
- indentWidth: 2,
130
- indentStyle: "space",
131
- semicolons: "always",
132
- arrowParentheses: "always",
133
- bracketSpacing: true,
134
- bracketSameLine: false,
135
- quoteStyle: "double",
136
- attributePosition: "auto",
137
- },
138
- },
139
- assist: {
140
- enabled: true,
141
- actions: {
142
- source: {
143
- organizeImports: "on",
144
- },
145
- },
146
- },
147
- vcs: {
148
- enabled: false,
149
- clientKind: "git",
150
- useIgnoreFile: false,
151
- },
152
- };
153
-
154
- await writeJsonFile(configPath, baseConfig);
155
- };
156
-
157
- export const updateBiomeConfig = async (
158
- configPath: string,
159
- content: any,
160
- ): Promise<void> => {
161
- logger.info(`šŸ“ Updating biome.json at ${configPath}`);
162
-
163
- // Ensure ultracite is in extends array
164
- if (!content.extends || !Array.isArray(content.extends)) {
165
- content.extends = [];
166
- }
167
-
168
- if (!content.extends.includes("ultracite")) {
169
- content.extends.unshift("ultracite");
170
- }
171
-
172
- await writeJsonFile(configPath, content);
173
- };
@@ -1,148 +0,0 @@
1
- // apps/dler/src/cmds/integrate/utils/context.ts
2
-
3
- import { existsSync } from "node:fs";
4
- import { join, resolve } from "node:path";
5
- import { logger } from "@reliverse/dler-logger";
6
- import {
7
- getWorkspacePatterns,
8
- hasWorkspaces,
9
- readPackageJSON,
10
- } from "@reliverse/dler-pkg-tsc";
11
- import { askQuestion } from "@reliverse/dler-prompt";
12
- import type { PackageInfo, ProjectContext } from "../types";
13
-
14
- export const detectProjectContext = async (
15
- cwd?: string,
16
- ): Promise<ProjectContext> => {
17
- const startDir = resolve(cwd ?? process.cwd());
18
- const monorepoRoot = await findMonorepoRoot(startDir);
19
-
20
- if (monorepoRoot) {
21
- logger.info("šŸ” Detected monorepo project");
22
- const packages = await getWorkspacePackages(monorepoRoot);
23
-
24
- return {
25
- type: "monorepo",
26
- rootPath: monorepoRoot,
27
- targetPath: monorepoRoot, // Will be updated when package is selected
28
- packages,
29
- };
30
- }
31
-
32
- logger.info("šŸ” Detected standalone project");
33
- return {
34
- type: "single-repo",
35
- rootPath: startDir,
36
- targetPath: startDir,
37
- };
38
- };
39
-
40
- const findMonorepoRoot = async (startDir: string): Promise<string | null> => {
41
- let currentDir = resolve(startDir);
42
-
43
- while (currentDir !== "/") {
44
- const pkgPath = join(currentDir, "package.json");
45
-
46
- if (existsSync(pkgPath)) {
47
- const pkg = await readPackageJSON(currentDir);
48
-
49
- if (pkg && hasWorkspaces(pkg)) {
50
- return currentDir;
51
- }
52
- }
53
-
54
- const parentDir = resolve(currentDir, "..");
55
- if (parentDir === currentDir) break;
56
- currentDir = parentDir;
57
- }
58
-
59
- return null;
60
- };
61
-
62
- const getWorkspacePackages = async (
63
- monorepoRoot: string,
64
- ): Promise<PackageInfo[]> => {
65
- const rootPkg = await readPackageJSON(monorepoRoot);
66
- if (!rootPkg) {
67
- throw new Error("āŒ Could not read root package.json");
68
- }
69
-
70
- const patterns = getWorkspacePatterns(rootPkg);
71
- if (!patterns.length) {
72
- throw new Error("āŒ No workspace patterns found in package.json");
73
- }
74
-
75
- const packages: PackageInfo[] = [];
76
- const seenPaths = new Set<string>();
77
-
78
- for (const pattern of patterns) {
79
- const glob = new Bun.Glob(pattern);
80
- const matches = glob.scanSync({ cwd: monorepoRoot, onlyFiles: false });
81
-
82
- for (const match of matches) {
83
- const packagePath = resolve(monorepoRoot, match);
84
-
85
- if (seenPaths.has(packagePath)) continue;
86
- seenPaths.add(packagePath);
87
-
88
- const pkgInfo = await resolvePackageInfo(packagePath);
89
- if (pkgInfo) {
90
- packages.push(pkgInfo);
91
- }
92
- }
93
- }
94
-
95
- return packages;
96
- };
97
-
98
- const resolvePackageInfo = async (
99
- packagePath: string,
100
- ): Promise<PackageInfo | null> => {
101
- try {
102
- const packageJsonPath = join(packagePath, "package.json");
103
- if (!existsSync(packageJsonPath)) return null;
104
-
105
- const packageJson = await readPackageJSON(packagePath);
106
- if (!packageJson || !packageJson.name) return null;
107
-
108
- return {
109
- name: packageJson.name,
110
- path: packagePath,
111
- packageJson,
112
- };
113
- } catch {
114
- return null;
115
- }
116
- };
117
-
118
- export const selectTargetPackage = async (
119
- packages: PackageInfo[],
120
- ): Promise<PackageInfo> => {
121
- if (packages.length === 0) {
122
- throw new Error("āŒ No packages found in workspace");
123
- }
124
-
125
- if (packages.length === 1) {
126
- logger.info(`šŸ“¦ Using package: ${packages[0]?.name}`);
127
- return packages[0]!;
128
- }
129
-
130
- logger.info("\nšŸ“¦ Available packages:");
131
- packages.forEach((pkg, index) => {
132
- logger.log(` ${index + 1}. ${pkg.name}`);
133
- });
134
-
135
- while (true) {
136
- const answer = await askQuestion(
137
- `Select target package (1-${packages.length})`,
138
- "1",
139
- );
140
-
141
- const index = parseInt(answer, 10) - 1;
142
- if (index >= 0 && index < packages.length) {
143
- return packages[index]!;
144
- }
145
-
146
- logger.error("āŒ Invalid selection. Please try again.");
147
- }
148
- };