@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.
Files changed (135) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +3 -0
  3. package/dist/cmds/build/cmd.d.ts +2 -0
  4. package/dist/cmds/build/cmd.js +564 -0
  5. package/dist/cmds/clean/cmd.d.ts +2 -0
  6. package/dist/cmds/clean/cmd.js +146 -0
  7. package/dist/cmds/clean/impl.d.ts +2 -0
  8. package/dist/cmds/clean/impl.js +627 -0
  9. package/dist/cmds/clean/presets.d.ts +10 -0
  10. package/dist/cmds/clean/presets.js +112 -0
  11. package/dist/cmds/clean/types.d.ts +62 -0
  12. package/dist/cmds/clean/types.js +0 -0
  13. package/dist/cmds/init/cmd.d.ts +3 -0
  14. package/dist/cmds/init/cmd.js +56 -0
  15. package/dist/cmds/init/impl/config.d.ts +45 -0
  16. package/dist/cmds/init/impl/config.js +99 -0
  17. package/dist/cmds/init/impl/generators.d.ts +6 -0
  18. package/dist/cmds/init/impl/generators.js +178 -0
  19. package/dist/cmds/init/impl/prompts.d.ts +2 -0
  20. package/dist/cmds/init/impl/prompts.js +98 -0
  21. package/dist/cmds/init/impl/types.d.ts +22 -0
  22. package/dist/cmds/init/impl/types.js +0 -0
  23. package/dist/cmds/init/impl/utils.d.ts +4 -0
  24. package/dist/cmds/init/impl/utils.js +11 -0
  25. package/dist/cmds/init/impl/validators.d.ts +4 -0
  26. package/dist/cmds/init/impl/validators.js +42 -0
  27. package/dist/cmds/integrate/cmd.d.ts +3 -0
  28. package/dist/cmds/integrate/cmd.js +70 -0
  29. package/dist/cmds/integrate/impl.d.ts +7 -0
  30. package/dist/cmds/integrate/impl.js +127 -0
  31. package/dist/cmds/integrate/integrations/base.d.ts +13 -0
  32. package/dist/cmds/integrate/integrations/base.js +41 -0
  33. package/dist/cmds/integrate/integrations/nextjs.d.ts +16 -0
  34. package/dist/cmds/integrate/integrations/nextjs.js +167 -0
  35. package/dist/cmds/integrate/integrations/registry.d.ts +7 -0
  36. package/dist/cmds/integrate/integrations/registry.js +31 -0
  37. package/dist/cmds/integrate/integrations/ultracite.d.ts +11 -0
  38. package/dist/cmds/integrate/integrations/ultracite.js +40 -0
  39. package/dist/cmds/integrate/types.d.ts +39 -0
  40. package/dist/cmds/integrate/types.js +0 -0
  41. package/dist/cmds/integrate/utils/biome.d.ts +4 -0
  42. package/dist/cmds/integrate/utils/biome.js +140 -0
  43. package/dist/cmds/integrate/utils/context.d.ts +3 -0
  44. package/dist/cmds/integrate/utils/context.js +111 -0
  45. package/dist/cmds/integrate/utils/temp.d.ts +3 -0
  46. package/dist/cmds/integrate/utils/temp.js +36 -0
  47. package/dist/cmds/perf/analysis/bundle.d.ts +20 -0
  48. package/dist/cmds/perf/analysis/bundle.js +225 -0
  49. package/dist/cmds/perf/analysis/filesystem.d.ts +27 -0
  50. package/dist/cmds/perf/analysis/filesystem.js +246 -0
  51. package/dist/cmds/perf/analysis/monorepo.d.ts +29 -0
  52. package/dist/cmds/perf/analysis/monorepo.js +307 -0
  53. package/dist/cmds/perf/benchmarks/command.d.ts +21 -0
  54. package/dist/cmds/perf/benchmarks/command.js +162 -0
  55. package/dist/cmds/perf/benchmarks/memory.d.ts +41 -0
  56. package/dist/cmds/perf/benchmarks/memory.js +169 -0
  57. package/dist/cmds/perf/benchmarks/runner.d.ts +22 -0
  58. package/dist/cmds/perf/benchmarks/runner.js +157 -0
  59. package/dist/cmds/perf/cmd.d.ts +2 -0
  60. package/dist/cmds/perf/cmd.js +238 -0
  61. package/dist/cmds/perf/impl.d.ts +24 -0
  62. package/dist/cmds/perf/impl.js +304 -0
  63. package/dist/cmds/perf/reporters/console.d.ts +12 -0
  64. package/dist/cmds/perf/reporters/console.js +257 -0
  65. package/dist/cmds/perf/reporters/html.d.ts +27 -0
  66. package/dist/cmds/perf/reporters/html.js +881 -0
  67. package/dist/cmds/perf/reporters/json.d.ts +9 -0
  68. package/dist/cmds/perf/reporters/json.js +32 -0
  69. package/dist/cmds/perf/types.d.ts +184 -0
  70. package/dist/cmds/perf/types.js +0 -0
  71. package/dist/cmds/perf/utils/cache.d.ts +23 -0
  72. package/dist/cmds/perf/utils/cache.js +171 -0
  73. package/dist/cmds/perf/utils/formatter.d.ts +17 -0
  74. package/dist/cmds/perf/utils/formatter.js +134 -0
  75. package/dist/cmds/perf/utils/stats.d.ts +15 -0
  76. package/dist/cmds/perf/utils/stats.js +101 -0
  77. package/dist/cmds/publish/cmd.d.ts +3 -0
  78. package/dist/cmds/publish/cmd.js +189 -0
  79. package/dist/cmds/shell/cmd.d.ts +3 -0
  80. package/dist/cmds/shell/cmd.js +50 -0
  81. package/dist/cmds/tsc/cache.d.ts +27 -0
  82. package/dist/cmds/tsc/cache.js +160 -0
  83. package/dist/cmds/tsc/cmd.d.ts +2 -0
  84. package/dist/cmds/tsc/cmd.js +111 -0
  85. package/dist/cmds/tsc/impl.d.ts +41 -0
  86. package/dist/cmds/tsc/impl.js +572 -0
  87. package/dist/cmds/tsc/types.d.ts +57 -0
  88. package/dist/cmds/tsc/types.js +0 -0
  89. package/package.json +4 -11
  90. package/src/cli.ts +8 -0
  91. package/src/cmds/build/cmd.ts +582 -0
  92. package/src/cmds/clean/cmd.ts +166 -0
  93. package/src/cmds/clean/impl.ts +900 -0
  94. package/src/cmds/clean/presets.ts +158 -0
  95. package/src/cmds/clean/types.ts +71 -0
  96. package/src/cmds/init/cmd.ts +68 -0
  97. package/src/cmds/init/impl/config.ts +105 -0
  98. package/src/cmds/init/impl/generators.ts +220 -0
  99. package/src/cmds/init/impl/prompts.ts +137 -0
  100. package/src/cmds/init/impl/types.ts +25 -0
  101. package/src/cmds/init/impl/utils.ts +17 -0
  102. package/src/cmds/init/impl/validators.ts +55 -0
  103. package/src/cmds/integrate/cmd.ts +82 -0
  104. package/src/cmds/integrate/impl.ts +204 -0
  105. package/src/cmds/integrate/integrations/base.ts +69 -0
  106. package/src/cmds/integrate/integrations/nextjs.ts +227 -0
  107. package/src/cmds/integrate/integrations/registry.ts +45 -0
  108. package/src/cmds/integrate/integrations/ultracite.ts +53 -0
  109. package/src/cmds/integrate/types.ts +48 -0
  110. package/src/cmds/integrate/utils/biome.ts +173 -0
  111. package/src/cmds/integrate/utils/context.ts +148 -0
  112. package/src/cmds/integrate/utils/temp.ts +47 -0
  113. package/src/cmds/perf/analysis/bundle.ts +311 -0
  114. package/src/cmds/perf/analysis/filesystem.ts +324 -0
  115. package/src/cmds/perf/analysis/monorepo.ts +439 -0
  116. package/src/cmds/perf/benchmarks/command.ts +230 -0
  117. package/src/cmds/perf/benchmarks/memory.ts +249 -0
  118. package/src/cmds/perf/benchmarks/runner.ts +220 -0
  119. package/src/cmds/perf/cmd.ts +285 -0
  120. package/src/cmds/perf/impl.ts +411 -0
  121. package/src/cmds/perf/reporters/console.ts +331 -0
  122. package/src/cmds/perf/reporters/html.ts +984 -0
  123. package/src/cmds/perf/reporters/json.ts +42 -0
  124. package/src/cmds/perf/types.ts +220 -0
  125. package/src/cmds/perf/utils/cache.ts +234 -0
  126. package/src/cmds/perf/utils/formatter.ts +190 -0
  127. package/src/cmds/perf/utils/stats.ts +153 -0
  128. package/src/cmds/publish/cmd.ts +215 -0
  129. package/src/cmds/shell/cmd.ts +61 -0
  130. package/src/cmds/tsc/cache.ts +237 -0
  131. package/src/cmds/tsc/cmd.ts +139 -0
  132. package/src/cmds/tsc/impl.ts +855 -0
  133. package/src/cmds/tsc/types.ts +66 -0
  134. package/tsconfig.json +9 -0
  135. package/cli.js +0 -1316
@@ -0,0 +1,158 @@
1
+ // apps/dler/src/cmds/clean/presets.ts
2
+
3
+ import type { PresetCategory } from "./types";
4
+
5
+ export const PRESET_CATEGORIES: Record<string, PresetCategory> = {
6
+ // Build artifacts (default, always included)
7
+ build: {
8
+ name: "build",
9
+ description: "Build artifacts and compiled output",
10
+ patterns: ["dist/", "dev-dist/", "target/"],
11
+ order: 1,
12
+ },
13
+
14
+ // Database
15
+ db: {
16
+ name: "db",
17
+ description: "Database generated files",
18
+ patterns: ["_generated/"],
19
+ order: 2,
20
+ },
21
+
22
+ // CMS
23
+ cms: {
24
+ name: "cms",
25
+ description: "CMS generated files",
26
+ patterns: [".basehub/"],
27
+ order: 3,
28
+ },
29
+
30
+ // Frontend
31
+ frontend: {
32
+ name: "frontend",
33
+ description: "Frontend framework build artifacts",
34
+ patterns: [".next/", ".nuxt/", ".expo/", "routeTree.gen.ts"],
35
+ order: 4,
36
+ },
37
+
38
+ // Documentation
39
+ docs: {
40
+ name: "docs",
41
+ description: "Documentation generated files",
42
+ patterns: [".source/"],
43
+ order: 5,
44
+ },
45
+
46
+ // Email
47
+ email: {
48
+ name: "email",
49
+ description: "Email template generated files",
50
+ patterns: [".react-email/"],
51
+ order: 6,
52
+ },
53
+
54
+ // Build tools
55
+ "build-tools": {
56
+ name: "build-tools",
57
+ description: "Build tool caches and artifacts",
58
+ patterns: [".turbo/", ".vercel/", ".wrangler/"],
59
+ order: 7,
60
+ },
61
+
62
+ // Dependencies (deleted last)
63
+ deps: {
64
+ name: "deps",
65
+ description: "Dependencies and lock files",
66
+ patterns: ["node_modules/"],
67
+ order: 10,
68
+ },
69
+ };
70
+
71
+ export const LOCK_FILE_PATTERNS = [
72
+ "bun.lock",
73
+ "yarn.lock",
74
+ "package-lock.json",
75
+ "pnpm-lock.yaml",
76
+ ];
77
+
78
+ export const parsePresets = (presetsString?: string): string[] => {
79
+ if (!presetsString) {
80
+ return [];
81
+ }
82
+
83
+ if (presetsString === "all") {
84
+ return Object.keys(PRESET_CATEGORIES);
85
+ }
86
+
87
+ return presetsString
88
+ .split(",")
89
+ .map((p) => p.trim())
90
+ .filter((p) => p.length > 0);
91
+ };
92
+
93
+ export const parseCustomPatterns = (customString?: string): string[] => {
94
+ if (!customString) {
95
+ return [];
96
+ }
97
+
98
+ return customString
99
+ .split(",")
100
+ .map((p) => p.trim())
101
+ .filter((p) => p.length > 0);
102
+ };
103
+
104
+ export const getPresetPatterns = (presets: string[]): string[] => {
105
+ const patterns: string[] = [];
106
+
107
+ for (const preset of presets) {
108
+ const category = PRESET_CATEGORIES[preset];
109
+ if (category) {
110
+ patterns.push(...category.patterns);
111
+ }
112
+ }
113
+
114
+ return patterns;
115
+ };
116
+
117
+ export const getPresetOrder = (presets: string[]): number[] =>
118
+ presets
119
+ .map((preset) => PRESET_CATEGORIES[preset]?.order ?? 999)
120
+ .sort((a, b) => a - b);
121
+
122
+ export const getPresetDescription = (presets: string[]): string => {
123
+ const categories = presets
124
+ .map((preset) => PRESET_CATEGORIES[preset])
125
+ .filter(Boolean);
126
+
127
+ if (categories.length === 0) {
128
+ return "No valid presets selected";
129
+ }
130
+
131
+ if (categories.length === 1) {
132
+ return categories[0]!.description;
133
+ }
134
+
135
+ return categories.map((cat) => cat!.name).join(", ");
136
+ };
137
+
138
+ export const mergePatterns = (
139
+ presets: string[],
140
+ customPatterns: string[],
141
+ ): string[] => {
142
+ const presetPatterns = getPresetPatterns(presets);
143
+ const allPatterns = [...presetPatterns, ...customPatterns];
144
+
145
+ // Remove duplicates while preserving order
146
+ return [...new Set(allPatterns)];
147
+ };
148
+
149
+ export const validatePatterns = (
150
+ presets: string[],
151
+ customPatterns: string[],
152
+ ): void => {
153
+ if (presets.length === 0 && customPatterns.length === 0) {
154
+ throw new Error(
155
+ "❌ At least one of --presets or --custom must be provided",
156
+ );
157
+ }
158
+ };
@@ -0,0 +1,71 @@
1
+ // apps/dler/src/cmds/clean/types.ts
2
+
3
+ export interface CleanOptions {
4
+ presets?: string;
5
+ custom?: string;
6
+ ignore?: string | string[];
7
+ cwd?: string;
8
+ subdirs?: boolean;
9
+ dryRun?: boolean;
10
+ force?: boolean;
11
+ verbose?: boolean;
12
+ deleteLockFiles?: boolean;
13
+ replaceExports?: boolean;
14
+ replaceExportsIgnorePackages?: string;
15
+ }
16
+
17
+ export interface FileMatch {
18
+ path: string;
19
+ size: number;
20
+ isDirectory: boolean;
21
+ category: string;
22
+ }
23
+
24
+ export interface CleanResult {
25
+ totalFiles: number;
26
+ totalSize: number;
27
+ deletedFiles: number;
28
+ deletedSize: number;
29
+ errors: CleanError[];
30
+ hasErrors: boolean;
31
+ results: PackageCleanResult[];
32
+ }
33
+
34
+ export interface PackageCleanResult {
35
+ package: PackageInfo;
36
+ files: FileMatch[];
37
+ deletedCount: number;
38
+ deletedSize: number;
39
+ errors: CleanError[];
40
+ }
41
+
42
+ export interface PackageInfo {
43
+ name: string;
44
+ path: string;
45
+ isRoot: boolean;
46
+ }
47
+
48
+ export interface CleanError {
49
+ path: string;
50
+ error: string;
51
+ package?: string;
52
+ }
53
+
54
+ export interface PresetCategory {
55
+ name: string;
56
+ description: string;
57
+ patterns: string[];
58
+ order: number; // Lower numbers are deleted first
59
+ }
60
+
61
+ export interface CleanSummary {
62
+ totalPackages: number;
63
+ processedPackages: number;
64
+ totalFiles: number;
65
+ totalSize: number;
66
+ deletedFiles: number;
67
+ deletedSize: number;
68
+ errors: CleanError[];
69
+ hasErrors: boolean;
70
+ results: PackageCleanResult[];
71
+ }
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import {
4
+ defineCmd,
5
+ defineCmdArgs,
6
+ defineCmdCfg,
7
+ } from "@reliverse/dler-launcher";
8
+ import { logger } from "@reliverse/dler-logger";
9
+ import { finalizePromptIO } from "@reliverse/dler-prompt";
10
+ import { $ } from "bun";
11
+ import {
12
+ generateAllPackages,
13
+ generateRootFiles,
14
+ generateRootPackageJson,
15
+ } from "./impl/generators";
16
+ import { promptMonorepoConfig } from "./impl/prompts";
17
+
18
+ const initCmd = async (): Promise<void> => {
19
+ try {
20
+ const config = await promptMonorepoConfig();
21
+ await finalizePromptIO();
22
+
23
+ logger.info("\n🔨 Generating monorepo structure...\n");
24
+
25
+ await generateRootPackageJson(config);
26
+ await generateRootFiles(config);
27
+ await generateAllPackages(config);
28
+
29
+ logger.info("\n📦 Installing dependencies...\n");
30
+
31
+ await $`bun install`.cwd(config.rootPath);
32
+
33
+ logger.success("\n✅ Monorepo created successfully!");
34
+ logger.success(`\n📁 Location: ${config.rootPath}`);
35
+ logger.success("\nTo get started:");
36
+ logger.log(` cd ${config.rootPath}`);
37
+ logger.log(" bun --filter '*' dev\n");
38
+ } catch (error) {
39
+ logger.error("\n❌ Error creating monorepo:");
40
+
41
+ if (error instanceof Error) {
42
+ logger.error(error.message);
43
+ } else {
44
+ logger.error(String(error));
45
+ }
46
+
47
+ process.exit(1);
48
+ }
49
+ };
50
+
51
+ function getCurrentWorkingDirectory() {
52
+ return process.cwd();
53
+ }
54
+
55
+ const initCmdArgs = defineCmdArgs({
56
+ name: {
57
+ type: "string",
58
+ description: "Current working directory",
59
+ default: getCurrentWorkingDirectory(),
60
+ },
61
+ });
62
+
63
+ const initCmdCfg = defineCmdCfg({
64
+ name: "init",
65
+ description: "Initialize a new monorepo",
66
+ });
67
+
68
+ export default defineCmd(initCmd, initCmdArgs, initCmdCfg);
@@ -0,0 +1,105 @@
1
+ import type { CatalogDependency } from "./types";
2
+
3
+ export const DEFAULT_VERSION = "0.1.0";
4
+ export const DEFAULT_LICENSE = "MIT";
5
+
6
+ export const WORKSPACES = {
7
+ PACKAGES: "packages",
8
+ TSCONFIG: "packages/tsconfig",
9
+ } as const;
10
+
11
+ export const DEFAULT_CATALOG: readonly CatalogDependency[] = [
12
+ { name: "typescript", version: "^5.7.2" },
13
+ { name: "@types/bun", version: "^1.3.0" },
14
+ ] as const;
15
+
16
+ export const TSCONFIG_PRESETS = {
17
+ base: {
18
+ $schema: "https://json.schemastore.org/tsconfig",
19
+ compilerOptions: {
20
+ lib: ["ESNext"],
21
+ target: "ESNext",
22
+ module: "ESNext",
23
+ moduleDetection: "force",
24
+ allowJs: true,
25
+ moduleResolution: "Bundler",
26
+ allowImportingTsExtensions: true,
27
+ verbatimModuleSyntax: true,
28
+ noEmit: true,
29
+ strict: true,
30
+ skipLibCheck: true,
31
+ noFallthroughCasesInSwitch: true,
32
+ noUnusedLocals: false,
33
+ noUnusedParameters: false,
34
+ noPropertyAccessFromIndexSignature: false,
35
+ esModuleInterop: true,
36
+ isolatedModules: true,
37
+ },
38
+ },
39
+ strict: {
40
+ $schema: "https://json.schemastore.org/tsconfig",
41
+ extends: "./base.json",
42
+ compilerOptions: {
43
+ noUncheckedIndexedAccess: true,
44
+ noUnusedLocals: true,
45
+ noUnusedParameters: true,
46
+ },
47
+ },
48
+ } as const;
49
+
50
+ export const ROOT_FILES = {
51
+ GITIGNORE: `# Dependencies
52
+ node_modules/
53
+
54
+ # Build outputs
55
+ dist/
56
+ out/
57
+ *.tsbuildinfo
58
+
59
+ # Environment
60
+ .env
61
+ .env*.local
62
+
63
+ # IDE
64
+ .vscode/
65
+ .idea/
66
+ *.swp
67
+ *.swo
68
+ *~
69
+
70
+ # OS
71
+ .DS_Store
72
+ Thumbs.db
73
+
74
+ # Logs
75
+ *.log
76
+ `,
77
+ README: (name: string) => `# ${name}
78
+
79
+ A Bun monorepo created with the monorepo bootstrapper.
80
+
81
+ ## Getting Started
82
+
83
+ \`\`\`bash
84
+ bun install
85
+ \`\`\`
86
+
87
+ ## Workspaces
88
+
89
+ This monorepo was generated by dler init. It uses bun workspaces to manage multiple packages.
90
+
91
+ ## Scripts
92
+
93
+ Run scripts across all workspaces:
94
+
95
+ \`\`\`bash
96
+ bun --filter '*' <script>
97
+ \`\`\`
98
+
99
+ Run scripts for specific packages:
100
+
101
+ \`\`\`bash
102
+ bun --filter <package-name> <script>
103
+ \`\`\`
104
+ `,
105
+ } as const;
@@ -0,0 +1,220 @@
1
+ import { writeJsonFile, writeTextFile } from "@reliverse/dler-helpers";
2
+ import { logger } from "@reliverse/dler-logger";
3
+ import {
4
+ DEFAULT_CATALOG,
5
+ ROOT_FILES,
6
+ TSCONFIG_PRESETS,
7
+ WORKSPACES,
8
+ } from "./config";
9
+ import type { MonorepoConfig, PackageInfo } from "./types";
10
+ import {
11
+ createFullPath,
12
+ ensureDir,
13
+ fileExists,
14
+ getWorkspaceScope,
15
+ } from "./utils";
16
+
17
+ export const generateRootPackageJson = async (
18
+ config: MonorepoConfig,
19
+ ): Promise<void> => {
20
+ const packageJsonPath = createFullPath(config.rootPath, "package.json");
21
+ const alreadyExists = await fileExists(packageJsonPath);
22
+
23
+ if (alreadyExists) {
24
+ logger.info("📝 Updating existing root package.json...");
25
+ const existingContent = await Bun.file(packageJsonPath).json();
26
+
27
+ const workspaces = new Set<string>([
28
+ ...(existingContent.workspaces?.packages || []),
29
+ ...getWorkspacePatterns(config),
30
+ ]);
31
+
32
+ const catalog = {
33
+ ...(existingContent.workspaces?.catalog || {}),
34
+ ...Object.fromEntries(
35
+ DEFAULT_CATALOG.map((dep) => [dep.name, dep.version]),
36
+ ),
37
+ };
38
+
39
+ const updatedPackageJson = {
40
+ ...existingContent,
41
+ // Persist core metadata from current config (overwrite with user's latest answers)
42
+ name: config.name,
43
+ version: config.version,
44
+ description: config.description,
45
+ ...(config.author && { author: config.author }),
46
+ ...(config.license && { license: config.license }),
47
+ workspaces: {
48
+ ...existingContent.workspaces,
49
+ packages: Array.from(workspaces).sort(),
50
+ catalog,
51
+ },
52
+ };
53
+
54
+ await writeJsonFile(packageJsonPath, updatedPackageJson);
55
+ } else {
56
+ logger.info("📝 Creating root package.json...");
57
+ const packageJson = {
58
+ name: config.name,
59
+ version: config.version,
60
+ description: config.description,
61
+ private: true,
62
+ workspaces: {
63
+ packages: getWorkspacePatterns(config),
64
+ catalog: Object.fromEntries(
65
+ DEFAULT_CATALOG.map((dep) => [dep.name, dep.version]),
66
+ ),
67
+ },
68
+ scripts: {
69
+ check: "bun typecheck && bun lint && bun format",
70
+ typecheck: "tsc --noEmit",
71
+ lint: "biome check .",
72
+ "lint:fix": "biome check --write .",
73
+ format: "biome format --write .",
74
+ },
75
+ devDependencies: {
76
+ "@biomejs/biome": "catalog:",
77
+ typescript: "catalog:",
78
+ "@types/bun": "catalog:",
79
+ },
80
+ ...(config.author && { author: config.author }),
81
+ ...(config.license && { license: config.license }),
82
+ };
83
+
84
+ await writeJsonFile(packageJsonPath, packageJson);
85
+ }
86
+ };
87
+
88
+ const getWorkspacePatterns = (config: MonorepoConfig): string[] => {
89
+ const patterns = new Set<string>();
90
+
91
+ for (const pkg of config.packages) {
92
+ patterns.add(`${pkg.workspace}/*`);
93
+ }
94
+
95
+ return Array.from(patterns).sort();
96
+ };
97
+
98
+ export const generateRootFiles = async (
99
+ config: MonorepoConfig,
100
+ ): Promise<void> => {
101
+ logger.info("📄 Creating root files...");
102
+
103
+ const gitignorePath = createFullPath(config.rootPath, ".gitignore");
104
+ if (!(await fileExists(gitignorePath))) {
105
+ await writeTextFile(gitignorePath, ROOT_FILES.GITIGNORE);
106
+ }
107
+
108
+ const readmePath = createFullPath(config.rootPath, "README.md");
109
+ if (!(await fileExists(readmePath))) {
110
+ await writeTextFile(readmePath, ROOT_FILES.README(config.name));
111
+ }
112
+ };
113
+
114
+ export const generateTsconfigPackage = async (
115
+ config: MonorepoConfig,
116
+ ): Promise<void> => {
117
+ logger.info("📦 Creating tsconfig package...");
118
+
119
+ const tsconfigPath = createFullPath(config.rootPath, WORKSPACES.TSCONFIG);
120
+ await ensureDir(tsconfigPath);
121
+
122
+ const packageJsonPath = createFullPath(tsconfigPath, "package.json");
123
+ if (!(await fileExists(packageJsonPath))) {
124
+ const scope = getWorkspaceScope(WORKSPACES.PACKAGES);
125
+ const packageJson = {
126
+ name: `${scope}tsconfig`,
127
+ version: "0.0.0",
128
+ private: true,
129
+ description: "Shared TypeScript configuration",
130
+ };
131
+
132
+ await writeJsonFile(packageJsonPath, packageJson);
133
+ }
134
+
135
+ for (const [name, content] of Object.entries(TSCONFIG_PRESETS)) {
136
+ const presetPath = createFullPath(tsconfigPath, `${name}.json`);
137
+ if (!(await fileExists(presetPath))) {
138
+ await writeJsonFile(presetPath, content);
139
+ }
140
+ }
141
+ };
142
+
143
+ export const generatePackage = async (
144
+ config: MonorepoConfig,
145
+ pkg: PackageInfo,
146
+ ): Promise<void> => {
147
+ const packagePath = createFullPath(config.rootPath, pkg.workspace, pkg.name);
148
+
149
+ logger.info(`📦 Creating package ${pkg.scope}${pkg.name}...`);
150
+
151
+ await ensureDir(packagePath);
152
+
153
+ const packageJsonPath = createFullPath(packagePath, "package.json");
154
+ if (!(await fileExists(packageJsonPath))) {
155
+ const tsconfigScope = getWorkspaceScope(WORKSPACES.PACKAGES);
156
+ const packageJson = {
157
+ name: `${pkg.scope}${pkg.name}`,
158
+ version: "0.1.0",
159
+ private: true,
160
+ type: "module",
161
+ exports: {
162
+ ".": {
163
+ types: "./src/mod.ts",
164
+ default: "./src/mod.ts",
165
+ },
166
+ },
167
+ scripts: {
168
+ dev: "bun src/mod.ts",
169
+ },
170
+ devDependencies: {
171
+ [`${tsconfigScope}tsconfig`]: "workspace:*",
172
+ typescript: "catalog:",
173
+ "@types/bun": "catalog:",
174
+ },
175
+ };
176
+
177
+ await writeJsonFile(packageJsonPath, packageJson);
178
+ }
179
+
180
+ const tsconfigPath = createFullPath(packagePath, "tsconfig.json");
181
+ if (!(await fileExists(tsconfigPath))) {
182
+ const tsconfigScope = getWorkspaceScope(WORKSPACES.PACKAGES);
183
+ const tsconfig = {
184
+ extends: `${tsconfigScope}tsconfig/strict.json`,
185
+ compilerOptions: {
186
+ rootDir: ".",
187
+ outDir: "./dist",
188
+ },
189
+ include: ["src/**/*"],
190
+ exclude: ["node_modules", "dist"],
191
+ };
192
+
193
+ await writeJsonFile(tsconfigPath, tsconfig);
194
+ }
195
+
196
+ const srcPath = createFullPath(packagePath, "src");
197
+ await ensureDir(srcPath);
198
+
199
+ const indexPath = createFullPath(srcPath, "index.ts");
200
+ if (!(await fileExists(indexPath))) {
201
+ const indexContent = `export const hello = (): string => {
202
+ return "Hello from ${pkg.scope}${pkg.name}!";
203
+ };
204
+
205
+ console.log(hello());
206
+ `;
207
+
208
+ await writeTextFile(indexPath, indexContent);
209
+ }
210
+ };
211
+
212
+ export const generateAllPackages = async (
213
+ config: MonorepoConfig,
214
+ ): Promise<void> => {
215
+ await generateTsconfigPackage(config);
216
+
217
+ for (const pkg of config.packages) {
218
+ await generatePackage(config, pkg);
219
+ }
220
+ };