alchemy 0.2.5 → 0.3.0

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 (151) hide show
  1. package/README.md +3 -3
  2. package/lib/ai/astro-file.d.ts +137 -0
  3. package/lib/ai/astro-file.js +173 -0
  4. package/lib/ai/client.d.ts +2 -10
  5. package/lib/ai/client.js +8 -24
  6. package/lib/ai/css-file.d.ts +131 -0
  7. package/lib/ai/css-file.js +158 -0
  8. package/lib/ai/data.d.ts +45 -5
  9. package/lib/ai/data.js +45 -10
  10. package/lib/ai/document.d.ts +44 -20
  11. package/lib/ai/document.js +95 -28
  12. package/lib/ai/html-file.d.ts +128 -0
  13. package/lib/ai/html-file.js +155 -0
  14. package/lib/ai/index.d.ts +7 -0
  15. package/lib/ai/index.js +7 -0
  16. package/lib/ai/json-file.d.ts +160 -0
  17. package/lib/ai/json-file.js +208 -0
  18. package/lib/ai/typescript-file.d.ts +140 -0
  19. package/lib/ai/typescript-file.js +176 -0
  20. package/lib/ai/vue-file.d.ts +126 -0
  21. package/lib/ai/vue-file.js +153 -0
  22. package/lib/ai/yaml-file.d.ts +169 -0
  23. package/lib/ai/yaml-file.js +236 -0
  24. package/lib/cloudflare/dns.d.ts +88 -0
  25. package/lib/cloudflare/dns.js +192 -0
  26. package/lib/cloudflare/index.d.ts +2 -1
  27. package/lib/cloudflare/index.js +2 -1
  28. package/lib/cloudflare/r2-rest-state-store.d.ts +125 -0
  29. package/lib/cloudflare/r2-rest-state-store.js +254 -0
  30. package/lib/cloudflare/response.d.ts +12 -0
  31. package/lib/cloudflare/response.js +0 -0
  32. package/lib/cloudflare/zone.d.ts +18 -0
  33. package/lib/cloudflare/zone.js +17 -4
  34. package/lib/dns/godaddy.d.ts +7 -0
  35. package/lib/dns/godaddy.js +21 -0
  36. package/lib/dns/import-dns.d.ts +82 -0
  37. package/lib/dns/import-dns.js +114 -0
  38. package/lib/dns/index.d.ts +2 -0
  39. package/lib/dns/index.js +2 -0
  40. package/lib/dns/record.d.ts +88 -0
  41. package/lib/dns/record.js +13 -0
  42. package/lib/fs/file-system-state-store.d.ts +17 -0
  43. package/lib/fs/file-system-state-store.js +87 -0
  44. package/lib/fs/folder.d.ts +10 -0
  45. package/lib/fs/folder.js +2 -2
  46. package/lib/fs/index.d.ts +4 -4
  47. package/lib/fs/index.js +4 -4
  48. package/lib/fs/{json-file.d.ts → static-json-file.d.ts} +2 -2
  49. package/lib/fs/static-json-file.js +14 -0
  50. package/lib/fs/{text-file.d.ts → static-text-file.d.ts} +2 -2
  51. package/lib/fs/{text-file.js → static-text-file.js} +1 -1
  52. package/lib/fs/{typescript-file.d.ts → static-typescript-file.d.ts} +2 -2
  53. package/lib/fs/{typescript-file.js → static-typescript-file.js} +1 -1
  54. package/lib/fs/{yaml-file.d.ts → static-yaml-file.d.ts} +2 -2
  55. package/lib/fs/{yaml-file.js → static-yaml-file.js} +1 -1
  56. package/lib/internal/getting-started.d.ts +10 -0
  57. package/lib/internal/getting-started.js +94 -0
  58. package/lib/internal/project.d.ts +13 -0
  59. package/lib/internal/project.js +101 -0
  60. package/lib/internal/providers.d.ts +23 -0
  61. package/lib/internal/providers.js +148 -0
  62. package/lib/resource.js +8 -1
  63. package/lib/scope.d.ts +1 -1
  64. package/lib/scope.js +4 -2
  65. package/lib/state.d.ts +1 -16
  66. package/lib/state.js +0 -87
  67. package/lib/test/bun.d.ts +11 -0
  68. package/lib/test/bun.js +36 -8
  69. package/lib/web/astro.d.ts +147 -0
  70. package/lib/web/astro.js +414 -0
  71. package/lib/{shadcn/component.js → web/shadcn-component.js} +2 -9
  72. package/lib/web/shadcn.d.ts +97 -0
  73. package/lib/web/shadcn.js +99 -0
  74. package/lib/web/tailwind.d.ts +64 -0
  75. package/lib/web/tailwind.js +97 -0
  76. package/lib/{vite → web}/vite.d.ts +5 -0
  77. package/lib/{vite → web}/vite.js +44 -44
  78. package/lib/web/vitepress/custom-theme.d.ts +173 -0
  79. package/lib/web/vitepress/custom-theme.js +336 -0
  80. package/lib/{vitepress → web/vitepress}/dependencies.d.ts +2 -2
  81. package/lib/{vitepress → web/vitepress}/dependencies.js +1 -1
  82. package/lib/web/vitepress/home-page.d.ts +244 -0
  83. package/lib/web/vitepress/home-page.js +134 -0
  84. package/lib/{vitepress → web/vitepress}/index.d.ts +1 -0
  85. package/lib/{vitepress → web/vitepress}/index.js +1 -0
  86. package/lib/{vitepress → web/vitepress}/vitepress.d.ts +10 -8
  87. package/lib/{vitepress → web/vitepress}/vitepress.js +11 -12
  88. package/package.json +6 -2
  89. package/src/ai/astro-file.ts +288 -0
  90. package/src/ai/client.ts +8 -28
  91. package/src/ai/css-file.ts +266 -0
  92. package/src/ai/data.ts +53 -16
  93. package/src/ai/document.ts +130 -33
  94. package/src/ai/html-file.ts +263 -0
  95. package/src/ai/index.ts +7 -0
  96. package/src/ai/json-file.ts +349 -0
  97. package/src/ai/typescript-file.ts +293 -0
  98. package/src/ai/vue-file.ts +261 -0
  99. package/src/ai/yaml-file.ts +368 -0
  100. package/src/apply.ts +0 -1
  101. package/src/cloudflare/dns.ts +344 -0
  102. package/src/cloudflare/index.ts +2 -1
  103. package/src/cloudflare/r2-rest-state-store.ts +353 -0
  104. package/src/cloudflare/response.ts +9 -0
  105. package/src/cloudflare/zone.ts +39 -23
  106. package/src/dns/godaddy.ts +29 -0
  107. package/src/dns/import-dns.ts +213 -0
  108. package/src/dns/index.ts +2 -0
  109. package/src/dns/record.ts +121 -0
  110. package/src/fs/file-system-state-store.ts +109 -0
  111. package/src/fs/folder.ts +14 -2
  112. package/src/fs/index.ts +4 -4
  113. package/src/fs/{json-file.ts → static-json-file.ts} +13 -3
  114. package/src/fs/{text-file.ts → static-text-file.ts} +5 -2
  115. package/src/fs/{typescript-file.ts → static-typescript-file.ts} +3 -3
  116. package/src/fs/{yaml-file.ts → static-yaml-file.ts} +5 -2
  117. package/src/internal/getting-started.ts +107 -0
  118. package/src/internal/project.ts +119 -0
  119. package/src/internal/providers.ts +209 -0
  120. package/src/resource.ts +10 -1
  121. package/src/scope.ts +5 -6
  122. package/src/state.ts +1 -111
  123. package/src/test/bun.ts +60 -10
  124. package/src/web/astro.ts +644 -0
  125. package/src/{shadcn/component.ts → web/shadcn-component.ts} +5 -13
  126. package/src/web/shadcn.ts +219 -0
  127. package/src/web/tailwind.ts +167 -0
  128. package/src/{vite → web}/vite.ts +54 -56
  129. package/src/web/vitepress/custom-theme.ts +514 -0
  130. package/src/{vitepress → web/vitepress}/dependencies.ts +2 -2
  131. package/src/web/vitepress/home-page.ts +363 -0
  132. package/src/{vitepress → web/vitepress}/index.ts +1 -0
  133. package/src/{vitepress → web/vitepress}/vitepress.ts +34 -27
  134. package/lib/cloudflare/state.d.ts +0 -82
  135. package/lib/cloudflare/state.js +0 -108
  136. package/lib/fs/json-file.js +0 -7
  137. package/lib/internal/docs.d.ts +0 -5
  138. package/lib/internal/docs.js +0 -287
  139. package/lib/shadcn/index.d.ts +0 -1
  140. package/lib/shadcn/index.js +0 -1
  141. package/lib/vite/index.d.ts +0 -1
  142. package/lib/vite/index.js +0 -1
  143. package/lib/vitepress/home-page.d.ts +0 -133
  144. package/lib/vitepress/home-page.js +0 -11
  145. package/src/cloudflare/state.ts +0 -138
  146. package/src/internal/docs.ts +0 -338
  147. package/src/shadcn/index.ts +0 -1
  148. package/src/vite/index.ts +0 -1
  149. package/src/vitepress/home-page.ts +0 -166
  150. /package/lib/{shadcn/component.d.ts → web/shadcn-component.d.ts} +0 -0
  151. /package/src/{vitepress → web/vitepress}/index.md +0 -0
@@ -0,0 +1,644 @@
1
+ import { exec } from "child_process";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { promisify } from "util";
5
+ import type { Context } from "../context";
6
+ import {
7
+ Folder,
8
+ StaticJsonFile,
9
+ StaticTextFile,
10
+ StaticTypeScriptFile,
11
+ } from "../fs";
12
+ import { Resource } from "../resource";
13
+ import { ShadcnUI } from "./shadcn";
14
+
15
+ const execAsync = promisify(exec);
16
+
17
+ /**
18
+ * Type of integrations that can be added to an Astro project
19
+ */
20
+ export type AstroIntegration =
21
+ | "react"
22
+ | "preact"
23
+ | "vue"
24
+ | "svelte"
25
+ | "solid"
26
+ | "lit"
27
+ | "tailwind"
28
+ | "mdx"
29
+ | "sitemap"
30
+ | "partytown"
31
+ | "markdoc";
32
+
33
+ /**
34
+ * Properties for creating an Astro project
35
+ */
36
+ export interface AstroProjectProps {
37
+ /**
38
+ * The name/path of the project
39
+ */
40
+ name: string;
41
+
42
+ /**
43
+ * The title of the site
44
+ * @default "Astro Site"
45
+ */
46
+ title?: string;
47
+
48
+ /**
49
+ * The description of the site
50
+ * @default "Welcome to my Astro site"
51
+ */
52
+ description?: string;
53
+
54
+ /**
55
+ * The directory to initialize the project in.
56
+ * @default {@link name}
57
+ */
58
+ dir?: string;
59
+
60
+ /**
61
+ * The integrations to add to the project
62
+ * @default []
63
+ */
64
+ integrations?: AstroIntegration[];
65
+
66
+ /**
67
+ * The TypeScript configuration
68
+ */
69
+ tsconfig?: {
70
+ /**
71
+ * Extends from this TypeScript configuration
72
+ */
73
+ extends?: string;
74
+
75
+ /**
76
+ * References to add to the tsconfig
77
+ */
78
+ references?: string[];
79
+
80
+ /**
81
+ * Compiler options to add to the tsconfig
82
+ */
83
+ compilerOptions?: Record<string, any>;
84
+ };
85
+
86
+ /**
87
+ * Whether to delete the project folder during the delete phase
88
+ * @default true
89
+ */
90
+ delete?: boolean;
91
+
92
+ /**
93
+ * Add Shadcn UI to the project
94
+ * @default false
95
+ */
96
+ shadcn?: {
97
+ /**
98
+ * The base color to use
99
+ * @default "neutral"
100
+ */
101
+ baseColor?: "neutral" | "gray" | "zinc" | "stone" | "slate";
102
+
103
+ /**
104
+ * Use default configuration
105
+ * @default false
106
+ */
107
+ defaults?: boolean;
108
+
109
+ /**
110
+ * Force overwrite of existing configuration
111
+ * @default false
112
+ */
113
+ force?: boolean;
114
+
115
+ /**
116
+ * Mute output
117
+ * @default false
118
+ */
119
+ silent?: boolean;
120
+
121
+ /**
122
+ * Use the src directory when creating a new project
123
+ * @default true
124
+ */
125
+ srcDir?: boolean;
126
+
127
+ /**
128
+ * Use css variables for theming
129
+ * @default true
130
+ */
131
+ cssVariables?: boolean;
132
+
133
+ /**
134
+ * The components to add
135
+ */
136
+ components?: string[];
137
+ };
138
+
139
+ /**
140
+ * The dependencies to install
141
+ */
142
+ dependencies?: Record<string, string>;
143
+
144
+ /**
145
+ * The dev dependencies to install
146
+ */
147
+ devDependencies?: Record<string, string>;
148
+
149
+ /**
150
+ * Additional scripts to add to package.json
151
+ */
152
+ scripts?: Record<string, string>;
153
+ }
154
+
155
+ /**
156
+ * Astro project resource
157
+ */
158
+ export interface AstroProject extends AstroProjectProps, Resource {
159
+ /**
160
+ * The name/path of the project
161
+ */
162
+ name: string;
163
+ }
164
+
165
+ /**
166
+ * Creates a new Astro project
167
+ *
168
+ * @example
169
+ * // Create a basic Astro project
170
+ * const basicProject = await AstroProject("my-astro-app", {
171
+ * title: "My Astro Site",
172
+ * description: "Built with Alchemy"
173
+ * });
174
+ *
175
+ * @example
176
+ * // Create an Astro project with React and Tailwind
177
+ * const reactProject = await AstroProject("astro-react", {
178
+ * title: "Astro + React",
179
+ * integrations: ["react", "tailwind"]
180
+ * });
181
+ *
182
+ * @example
183
+ * // Create an Astro project with Shadcn UI
184
+ * const shadcnProject = await AstroProject("astro-shadcn", {
185
+ * title: "Astro with Shadcn UI",
186
+ * integrations: ["react", "tailwind"],
187
+ * shadcn: {
188
+ * baseColor: "zinc",
189
+ * components: ["button", "card", "input"]
190
+ * }
191
+ * });
192
+ */
193
+ export const AstroProject = Resource(
194
+ "project::AstroProject",
195
+ {
196
+ alwaysUpdate: true,
197
+ },
198
+ async function (
199
+ this: Context<AstroProject>,
200
+ id: string,
201
+ props: AstroProjectProps,
202
+ ): Promise<AstroProject> {
203
+ const dir = props.dir ?? props.name;
204
+
205
+ if (this.phase === "delete") {
206
+ try {
207
+ if (props.delete !== false) {
208
+ if (await fs.stat(dir).catch(() => null)) {
209
+ await execAsync(`rm -rf ${dir}`);
210
+ }
211
+ }
212
+ } catch (error) {
213
+ console.error(`Error deleting project ${id}:`, error);
214
+ }
215
+ return this.destroy();
216
+ }
217
+
218
+ const cwd = path.resolve(process.cwd(), dir);
219
+
220
+ // Create the project directory
221
+ await Folder("project-dir", {
222
+ path: dir,
223
+ delete: true,
224
+ });
225
+
226
+ await Folder(".astro", {
227
+ path: dir,
228
+ delete: true,
229
+ clean: true,
230
+ });
231
+
232
+ await setupProject(props);
233
+
234
+ return this(props);
235
+
236
+ /**
237
+ * Set up the Astro project structure and configuration
238
+ */
239
+ async function setupProject(props: AstroProjectProps) {
240
+ // Create project structure
241
+ await ProjectStructure();
242
+
243
+ // Set up package.json
244
+ await StaticJsonFile(path.join(dir, "package.json"), {
245
+ name: props.name,
246
+ type: "module",
247
+ version: "0.0.1",
248
+ scripts: {
249
+ dev: "astro dev",
250
+ start: "astro dev",
251
+ build: "astro build",
252
+ preview: "astro preview",
253
+ astro: "astro",
254
+ ...props.scripts,
255
+ },
256
+ dependencies: props.dependencies || {},
257
+ devDependencies: props.devDependencies || {},
258
+ });
259
+
260
+ // Set up tsconfig.json
261
+ await StaticJsonFile(path.join(dir, "tsconfig.json"), {
262
+ extends: props.tsconfig?.extends || "astro/tsconfigs/strict",
263
+ compilerOptions: {
264
+ baseUrl: ".",
265
+ paths: {
266
+ "@/*": ["./src/*"],
267
+ },
268
+ jsx: "react-jsx",
269
+ jsxImportSource: "react",
270
+ ...props.tsconfig?.compilerOptions,
271
+ },
272
+ include: ["src/**/*.ts", "src/**/*.tsx", "src/**/*.astro"],
273
+ references: props.tsconfig?.references?.map((path) => ({ path })),
274
+ });
275
+
276
+ // Set up astro.config.mjs
277
+ await AstroConfig();
278
+
279
+ // Set up initial files
280
+ await InitialFiles();
281
+
282
+ // Install integrations
283
+ if (props.integrations && props.integrations.length > 0) {
284
+ await InstallIntegrations();
285
+ }
286
+
287
+ // Install dependencies
288
+ await InstallDependencies();
289
+
290
+ // Set up Shadcn if requested
291
+ if (props.shadcn) {
292
+ await ShadcnUI(id, {
293
+ ...props.shadcn,
294
+ cwd: dir,
295
+ });
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Create the basic project structure
301
+ */
302
+ async function ProjectStructure() {
303
+ const folderPaths = [
304
+ "src",
305
+ "src/components",
306
+ "src/layouts",
307
+ "src/pages",
308
+ "public",
309
+ ];
310
+
311
+ for (const folderPath of folderPaths) {
312
+ await Folder(`${dir}-${folderPath}`, {
313
+ path: path.join(dir, folderPath),
314
+ });
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Set up astro.config.mjs
320
+ */
321
+ async function AstroConfig() {
322
+ const integrations = [];
323
+ const vitePlugins = [];
324
+
325
+ // Add imports and integrations
326
+ const configImports = ['import { defineConfig } from "astro/config";'];
327
+
328
+ if (props.integrations?.includes("react")) {
329
+ configImports.push('import react from "@astrojs/react";');
330
+ integrations.push("react()");
331
+ }
332
+
333
+ if (props.integrations?.includes("preact")) {
334
+ configImports.push('import preact from "@astrojs/preact";');
335
+ integrations.push("preact()");
336
+ }
337
+
338
+ if (props.integrations?.includes("vue")) {
339
+ configImports.push('import vue from "@astrojs/vue";');
340
+ integrations.push("vue()");
341
+ }
342
+
343
+ if (props.integrations?.includes("svelte")) {
344
+ configImports.push('import svelte from "@astrojs/svelte";');
345
+ integrations.push("svelte()");
346
+ }
347
+
348
+ if (props.integrations?.includes("solid")) {
349
+ configImports.push('import solid from "@astrojs/solid-js";');
350
+ integrations.push("solid()");
351
+ }
352
+
353
+ if (props.integrations?.includes("lit")) {
354
+ configImports.push('import lit from "@astrojs/lit";');
355
+ integrations.push("lit()");
356
+ }
357
+
358
+ if (props.integrations?.includes("tailwind")) {
359
+ configImports.push('import tailwindcss from "@tailwindcss/vite";');
360
+ vitePlugins.push("tailwindcss()");
361
+ }
362
+
363
+ if (props.integrations?.includes("mdx")) {
364
+ configImports.push('import mdx from "@astrojs/mdx";');
365
+ integrations.push("mdx()");
366
+ }
367
+
368
+ if (props.integrations?.includes("sitemap")) {
369
+ configImports.push('import sitemap from "@astrojs/sitemap";');
370
+ integrations.push("sitemap()");
371
+ }
372
+
373
+ if (props.integrations?.includes("partytown")) {
374
+ configImports.push('import partytown from "@astrojs/partytown";');
375
+ integrations.push("partytown()");
376
+ }
377
+
378
+ if (props.integrations?.includes("markdoc")) {
379
+ configImports.push('import markdoc from "@astrojs/markdoc";');
380
+ integrations.push("markdoc()");
381
+ }
382
+
383
+ const integrationsStr = integrations.length
384
+ ? `\n integrations: [${integrations.join(", ")}],`
385
+ : "";
386
+
387
+ const vitePluginsStr = vitePlugins.length
388
+ ? `\n vite: {\n plugins: [${vitePlugins.join(", ")}]\n },`
389
+ : "";
390
+
391
+ return StaticTypeScriptFile(
392
+ path.join(dir, "astro.config.ts"),
393
+ `${configImports.join("\n")}
394
+
395
+ // https://astro.build/config
396
+ export default defineConfig({${integrationsStr}${vitePluginsStr}
397
+ site: "https://example.com",
398
+ output: "static"
399
+ });`,
400
+ );
401
+ }
402
+
403
+ /**
404
+ * Create initial files for the project
405
+ */
406
+ async function InitialFiles() {
407
+ // Create .gitignore
408
+ await StaticTextFile(
409
+ path.join(dir, ".gitignore"),
410
+ `# build output
411
+ dist/
412
+ .output/
413
+
414
+ # dependencies
415
+ node_modules/
416
+
417
+ # logs
418
+ npm-debug.log*
419
+ yarn-debug.log*
420
+ yarn-error.log*
421
+ pnpm-debug.log*
422
+
423
+ # environment variables
424
+ .env
425
+ .env.production
426
+
427
+ # macOS-specific files
428
+ .DS_Store
429
+ .astro/
430
+ `,
431
+ );
432
+
433
+ // Create .env.d.ts
434
+ await StaticTextFile(
435
+ path.join(dir, "src", "env.d.ts"),
436
+ `/// <reference types="astro/client" />
437
+ `,
438
+ );
439
+
440
+ // Create a basic layout
441
+ await StaticTextFile(
442
+ path.join(dir, "src", "layouts", "Layout.astro"),
443
+ `---
444
+ interface Props {
445
+ title: string;
446
+ description?: string;
447
+ }
448
+
449
+ const { title, description = "Welcome to my Astro site" } = Astro.props;
450
+ ---
451
+
452
+ <!DOCTYPE html>
453
+ <html lang="en">
454
+ <head>
455
+ <meta charset="UTF-8" />
456
+ <meta name="viewport" content="width=device-width" />
457
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
458
+ <meta name="generator" content={Astro.generator} />
459
+ <meta name="description" content={description} />
460
+ <title>{title}</title>
461
+ </head>
462
+ <body>
463
+ <slot />
464
+ </body>
465
+ </html>
466
+
467
+ <style is:global>
468
+ :root {
469
+ --accent: 124, 58, 237;
470
+ --accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
471
+ }
472
+ html {
473
+ font-family: system-ui, sans-serif;
474
+ background-color: #f6f6f6;
475
+ }
476
+ code {
477
+ font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
478
+ Bitstream Vera Sans Mono, Courier New, monospace;
479
+ }
480
+ </style>
481
+ `,
482
+ );
483
+
484
+ // Create a basic index page
485
+ await StaticTextFile(
486
+ path.join(dir, "src", "pages", "index.astro"),
487
+ `---
488
+ import Layout from '../layouts/Layout.astro';
489
+ ---
490
+
491
+ <Layout title="${props.title || "Astro Site"}" description="${props.description || "Welcome to my Astro site"}">
492
+ <main>
493
+ <h1><span class="text-gradient">Astro</span> Site</h1>
494
+ <p class="instructions">
495
+ To get started, edit <code>src/pages/index.astro</code> and save to see your changes.
496
+ </p>
497
+ </main>
498
+ </Layout>
499
+
500
+ <style>
501
+ main {
502
+ margin: auto;
503
+ padding: 1.5rem;
504
+ max-width: 60ch;
505
+ }
506
+ h1 {
507
+ font-size: 3rem;
508
+ font-weight: 800;
509
+ margin: 0;
510
+ }
511
+ .text-gradient {
512
+ background-image: var(--accent-gradient);
513
+ -webkit-background-clip: text;
514
+ -webkit-text-fill-color: transparent;
515
+ background-size: 400%;
516
+ background-position: 0%;
517
+ }
518
+ .instructions {
519
+ line-height: 1.6;
520
+ margin: 1rem 0;
521
+ border: 1px solid rgba(var(--accent), 25%);
522
+ background-color: white;
523
+ padding: 1rem;
524
+ border-radius: 0.4rem;
525
+ }
526
+ .instructions code {
527
+ font-size: 0.875em;
528
+ font-weight: bold;
529
+ background: rgba(var(--accent), 12%);
530
+ color: rgb(var(--accent));
531
+ border-radius: 4px;
532
+ padding: 0.3em 0.45em;
533
+ }
534
+ </style>
535
+ `,
536
+ );
537
+
538
+ // Create public/favicon.svg
539
+ await StaticTextFile(
540
+ path.join(dir, "public", "favicon.svg"),
541
+ `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 36 36">
542
+ <path fill="#000" d="M22.25 4h-8.5a1 1 0 0 0-.96.73l-5.54 19.4a.5.5 0 0 0 .62.62l5.05-1.44a2 2 0 0 0 1.38-1.4l3.22-11.66a.5.5 0 0 1 .96 0l3.22 11.67a2 2 0 0 0 1.38 1.39l5.05 1.44a.5.5 0 0 0 .62-.62l-5.54-19.4a1 1 0 0 0-.96-.73Z"/>
543
+ <path fill="url(#gradient)" d="M18 28a7.63 7.63 0 0 1-5-2c-1.4 2.1-.35 4.35.6 5.55.14.17.41.07.47-.15.44-1.8 2.93-1.22 2.93.6 0 2.28.87 3.4 1.72 3.81.34.16.59-.2.49-.56-.31-1.05-.29-2.46 1.29-3.25 3-1.5 3.17-4.83 2.5-6-.67.67-2.6 2-5 2Z"/>
544
+ <defs>
545
+ <linearGradient id="gradient" x1="16" x2="16" y1="32" y2="24" gradientUnits="userSpaceOnUse">
546
+ <stop stop-color="#FF1639"/>
547
+ <stop offset="1" stop-color="#FF1639" stop-opacity="0"/>
548
+ </linearGradient>
549
+ </defs>
550
+ </svg>
551
+ `,
552
+ );
553
+ }
554
+
555
+ /**
556
+ * Install Astro integrations
557
+ */
558
+ async function InstallIntegrations() {
559
+ const exec = (command: string) => execAsync(command, { cwd });
560
+ const integrationPackages = [];
561
+
562
+ for (const integration of props.integrations!) {
563
+ switch (integration) {
564
+ case "react":
565
+ integrationPackages.push("@astrojs/react", "react", "react-dom");
566
+ break;
567
+ case "preact":
568
+ integrationPackages.push("@astrojs/preact", "preact");
569
+ break;
570
+ case "vue":
571
+ integrationPackages.push("@astrojs/vue", "vue");
572
+ break;
573
+ case "svelte":
574
+ integrationPackages.push("@astrojs/svelte", "svelte");
575
+ break;
576
+ case "solid":
577
+ integrationPackages.push("@astrojs/solid-js", "solid-js");
578
+ break;
579
+ case "lit":
580
+ integrationPackages.push("@astrojs/lit", "lit");
581
+ break;
582
+ case "tailwind":
583
+ integrationPackages.push("@tailwindcss/vite", "tailwindcss");
584
+
585
+ // Create a base.css file with @tailwind directives
586
+ await Folder(path.join(dir, "src", "styles"));
587
+
588
+ await StaticTextFile(
589
+ path.join(dir, "src", "styles", "global.css"),
590
+ `@tailwind base;
591
+ @tailwind components;
592
+ @tailwind utilities;
593
+ `,
594
+ );
595
+ break;
596
+ case "mdx":
597
+ integrationPackages.push("@astrojs/mdx");
598
+ break;
599
+ case "sitemap":
600
+ integrationPackages.push("@astrojs/sitemap");
601
+ break;
602
+ case "partytown":
603
+ integrationPackages.push("@astrojs/partytown");
604
+ break;
605
+ case "markdoc":
606
+ integrationPackages.push("@astrojs/markdoc");
607
+ break;
608
+ }
609
+ }
610
+
611
+ if (integrationPackages.length > 0) {
612
+ await exec(`bun add astro ${integrationPackages.join(" ")}`);
613
+ }
614
+ }
615
+
616
+ /**
617
+ * Install dependencies
618
+ */
619
+ async function InstallDependencies() {
620
+ const exec = (command: string) => execAsync(command, { cwd });
621
+
622
+ // Install Astro and general dependencies
623
+ await exec(`bun add astro`);
624
+
625
+ // Install dev dependencies
626
+ const devDepsEntries = Object.entries(props.devDependencies || {});
627
+ if (devDepsEntries.length > 0) {
628
+ const devDepsArg = devDepsEntries
629
+ .map(([name, version]) => `${name}@${version}`)
630
+ .join(" ");
631
+ await exec(`bun add -D ${devDepsArg}`);
632
+ }
633
+
634
+ // Install regular dependencies
635
+ const depsEntries = Object.entries(props.dependencies || {});
636
+ if (depsEntries.length > 0) {
637
+ const depsArg = depsEntries
638
+ .map(([name, version]) => `${name}@${version}`)
639
+ .join(" ");
640
+ await exec(`bun add ${depsArg}`);
641
+ }
642
+ }
643
+ },
644
+ );
@@ -4,6 +4,7 @@ import path from "path";
4
4
  import { promisify } from "util";
5
5
  import type { Context } from "../context";
6
6
  import { Resource } from "../resource";
7
+ import { ignore } from "../util/ignore";
7
8
 
8
9
  const execAsync = promisify(exec);
9
10
 
@@ -46,20 +47,11 @@ export const ShadcnComponent = Resource(
46
47
  props: ShadcnComponentProps,
47
48
  ): Promise<ShadcnComponent> {
48
49
  if (this.phase === "delete") {
49
- const componentPath = path.join(
50
- props.cwd,
51
- "src",
52
- "components",
53
- "ui",
54
- `${props.name}.tsx`,
50
+ await ignore("ENOENT", () =>
51
+ fs.unlink(
52
+ path.join(props.cwd, "src", "components", "ui", `${props.name}.tsx`),
53
+ ),
55
54
  );
56
- try {
57
- await fs.unlink(componentPath);
58
- } catch (error) {
59
- if ((error as any).code !== "ENOENT") {
60
- throw error;
61
- }
62
- }
63
55
  return this.destroy();
64
56
  }
65
57