alchemy 0.2.5 → 0.3.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 (197) hide show
  1. package/README.md +3 -3
  2. package/lib/ai/approve.d.ts +99 -0
  3. package/lib/ai/approve.js +76 -0
  4. package/lib/ai/astro-file.d.ts +137 -0
  5. package/lib/ai/astro-file.js +156 -0
  6. package/lib/ai/client.d.ts +7 -8
  7. package/lib/ai/client.js +48 -19
  8. package/lib/ai/css-file.d.ts +131 -0
  9. package/lib/ai/css-file.js +141 -0
  10. package/lib/ai/data.d.ts +51 -6
  11. package/lib/ai/data.js +58 -12
  12. package/lib/ai/document.d.ts +108 -24
  13. package/lib/ai/document.js +166 -52
  14. package/lib/ai/html-file.d.ts +128 -0
  15. package/lib/ai/html-file.js +138 -0
  16. package/lib/ai/index.d.ts +9 -0
  17. package/lib/ai/index.js +9 -0
  18. package/lib/ai/json-file.d.ts +160 -0
  19. package/lib/ai/json-file.js +187 -0
  20. package/lib/ai/review.d.ts +122 -0
  21. package/lib/ai/review.js +101 -0
  22. package/lib/ai/typescript-file.d.ts +139 -0
  23. package/lib/ai/typescript-file.js +145 -0
  24. package/lib/ai/vue-file.d.ts +126 -0
  25. package/lib/ai/vue-file.js +136 -0
  26. package/lib/ai/yaml-file.d.ts +169 -0
  27. package/lib/ai/yaml-file.js +200 -0
  28. package/lib/alchemy.js +17 -2
  29. package/lib/apply.js +1 -1
  30. package/lib/cloudflare/dns.d.ts +88 -0
  31. package/lib/cloudflare/dns.js +192 -0
  32. package/lib/cloudflare/generate-asset-manifest.js +1 -1
  33. package/lib/cloudflare/index.d.ts +2 -1
  34. package/lib/cloudflare/index.js +2 -1
  35. package/lib/cloudflare/r2-rest-state-store.d.ts +125 -0
  36. package/lib/cloudflare/r2-rest-state-store.js +254 -0
  37. package/lib/cloudflare/response.d.ts +12 -0
  38. package/lib/cloudflare/response.js +0 -0
  39. package/lib/cloudflare/static-site-router.js +16 -7
  40. package/lib/cloudflare/static-site.js +3 -0
  41. package/lib/cloudflare/upload-asset-manifest.js +4 -2
  42. package/lib/cloudflare/zone.d.ts +18 -0
  43. package/lib/cloudflare/zone.js +17 -4
  44. package/lib/dns/godaddy.d.ts +7 -0
  45. package/lib/dns/godaddy.js +21 -0
  46. package/lib/dns/import-dns.d.ts +82 -0
  47. package/lib/dns/import-dns.js +114 -0
  48. package/lib/dns/index.d.ts +2 -0
  49. package/lib/dns/index.js +2 -0
  50. package/lib/dns/record.d.ts +88 -0
  51. package/lib/dns/record.js +13 -0
  52. package/lib/fs/copy-file.d.ts +54 -0
  53. package/lib/fs/copy-file.js +63 -0
  54. package/lib/fs/file-system-state-store.d.ts +17 -0
  55. package/lib/fs/file-system-state-store.js +87 -0
  56. package/lib/fs/file.d.ts +13 -0
  57. package/lib/fs/file.js +24 -5
  58. package/lib/fs/folder.d.ts +10 -0
  59. package/lib/fs/folder.js +2 -2
  60. package/lib/fs/index.d.ts +10 -4
  61. package/lib/fs/index.js +10 -4
  62. package/lib/fs/static-astro-file.d.ts +34 -0
  63. package/lib/fs/static-astro-file.js +39 -0
  64. package/lib/fs/static-css-file.d.ts +24 -0
  65. package/lib/fs/static-css-file.js +29 -0
  66. package/lib/fs/static-html-file.d.ts +31 -0
  67. package/lib/fs/static-html-file.js +36 -0
  68. package/lib/fs/{json-file.d.ts → static-json-file.d.ts} +3 -3
  69. package/lib/fs/static-json-file.js +15 -0
  70. package/lib/fs/{text-file.d.ts → static-text-file.d.ts} +2 -2
  71. package/lib/fs/static-text-file.js +8 -0
  72. package/lib/fs/{typescript-file.d.ts → static-typescript-file.d.ts} +3 -3
  73. package/lib/fs/{typescript-file.js → static-typescript-file.js} +3 -2
  74. package/lib/fs/static-vue-file.d.ts +28 -0
  75. package/lib/fs/static-vue-file.js +33 -0
  76. package/lib/fs/static-yaml-file.d.ts +22 -0
  77. package/lib/fs/{yaml-file.js → static-yaml-file.js} +3 -2
  78. package/lib/internal/getting-started.d.ts +21 -0
  79. package/lib/internal/getting-started.js +87 -0
  80. package/lib/internal/index.d.ts +3 -0
  81. package/lib/internal/index.js +3 -0
  82. package/lib/internal/providers.d.ts +27 -0
  83. package/lib/internal/providers.js +172 -0
  84. package/lib/internal/tutorial.d.ts +104 -0
  85. package/lib/internal/tutorial.js +251 -0
  86. package/lib/resource.js +8 -1
  87. package/lib/scope.d.ts +1 -1
  88. package/lib/scope.js +4 -2
  89. package/lib/state.d.ts +1 -16
  90. package/lib/state.js +0 -87
  91. package/lib/test/bun.d.ts +11 -0
  92. package/lib/test/bun.js +36 -8
  93. package/lib/web/astro.d.ts +147 -0
  94. package/lib/web/astro.js +414 -0
  95. package/lib/{shadcn/component.js → web/shadcn-component.js} +2 -9
  96. package/lib/web/shadcn.d.ts +97 -0
  97. package/lib/web/shadcn.js +99 -0
  98. package/lib/web/tailwind.d.ts +64 -0
  99. package/lib/web/tailwind.js +97 -0
  100. package/lib/{vite → web}/vite.d.ts +5 -0
  101. package/lib/{vite → web}/vite.js +44 -44
  102. package/lib/web/vitepress/config.d.ts +10 -0
  103. package/lib/web/vitepress/config.js +31 -0
  104. package/lib/web/vitepress/custom-theme.d.ts +173 -0
  105. package/lib/web/vitepress/custom-theme.js +336 -0
  106. package/lib/{vitepress → web/vitepress}/dependencies.d.ts +2 -2
  107. package/lib/{vitepress → web/vitepress}/dependencies.js +1 -1
  108. package/lib/web/vitepress/home-page.d.ts +246 -0
  109. package/lib/web/vitepress/home-page.js +147 -0
  110. package/lib/{vitepress → web/vitepress}/index.d.ts +2 -0
  111. package/lib/{vitepress → web/vitepress}/index.js +2 -0
  112. package/lib/{vitepress → web/vitepress}/vitepress.d.ts +15 -12
  113. package/lib/{vitepress → web/vitepress}/vitepress.js +26 -44
  114. package/package.json +6 -2
  115. package/src/ai/approve.ts +163 -0
  116. package/src/ai/astro-file.ts +269 -0
  117. package/src/ai/client.ts +60 -21
  118. package/src/ai/css-file.ts +247 -0
  119. package/src/ai/data.ts +81 -19
  120. package/src/ai/document.ts +240 -62
  121. package/src/ai/html-file.ts +244 -0
  122. package/src/ai/index.ts +9 -0
  123. package/src/ai/json-file.ts +325 -0
  124. package/src/ai/review.ts +213 -0
  125. package/src/ai/typescript-file.ts +259 -0
  126. package/src/ai/vue-file.ts +242 -0
  127. package/src/ai/yaml-file.ts +328 -0
  128. package/src/alchemy.ts +18 -7
  129. package/src/apply.ts +8 -9
  130. package/src/cloudflare/dns.ts +344 -0
  131. package/src/cloudflare/generate-asset-manifest.ts +4 -4
  132. package/src/cloudflare/index.ts +2 -1
  133. package/src/cloudflare/r2-rest-state-store.ts +353 -0
  134. package/src/cloudflare/response.ts +9 -0
  135. package/src/cloudflare/static-site-router.ts +18 -8
  136. package/src/cloudflare/static-site.ts +11 -7
  137. package/src/cloudflare/upload-asset-manifest.ts +6 -4
  138. package/src/cloudflare/worker.ts +44 -43
  139. package/src/cloudflare/zone.ts +39 -23
  140. package/src/dns/godaddy.ts +29 -0
  141. package/src/dns/import-dns.ts +213 -0
  142. package/src/dns/index.ts +2 -0
  143. package/src/dns/record.ts +121 -0
  144. package/src/fs/copy-file.ts +115 -0
  145. package/src/fs/file-system-state-store.ts +109 -0
  146. package/src/fs/file.ts +35 -9
  147. package/src/fs/folder.ts +14 -2
  148. package/src/fs/index.ts +10 -4
  149. package/src/fs/static-astro-file.ts +45 -0
  150. package/src/fs/static-css-file.ts +35 -0
  151. package/src/fs/static-html-file.ts +42 -0
  152. package/src/fs/static-json-file.ts +34 -0
  153. package/src/fs/{text-file.ts → static-text-file.ts} +9 -3
  154. package/src/fs/{typescript-file.ts → static-typescript-file.ts} +7 -6
  155. package/src/fs/static-vue-file.ts +39 -0
  156. package/src/fs/static-yaml-file.ts +33 -0
  157. package/src/internal/getting-started.ts +115 -0
  158. package/src/internal/index.ts +3 -0
  159. package/src/internal/providers.ts +241 -0
  160. package/src/internal/tutorial.ts +392 -0
  161. package/src/resource.ts +10 -1
  162. package/src/scope.ts +5 -6
  163. package/src/state.ts +1 -111
  164. package/src/test/bun.ts +60 -10
  165. package/src/web/astro.ts +644 -0
  166. package/src/{shadcn/component.ts → web/shadcn-component.ts} +5 -13
  167. package/src/web/shadcn.ts +219 -0
  168. package/src/web/tailwind.ts +167 -0
  169. package/src/{vite → web}/vite.ts +54 -56
  170. package/src/web/vitepress/config.ts +48 -0
  171. package/src/web/vitepress/custom-theme.ts +514 -0
  172. package/src/{vitepress → web/vitepress}/dependencies.ts +2 -2
  173. package/src/web/vitepress/home-page.ts +375 -0
  174. package/src/{vitepress → web/vitepress}/index.ts +2 -0
  175. package/src/{vitepress → web/vitepress}/vitepress.ts +62 -72
  176. package/lib/cloudflare/state.d.ts +0 -82
  177. package/lib/cloudflare/state.js +0 -108
  178. package/lib/fs/json-file.js +0 -7
  179. package/lib/fs/text-file.js +0 -7
  180. package/lib/fs/yaml-file.d.ts +0 -19
  181. package/lib/internal/docs.d.ts +0 -5
  182. package/lib/internal/docs.js +0 -287
  183. package/lib/shadcn/index.d.ts +0 -1
  184. package/lib/shadcn/index.js +0 -1
  185. package/lib/vite/index.d.ts +0 -1
  186. package/lib/vite/index.js +0 -1
  187. package/lib/vitepress/home-page.d.ts +0 -133
  188. package/lib/vitepress/home-page.js +0 -11
  189. package/src/cloudflare/state.ts +0 -138
  190. package/src/fs/json-file.ts +0 -23
  191. package/src/fs/yaml-file.ts +0 -26
  192. package/src/internal/docs.ts +0 -338
  193. package/src/shadcn/index.ts +0 -1
  194. package/src/vite/index.ts +0 -1
  195. package/src/vitepress/home-page.ts +0 -166
  196. /package/lib/{shadcn/component.d.ts → web/shadcn-component.d.ts} +0 -0
  197. /package/src/{vitepress → web/vitepress}/index.md +0 -0
@@ -0,0 +1,97 @@
1
+ import type { Context } from "../context";
2
+ import { Folder } from "../fs";
3
+ import { Resource } from "../resource";
4
+ /**
5
+ * Properties for initializing Shadcn UI
6
+ */
7
+ export interface ShadcnUIProps {
8
+ /**
9
+ * The working directory where Shadcn UI should be installed
10
+ */
11
+ cwd: string;
12
+ /**
13
+ * The base color to use
14
+ * @default "neutral"
15
+ */
16
+ baseColor?: "neutral" | "gray" | "zinc" | "stone" | "slate";
17
+ /**
18
+ * Use default configuration
19
+ * @default false
20
+ */
21
+ defaults?: boolean;
22
+ /**
23
+ * Force overwrite of existing configuration
24
+ * @default false
25
+ */
26
+ force?: boolean;
27
+ /**
28
+ * Mute output
29
+ * @default false
30
+ */
31
+ silent?: boolean;
32
+ /**
33
+ * Use the src directory when creating a new project
34
+ * @default true
35
+ */
36
+ srcDir?: boolean;
37
+ /**
38
+ * Use css variables for theming
39
+ * @default true
40
+ */
41
+ cssVariables?: boolean;
42
+ /**
43
+ * The components to add
44
+ */
45
+ components?: string[];
46
+ /**
47
+ * Whether tailwind is already installed and configured.
48
+ * Shadcn UI requires Tailwind CSS to be installed and configured.
49
+ * @default false
50
+ */
51
+ tailwind?: boolean;
52
+ /**
53
+ * Whether react is already installed
54
+ * @default false
55
+ */
56
+ react?: boolean;
57
+ }
58
+ /**
59
+ * Shadcn UI resource
60
+ */
61
+ export interface ShadcnUI extends ShadcnUIProps, Resource<"project::ShadcnUI"> {
62
+ /**
63
+ * The working directory where Shadcn UI is installed
64
+ */
65
+ cwd: string;
66
+ /**
67
+ * The ui directory
68
+ */
69
+ ui: Folder;
70
+ /**
71
+ * The lib directory
72
+ */
73
+ lib: Folder;
74
+ }
75
+ /**
76
+ * Initializes Shadcn UI in a project directory
77
+ *
78
+ * @example
79
+ * // Initialize Shadcn UI with default settings
80
+ * const shadcn = await ShadcnUI("my-shadcn", {
81
+ * cwd: "my-project",
82
+ * tailwind: true, // Tailwind must be installed separately
83
+ * react: true // React must be installed separately
84
+ * });
85
+ *
86
+ * @example
87
+ * // Initialize Shadcn UI with custom settings and components
88
+ * const shadcn = await ShadcnUI("custom-shadcn", {
89
+ * cwd: "my-project",
90
+ * baseColor: "zinc",
91
+ * force: true,
92
+ * components: ["button", "card", "input"],
93
+ * tailwind: true, // Tailwind must be installed separately
94
+ * react: true // React must be installed separately
95
+ * });
96
+ */
97
+ export declare const ShadcnUI: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<ShadcnUI>, id: string, props: ShadcnUIProps) => Promise<ShadcnUI>);
@@ -0,0 +1,99 @@
1
+ import { exec } from "child_process";
2
+ import path from "path";
3
+ import { promisify } from "util";
4
+ import { Folder, StaticJsonFile } from "../fs";
5
+ import { StaticTypeScriptFile } from "../fs/static-typescript-file";
6
+ import { Resource } from "../resource";
7
+ import { ShadcnComponent } from "./shadcn-component";
8
+ const execAsync = promisify(exec);
9
+ /**
10
+ * Initializes Shadcn UI in a project directory
11
+ *
12
+ * @example
13
+ * // Initialize Shadcn UI with default settings
14
+ * const shadcn = await ShadcnUI("my-shadcn", {
15
+ * cwd: "my-project",
16
+ * tailwind: true, // Tailwind must be installed separately
17
+ * react: true // React must be installed separately
18
+ * });
19
+ *
20
+ * @example
21
+ * // Initialize Shadcn UI with custom settings and components
22
+ * const shadcn = await ShadcnUI("custom-shadcn", {
23
+ * cwd: "my-project",
24
+ * baseColor: "zinc",
25
+ * force: true,
26
+ * components: ["button", "card", "input"],
27
+ * tailwind: true, // Tailwind must be installed separately
28
+ * react: true // React must be installed separately
29
+ * });
30
+ */
31
+ export const ShadcnUI = Resource("project::ShadcnUI", async function (id, props) {
32
+ if (this.phase === "delete") {
33
+ // For a delete phase, we don't perform any action
34
+ // as removing Shadcn UI would require removing many files
35
+ // which could be destructive to the project
36
+ console.log("Note: ShadcnUI delete phase does not remove installed components");
37
+ return this.destroy();
38
+ }
39
+ // Setup execAsync with the correct cwd
40
+ const exec = (command) => execAsync(command, { cwd: props.cwd });
41
+ // Ensure React is installed if not already
42
+ if (!props.react) {
43
+ await exec(`bun add react react-dom`);
44
+ }
45
+ // Install shadcn dependencies
46
+ await exec(`bun add -D @types/node`);
47
+ // Create components.json directly instead of running shadcn init
48
+ await StaticJsonFile(path.join(props.cwd, "components.json"), {
49
+ $schema: "https://ui.shadcn.com/schema.json",
50
+ style: props.cssVariables !== false ? "default" : "new-york",
51
+ tsx: true,
52
+ rsc: false,
53
+ tailwind: {
54
+ config: "tailwind.config.js",
55
+ css: props.srcDir !== false
56
+ ? "src/styles/globals.css"
57
+ : "styles/globals.css",
58
+ baseColor: props.baseColor || "neutral",
59
+ cssVariables: props.cssVariables !== false,
60
+ },
61
+ aliases: {
62
+ components: props.srcDir !== false ? "@/components" : "./components",
63
+ utils: props.srcDir !== false ? "@/lib/utils" : "./lib/utils",
64
+ },
65
+ });
66
+ // Ensure ui components directory exists
67
+ const ui = await Folder(path.join(props.cwd, props.srcDir !== false ? "src" : "", "components", "ui"));
68
+ // Create lib directory
69
+ const libPath = path.join(props.cwd, props.srcDir !== false ? "src" : "", "lib");
70
+ const lib = await Folder(libPath);
71
+ // Create utils.ts file
72
+ const utilsContent = `
73
+ import { type ClassValue, clsx } from "clsx";
74
+ import { twMerge } from "tailwind-merge";
75
+
76
+ export function cn(...inputs: ClassValue[]) {
77
+ return twMerge(clsx(inputs));
78
+ }
79
+ `;
80
+ await StaticTypeScriptFile(path.join(libPath, "utils.ts"), utilsContent);
81
+ // Install clsx and tailwind-merge
82
+ await exec(`bun add clsx tailwind-merge`);
83
+ // Install requested components
84
+ if (props.components && props.components.length > 0) {
85
+ for (const componentName of props.components) {
86
+ await ShadcnComponent(`shadcn-component-${componentName}`, {
87
+ name: componentName,
88
+ cwd: props.cwd,
89
+ force: props.force,
90
+ silent: props.silent,
91
+ });
92
+ }
93
+ }
94
+ return this({
95
+ ...props,
96
+ ui,
97
+ lib,
98
+ });
99
+ });
@@ -0,0 +1,64 @@
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ /**
4
+ * Framework types supported by the Tailwind resource
5
+ */
6
+ export type TailwindFramework = "vite" | "astro" | "next" | "standalone";
7
+ /**
8
+ * Properties for Tailwind configuration
9
+ */
10
+ export interface TailwindConfigProps {
11
+ /**
12
+ * The working directory where Tailwind should be installed
13
+ */
14
+ cwd: string;
15
+ /**
16
+ * The framework being used (determines which dependencies to install)
17
+ * @default "standalone"
18
+ */
19
+ framework?: TailwindFramework;
20
+ /**
21
+ * The path to the CSS file where Tailwind directives should be added
22
+ * If not provided, a new file will be created at src/styles/base.css
23
+ */
24
+ cssPath?: string;
25
+ /**
26
+ * Custom additional packages to install with Tailwind
27
+ */
28
+ additionalPackages?: string[];
29
+ }
30
+ /**
31
+ * Tailwind configuration resource
32
+ */
33
+ export interface TailwindConfig extends TailwindConfigProps, Resource<"config::TailwindConfig"> {
34
+ /**
35
+ * The working directory where Tailwind is installed
36
+ */
37
+ cwd: string;
38
+ }
39
+ /**
40
+ * Installs and configures Tailwind CSS for a project
41
+ *
42
+ * @example
43
+ * // Install Tailwind for a Vite project
44
+ * const tailwind = await TailwindConfig("vite-tailwind", {
45
+ * cwd: "my-vite-app",
46
+ * framework: "vite"
47
+ * });
48
+ *
49
+ * @example
50
+ * // Install Tailwind for an Astro project
51
+ * const tailwind = await TailwindConfig("astro-tailwind", {
52
+ * cwd: "my-astro-app",
53
+ * framework: "astro"
54
+ * });
55
+ *
56
+ * @example
57
+ * // Install Tailwind as standalone with a custom CSS path
58
+ * const tailwind = await TailwindConfig("custom-tailwind", {
59
+ * cwd: "my-project",
60
+ * cssPath: "src/css/main.css",
61
+ * additionalPackages: ["@tailwindcss/typography", "@tailwindcss/forms"]
62
+ * });
63
+ */
64
+ export declare const TailwindConfig: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<TailwindConfig>, id: string, props: TailwindConfigProps) => Promise<TailwindConfig>);
@@ -0,0 +1,97 @@
1
+ import { exec } from "child_process";
2
+ import path from "path";
3
+ import { promisify } from "util";
4
+ import { Folder, StaticTextFile } from "../fs";
5
+ import { Resource } from "../resource";
6
+ const execAsync = promisify(exec);
7
+ /**
8
+ * Installs and configures Tailwind CSS for a project
9
+ *
10
+ * @example
11
+ * // Install Tailwind for a Vite project
12
+ * const tailwind = await TailwindConfig("vite-tailwind", {
13
+ * cwd: "my-vite-app",
14
+ * framework: "vite"
15
+ * });
16
+ *
17
+ * @example
18
+ * // Install Tailwind for an Astro project
19
+ * const tailwind = await TailwindConfig("astro-tailwind", {
20
+ * cwd: "my-astro-app",
21
+ * framework: "astro"
22
+ * });
23
+ *
24
+ * @example
25
+ * // Install Tailwind as standalone with a custom CSS path
26
+ * const tailwind = await TailwindConfig("custom-tailwind", {
27
+ * cwd: "my-project",
28
+ * cssPath: "src/css/main.css",
29
+ * additionalPackages: ["@tailwindcss/typography", "@tailwindcss/forms"]
30
+ * });
31
+ */
32
+ export const TailwindConfig = Resource("config::TailwindConfig", async function (id, props) {
33
+ if (this.phase === "delete") {
34
+ // Nothing to clean up specifically for Tailwind
35
+ return this.destroy();
36
+ }
37
+ const framework = props.framework || "standalone";
38
+ // Setup execAsync with the correct cwd
39
+ const exec = (command) => execAsync(command, { cwd: props.cwd });
40
+ // Install Tailwind and framework-specific dependencies
41
+ await installTailwindDependencies(framework);
42
+ // Create CSS file with Tailwind directives
43
+ await createTailwindCssFile();
44
+ return this({
45
+ ...props,
46
+ framework: framework,
47
+ });
48
+ /**
49
+ * Install Tailwind and framework-specific dependencies
50
+ */
51
+ async function installTailwindDependencies(framework) {
52
+ const basePackages = ["tailwindcss", "postcss", "autoprefixer"];
53
+ // Add framework-specific packages
54
+ const frameworkPackages = getFrameworkPackages(framework);
55
+ // Add custom additional packages
56
+ const additionalPackages = props.additionalPackages || [];
57
+ // Combine all packages
58
+ const allPackages = [
59
+ ...basePackages,
60
+ ...frameworkPackages,
61
+ ...additionalPackages,
62
+ ];
63
+ // Install all packages
64
+ await exec(`bun add -D ${allPackages.join(" ")}`);
65
+ }
66
+ /**
67
+ * Get framework-specific packages for Tailwind
68
+ */
69
+ function getFrameworkPackages(framework) {
70
+ switch (framework) {
71
+ case "vite":
72
+ return ["@tailwindcss/vite"];
73
+ case "astro":
74
+ return ["@astrojs/tailwind"];
75
+ case "next":
76
+ return [];
77
+ case "standalone":
78
+ default:
79
+ return [];
80
+ }
81
+ }
82
+ /**
83
+ * Create or update CSS file with Tailwind directives
84
+ */
85
+ async function createTailwindCssFile() {
86
+ const tailwindDirectives = `@import 'tailwindcss';`;
87
+ // Determine CSS file path
88
+ const cssPath = props.cssPath || path.join(props.cwd, "src", "styles", "global.css");
89
+ // Create directory structure if needed
90
+ const cssDir = path.dirname(cssPath);
91
+ await Folder(path.join(id, "css-dir"), {
92
+ path: cssDir,
93
+ });
94
+ // Create CSS file with Tailwind directives
95
+ await StaticTextFile(cssPath, tailwindDirectives);
96
+ }
97
+ });
@@ -79,6 +79,11 @@ export interface ViteProjectProps {
79
79
  * @default false
80
80
  */
81
81
  overwrite?: boolean;
82
+ /**
83
+ * Whether to delete the project folder during the delete phase
84
+ * @default true
85
+ */
86
+ delete?: boolean;
82
87
  }
83
88
  export interface ViteProject extends ViteProjectProps, Resource {
84
89
  /**
@@ -1,10 +1,11 @@
1
1
  import { exec } from "child_process";
2
- import fs from "fs/promises";
3
2
  import path from "path";
4
3
  import { promisify } from "util";
4
+ import { Folder, StaticJsonFile, StaticTypeScriptFile } from "../fs";
5
5
  import { Resource } from "../resource";
6
- import { ShadcnComponent } from "../shadcn/component";
7
6
  import { rm } from "../util/rm";
7
+ import { ShadcnComponent } from "./shadcn-component";
8
+ import { TailwindConfig } from "./tailwind";
8
9
  const execAsync = promisify(exec);
9
10
  export const ViteProject = Resource("project::ViteProject", {
10
11
  alwaysUpdate: true,
@@ -12,9 +13,8 @@ export const ViteProject = Resource("project::ViteProject", {
12
13
  const phase = this.phase;
13
14
  if (this.phase === "delete") {
14
15
  try {
15
- if (await fs.exists(props.name)) {
16
- // TODO: OS agnostic - fs.rm is slow to delete node_modules/
17
- await execAsync("rm -rf " + props.name);
16
+ if (props.delete !== false) {
17
+ await execAsync(`rm -rf ${props.name}`);
18
18
  }
19
19
  }
20
20
  catch (error) {
@@ -45,6 +45,11 @@ export const ViteProject = Resource("project::ViteProject", {
45
45
  "react()",
46
46
  ].filter((s) => typeof s === "string");
47
47
  const cwd = path.resolve(process.cwd(), props.name);
48
+ // Create folder for project
49
+ await Folder("project-dir", {
50
+ path: props.name,
51
+ delete: props.delete,
52
+ });
48
53
  const exec = (command) => execAsync(command, { cwd });
49
54
  if (phase === "create" || props.overwrite) {
50
55
  await removeUnnecessaryFiles();
@@ -65,8 +70,11 @@ export const ViteProject = Resource("project::ViteProject", {
65
70
  await execAsync(`bun vite build`, { cwd: props.name });
66
71
  }
67
72
  async function installTailwind() {
68
- await exec(`bun add tailwindcss @tailwindcss/vite`);
69
- await fs.writeFile(path.join(props.name, "vite.config.ts"), `import path from "path";
73
+ await TailwindConfig(`${id}-tailwind`, {
74
+ cwd: props.name,
75
+ framework: "vite",
76
+ });
77
+ await StaticTypeScriptFile(path.join(props.name, "vite.config.ts"), `import path from "path";
70
78
  import react from "@vitejs/plugin-react";
71
79
  import { defineConfig } from "vite";
72
80
  ${tailwind ? "import tailwindcss from '@tailwindcss/vite';" : ""}
@@ -81,12 +89,6 @@ export default defineConfig({
81
89
  },
82
90
  },
83
91
  });`);
84
- // Add Tailwind CSS import to index.css
85
- const indexCssPath = path.join(props.name, "src", "index.css");
86
- const currentCss = await fs.readFile(indexCssPath, "utf-8");
87
- if (!currentCss.includes('@import "tailwindcss";')) {
88
- await fs.writeFile(indexCssPath, '@import "tailwindcss";\n\n' + currentCss);
89
- }
90
92
  }
91
93
  async function installShadcn() {
92
94
  await exec("bun add -D @types/node");
@@ -120,8 +122,12 @@ export default defineConfig({
120
122
  await exec(`bun add -D @tanstack/router-plugin @tanstack/react-router-devtools`);
121
123
  const src = path.join(props.name, "src");
122
124
  const routes = path.join(src, "routes");
123
- await fs.mkdir(routes, { recursive: true });
124
- await fs.writeFile(path.join(routes, "__root.tsx"), `import { Link, Outlet, createRootRoute } from "@tanstack/react-router";
125
+ // Create routes directory
126
+ await Folder("routes-dir", {
127
+ path: routes,
128
+ });
129
+ // Create root route file
130
+ await StaticTypeScriptFile(path.join(routes, "__root.tsx"), `import { Link, Outlet, createRootRoute } from "@tanstack/react-router";
125
131
  import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
126
132
 
127
133
  export const Route = createRootRoute({
@@ -142,7 +148,8 @@ export const Route = createRootRoute({
142
148
  ),
143
149
  });
144
150
  `);
145
- await fs.writeFile(path.join(routes, "index.tsx"), `import { createLazyFileRoute } from '@tanstack/react-router'
151
+ // Create index route file
152
+ await StaticTypeScriptFile(path.join(routes, "index.tsx"), `import { createLazyFileRoute } from '@tanstack/react-router'
146
153
 
147
154
  export const Route = createLazyFileRoute('/')({
148
155
  component: Index,
@@ -155,7 +162,8 @@ function Index() {
155
162
  </div>
156
163
  )
157
164
  }`);
158
- await fs.writeFile(path.join(routes, "about.tsx"), `import { createLazyFileRoute } from '@tanstack/react-router'
165
+ // Create about route file
166
+ await StaticTypeScriptFile(path.join(routes, "about.tsx"), `import { createLazyFileRoute } from '@tanstack/react-router'
159
167
 
160
168
  export const Route = createLazyFileRoute('/about')({
161
169
  component: About,
@@ -164,7 +172,8 @@ export const Route = createLazyFileRoute('/about')({
164
172
  function About() {
165
173
  return <div className="p-2">Hello from About!</div>
166
174
  }`);
167
- await fs.writeFile(path.join(src, "main.tsx"), `import { StrictMode } from 'react'
175
+ // Create main.tsx
176
+ await StaticTypeScriptFile(path.join(src, "main.tsx"), `import { StrictMode } from 'react'
168
177
  import ReactDOM from 'react-dom/client'
169
178
  import { RouterProvider, createRouter } from '@tanstack/react-router'
170
179
  import './index.css'
@@ -194,35 +203,26 @@ if (!rootElement.innerHTML) {
194
203
  }`);
195
204
  }
196
205
  async function removeUnnecessaryFiles() {
197
- await Promise.all([
198
- rm(path.join(props.name, "src", "App.tsx")),
199
- rm(path.join(props.name, "src", "App.css")),
200
- ]);
206
+ await rm(path.join(props.name, "src", "App.tsx"));
207
+ await rm(path.join(props.name, "src", "App.css"));
201
208
  }
202
209
  async function patchTsConfig() {
203
- await Promise.all([
204
- rm(path.join(props.name, "tsconfig.app.json")),
205
- rm(path.join(props.name, "tsconfig.node.json")),
206
- fs.writeFile(path.join(props.name, "tsconfig.json"), JSON.stringify({
207
- extends: props.extends,
208
- compilerOptions: {
209
- baseUrl: ".",
210
- paths: {
211
- "@/*": ["./src/*"],
212
- },
213
- types: ["@cloudflare/workers-types"],
214
- allowImportingTsExtensions: true,
215
- jsx: "react-jsx",
210
+ await rm(path.join(props.name, "tsconfig.app.json"));
211
+ await rm(path.join(props.name, "tsconfig.node.json"));
212
+ await StaticJsonFile(path.join(props.name, "tsconfig.json"), {
213
+ extends: props.extends,
214
+ compilerOptions: {
215
+ baseUrl: ".",
216
+ paths: {
217
+ "@/*": ["./src/*"],
216
218
  },
217
- include: [
218
- "vite/*.ts",
219
- "src/**/*.ts",
220
- "src/**/*.tsx",
221
- "src/env.d.ts",
222
- ],
223
- references: props.references?.map((path) => ({ path })),
224
- }, null, 2)),
225
- ]);
219
+ types: ["@cloudflare/workers-types"],
220
+ allowImportingTsExtensions: true,
221
+ jsx: "react-jsx",
222
+ },
223
+ include: ["vite/*.ts", "src/**/*.ts", "src/**/*.tsx", "src/env.d.ts"],
224
+ references: props.references?.map((path) => ({ path })),
225
+ });
226
226
  }
227
227
  }
228
228
  });
@@ -0,0 +1,10 @@
1
+ import type { DefaultTheme, ThemeOptions } from "vitepress";
2
+ export type VitePressConfigProps = {
3
+ cwd: string;
4
+ title?: string;
5
+ description?: string;
6
+ theme?: ThemeOptions;
7
+ themeConfig: DefaultTheme.Config;
8
+ };
9
+ export type VitePressConfig = Awaited<ReturnType<typeof VitePressConfig>>;
10
+ export declare function VitePressConfig(props: VitePressConfigProps): Promise<import("../../fs").File>;
@@ -0,0 +1,31 @@
1
+ import path from "path";
2
+ import { StaticTypeScriptFile } from "../../fs/static-typescript-file";
3
+ export function VitePressConfig(props) {
4
+ return StaticTypeScriptFile(path.join(props.cwd, ".vitepress", "config.mts"), `import { transformerTwoslash } from "@shikijs/vitepress-twoslash";
5
+ import footnotePlugin from "markdown-it-footnote";
6
+ import { defineConfig } from "vitepress";
7
+
8
+ // https://vitepress.dev/reference/site-config
9
+ export default defineConfig({
10
+ title: ${JSON.stringify(props.title || "Alchemy")},
11
+ description: ${JSON.stringify(props.description || "Alchemy Docs")},
12
+ markdown: {
13
+ // @ts-ignore
14
+ codeTransformers: [transformerTwoslash()],
15
+ theme: ${JSON.stringify(props.theme ?? {
16
+ light: "light-plus",
17
+ dark: "dark-plus",
18
+ })},
19
+ config: (md) => md.use(footnotePlugin),
20
+ },
21
+ // https://vitepress.dev/reference/default-theme-config
22
+ themeConfig: ${JSON.stringify({
23
+ ...props.themeConfig,
24
+ search: props.themeConfig.search ?? { provider: "local" },
25
+ nav: props.themeConfig.nav ?? [{ text: "Home", link: "/" }],
26
+ sidebar: props.themeConfig.sidebar ?? [],
27
+ socialLinks: props.themeConfig.socialLinks ?? [],
28
+ })}
29
+ });
30
+ `);
31
+ }