@reliverse/dler 2.0.0 ā 2.0.1
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/cli.d.ts +2 -0
- package/dist/cli.js +3 -0
- package/dist/cmds/build/cmd.d.ts +2 -0
- package/dist/cmds/build/cmd.js +564 -0
- package/dist/cmds/clean/cmd.d.ts +2 -0
- package/dist/cmds/clean/cmd.js +146 -0
- package/dist/cmds/clean/impl.d.ts +2 -0
- package/dist/cmds/clean/impl.js +627 -0
- package/dist/cmds/clean/presets.d.ts +10 -0
- package/dist/cmds/clean/presets.js +112 -0
- package/dist/cmds/clean/types.d.ts +62 -0
- package/dist/cmds/clean/types.js +0 -0
- package/dist/cmds/init/cmd.d.ts +3 -0
- package/dist/cmds/init/cmd.js +56 -0
- package/dist/cmds/init/impl/config.d.ts +45 -0
- package/dist/cmds/init/impl/config.js +99 -0
- package/dist/cmds/init/impl/generators.d.ts +6 -0
- package/dist/cmds/init/impl/generators.js +178 -0
- package/dist/cmds/init/impl/prompts.d.ts +2 -0
- package/dist/cmds/init/impl/prompts.js +98 -0
- package/dist/cmds/init/impl/types.d.ts +22 -0
- package/dist/cmds/init/impl/types.js +0 -0
- package/dist/cmds/init/impl/utils.d.ts +4 -0
- package/dist/cmds/init/impl/utils.js +11 -0
- package/dist/cmds/init/impl/validators.d.ts +4 -0
- package/dist/cmds/init/impl/validators.js +42 -0
- package/dist/cmds/integrate/cmd.d.ts +3 -0
- package/dist/cmds/integrate/cmd.js +70 -0
- package/dist/cmds/integrate/impl.d.ts +7 -0
- package/dist/cmds/integrate/impl.js +127 -0
- package/dist/cmds/integrate/integrations/base.d.ts +13 -0
- package/dist/cmds/integrate/integrations/base.js +41 -0
- package/dist/cmds/integrate/integrations/nextjs.d.ts +16 -0
- package/dist/cmds/integrate/integrations/nextjs.js +167 -0
- package/dist/cmds/integrate/integrations/registry.d.ts +7 -0
- package/dist/cmds/integrate/integrations/registry.js +31 -0
- package/dist/cmds/integrate/integrations/ultracite.d.ts +11 -0
- package/dist/cmds/integrate/integrations/ultracite.js +40 -0
- package/dist/cmds/integrate/types.d.ts +39 -0
- package/dist/cmds/integrate/types.js +0 -0
- package/dist/cmds/integrate/utils/biome.d.ts +4 -0
- package/dist/cmds/integrate/utils/biome.js +140 -0
- package/dist/cmds/integrate/utils/context.d.ts +3 -0
- package/dist/cmds/integrate/utils/context.js +111 -0
- package/dist/cmds/integrate/utils/temp.d.ts +3 -0
- package/dist/cmds/integrate/utils/temp.js +36 -0
- package/dist/cmds/perf/analysis/bundle.d.ts +20 -0
- package/dist/cmds/perf/analysis/bundle.js +225 -0
- package/dist/cmds/perf/analysis/filesystem.d.ts +27 -0
- package/dist/cmds/perf/analysis/filesystem.js +246 -0
- package/dist/cmds/perf/analysis/monorepo.d.ts +29 -0
- package/dist/cmds/perf/analysis/monorepo.js +307 -0
- package/dist/cmds/perf/benchmarks/command.d.ts +21 -0
- package/dist/cmds/perf/benchmarks/command.js +162 -0
- package/dist/cmds/perf/benchmarks/memory.d.ts +41 -0
- package/dist/cmds/perf/benchmarks/memory.js +169 -0
- package/dist/cmds/perf/benchmarks/runner.d.ts +22 -0
- package/dist/cmds/perf/benchmarks/runner.js +157 -0
- package/dist/cmds/perf/cmd.d.ts +2 -0
- package/dist/cmds/perf/cmd.js +238 -0
- package/dist/cmds/perf/impl.d.ts +24 -0
- package/dist/cmds/perf/impl.js +304 -0
- package/dist/cmds/perf/reporters/console.d.ts +12 -0
- package/dist/cmds/perf/reporters/console.js +257 -0
- package/dist/cmds/perf/reporters/html.d.ts +27 -0
- package/dist/cmds/perf/reporters/html.js +881 -0
- package/dist/cmds/perf/reporters/json.d.ts +9 -0
- package/dist/cmds/perf/reporters/json.js +32 -0
- package/dist/cmds/perf/types.d.ts +184 -0
- package/dist/cmds/perf/types.js +0 -0
- package/dist/cmds/perf/utils/cache.d.ts +23 -0
- package/dist/cmds/perf/utils/cache.js +171 -0
- package/dist/cmds/perf/utils/formatter.d.ts +17 -0
- package/dist/cmds/perf/utils/formatter.js +134 -0
- package/dist/cmds/perf/utils/stats.d.ts +15 -0
- package/dist/cmds/perf/utils/stats.js +101 -0
- package/dist/cmds/publish/cmd.d.ts +3 -0
- package/dist/cmds/publish/cmd.js +189 -0
- package/dist/cmds/shell/cmd.d.ts +3 -0
- package/dist/cmds/shell/cmd.js +50 -0
- package/dist/cmds/tsc/cache.d.ts +27 -0
- package/dist/cmds/tsc/cache.js +160 -0
- package/dist/cmds/tsc/cmd.d.ts +2 -0
- package/dist/cmds/tsc/cmd.js +111 -0
- package/dist/cmds/tsc/impl.d.ts +41 -0
- package/dist/cmds/tsc/impl.js +572 -0
- package/dist/cmds/tsc/types.d.ts +57 -0
- package/dist/cmds/tsc/types.js +0 -0
- package/package.json +4 -11
- package/src/cli.ts +8 -0
- package/src/cmds/build/cmd.ts +582 -0
- package/src/cmds/clean/cmd.ts +166 -0
- package/src/cmds/clean/impl.ts +900 -0
- package/src/cmds/clean/presets.ts +158 -0
- package/src/cmds/clean/types.ts +71 -0
- package/src/cmds/init/cmd.ts +68 -0
- package/src/cmds/init/impl/config.ts +105 -0
- package/src/cmds/init/impl/generators.ts +220 -0
- package/src/cmds/init/impl/prompts.ts +137 -0
- package/src/cmds/init/impl/types.ts +25 -0
- package/src/cmds/init/impl/utils.ts +17 -0
- package/src/cmds/init/impl/validators.ts +55 -0
- package/src/cmds/integrate/cmd.ts +82 -0
- package/src/cmds/integrate/impl.ts +204 -0
- package/src/cmds/integrate/integrations/base.ts +69 -0
- package/src/cmds/integrate/integrations/nextjs.ts +227 -0
- package/src/cmds/integrate/integrations/registry.ts +45 -0
- package/src/cmds/integrate/integrations/ultracite.ts +53 -0
- package/src/cmds/integrate/types.ts +48 -0
- package/src/cmds/integrate/utils/biome.ts +173 -0
- package/src/cmds/integrate/utils/context.ts +148 -0
- package/src/cmds/integrate/utils/temp.ts +47 -0
- package/src/cmds/perf/analysis/bundle.ts +311 -0
- package/src/cmds/perf/analysis/filesystem.ts +324 -0
- package/src/cmds/perf/analysis/monorepo.ts +439 -0
- package/src/cmds/perf/benchmarks/command.ts +230 -0
- package/src/cmds/perf/benchmarks/memory.ts +249 -0
- package/src/cmds/perf/benchmarks/runner.ts +220 -0
- package/src/cmds/perf/cmd.ts +285 -0
- package/src/cmds/perf/impl.ts +411 -0
- package/src/cmds/perf/reporters/console.ts +331 -0
- package/src/cmds/perf/reporters/html.ts +984 -0
- package/src/cmds/perf/reporters/json.ts +42 -0
- package/src/cmds/perf/types.ts +220 -0
- package/src/cmds/perf/utils/cache.ts +234 -0
- package/src/cmds/perf/utils/formatter.ts +190 -0
- package/src/cmds/perf/utils/stats.ts +153 -0
- package/src/cmds/publish/cmd.ts +215 -0
- package/src/cmds/shell/cmd.ts +61 -0
- package/src/cmds/tsc/cache.ts +237 -0
- package/src/cmds/tsc/cmd.ts +139 -0
- package/src/cmds/tsc/impl.ts +855 -0
- package/src/cmds/tsc/types.ts +66 -0
- package/tsconfig.json +9 -0
- package/cli.js +0 -1316
|
@@ -0,0 +1,227 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
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
|
+
};
|