create-velocity-astro 1.5.0 → 1.5.2
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/index.js
CHANGED
|
@@ -5,11 +5,11 @@ import mri from "mri";
|
|
|
5
5
|
import { resolve as resolve2 } from "path";
|
|
6
6
|
import { existsSync as existsSync5 } from "fs";
|
|
7
7
|
import * as p3 from "@clack/prompts";
|
|
8
|
-
import
|
|
8
|
+
import pc4 from "picocolors";
|
|
9
9
|
|
|
10
10
|
// src/prompts.ts
|
|
11
11
|
import * as p from "@clack/prompts";
|
|
12
|
-
import
|
|
12
|
+
import pc2 from "picocolors";
|
|
13
13
|
|
|
14
14
|
// src/utils/validate.ts
|
|
15
15
|
function validateProjectName(name) {
|
|
@@ -163,6 +163,38 @@ function getSelectionStats(resolved, registry) {
|
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
// src/display.ts
|
|
167
|
+
import gradient from "gradient-string";
|
|
168
|
+
import figures from "figures";
|
|
169
|
+
import pc from "picocolors";
|
|
170
|
+
var velocityGrad = gradient(["#3b82f6", "#06b6d4", "#8b5cf6"]);
|
|
171
|
+
var successGrad = gradient(["#22c55e", "#10b981"]);
|
|
172
|
+
var BANNER = `
|
|
173
|
+
\u2588 \u2588 \u2588\u2580\u2580 \u2588 \u2588\u2580\u2588 \u2588\u2580\u2580 \u2588 \u2580\u2588\u2580 \u2588 \u2588
|
|
174
|
+
\u2580\u2584\u2580 \u2588\u2588\u2584 \u2588\u2584\u2584 \u2588\u2584\u2588 \u2588\u2584\u2584 \u2588 \u2588 \u2580\u2584\u2580
|
|
175
|
+
`;
|
|
176
|
+
function showBanner() {
|
|
177
|
+
console.log();
|
|
178
|
+
console.log(velocityGrad.multiline(BANNER));
|
|
179
|
+
console.log(pc.dim(" Astro + Tailwind v4 Starter Kit"));
|
|
180
|
+
console.log();
|
|
181
|
+
}
|
|
182
|
+
var symbols = {
|
|
183
|
+
rocket: "\u{1F680}",
|
|
184
|
+
sparkles: "\u2728",
|
|
185
|
+
package: "\u{1F4E6}",
|
|
186
|
+
check: figures.tick,
|
|
187
|
+
pointer: figures.pointer
|
|
188
|
+
};
|
|
189
|
+
function showSuccessBanner() {
|
|
190
|
+
console.log();
|
|
191
|
+
console.log(successGrad(" \u2728 Project created successfully! \u2728"));
|
|
192
|
+
console.log();
|
|
193
|
+
}
|
|
194
|
+
function velocityGradient(text2) {
|
|
195
|
+
return velocityGrad(text2);
|
|
196
|
+
}
|
|
197
|
+
|
|
166
198
|
// src/prompts.ts
|
|
167
199
|
function parsePageNames(input) {
|
|
168
200
|
if (!input.trim()) return [];
|
|
@@ -175,7 +207,7 @@ async function promptComponentMode() {
|
|
|
175
207
|
{
|
|
176
208
|
value: "all",
|
|
177
209
|
label: "All",
|
|
178
|
-
hint: "Include all
|
|
210
|
+
hint: "Include all 26 optional components"
|
|
179
211
|
},
|
|
180
212
|
{
|
|
181
213
|
value: "categories",
|
|
@@ -291,7 +323,7 @@ async function getComponentSelection(defaultSelection) {
|
|
|
291
323
|
const resolved = resolveDependencies(selection, registry);
|
|
292
324
|
const stats = getSelectionStats(resolved, registry);
|
|
293
325
|
p.log.info(
|
|
294
|
-
|
|
326
|
+
pc2.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)
|
|
295
327
|
);
|
|
296
328
|
return selection;
|
|
297
329
|
}
|
|
@@ -302,13 +334,13 @@ async function getComponentSelection(defaultSelection) {
|
|
|
302
334
|
const stats = getSelectionStats(resolved, registry);
|
|
303
335
|
if (resolved.components.length > components.length) {
|
|
304
336
|
p.log.info(
|
|
305
|
-
|
|
337
|
+
pc2.dim(
|
|
306
338
|
`Selected ${components.length} components + ${resolved.components.length - components.length} dependencies (${resolved.files.length} files)`
|
|
307
339
|
)
|
|
308
340
|
);
|
|
309
341
|
} else {
|
|
310
342
|
p.log.info(
|
|
311
|
-
|
|
343
|
+
pc2.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)
|
|
312
344
|
);
|
|
313
345
|
}
|
|
314
346
|
return selection;
|
|
@@ -449,28 +481,29 @@ async function runPrompts(defaults = {}) {
|
|
|
449
481
|
};
|
|
450
482
|
}
|
|
451
483
|
function showIntro() {
|
|
452
|
-
|
|
453
|
-
p.intro(pc.bgCyan(pc.black(" Create Velocity ")));
|
|
484
|
+
showBanner();
|
|
454
485
|
}
|
|
455
486
|
function showOutro(projectName, packageManager) {
|
|
456
487
|
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
);
|
|
464
|
-
|
|
488
|
+
showSuccessBanner();
|
|
489
|
+
console.log(pc2.bold(" Next steps:"));
|
|
490
|
+
console.log();
|
|
491
|
+
console.log(` ${pc2.dim("$")} ${pc2.cyan(`cd ${projectName}`)}`);
|
|
492
|
+
console.log(` ${pc2.dim("$")} ${pc2.cyan(`${runCmd} dev`)}`);
|
|
493
|
+
console.log();
|
|
494
|
+
console.log(` ${pc2.dim("Docs:")} ${pc2.cyan("https://docs.deployvelocity.com")}`);
|
|
495
|
+
console.log();
|
|
496
|
+
console.log(velocityGradient(" Happy building! \u{1F680}"));
|
|
497
|
+
console.log();
|
|
465
498
|
}
|
|
466
499
|
function showError(message) {
|
|
467
|
-
p.log.error(
|
|
500
|
+
p.log.error(pc2.red(message));
|
|
468
501
|
}
|
|
469
502
|
function showWarning(message) {
|
|
470
|
-
p.log.warn(
|
|
503
|
+
p.log.warn(pc2.yellow(message));
|
|
471
504
|
}
|
|
472
505
|
function showSuccess(message) {
|
|
473
|
-
p.log.success(
|
|
506
|
+
p.log.success(pc2.green(message));
|
|
474
507
|
}
|
|
475
508
|
|
|
476
509
|
// src/scaffold.ts
|
|
@@ -478,6 +511,7 @@ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, copyFi
|
|
|
478
511
|
import { join as join2, dirname as dirname2 } from "path";
|
|
479
512
|
import * as p2 from "@clack/prompts";
|
|
480
513
|
import { execa as execa2 } from "execa";
|
|
514
|
+
import pc3 from "picocolors";
|
|
481
515
|
import { downloadTemplate } from "giget";
|
|
482
516
|
|
|
483
517
|
// src/template.ts
|
|
@@ -593,18 +627,23 @@ function addI18nRouteEntry(targetDir, pageName) {
|
|
|
593
627
|
}
|
|
594
628
|
function addI18nTranslationKeys(targetDir, routeId, title) {
|
|
595
629
|
const locales = ["en", "es", "fr"];
|
|
630
|
+
const defaultLocale = "en";
|
|
596
631
|
for (const locale of locales) {
|
|
597
632
|
const translationPath = join(targetDir, "src", "i18n", "translations", `${locale}.ts`);
|
|
598
633
|
if (!existsSync2(translationPath)) {
|
|
599
634
|
continue;
|
|
600
635
|
}
|
|
601
636
|
let content = readFileSync(translationPath, "utf-8");
|
|
637
|
+
const isDefaultLocale = locale === defaultLocale;
|
|
638
|
+
const navLabel = isDefaultLocale ? title : `[TODO: Translate] ${title}`;
|
|
639
|
+
const pageTitle = isDefaultLocale ? title : `[TODO: Translate] ${title}`;
|
|
640
|
+
const pageDesc = isDefaultLocale ? `Add your ${title.toLowerCase()} page description here.` : `[TODO: Translate] Add your ${title.toLowerCase()} page description here.`;
|
|
602
641
|
if (!content.includes(`${routeId}:`)) {
|
|
603
642
|
const navSectionMatch = content.match(/nav:\s*\{([^}]+)\}/);
|
|
604
643
|
if (navSectionMatch) {
|
|
605
644
|
const navSection = navSectionMatch[0];
|
|
606
645
|
const insertPoint = navSection.lastIndexOf("}");
|
|
607
|
-
const newNavSection = navSection.slice(0, insertPoint) + ` ${routeId}: '${
|
|
646
|
+
const newNavSection = navSection.slice(0, insertPoint) + ` ${routeId}: '${navLabel}',
|
|
608
647
|
` + navSection.slice(insertPoint);
|
|
609
648
|
content = content.replace(navSection, newNavSection);
|
|
610
649
|
}
|
|
@@ -616,8 +655,8 @@ function addI18nTranslationKeys(targetDir, routeId, title) {
|
|
|
616
655
|
const pageTranslations = `
|
|
617
656
|
// ${title} page
|
|
618
657
|
${routeId}: {
|
|
619
|
-
title: '${
|
|
620
|
-
description: '
|
|
658
|
+
title: '${pageTitle}',
|
|
659
|
+
description: '${pageDesc}',
|
|
621
660
|
},
|
|
622
661
|
|
|
623
662
|
`;
|
|
@@ -657,6 +696,47 @@ import ${layoutName} from '@/layouts/${layoutName}.astro';
|
|
|
657
696
|
</${layoutName}>
|
|
658
697
|
`;
|
|
659
698
|
}
|
|
699
|
+
function generateI18nDefaultLocaleTemplate(pageName, layout) {
|
|
700
|
+
const title = toTitle(pageName);
|
|
701
|
+
const layoutName = layout === "landing" ? "LandingLayout" : "PageLayout";
|
|
702
|
+
const routeId = toRouteId(pageName);
|
|
703
|
+
const titleKey = `${routeId}.title`;
|
|
704
|
+
const descKey = `${routeId}.description`;
|
|
705
|
+
return `---
|
|
706
|
+
import ${layoutName} from '@/layouts/${layoutName}.astro';
|
|
707
|
+
import { defaultLocale } from '@/i18n/config';
|
|
708
|
+
import { useTranslations } from '@/i18n/index';
|
|
709
|
+
|
|
710
|
+
const t = useTranslations(defaultLocale);
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
<${layoutName}
|
|
714
|
+
title={t('${titleKey}') || '${title}'}
|
|
715
|
+
description={t('${descKey}') || 'Add your description here'}
|
|
716
|
+
lang={defaultLocale}
|
|
717
|
+
routeId="${routeId}"
|
|
718
|
+
>
|
|
719
|
+
<!-- Hero Section -->
|
|
720
|
+
<section class="py-20 bg-secondary">
|
|
721
|
+
<div class="container">
|
|
722
|
+
<h1 class="text-4xl font-bold text-foreground">
|
|
723
|
+
{t('${titleKey}') || '${title}'}
|
|
724
|
+
</h1>
|
|
725
|
+
<p class="mt-4 text-foreground-muted max-w-2xl">
|
|
726
|
+
{t('${descKey}') || 'Add your content here.'}
|
|
727
|
+
</p>
|
|
728
|
+
</div>
|
|
729
|
+
</section>
|
|
730
|
+
|
|
731
|
+
<!-- Content Section -->
|
|
732
|
+
<section class="py-16">
|
|
733
|
+
<div class="container">
|
|
734
|
+
<!-- Your content -->
|
|
735
|
+
</div>
|
|
736
|
+
</section>
|
|
737
|
+
</${layoutName}>
|
|
738
|
+
`;
|
|
739
|
+
}
|
|
660
740
|
function generateI18nPageTemplate(pageName, layout) {
|
|
661
741
|
const title = toTitle(pageName);
|
|
662
742
|
const layoutName = layout === "landing" ? "LandingLayout" : "PageLayout";
|
|
@@ -728,7 +808,7 @@ async function generatePages(targetDir, pages, layout, isI18n) {
|
|
|
728
808
|
}
|
|
729
809
|
for (const pageName of pages) {
|
|
730
810
|
const filePath = join(pagesDir, `${pageName}.astro`);
|
|
731
|
-
const template = generatePageTemplate(pageName, layout);
|
|
811
|
+
const template = isI18n ? generateI18nDefaultLocaleTemplate(pageName, layout) : generatePageTemplate(pageName, layout);
|
|
732
812
|
writeFileSync(filePath, template);
|
|
733
813
|
generatedFiles.push(`src/pages/${pageName}.astro`);
|
|
734
814
|
if (!isI18n) {
|
|
@@ -762,9 +842,8 @@ var CLEANUP_ITEMS = [
|
|
|
762
842
|
".git"
|
|
763
843
|
];
|
|
764
844
|
var DEMO_CONTENT = [
|
|
765
|
-
// Landing page components
|
|
845
|
+
// Landing page components (NOT hero - that's a core component)
|
|
766
846
|
"src/components/landing",
|
|
767
|
-
"src/components/hero",
|
|
768
847
|
// Landing-specific pages (base paths)
|
|
769
848
|
"src/pages/index.astro",
|
|
770
849
|
"src/pages/about.astro",
|
|
@@ -867,6 +946,16 @@ function applyI18nOverlay(targetDir) {
|
|
|
867
946
|
const i18nTemplate = getI18nTemplatePath();
|
|
868
947
|
copyTemplateFiles(i18nTemplate, targetDir);
|
|
869
948
|
}
|
|
949
|
+
function removeComponentsRoute(targetDir, isI18n) {
|
|
950
|
+
const routesPath = isI18n ? join2(targetDir, "src", "i18n", "routes.ts") : join2(targetDir, "src", "config", "routes.ts");
|
|
951
|
+
if (!existsSync3(routesPath)) return;
|
|
952
|
+
let content = readFileSync2(routesPath, "utf-8");
|
|
953
|
+
content = content.replace(
|
|
954
|
+
/\n\s*\/\/ Components showcase\n\s*components:\s*\{[^}]+\},?\n/g,
|
|
955
|
+
"\n"
|
|
956
|
+
);
|
|
957
|
+
writeFileSync2(routesPath, content);
|
|
958
|
+
}
|
|
870
959
|
function createContentDirectories(targetDir) {
|
|
871
960
|
const contentDirs = [
|
|
872
961
|
"src/content/blog"
|
|
@@ -948,6 +1037,7 @@ ${error instanceof Error ? error.message : ""}`
|
|
|
948
1037
|
removeItems(targetDir, DEMO_CONTENT);
|
|
949
1038
|
applyBaseTemplate(targetDir);
|
|
950
1039
|
createContentDirectories(targetDir);
|
|
1040
|
+
removeComponentsRoute(targetDir, i18n);
|
|
951
1041
|
spinner2.stop("Minimal template configured");
|
|
952
1042
|
}
|
|
953
1043
|
if (pages.length > 0) {
|
|
@@ -955,6 +1045,16 @@ ${error instanceof Error ? error.message : ""}`
|
|
|
955
1045
|
try {
|
|
956
1046
|
const generatedFiles = await generatePages(targetDir, pages, pageLayout, i18n);
|
|
957
1047
|
spinner2.stop(`Generated ${generatedFiles.length} page file${generatedFiles.length > 1 ? "s" : ""}`);
|
|
1048
|
+
if (i18n) {
|
|
1049
|
+
showWarning(`i18n pages created with English-only content.
|
|
1050
|
+
|
|
1051
|
+
You must manually:
|
|
1052
|
+
1. Translate URL slugs in src/i18n/routes.ts
|
|
1053
|
+
2. Add translations to src/i18n/translations/es.ts
|
|
1054
|
+
3. Add translations to src/i18n/translations/fr.ts
|
|
1055
|
+
|
|
1056
|
+
Look for [TODO: Translate] markers in the translation files.`);
|
|
1057
|
+
}
|
|
958
1058
|
} catch (error) {
|
|
959
1059
|
spinner2.stop("Failed to generate pages");
|
|
960
1060
|
throw error;
|
|
@@ -975,15 +1075,32 @@ ${error instanceof Error ? error.message : ""}`
|
|
|
975
1075
|
} else {
|
|
976
1076
|
spinner2.stop("Git not available, skipping");
|
|
977
1077
|
}
|
|
978
|
-
|
|
1078
|
+
console.log();
|
|
1079
|
+
p2.log.step(`Installing dependencies with ${packageManager}...`);
|
|
1080
|
+
console.log(pc3.dim("\u2500".repeat(50)));
|
|
979
1081
|
try {
|
|
980
1082
|
const installCmd = getInstallCommand(packageManager);
|
|
981
1083
|
const [cmd, ...args] = installCmd.split(" ");
|
|
982
|
-
await execa2(cmd, args, {
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1084
|
+
await execa2(cmd, args, {
|
|
1085
|
+
cwd: targetDir,
|
|
1086
|
+
stdio: "inherit",
|
|
1087
|
+
// Stream output to terminal
|
|
1088
|
+
shell: process.platform === "win32"
|
|
1089
|
+
// Windows compatibility
|
|
1090
|
+
});
|
|
1091
|
+
console.log(pc3.dim("\u2500".repeat(50)));
|
|
1092
|
+
showSuccess("Dependencies installed");
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
console.log(pc3.dim("\u2500".repeat(50)));
|
|
1095
|
+
showWarning("Failed to install dependencies");
|
|
1096
|
+
const execaError = error;
|
|
1097
|
+
if (execaError.message) {
|
|
1098
|
+
console.log(pc3.dim(`
|
|
1099
|
+
Error: ${execaError.message}`));
|
|
1100
|
+
}
|
|
1101
|
+
console.log();
|
|
1102
|
+
console.log(pc3.yellow("To install manually, run:"));
|
|
1103
|
+
console.log(` ${pc3.cyan(getInstallCommand(packageManager))}`);
|
|
987
1104
|
}
|
|
988
1105
|
showSuccess(`Project "${projectName}" created successfully!`);
|
|
989
1106
|
}
|
|
@@ -999,15 +1116,15 @@ function isEmptyDir(path) {
|
|
|
999
1116
|
|
|
1000
1117
|
// src/cli.ts
|
|
1001
1118
|
var HELP_TEXT = `
|
|
1002
|
-
${
|
|
1119
|
+
${pc4.bold("create-velocity-astro")} - Create a new Velocity project
|
|
1003
1120
|
|
|
1004
|
-
${
|
|
1121
|
+
${pc4.bold("Usage:")}
|
|
1005
1122
|
npm create velocity-astro@latest [project-name] [options]
|
|
1006
1123
|
pnpm create velocity-astro [project-name] [options]
|
|
1007
1124
|
yarn create velocity-astro [project-name] [options]
|
|
1008
1125
|
bun create velocity-astro [project-name] [options]
|
|
1009
1126
|
|
|
1010
|
-
${
|
|
1127
|
+
${pc4.bold("Options:")}
|
|
1011
1128
|
--demo Include demo landing page and sample content
|
|
1012
1129
|
--components Include all components (default: prompt for selection)
|
|
1013
1130
|
--components=none Exclude all components
|
|
@@ -1018,12 +1135,12 @@ ${pc2.bold("Options:")}
|
|
|
1018
1135
|
--help, -h Show this help message
|
|
1019
1136
|
--version, -v Show version number
|
|
1020
1137
|
|
|
1021
|
-
${
|
|
1138
|
+
${pc4.bold("Component Categories:")}
|
|
1022
1139
|
ui UI components (buttons, forms, cards, dialogs) - 20 components
|
|
1023
1140
|
patterns Form patterns (contact form, newsletter) - 3 components
|
|
1024
1141
|
hero Flexible hero section component - 1 component
|
|
1025
1142
|
|
|
1026
|
-
${
|
|
1143
|
+
${pc4.bold("Examples:")}
|
|
1027
1144
|
npm create velocity-astro@latest my-site
|
|
1028
1145
|
npm create velocity-astro@latest my-site --demo --components
|
|
1029
1146
|
npm create velocity-astro@latest my-site --components=ui,patterns
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/prompts.ts","../src/utils/validate.ts","../src/utils/package-manager.ts","../src/registry/fetcher.ts","../src/registry/resolver.ts","../src/scaffold.ts","../src/template.ts","../src/utils/git.ts","../src/features/pages.ts","../src/utils/fs.ts","../src/index.ts"],"sourcesContent":["import mri from 'mri';\nimport { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { CliOptions } from './types.js';\nimport type { ComponentSelection } from './registry/types.js';\nimport { runPrompts, showIntro, showOutro, showError } from './prompts.js';\nimport { scaffold } from './scaffold.js';\nimport { isEmptyDir } from './utils/fs.js';\nimport { toValidProjectName } from './utils/validate.js';\n\nconst HELP_TEXT = `\n${pc.bold('create-velocity-astro')} - Create a new Velocity project\n\n${pc.bold('Usage:')}\n npm create velocity-astro@latest [project-name] [options]\n pnpm create velocity-astro [project-name] [options]\n yarn create velocity-astro [project-name] [options]\n bun create velocity-astro [project-name] [options]\n\n${pc.bold('Options:')}\n --demo Include demo landing page and sample content\n --components Include all components (default: prompt for selection)\n --components=none Exclude all components\n --components=ui,patterns Include specific categories\n --i18n Add internationalization support\n --pages Prompt for starter pages to generate\n --yes, -y Skip prompts and use defaults\n --help, -h Show this help message\n --version, -v Show version number\n\n${pc.bold('Component Categories:')}\n ui UI components (buttons, forms, cards, dialogs) - 20 components\n patterns Form patterns (contact form, newsletter) - 3 components\n hero Flexible hero section component - 1 component\n\n${pc.bold('Examples:')}\n npm create velocity-astro@latest my-site\n npm create velocity-astro@latest my-site --demo --components\n npm create velocity-astro@latest my-site --components=ui,patterns\n npm create velocity-astro@latest my-site --components=none\n npm create velocity-astro@latest my-site --i18n --pages\n pnpm create velocity-astro my-site -y\n`;\n\nconst VERSION = '1.4.2';\n\n/**\n * Parses the --components flag into a ComponentSelection\n */\nfunction parseComponentsFlag(value: string | boolean | undefined): ComponentSelection | undefined {\n // Not specified - will prompt user\n if (value === undefined) {\n return undefined;\n }\n\n // --components (boolean true) - include all\n if (value === true) {\n return { mode: 'all' };\n }\n\n // --components=false or explicit false\n if (value === false) {\n return { mode: 'none' };\n }\n\n // --components=none\n if (value === 'none' || value === 'false') {\n return { mode: 'none' };\n }\n\n // --components=all\n if (value === 'all' || value === 'true') {\n return { mode: 'all' };\n }\n\n // --components=ui,patterns,hero (category list)\n const categories = value.split(',').map((s) => s.trim().toLowerCase());\n const validCategories = ['ui', 'patterns', 'hero'];\n const filtered = categories.filter((c) => validCategories.includes(c));\n\n if (filtered.length === 0) {\n return { mode: 'all' }; // Fall back to all if no valid categories\n }\n\n return { mode: 'categories', categories: filtered };\n}\n\nexport async function run(argv: string[]): Promise<void> {\n const args = mri<CliOptions>(argv, {\n boolean: ['demo', 'i18n', 'pages', 'help', 'version', 'yes'],\n string: ['components'],\n alias: {\n h: 'help',\n v: 'version',\n y: 'yes',\n },\n });\n\n // Handle help\n if (args.help) {\n console.log(HELP_TEXT);\n return;\n }\n\n // Handle version\n if (args.version) {\n console.log(VERSION);\n return;\n }\n\n showIntro();\n\n // Get project name from args or prompt\n const argProjectName = args._[0] as string | undefined;\n\n // Parse component selection from CLI\n const componentSelection = parseComponentsFlag(args.components);\n\n // Skip prompts mode\n if (args.yes) {\n const projectName = toValidProjectName(argProjectName || 'my-velocity-site');\n const targetDir = resolve(process.cwd(), projectName);\n\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n showError(`Directory \"${projectName}\" already exists and is not empty.`);\n process.exit(1);\n }\n\n await scaffold({\n projectName,\n targetDir,\n demo: args.demo || false,\n componentSelection: componentSelection || { mode: 'all' },\n i18n: args.i18n || false,\n pages: [],\n pageLayout: 'page',\n packageManager: 'pnpm',\n });\n\n showOutro(projectName, 'pnpm');\n return;\n }\n\n // Interactive mode\n const answers = await runPrompts({\n projectName: argProjectName,\n demo: args.demo,\n componentSelection: componentSelection,\n i18n: args.i18n,\n pages: args.pages,\n });\n\n // User cancelled\n if (typeof answers === 'symbol') {\n return;\n }\n\n const { projectName, demo, componentSelection: selectedComponents, i18n, pages, pageLayout, packageManager } = answers;\n const targetDir = resolve(process.cwd(), projectName);\n\n // Check if directory exists and is not empty\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n const shouldOverwrite = await p.confirm({\n message: `Directory \"${projectName}\" already exists. Continue and overwrite?`,\n initialValue: false,\n });\n\n if (!shouldOverwrite || p.isCancel(shouldOverwrite)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n }\n\n // Run scaffold\n try {\n await scaffold({\n projectName,\n targetDir,\n demo,\n componentSelection: selectedComponents,\n i18n,\n pages,\n pageLayout,\n packageManager,\n });\n\n showOutro(projectName, packageManager);\n } catch (error) {\n showError(error instanceof Error ? error.message : 'An unexpected error occurred');\n process.exit(1);\n }\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { PackageManager, PageLayout, PromptAnswers } from './types.js';\nimport type { ComponentSelection, ComponentRegistry, ComponentSelectionMode } from './registry/types.js';\nimport { validateProjectName, toValidProjectName } from './utils/validate.js';\nimport { detectPackageManager } from './utils/package-manager.js';\nimport { fetchRegistry } from './registry/fetcher.js';\nimport { getComponentsByCategory, resolveDependencies, getSelectionStats } from './registry/resolver.js';\n\ninterface PromptDefaults {\n projectName?: string;\n demo?: boolean;\n componentSelection?: ComponentSelection;\n i18n?: boolean;\n pages?: boolean;\n}\n\n/**\n * Parses comma-separated page names into an array of valid page slugs\n */\nfunction parsePageNames(input: string): string[] {\n if (!input.trim()) return [];\n\n return input\n .split(',')\n .map((name) => name.trim().toLowerCase())\n .filter((name) => name.length > 0)\n .map((name) => name.replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''))\n .filter((name) => name.length > 0 && !['index', 'blog', '404', 'rss'].includes(name));\n}\n\n/**\n * Prompts user for component selection mode\n */\nasync function promptComponentMode(): Promise<ComponentSelectionMode> {\n const result = await p.select({\n message: 'Include optional components?',\n options: [\n {\n value: 'all' as ComponentSelectionMode,\n label: 'All',\n hint: 'Include all 24 optional components',\n },\n {\n value: 'categories' as ComponentSelectionMode,\n label: 'Select categories',\n hint: 'Choose component groups',\n },\n {\n value: 'individual' as ComponentSelectionMode,\n label: 'Select individual',\n hint: 'Pick specific components',\n },\n {\n value: 'none' as ComponentSelectionMode,\n label: 'None',\n hint: 'Minimal template',\n },\n ],\n initialValue: 'all' as ComponentSelectionMode,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result;\n}\n\n/**\n * Prompts user to select component categories\n */\nasync function promptCategories(registry: ComponentRegistry): Promise<string[]> {\n const categoryOptions = Object.entries(registry.categories).map(([id, cat]) => {\n const componentCount = getComponentsByCategory(id, registry).length;\n return {\n value: id,\n label: cat.name,\n hint: `${componentCount} components - ${cat.description}`,\n };\n });\n\n const result = await p.multiselect({\n message: 'Select component categories:',\n options: categoryOptions,\n required: true,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result as string[];\n}\n\n/**\n * Prompts user to select individual components\n */\nasync function promptComponents(registry: ComponentRegistry): Promise<string[]> {\n // Group components by category for better UX\n const componentsByCategory: Record<string, { value: string; label: string; hint: string }[]> = {};\n\n for (const [id, comp] of Object.entries(registry.components)) {\n if (!componentsByCategory[comp.category]) {\n componentsByCategory[comp.category] = [];\n }\n const depCount = comp.dependencies.components.length;\n const depHint = depCount > 0 ? ` (requires ${depCount} dep${depCount > 1 ? 's' : ''})` : '';\n const categoryName = registry.categories[comp.category]?.name ?? comp.category;\n componentsByCategory[comp.category]!.push({\n value: id,\n label: comp.name,\n hint: `${categoryName}${depHint}`,\n });\n }\n\n // Flatten into options with category headers\n const options: { value: string; label: string; hint?: string }[] = [];\n for (const [categoryId, components] of Object.entries(componentsByCategory)) {\n const categoryName = registry.categories[categoryId]?.name || categoryId;\n // Add all components from this category\n for (const comp of components) {\n options.push({\n ...comp,\n hint: categoryName,\n });\n }\n }\n\n const result = await p.multiselect({\n message: 'Select components (dependencies auto-included):',\n options,\n required: true,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result as string[];\n}\n\n/**\n * Gets component selection from user prompts\n */\nasync function getComponentSelection(\n defaultSelection?: ComponentSelection\n): Promise<ComponentSelection> {\n if (defaultSelection) {\n return defaultSelection;\n }\n\n let registry: ComponentRegistry;\n try {\n registry = await fetchRegistry();\n } catch {\n // Fallback to simple yes/no if registry unavailable\n const useComponents = await p.select({\n message: 'Include UI component library?',\n options: [\n { value: true, label: 'Yes', hint: 'Buttons, forms, cards, dialogs, etc.' },\n { value: false, label: 'No', hint: 'Just the basics' },\n ],\n initialValue: true,\n });\n\n if (p.isCancel(useComponents)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return { mode: useComponents ? 'all' : 'none' };\n }\n\n const mode = await promptComponentMode();\n\n switch (mode) {\n case 'none':\n return { mode: 'none' };\n\n case 'all':\n return { mode: 'all' };\n\n case 'categories': {\n const categories = await promptCategories(registry);\n // Show what will be included\n const selection: ComponentSelection = { mode: 'categories', categories };\n const resolved = resolveDependencies(selection, registry);\n const stats = getSelectionStats(resolved, registry);\n p.log.info(\n pc.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)\n );\n return selection;\n }\n\n case 'individual': {\n const components = await promptComponents(registry);\n // Show what will be included (with dependencies)\n const selection: ComponentSelection = { mode: 'individual', components };\n const resolved = resolveDependencies(selection, registry);\n const stats = getSelectionStats(resolved, registry);\n if (resolved.components.length > components.length) {\n p.log.info(\n pc.dim(\n `Selected ${components.length} components + ${resolved.components.length - components.length} dependencies (${resolved.files.length} files)`\n )\n );\n } else {\n p.log.info(\n pc.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)\n );\n }\n return selection;\n }\n }\n}\n\nexport async function runPrompts(defaults: PromptDefaults = {}): Promise<PromptAnswers | symbol> {\n const detectedPm = detectPackageManager();\n\n const answers = await p.group(\n {\n projectName: () =>\n p.text({\n message: 'What is your project name?',\n placeholder: defaults.projectName || 'my-velocity-site',\n defaultValue: defaults.projectName,\n validate: (value) => {\n const name = value || defaults.projectName || 'my-velocity-site';\n const result = validateProjectName(toValidProjectName(name));\n if (!result.valid) return result.message;\n },\n }),\n\n demo:\n defaults.demo !== undefined\n ? () => Promise.resolve(defaults.demo)\n : () =>\n p.select({\n message: 'Include demo landing page and sample content?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Minimal starter with basic pages',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Full demo with landing page, blog posts',\n },\n ],\n initialValue: false,\n }),\n\n componentSelection: () => getComponentSelection(defaults.componentSelection),\n\n i18n:\n defaults.i18n !== undefined\n ? () => Promise.resolve(defaults.i18n)\n : () =>\n p.select({\n message: 'Add internationalization (i18n)?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'English only',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Locale routing, translations',\n },\n ],\n initialValue: false,\n }),\n\n generatePages:\n defaults.pages !== undefined\n ? () => Promise.resolve(defaults.pages)\n : () =>\n p.select({\n message: 'Generate starter pages?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Create pages manually later',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Auto-generate page files with layout',\n },\n ],\n initialValue: false,\n }),\n\n pageNames: ({ results }) =>\n results.generatePages\n ? p.text({\n message: 'Enter page names (comma-separated):',\n placeholder: 'about, pricing, faq, contact',\n validate: (value) => {\n const pages = parsePageNames(value);\n if (pages.length === 0) {\n return 'Please enter at least one valid page name';\n }\n },\n })\n : Promise.resolve(''),\n\n pageLayout: ({ results }) =>\n results.generatePages\n ? results.demo\n ? p.select({\n message: 'Select layout for pages:',\n options: [\n {\n value: 'page' as PageLayout,\n label: 'PageLayout',\n hint: 'Standard content pages (Header + Footer)',\n },\n {\n value: 'landing' as PageLayout,\n label: 'LandingLayout',\n hint: 'Marketing pages (Navbar + LandingFooter)',\n },\n ],\n initialValue: 'page' as PageLayout,\n })\n : Promise.resolve('page' as PageLayout) // Force PageLayout when demo=No\n : Promise.resolve('page' as PageLayout),\n\n packageManager: () =>\n p.select({\n message: 'Which package manager?',\n options: [\n {\n value: 'pnpm' as PackageManager,\n label: 'pnpm',\n hint: detectedPm === 'pnpm' ? 'detected' : 'recommended',\n },\n {\n value: 'npm' as PackageManager,\n label: 'npm',\n hint: detectedPm === 'npm' ? 'detected' : undefined,\n },\n {\n value: 'yarn' as PackageManager,\n label: 'yarn',\n hint: detectedPm === 'yarn' ? 'detected' : undefined,\n },\n {\n value: 'bun' as PackageManager,\n label: 'bun',\n hint: detectedPm === 'bun' ? 'detected' : undefined,\n },\n ],\n initialValue: detectedPm,\n }),\n },\n {\n onCancel: () => {\n p.cancel('Operation cancelled.');\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: toValidProjectName(answers.projectName || defaults.projectName || 'my-velocity-site'),\n demo: answers.demo as boolean,\n componentSelection: answers.componentSelection as ComponentSelection,\n i18n: answers.i18n as boolean,\n pages: parsePageNames(answers.pageNames as string),\n pageLayout: (answers.pageLayout as PageLayout) || 'page',\n packageManager: answers.packageManager as PackageManager,\n };\n}\n\nexport function showIntro(): void {\n console.log();\n p.intro(pc.bgCyan(pc.black(' Create Velocity ')));\n}\n\nexport function showOutro(projectName: string, packageManager: PackageManager): void {\n const runCmd = packageManager === 'npm' ? 'npm run' : packageManager;\n\n p.note(\n [\n `cd ${projectName}`,\n `${runCmd} dev`,\n ].join('\\n'),\n 'Next steps'\n );\n\n p.outro(pc.green('Happy building!'));\n}\n\nexport function showError(message: string): void {\n p.log.error(pc.red(message));\n}\n\nexport function showWarning(message: string): void {\n p.log.warn(pc.yellow(message));\n}\n\nexport function showSuccess(message: string): void {\n p.log.success(pc.green(message));\n}\n\nexport function showStep(message: string): void {\n p.log.step(message);\n}\n","/**\n * Validates a project name for npm package naming conventions\n */\nexport function validateProjectName(name: string): { valid: boolean; message?: string } {\n if (!name || name.trim() === '') {\n return { valid: false, message: 'Project name cannot be empty' };\n }\n\n // Must be lowercase\n if (name !== name.toLowerCase()) {\n return { valid: false, message: 'Project name must be lowercase' };\n }\n\n // Cannot start with . or _\n if (name.startsWith('.') || name.startsWith('_')) {\n return { valid: false, message: 'Project name cannot start with . or _' };\n }\n\n // Cannot contain spaces\n if (/\\s/.test(name)) {\n return { valid: false, message: 'Project name cannot contain spaces' };\n }\n\n // Cannot contain special characters except - and @/\n if (!/^(@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) {\n return {\n valid: false,\n message: 'Project name can only contain lowercase letters, numbers, hyphens, and underscores',\n };\n }\n\n // Length check\n if (name.length > 214) {\n return { valid: false, message: 'Project name must be 214 characters or fewer' };\n }\n\n return { valid: true };\n}\n\n/**\n * Sanitizes a string to be a valid project name\n */\nexport function toValidProjectName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-_~.]/g, '-')\n .replace(/^[-._]+/, '')\n .replace(/[-._]+$/, '')\n .replace(/-+/g, '-');\n}\n","import type { PackageManager } from '../types.js';\n\n/**\n * Detects the package manager used to run this command\n */\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent || '';\n\n if (userAgent.startsWith('pnpm')) return 'pnpm';\n if (userAgent.startsWith('yarn')) return 'yarn';\n if (userAgent.startsWith('bun')) return 'bun';\n return 'npm';\n}\n\n/**\n * Gets the install command for a package manager\n */\nexport function getInstallCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm install';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun install';\n case 'npm':\n default:\n return 'npm install';\n }\n}\n\n/**\n * Gets the run command for a package manager\n */\nexport function getRunCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun';\n case 'npm':\n default:\n return 'npm run';\n }\n}\n","/**\n * Registry Fetcher\n * Fetches the component registry from GitHub\n */\n\nimport type { ComponentRegistry } from './types.js';\n\nconst REGISTRY_URL = 'https://raw.githubusercontent.com/southwellmedia/velocity/main/component-registry.json';\n\nlet cachedRegistry: ComponentRegistry | null = null;\n\n/**\n * Fetches the component registry from GitHub\n * Results are cached for the duration of the process\n */\nexport async function fetchRegistry(): Promise<ComponentRegistry> {\n if (cachedRegistry) {\n return cachedRegistry;\n }\n\n try {\n const response = await fetch(REGISTRY_URL);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch registry: ${response.status} ${response.statusText}`);\n }\n\n cachedRegistry = await response.json() as ComponentRegistry;\n return cachedRegistry;\n } catch (error) {\n throw new Error(\n `Could not fetch component registry. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n}\n\n/**\n * Fetches a single file from the velocity repository\n */\nexport async function fetchComponentFile(filePath: string): Promise<string> {\n const url = `https://raw.githubusercontent.com/southwellmedia/velocity/main/${filePath}`;\n\n try {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n } catch (error) {\n throw new Error(\n `Could not fetch file: ${filePath}\\n${error instanceof Error ? error.message : ''}`\n );\n }\n}\n\n/**\n * Clears the cached registry\n */\nexport function clearRegistryCache(): void {\n cachedRegistry = null;\n}\n","/**\n * Dependency Resolver\n * Resolves component dependencies and collects all required files\n */\n\nimport type { ComponentRegistry, ComponentSelection, ResolvedComponents } from './types.js';\n\n/**\n * Resolves dependencies for requested components\n * Returns all components, utilities, files, and npm packages needed\n */\nexport function resolveDependencies(\n selection: ComponentSelection,\n registry: ComponentRegistry\n): ResolvedComponents {\n const resolved = new Set<string>();\n const utilities = new Set<string>();\n const files = new Set<string>();\n const npmPackages = new Set<string>();\n\n // Handle different selection modes\n let requestedComponents: string[] = [];\n\n switch (selection.mode) {\n case 'none':\n return { components: [], utilities: [], files: [], npmPackages: [] };\n\n case 'all':\n requestedComponents = Object.keys(registry.components);\n break;\n\n case 'categories':\n if (selection.categories) {\n requestedComponents = Object.entries(registry.components)\n .filter(([, comp]) => selection.categories!.includes(comp.category))\n .map(([id]) => id);\n }\n break;\n\n case 'individual':\n requestedComponents = selection.components || [];\n break;\n }\n\n // Recursively resolve each component's dependencies\n function resolve(componentId: string): void {\n if (resolved.has(componentId)) return;\n\n const component = registry.components[componentId];\n if (!component) {\n console.warn(`Component not found: ${componentId}`);\n return;\n }\n\n // Resolve component dependencies first (recursive)\n for (const dep of component.dependencies.components) {\n resolve(dep);\n }\n\n // Collect utilities\n for (const util of component.dependencies.utilities) {\n utilities.add(util);\n }\n\n // Collect files\n for (const file of component.files) {\n files.add(file);\n }\n\n resolved.add(componentId);\n }\n\n // Resolve all requested components\n for (const componentId of requestedComponents) {\n resolve(componentId);\n }\n\n // Collect utility files and npm packages\n for (const utilId of utilities) {\n const utility = registry.utilities[utilId];\n if (utility) {\n for (const file of utility.files) {\n files.add(file);\n }\n for (const pkg of utility.npm) {\n npmPackages.add(pkg);\n }\n }\n }\n\n return {\n components: [...resolved],\n utilities: [...utilities],\n files: [...files],\n npmPackages: [...npmPackages],\n };\n}\n\n/**\n * Gets all components in a category\n */\nexport function getComponentsByCategory(\n categoryId: string,\n registry: ComponentRegistry\n): string[] {\n return Object.entries(registry.components)\n .filter(([, comp]) => comp.category === categoryId)\n .map(([id]) => id);\n}\n\n/**\n * Gets the dependency tree for a component (for visualization)\n */\nexport function getDependencyTree(\n componentId: string,\n registry: ComponentRegistry,\n visited = new Set<string>()\n): { id: string; name: string; deps: ReturnType<typeof getDependencyTree>[] } | null {\n if (visited.has(componentId)) return null;\n visited.add(componentId);\n\n const component = registry.components[componentId];\n if (!component) return null;\n\n const deps = component.dependencies.components\n .map((dep) => getDependencyTree(dep, registry, visited))\n .filter((d): d is NonNullable<typeof d> => d !== null);\n\n return {\n id: componentId,\n name: component.name,\n deps,\n };\n}\n\n/**\n * Validates that all components exist in the registry\n */\nexport function validateComponents(\n componentIds: string[],\n registry: ComponentRegistry\n): { valid: boolean; invalid: string[] } {\n const invalid = componentIds.filter((id) => !registry.components[id]);\n return {\n valid: invalid.length === 0,\n invalid,\n };\n}\n\n/**\n * Validates that all categories exist in the registry\n */\nexport function validateCategories(\n categoryIds: string[],\n registry: ComponentRegistry\n): { valid: boolean; invalid: string[] } {\n const invalid = categoryIds.filter((id) => !registry.categories[id]);\n return {\n valid: invalid.length === 0,\n invalid,\n };\n}\n\n/**\n * Gets summary stats for a component selection\n */\nexport function getSelectionStats(\n resolved: ResolvedComponents,\n registry: ComponentRegistry\n): { componentCount: number; fileCount: number; categories: string[] } {\n const categories = new Set<string>();\n\n for (const componentId of resolved.components) {\n const component = registry.components[componentId];\n if (component) {\n categories.add(component.category);\n }\n }\n\n return {\n componentCount: resolved.components.length,\n fileCount: resolved.files.length,\n categories: [...categories],\n };\n}\n","import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync, rmSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport * as p from '@clack/prompts';\nimport { execa } from 'execa';\nimport { downloadTemplate } from 'giget';\nimport type { ScaffoldOptions } from './types.js';\nimport type { ComponentSelection, ResolvedComponents } from './registry/types.js';\nimport { getI18nTemplatePath, getBaseTemplatePath } from './template.js';\nimport { getInstallCommand } from './utils/package-manager.js';\nimport { initGit } from './utils/git.js';\nimport { showSuccess, showWarning } from './prompts.js';\nimport { generatePages } from './features/pages.js';\nimport { fetchRegistry } from './registry/fetcher.js';\nimport { resolveDependencies } from './registry/resolver.js';\n\n// GitHub repository for the Velocity template\nconst TEMPLATE_REPO = 'github:southwellmedia/velocity';\n\n// Files/directories to remove after download\nconst CLEANUP_ITEMS = [\n 'pnpm-lock.yaml',\n 'package-lock.json',\n 'yarn.lock',\n 'bun.lockb',\n '.git',\n];\n\n// Demo-specific content to remove when --demo is false\n// Includes both base paths and i18n paths to handle all scenarios\nconst DEMO_CONTENT = [\n // Landing page components\n 'src/components/landing',\n 'src/components/hero',\n // Landing-specific pages (base paths)\n 'src/pages/index.astro',\n 'src/pages/about.astro',\n 'src/pages/contact.astro',\n 'src/pages/components.astro',\n // Landing-specific pages (i18n paths)\n 'src/pages/[lang]/index.astro',\n 'src/pages/[lang]/[...about].astro',\n 'src/pages/[lang]/[...contact].astro',\n 'src/pages/[lang]/[...components].astro',\n // Landing layout (depends on Navbar from landing components)\n 'src/layouts/LandingLayout.astro',\n // Demo content\n 'src/content/blog',\n 'src/content/faqs',\n 'src/content/authors',\n 'src/content/pages',\n];\n\n// Optional component directories (for removal when mode='none')\n// Note: layout, seo, landing, blog are core template - not optional\nconst OPTIONAL_COMPONENT_DIRS = [\n 'src/components/ui',\n 'src/components/patterns',\n 'src/components/hero',\n];\n\n/**\n * Copies template files recursively\n */\nfunction copyTemplateFiles(src: string, dest: string): void {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyTemplateFiles(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * Removes files/directories from the target\n */\nfunction removeItems(targetDir: string, items: string[]): void {\n for (const item of items) {\n const itemPath = join(targetDir, item);\n if (existsSync(itemPath)) {\n try {\n rmSync(itemPath, { recursive: true, force: true });\n } catch {\n // Ignore errors - item may not exist or be locked\n }\n }\n }\n}\n\n/**\n * Keeps only specified files, removes everything else in optional component directories\n */\nfunction keepOnlyFiles(targetDir: string, filesToKeep: Set<string>): void {\n // Only filter optional component directories - core template dirs are untouched\n const componentDirs = [\n 'src/components/ui',\n 'src/components/patterns',\n 'src/components/hero',\n ];\n\n for (const dir of componentDirs) {\n const dirPath = join(targetDir, dir);\n if (!existsSync(dirPath)) continue;\n\n const entries = readdirSync(dirPath, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n const relativePath = `${dir}/${entry.name}`;\n if (!filesToKeep.has(relativePath)) {\n try {\n rmSync(join(dirPath, entry.name), { force: true });\n } catch {\n // Ignore errors\n }\n }\n }\n }\n\n // Remove empty directories\n try {\n const remaining = readdirSync(dirPath);\n if (remaining.length === 0) {\n rmSync(dirPath, { recursive: true, force: true });\n }\n } catch {\n // Ignore errors\n }\n }\n}\n\n/**\n * Updates the package.json with the new project name\n */\nfunction updatePackageJson(targetDir: string, projectName: string): void {\n const pkgPath = join(targetDir, 'package.json');\n\n if (!existsSync(pkgPath)) {\n throw new Error('package.json not found in template');\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n pkg.name = projectName;\n pkg.version = '0.1.0';\n delete pkg.repository;\n delete pkg.bugs;\n delete pkg.homepage;\n\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\n/**\n * Applies base template (minimal pages) when demo is not selected\n */\nfunction applyBaseTemplate(targetDir: string): void {\n const baseTemplate = getBaseTemplatePath();\n if (existsSync(baseTemplate)) {\n copyTemplateFiles(baseTemplate, targetDir);\n }\n}\n\n/**\n * Applies the i18n overlay to the project\n */\nfunction applyI18nOverlay(targetDir: string): void {\n const i18nTemplate = getI18nTemplatePath();\n copyTemplateFiles(i18nTemplate, targetDir);\n}\n\n/**\n * Creates empty content directories with .gitkeep files\n */\nfunction createContentDirectories(targetDir: string): void {\n const contentDirs = [\n 'src/content/blog',\n ];\n\n for (const dir of contentDirs) {\n const dirPath = join(targetDir, dir);\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n writeFileSync(join(dirPath, '.gitkeep'), '');\n }\n }\n}\n\n/**\n * Applies selective component filtering based on registry resolution\n */\nasync function applyComponentSelection(\n targetDir: string,\n selection: ComponentSelection\n): Promise<void> {\n // Handle 'all' mode - keep everything\n if (selection.mode === 'all') {\n return;\n }\n\n // Handle 'none' mode - remove optional components only\n if (selection.mode === 'none') {\n removeItems(targetDir, OPTIONAL_COMPONENT_DIRS);\n return;\n }\n\n // For 'categories' and 'individual' modes, we need the registry\n let resolved: ResolvedComponents;\n try {\n const registry = await fetchRegistry();\n resolved = resolveDependencies(selection, registry);\n } catch {\n // If registry fetch fails, fall back to keeping all components\n console.warn('Could not fetch component registry, keeping all components');\n return;\n }\n\n // Create set of files to keep\n const filesToKeep = new Set(resolved.files);\n\n // Keep only the resolved files\n keepOnlyFiles(targetDir, filesToKeep);\n\n // Ensure utility files are present if needed\n if (resolved.utilities.includes('cn')) {\n const cnPath = join(targetDir, 'src/lib/cn.ts');\n const cnDir = dirname(cnPath);\n if (!existsSync(cnDir)) {\n mkdirSync(cnDir, { recursive: true });\n }\n }\n}\n\n/**\n * Main scaffold function\n *\n * IMPORTANT: Step order matters for option combinations\n * - i18n overlay is applied BEFORE demo removal\n * - This ensures demo=Yes + i18n=Yes gets full translated demo\n * - And demo=No + i18n=Yes gets i18n routing without demo pages\n */\nexport async function scaffold(options: ScaffoldOptions): Promise<void> {\n const { projectName, targetDir, demo, componentSelection, i18n, pages, pageLayout, packageManager } = options;\n const spinner = p.spinner();\n\n // Step 1: Download base template from GitHub\n spinner.start('Downloading template from GitHub...');\n\n try {\n await downloadTemplate(TEMPLATE_REPO, {\n dir: targetDir,\n force: true,\n });\n removeItems(targetDir, CLEANUP_ITEMS);\n spinner.stop('Template downloaded');\n } catch (error) {\n spinner.stop('Failed to download template');\n throw new Error(\n `Could not download template from GitHub. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n\n // Step 2: Apply component selection\n if (componentSelection.mode !== 'all') {\n spinner.start('Configuring components...');\n try {\n await applyComponentSelection(targetDir, componentSelection);\n spinner.stop('Components configured');\n } catch (error) {\n spinner.stop('Failed to configure components');\n throw error;\n }\n }\n\n // Step 3: Apply i18n overlay if requested (BEFORE demo removal)\n // This ensures demo=Yes + i18n=Yes gets translated demo pages\n if (i18n) {\n spinner.start('Adding i18n support...');\n try {\n applyI18nOverlay(targetDir);\n spinner.stop('i18n support added');\n } catch (error) {\n spinner.stop('Failed to add i18n support');\n throw error;\n }\n }\n\n // Step 4: Remove demo content LAST (handles both base and i18n paths)\n // This runs after i18n overlay so it can remove i18n demo pages if needed\n if (!demo) {\n spinner.start('Configuring minimal template...');\n removeItems(targetDir, DEMO_CONTENT);\n applyBaseTemplate(targetDir);\n createContentDirectories(targetDir);\n spinner.stop('Minimal template configured');\n }\n\n // Step 5: Generate starter pages if requested\n if (pages.length > 0) {\n spinner.start(`Generating ${pages.length} starter page${pages.length > 1 ? 's' : ''}...`);\n try {\n const generatedFiles = await generatePages(targetDir, pages, pageLayout, i18n);\n spinner.stop(`Generated ${generatedFiles.length} page file${generatedFiles.length > 1 ? 's' : ''}`);\n } catch (error) {\n spinner.stop('Failed to generate pages');\n throw error;\n }\n }\n\n // Step 6: Update package.json\n spinner.start('Configuring project...');\n try {\n updatePackageJson(targetDir, projectName);\n spinner.stop('Project configured');\n } catch (error) {\n spinner.stop('Failed to configure project');\n throw error;\n }\n\n // Step 7: Initialize git\n spinner.start('Initializing git repository...');\n const gitInitialized = await initGit(targetDir);\n if (gitInitialized) {\n spinner.stop('Git repository initialized');\n } else {\n spinner.stop('Git not available, skipping');\n }\n\n // Step 8: Install dependencies\n spinner.start(`Installing dependencies with ${packageManager}...`);\n try {\n const installCmd = getInstallCommand(packageManager);\n const [cmd, ...args] = installCmd.split(' ');\n await execa(cmd!, args, { cwd: targetDir });\n spinner.stop('Dependencies installed');\n } catch {\n spinner.stop('Failed to install dependencies');\n showWarning(`Run \"${getInstallCommand(packageManager)}\" manually to install dependencies`);\n }\n\n showSuccess(`Project \"${projectName}\" created successfully!`);\n}\n","import { existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolves the path to the base template (minimal pages)\n */\nexport function getBaseTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'base');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find base template. Package may be corrupted.');\n}\n\n/**\n * Resolves the path to the i18n overlay template\n */\nexport function getI18nTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'i18n');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find i18n template. Package may be corrupted.');\n}\n","import { execa } from 'execa';\n\n/**\n * Initializes a git repository in the target directory\n */\nexport async function initGit(targetDir: string): Promise<boolean> {\n try {\n await execa('git', ['init'], { cwd: targetDir });\n await execa('git', ['add', '-A'], { cwd: targetDir });\n await execa('git', ['commit', '-m', 'Initial commit from create-velocity'], {\n cwd: targetDir,\n });\n return true;\n } catch {\n // Git may not be installed or configured\n return false;\n }\n}\n\n/**\n * Checks if git is available\n */\nexport async function isGitInstalled(): Promise<boolean> {\n try {\n await execa('git', ['--version']);\n return true;\n } catch {\n return false;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { PageLayout } from '../types.js';\n\n/**\n * Converts a page slug to a display title\n * e.g., 'about-us' -> 'About Us'\n */\nfunction toTitle(slug: string): string {\n return slug\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Converts a page slug to a route ID (snake_case)\n * e.g., 'about-us' -> 'about_us'\n */\nfunction toRouteId(slug: string): string {\n return slug.replace(/-/g, '_');\n}\n\n/**\n * Calculates the next available nav order by finding the highest existing order\n */\nfunction getNextNavOrder(content: string): number {\n // Match all order values in nav configs\n const orderMatches = [...content.matchAll(/order:\\s*(\\d+)/g)];\n let maxOrder = 0;\n\n for (const match of orderMatches) {\n const orderStr = match[1];\n if (orderStr) {\n const order = parseInt(orderStr, 10);\n if (order > maxOrder) {\n maxOrder = order;\n }\n }\n }\n\n // Return the next order (10 more than current max for room to insert)\n return maxOrder + 10;\n}\n\n/**\n * Adds a new route entry to base routes.ts (non-i18n projects)\n * Includes nav config so the page appears in navigation\n */\nfunction addBaseRouteEntry(targetDir: string, pageName: string): void {\n const routesPath = join(targetDir, 'src', 'config', 'routes.ts');\n\n if (!existsSync(routesPath)) {\n return; // routes.ts doesn't exist, skip\n }\n\n const routeId = toRouteId(pageName);\n const title = toTitle(pageName);\n const content = readFileSync(routesPath, 'utf-8');\n\n // Check if route already exists\n if (content.includes(`${routeId}:`)) {\n return; // Route already defined\n }\n\n // Find the closing of routes object (before \"} as const satisfies\")\n const insertPoint = content.indexOf('} as const satisfies');\n if (insertPoint === -1) {\n return; // Can't find insertion point\n }\n\n // Calculate the next nav order\n const navOrder = getNextNavOrder(content);\n\n // Create new route entry with nav config\n const newRoute = `\n // Custom page: ${pageName}\n ${routeId}: {\n path: '/${pageName}',\n nav: { show: true, order: ${navOrder}, label: '${title}' },\n },\n`;\n\n const newContent = content.slice(0, insertPoint) + newRoute + content.slice(insertPoint);\n writeFileSync(routesPath, newContent);\n}\n\n/**\n * Adds a new route entry to i18n routes.ts\n * Creates the route with the same English slug for all locales (user customizes later)\n * Includes nav config so the page appears in navigation\n */\nfunction addI18nRouteEntry(targetDir: string, pageName: string): void {\n const routesPath = join(targetDir, 'src', 'i18n', 'routes.ts');\n\n if (!existsSync(routesPath)) {\n return; // routes.ts doesn't exist, skip\n }\n\n const routeId = toRouteId(pageName);\n const content = readFileSync(routesPath, 'utf-8');\n\n // Check if route already exists\n if (content.includes(`${routeId}:`)) {\n return; // Route already defined\n }\n\n // Find the closing of routes object (before \"} as const satisfies\")\n const insertPoint = content.indexOf('} as const satisfies');\n if (insertPoint === -1) {\n return; // Can't find insertion point\n }\n\n // Calculate the next nav order\n const navOrder = getNextNavOrder(content);\n\n // Create new route entry with nav config\n // Uses the route ID as the translation key (user should add translation)\n const title = toTitle(pageName);\n const newRoute = `\n // Custom page: ${pageName}\n ${routeId}: {\n en: '${pageName}', es: '${pageName}', fr: '${pageName}',\n nav: { show: true, order: ${navOrder}, label: 'nav.${routeId}' },\n },\n`;\n\n const newContent = content.slice(0, insertPoint) + newRoute + content.slice(insertPoint);\n writeFileSync(routesPath, newContent);\n\n // Also add translation keys to translation files\n addI18nTranslationKeys(targetDir, routeId, title);\n}\n\n/**\n * Adds translation keys for a new route to all i18n translation files\n */\nfunction addI18nTranslationKeys(targetDir: string, routeId: string, title: string): void {\n const locales = ['en', 'es', 'fr'];\n\n for (const locale of locales) {\n const translationPath = join(targetDir, 'src', 'i18n', 'translations', `${locale}.ts`);\n\n if (!existsSync(translationPath)) {\n continue;\n }\n\n let content = readFileSync(translationPath, 'utf-8');\n\n // Add nav translation if not exists\n if (!content.includes(`${routeId}:`)) {\n // Find the nav section and add the key\n const navSectionMatch = content.match(/nav:\\s*\\{([^}]+)\\}/);\n if (navSectionMatch) {\n const navSection = navSectionMatch[0];\n const insertPoint = navSection.lastIndexOf('}');\n const newNavSection =\n navSection.slice(0, insertPoint) +\n ` ${routeId}: '${title}',\\n ` +\n navSection.slice(insertPoint);\n content = content.replace(navSection, newNavSection);\n }\n }\n\n // Add page-specific translations if not exists\n const pageKeyPattern = new RegExp(`^\\\\s*${routeId}:\\\\s*\\\\{`, 'm');\n if (!pageKeyPattern.test(content)) {\n // Find a good insertion point (before the closing export)\n const insertPoint = content.lastIndexOf('} as const');\n if (insertPoint !== -1) {\n const pageTranslations = `\n // ${title} page\n ${routeId}: {\n title: '${title}',\n description: 'Add your ${title.toLowerCase()} page description here.',\n },\n\n`;\n content = content.slice(0, insertPoint) + pageTranslations + content.slice(insertPoint);\n }\n }\n\n writeFileSync(translationPath, content);\n }\n}\n\n/**\n * Generates the standard page template (non-i18n)\n */\nfunction generatePageTemplate(pageName: string, layout: PageLayout): string {\n const title = toTitle(pageName);\n const layoutName = layout === 'landing' ? 'LandingLayout' : 'PageLayout';\n\n return `---\nimport ${layoutName} from '@/layouts/${layoutName}.astro';\n---\n\n<${layoutName}\n title=\"${title}\"\n description=\"Add your description here\"\n>\n <!-- Hero Section -->\n <section class=\"py-20 bg-secondary\">\n <div class=\"container\">\n <h1 class=\"text-4xl font-bold text-foreground\">${title}</h1>\n <p class=\"mt-4 text-foreground-muted max-w-2xl\">\n Add your content here.\n </p>\n </div>\n </section>\n\n <!-- Content Section -->\n <section class=\"py-16\">\n <div class=\"container\">\n <!-- Your content -->\n </div>\n </section>\n</${layoutName}>\n`;\n}\n\n/**\n * Generates the i18n-aware page template with translated URL support\n */\nfunction generateI18nPageTemplate(pageName: string, layout: PageLayout): string {\n const title = toTitle(pageName);\n const layoutName = layout === 'landing' ? 'LandingLayout' : 'PageLayout';\n const routeId = toRouteId(pageName);\n const titleKey = `${routeId}.title`;\n const descKey = `${routeId}.description`;\n\n return `---\nimport ${layoutName} from '@/layouts/${layoutName}.astro';\nimport { locales, isValidLocale, defaultLocale, type Locale } from '@/i18n/config';\nimport { useTranslations } from '@/i18n/index';\nimport { routes } from '@/i18n/routes';\n\nexport function getStaticPaths() {\n return locales\n .filter((lang) => lang !== defaultLocale)\n .map((lang) => ({\n params: {\n lang,\n ${routeId}: routes.${routeId}[lang],\n },\n }));\n}\n\nconst { lang } = Astro.params;\n\nif (!lang || !isValidLocale(lang)) {\n return Astro.redirect('/');\n}\n\nconst locale = lang as Locale;\nconst t = useTranslations(locale);\n---\n\n<${layoutName}\n title={t('${titleKey}') || '${title}'}\n description={t('${descKey}') || 'Add your description here'}\n lang={locale}\n routeId=\"${routeId}\"\n>\n <!-- Hero Section -->\n <section class=\"py-20 bg-secondary\">\n <div class=\"container\">\n <h1 class=\"text-4xl font-bold text-foreground\">\n {t('${titleKey}') || '${title}'}\n </h1>\n <p class=\"mt-4 text-foreground-muted max-w-2xl\">\n {t('${descKey}') || 'Add your content here.'}\n </p>\n </div>\n </section>\n\n <!-- Content Section -->\n <section class=\"py-16\">\n <div class=\"container\">\n <!-- Your content -->\n </div>\n </section>\n</${layoutName}>\n`;\n}\n\n/**\n * Generates pages in the target directory\n */\nexport async function generatePages(\n targetDir: string,\n pages: string[],\n layout: PageLayout,\n isI18n: boolean\n): Promise<string[]> {\n const generatedFiles: string[] = [];\n\n if (pages.length === 0) {\n return generatedFiles;\n }\n\n // Ensure pages directory exists\n const pagesDir = join(targetDir, 'src', 'pages');\n if (!existsSync(pagesDir)) {\n mkdirSync(pagesDir, { recursive: true });\n }\n\n // Generate standard pages (English / default locale)\n for (const pageName of pages) {\n const filePath = join(pagesDir, `${pageName}.astro`);\n const template = generatePageTemplate(pageName, layout);\n writeFileSync(filePath, template);\n generatedFiles.push(`src/pages/${pageName}.astro`);\n\n // Add route entry to base routes.ts (for non-i18n nav)\n if (!isI18n) {\n addBaseRouteEntry(targetDir, pageName);\n }\n }\n\n // Generate i18n pages if enabled\n if (isI18n) {\n const langDir = join(pagesDir, '[lang]');\n if (!existsSync(langDir)) {\n mkdirSync(langDir, { recursive: true });\n }\n\n for (const pageName of pages) {\n const routeId = toRouteId(pageName);\n // Use rest parameter syntax for translated URL slugs\n const filePath = join(langDir, `[...${routeId}].astro`);\n const template = generateI18nPageTemplate(pageName, layout);\n writeFileSync(filePath, template);\n generatedFiles.push(`src/pages/[lang]/[...${routeId}].astro`);\n\n // Add route entry to i18n routes.ts\n addI18nRouteEntry(targetDir, pageName);\n }\n }\n\n return generatedFiles;\n}\n\n/**\n * List of page-related files that could be generated\n */\nexport const PAGES_FILES = [\n 'src/pages/{pageName}.astro',\n 'src/pages/[lang]/[...{routeId}].astro',\n];\n","import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\n/**\n * Recursively copies a directory\n */\nexport function copyDirectory(src: string, dest: string, overwrite = false): void {\n if (!existsSync(src)) {\n throw new Error(`Source directory does not exist: ${src}`);\n }\n\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDirectory(srcPath, destPath, overwrite);\n } else {\n if (overwrite || !existsSync(destPath)) {\n const destDir = dirname(destPath);\n if (!existsSync(destDir)) {\n mkdirSync(destDir, { recursive: true });\n }\n copyFileSync(srcPath, destPath);\n }\n }\n }\n}\n\n/**\n * Checks if a directory is empty\n */\nexport function isEmptyDir(path: string): boolean {\n if (!existsSync(path)) return true;\n const files = readdirSync(path);\n return files.length === 0 || (files.length === 1 && files[0] === '.git');\n}\n\n/**\n * Reads a JSON file and parses it\n */\nexport function readJson<T = Record<string, unknown>>(path: string): T {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content) as T;\n}\n\n/**\n * Writes an object as JSON to a file\n */\nexport function writeJson(path: string, data: unknown): void {\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Checks if path exists and is a directory\n */\nexport function isDirectory(path: string): boolean {\n return existsSync(path) && statSync(path).isDirectory();\n}\n","import { run } from './cli.js';\n\nrun(process.argv.slice(2)).catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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","names":["resolve","existsSync","p","pc","resolve","existsSync","mkdirSync","readFileSync","writeFileSync","join","dirname","p","execa","__dirname","existsSync","existsSync","mkdirSync","join","readFileSync","writeFileSync","dirname","spinner","execa","existsSync","mkdirSync","readdirSync","copyFileSync","readFileSync","writeFileSync","join","dirname","existsSync","readdirSync","pc","projectName","targetDir","resolve","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/prompts.ts","../src/utils/validate.ts","../src/utils/package-manager.ts","../src/registry/fetcher.ts","../src/registry/resolver.ts","../src/display.ts","../src/scaffold.ts","../src/template.ts","../src/utils/git.ts","../src/features/pages.ts","../src/utils/fs.ts","../src/index.ts"],"sourcesContent":["import mri from 'mri';\nimport { resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { CliOptions } from './types.js';\nimport type { ComponentSelection } from './registry/types.js';\nimport { runPrompts, showIntro, showOutro, showError } from './prompts.js';\nimport { scaffold } from './scaffold.js';\nimport { isEmptyDir } from './utils/fs.js';\nimport { toValidProjectName } from './utils/validate.js';\n\nconst HELP_TEXT = `\n${pc.bold('create-velocity-astro')} - Create a new Velocity project\n\n${pc.bold('Usage:')}\n npm create velocity-astro@latest [project-name] [options]\n pnpm create velocity-astro [project-name] [options]\n yarn create velocity-astro [project-name] [options]\n bun create velocity-astro [project-name] [options]\n\n${pc.bold('Options:')}\n --demo Include demo landing page and sample content\n --components Include all components (default: prompt for selection)\n --components=none Exclude all components\n --components=ui,patterns Include specific categories\n --i18n Add internationalization support\n --pages Prompt for starter pages to generate\n --yes, -y Skip prompts and use defaults\n --help, -h Show this help message\n --version, -v Show version number\n\n${pc.bold('Component Categories:')}\n ui UI components (buttons, forms, cards, dialogs) - 20 components\n patterns Form patterns (contact form, newsletter) - 3 components\n hero Flexible hero section component - 1 component\n\n${pc.bold('Examples:')}\n npm create velocity-astro@latest my-site\n npm create velocity-astro@latest my-site --demo --components\n npm create velocity-astro@latest my-site --components=ui,patterns\n npm create velocity-astro@latest my-site --components=none\n npm create velocity-astro@latest my-site --i18n --pages\n pnpm create velocity-astro my-site -y\n`;\n\nconst VERSION = '1.4.2';\n\n/**\n * Parses the --components flag into a ComponentSelection\n */\nfunction parseComponentsFlag(value: string | boolean | undefined): ComponentSelection | undefined {\n // Not specified - will prompt user\n if (value === undefined) {\n return undefined;\n }\n\n // --components (boolean true) - include all\n if (value === true) {\n return { mode: 'all' };\n }\n\n // --components=false or explicit false\n if (value === false) {\n return { mode: 'none' };\n }\n\n // --components=none\n if (value === 'none' || value === 'false') {\n return { mode: 'none' };\n }\n\n // --components=all\n if (value === 'all' || value === 'true') {\n return { mode: 'all' };\n }\n\n // --components=ui,patterns,hero (category list)\n const categories = value.split(',').map((s) => s.trim().toLowerCase());\n const validCategories = ['ui', 'patterns', 'hero'];\n const filtered = categories.filter((c) => validCategories.includes(c));\n\n if (filtered.length === 0) {\n return { mode: 'all' }; // Fall back to all if no valid categories\n }\n\n return { mode: 'categories', categories: filtered };\n}\n\nexport async function run(argv: string[]): Promise<void> {\n const args = mri<CliOptions>(argv, {\n boolean: ['demo', 'i18n', 'pages', 'help', 'version', 'yes'],\n string: ['components'],\n alias: {\n h: 'help',\n v: 'version',\n y: 'yes',\n },\n });\n\n // Handle help\n if (args.help) {\n console.log(HELP_TEXT);\n return;\n }\n\n // Handle version\n if (args.version) {\n console.log(VERSION);\n return;\n }\n\n showIntro();\n\n // Get project name from args or prompt\n const argProjectName = args._[0] as string | undefined;\n\n // Parse component selection from CLI\n const componentSelection = parseComponentsFlag(args.components);\n\n // Skip prompts mode\n if (args.yes) {\n const projectName = toValidProjectName(argProjectName || 'my-velocity-site');\n const targetDir = resolve(process.cwd(), projectName);\n\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n showError(`Directory \"${projectName}\" already exists and is not empty.`);\n process.exit(1);\n }\n\n await scaffold({\n projectName,\n targetDir,\n demo: args.demo || false,\n componentSelection: componentSelection || { mode: 'all' },\n i18n: args.i18n || false,\n pages: [],\n pageLayout: 'page',\n packageManager: 'pnpm',\n });\n\n showOutro(projectName, 'pnpm');\n return;\n }\n\n // Interactive mode\n const answers = await runPrompts({\n projectName: argProjectName,\n demo: args.demo,\n componentSelection: componentSelection,\n i18n: args.i18n,\n pages: args.pages,\n });\n\n // User cancelled\n if (typeof answers === 'symbol') {\n return;\n }\n\n const { projectName, demo, componentSelection: selectedComponents, i18n, pages, pageLayout, packageManager } = answers;\n const targetDir = resolve(process.cwd(), projectName);\n\n // Check if directory exists and is not empty\n if (existsSync(targetDir) && !isEmptyDir(targetDir)) {\n const shouldOverwrite = await p.confirm({\n message: `Directory \"${projectName}\" already exists. Continue and overwrite?`,\n initialValue: false,\n });\n\n if (!shouldOverwrite || p.isCancel(shouldOverwrite)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n }\n\n // Run scaffold\n try {\n await scaffold({\n projectName,\n targetDir,\n demo,\n componentSelection: selectedComponents,\n i18n,\n pages,\n pageLayout,\n packageManager,\n });\n\n showOutro(projectName, packageManager);\n } catch (error) {\n showError(error instanceof Error ? error.message : 'An unexpected error occurred');\n process.exit(1);\n }\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { PackageManager, PageLayout, PromptAnswers } from './types.js';\nimport type { ComponentSelection, ComponentRegistry, ComponentSelectionMode } from './registry/types.js';\nimport { validateProjectName, toValidProjectName } from './utils/validate.js';\nimport { detectPackageManager } from './utils/package-manager.js';\nimport { fetchRegistry } from './registry/fetcher.js';\nimport { getComponentsByCategory, resolveDependencies, getSelectionStats } from './registry/resolver.js';\nimport { showBanner, showSuccessBanner, velocityGradient } from './display.js';\n\ninterface PromptDefaults {\n projectName?: string;\n demo?: boolean;\n componentSelection?: ComponentSelection;\n i18n?: boolean;\n pages?: boolean;\n}\n\n/**\n * Parses comma-separated page names into an array of valid page slugs\n */\nfunction parsePageNames(input: string): string[] {\n if (!input.trim()) return [];\n\n return input\n .split(',')\n .map((name) => name.trim().toLowerCase())\n .filter((name) => name.length > 0)\n .map((name) => name.replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, ''))\n .filter((name) => name.length > 0 && !['index', 'blog', '404', 'rss'].includes(name));\n}\n\n/**\n * Prompts user for component selection mode\n */\nasync function promptComponentMode(): Promise<ComponentSelectionMode> {\n const result = await p.select({\n message: 'Include optional components?',\n options: [\n {\n value: 'all' as ComponentSelectionMode,\n label: 'All',\n hint: 'Include all 26 optional components',\n },\n {\n value: 'categories' as ComponentSelectionMode,\n label: 'Select categories',\n hint: 'Choose component groups',\n },\n {\n value: 'individual' as ComponentSelectionMode,\n label: 'Select individual',\n hint: 'Pick specific components',\n },\n {\n value: 'none' as ComponentSelectionMode,\n label: 'None',\n hint: 'Minimal template',\n },\n ],\n initialValue: 'all' as ComponentSelectionMode,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result;\n}\n\n/**\n * Prompts user to select component categories\n */\nasync function promptCategories(registry: ComponentRegistry): Promise<string[]> {\n const categoryOptions = Object.entries(registry.categories).map(([id, cat]) => {\n const componentCount = getComponentsByCategory(id, registry).length;\n return {\n value: id,\n label: cat.name,\n hint: `${componentCount} components - ${cat.description}`,\n };\n });\n\n const result = await p.multiselect({\n message: 'Select component categories:',\n options: categoryOptions,\n required: true,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result as string[];\n}\n\n/**\n * Prompts user to select individual components\n */\nasync function promptComponents(registry: ComponentRegistry): Promise<string[]> {\n // Group components by category for better UX\n const componentsByCategory: Record<string, { value: string; label: string; hint: string }[]> = {};\n\n for (const [id, comp] of Object.entries(registry.components)) {\n if (!componentsByCategory[comp.category]) {\n componentsByCategory[comp.category] = [];\n }\n const depCount = comp.dependencies.components.length;\n const depHint = depCount > 0 ? ` (requires ${depCount} dep${depCount > 1 ? 's' : ''})` : '';\n const categoryName = registry.categories[comp.category]?.name ?? comp.category;\n componentsByCategory[comp.category]!.push({\n value: id,\n label: comp.name,\n hint: `${categoryName}${depHint}`,\n });\n }\n\n // Flatten into options with category headers\n const options: { value: string; label: string; hint?: string }[] = [];\n for (const [categoryId, components] of Object.entries(componentsByCategory)) {\n const categoryName = registry.categories[categoryId]?.name || categoryId;\n // Add all components from this category\n for (const comp of components) {\n options.push({\n ...comp,\n hint: categoryName,\n });\n }\n }\n\n const result = await p.multiselect({\n message: 'Select components (dependencies auto-included):',\n options,\n required: true,\n });\n\n if (p.isCancel(result)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return result as string[];\n}\n\n/**\n * Gets component selection from user prompts\n */\nasync function getComponentSelection(\n defaultSelection?: ComponentSelection\n): Promise<ComponentSelection> {\n if (defaultSelection) {\n return defaultSelection;\n }\n\n let registry: ComponentRegistry;\n try {\n registry = await fetchRegistry();\n } catch {\n // Fallback to simple yes/no if registry unavailable\n const useComponents = await p.select({\n message: 'Include UI component library?',\n options: [\n { value: true, label: 'Yes', hint: 'Buttons, forms, cards, dialogs, etc.' },\n { value: false, label: 'No', hint: 'Just the basics' },\n ],\n initialValue: true,\n });\n\n if (p.isCancel(useComponents)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n return { mode: useComponents ? 'all' : 'none' };\n }\n\n const mode = await promptComponentMode();\n\n switch (mode) {\n case 'none':\n return { mode: 'none' };\n\n case 'all':\n return { mode: 'all' };\n\n case 'categories': {\n const categories = await promptCategories(registry);\n // Show what will be included\n const selection: ComponentSelection = { mode: 'categories', categories };\n const resolved = resolveDependencies(selection, registry);\n const stats = getSelectionStats(resolved, registry);\n p.log.info(\n pc.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)\n );\n return selection;\n }\n\n case 'individual': {\n const components = await promptComponents(registry);\n // Show what will be included (with dependencies)\n const selection: ComponentSelection = { mode: 'individual', components };\n const resolved = resolveDependencies(selection, registry);\n const stats = getSelectionStats(resolved, registry);\n if (resolved.components.length > components.length) {\n p.log.info(\n pc.dim(\n `Selected ${components.length} components + ${resolved.components.length - components.length} dependencies (${resolved.files.length} files)`\n )\n );\n } else {\n p.log.info(\n pc.dim(`Selected ${stats.componentCount} components (${resolved.files.length} files)`)\n );\n }\n return selection;\n }\n }\n}\n\nexport async function runPrompts(defaults: PromptDefaults = {}): Promise<PromptAnswers | symbol> {\n const detectedPm = detectPackageManager();\n\n const answers = await p.group(\n {\n projectName: () =>\n p.text({\n message: 'What is your project name?',\n placeholder: defaults.projectName || 'my-velocity-site',\n defaultValue: defaults.projectName,\n validate: (value) => {\n const name = value || defaults.projectName || 'my-velocity-site';\n const result = validateProjectName(toValidProjectName(name));\n if (!result.valid) return result.message;\n },\n }),\n\n demo:\n defaults.demo !== undefined\n ? () => Promise.resolve(defaults.demo)\n : () =>\n p.select({\n message: 'Include demo landing page and sample content?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Minimal starter with basic pages',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Full demo with landing page, blog posts',\n },\n ],\n initialValue: false,\n }),\n\n componentSelection: () => getComponentSelection(defaults.componentSelection),\n\n i18n:\n defaults.i18n !== undefined\n ? () => Promise.resolve(defaults.i18n)\n : () =>\n p.select({\n message: 'Add internationalization (i18n)?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'English only',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Locale routing, translations',\n },\n ],\n initialValue: false,\n }),\n\n generatePages:\n defaults.pages !== undefined\n ? () => Promise.resolve(defaults.pages)\n : () =>\n p.select({\n message: 'Generate starter pages?',\n options: [\n {\n value: false,\n label: 'No',\n hint: 'Create pages manually later',\n },\n {\n value: true,\n label: 'Yes',\n hint: 'Auto-generate page files with layout',\n },\n ],\n initialValue: false,\n }),\n\n pageNames: ({ results }) =>\n results.generatePages\n ? p.text({\n message: 'Enter page names (comma-separated):',\n placeholder: 'about, pricing, faq, contact',\n validate: (value) => {\n const pages = parsePageNames(value);\n if (pages.length === 0) {\n return 'Please enter at least one valid page name';\n }\n },\n })\n : Promise.resolve(''),\n\n pageLayout: ({ results }) =>\n results.generatePages\n ? results.demo\n ? p.select({\n message: 'Select layout for pages:',\n options: [\n {\n value: 'page' as PageLayout,\n label: 'PageLayout',\n hint: 'Standard content pages (Header + Footer)',\n },\n {\n value: 'landing' as PageLayout,\n label: 'LandingLayout',\n hint: 'Marketing pages (Navbar + LandingFooter)',\n },\n ],\n initialValue: 'page' as PageLayout,\n })\n : Promise.resolve('page' as PageLayout) // Force PageLayout when demo=No\n : Promise.resolve('page' as PageLayout),\n\n packageManager: () =>\n p.select({\n message: 'Which package manager?',\n options: [\n {\n value: 'pnpm' as PackageManager,\n label: 'pnpm',\n hint: detectedPm === 'pnpm' ? 'detected' : 'recommended',\n },\n {\n value: 'npm' as PackageManager,\n label: 'npm',\n hint: detectedPm === 'npm' ? 'detected' : undefined,\n },\n {\n value: 'yarn' as PackageManager,\n label: 'yarn',\n hint: detectedPm === 'yarn' ? 'detected' : undefined,\n },\n {\n value: 'bun' as PackageManager,\n label: 'bun',\n hint: detectedPm === 'bun' ? 'detected' : undefined,\n },\n ],\n initialValue: detectedPm,\n }),\n },\n {\n onCancel: () => {\n p.cancel('Operation cancelled.');\n process.exit(0);\n },\n }\n );\n\n return {\n projectName: toValidProjectName(answers.projectName || defaults.projectName || 'my-velocity-site'),\n demo: answers.demo as boolean,\n componentSelection: answers.componentSelection as ComponentSelection,\n i18n: answers.i18n as boolean,\n pages: parsePageNames(answers.pageNames as string),\n pageLayout: (answers.pageLayout as PageLayout) || 'page',\n packageManager: answers.packageManager as PackageManager,\n };\n}\n\nexport function showIntro(): void {\n showBanner();\n}\n\nexport function showOutro(projectName: string, packageManager: PackageManager): void {\n const runCmd = packageManager === 'npm' ? 'npm run' : packageManager;\n\n showSuccessBanner();\n\n console.log(pc.bold(' Next steps:'));\n console.log();\n console.log(` ${pc.dim('$')} ${pc.cyan(`cd ${projectName}`)}`);\n console.log(` ${pc.dim('$')} ${pc.cyan(`${runCmd} dev`)}`);\n console.log();\n console.log(` ${pc.dim('Docs:')} ${pc.cyan('https://docs.deployvelocity.com')}`);\n console.log();\n console.log(velocityGradient(' Happy building! 🚀'));\n console.log();\n}\n\nexport function showError(message: string): void {\n p.log.error(pc.red(message));\n}\n\nexport function showWarning(message: string): void {\n p.log.warn(pc.yellow(message));\n}\n\nexport function showSuccess(message: string): void {\n p.log.success(pc.green(message));\n}\n\nexport function showStep(message: string): void {\n p.log.step(message);\n}\n","/**\n * Validates a project name for npm package naming conventions\n */\nexport function validateProjectName(name: string): { valid: boolean; message?: string } {\n if (!name || name.trim() === '') {\n return { valid: false, message: 'Project name cannot be empty' };\n }\n\n // Must be lowercase\n if (name !== name.toLowerCase()) {\n return { valid: false, message: 'Project name must be lowercase' };\n }\n\n // Cannot start with . or _\n if (name.startsWith('.') || name.startsWith('_')) {\n return { valid: false, message: 'Project name cannot start with . or _' };\n }\n\n // Cannot contain spaces\n if (/\\s/.test(name)) {\n return { valid: false, message: 'Project name cannot contain spaces' };\n }\n\n // Cannot contain special characters except - and @/\n if (!/^(@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)) {\n return {\n valid: false,\n message: 'Project name can only contain lowercase letters, numbers, hyphens, and underscores',\n };\n }\n\n // Length check\n if (name.length > 214) {\n return { valid: false, message: 'Project name must be 214 characters or fewer' };\n }\n\n return { valid: true };\n}\n\n/**\n * Sanitizes a string to be a valid project name\n */\nexport function toValidProjectName(name: string): string {\n return name\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-_~.]/g, '-')\n .replace(/^[-._]+/, '')\n .replace(/[-._]+$/, '')\n .replace(/-+/g, '-');\n}\n","import type { PackageManager } from '../types.js';\n\n/**\n * Detects the package manager used to run this command\n */\nexport function detectPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent || '';\n\n if (userAgent.startsWith('pnpm')) return 'pnpm';\n if (userAgent.startsWith('yarn')) return 'yarn';\n if (userAgent.startsWith('bun')) return 'bun';\n return 'npm';\n}\n\n/**\n * Gets the install command for a package manager\n */\nexport function getInstallCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm install';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun install';\n case 'npm':\n default:\n return 'npm install';\n }\n}\n\n/**\n * Gets the run command for a package manager\n */\nexport function getRunCommand(pm: PackageManager): string {\n switch (pm) {\n case 'pnpm':\n return 'pnpm';\n case 'yarn':\n return 'yarn';\n case 'bun':\n return 'bun';\n case 'npm':\n default:\n return 'npm run';\n }\n}\n","/**\n * Registry Fetcher\n * Fetches the component registry from GitHub\n */\n\nimport type { ComponentRegistry } from './types.js';\n\nconst REGISTRY_URL = 'https://raw.githubusercontent.com/southwellmedia/velocity/main/component-registry.json';\n\nlet cachedRegistry: ComponentRegistry | null = null;\n\n/**\n * Fetches the component registry from GitHub\n * Results are cached for the duration of the process\n */\nexport async function fetchRegistry(): Promise<ComponentRegistry> {\n if (cachedRegistry) {\n return cachedRegistry;\n }\n\n try {\n const response = await fetch(REGISTRY_URL);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch registry: ${response.status} ${response.statusText}`);\n }\n\n cachedRegistry = await response.json() as ComponentRegistry;\n return cachedRegistry;\n } catch (error) {\n throw new Error(\n `Could not fetch component registry. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n}\n\n/**\n * Fetches a single file from the velocity repository\n */\nexport async function fetchComponentFile(filePath: string): Promise<string> {\n const url = `https://raw.githubusercontent.com/southwellmedia/velocity/main/${filePath}`;\n\n try {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n } catch (error) {\n throw new Error(\n `Could not fetch file: ${filePath}\\n${error instanceof Error ? error.message : ''}`\n );\n }\n}\n\n/**\n * Clears the cached registry\n */\nexport function clearRegistryCache(): void {\n cachedRegistry = null;\n}\n","/**\n * Dependency Resolver\n * Resolves component dependencies and collects all required files\n */\n\nimport type { ComponentRegistry, ComponentSelection, ResolvedComponents } from './types.js';\n\n/**\n * Resolves dependencies for requested components\n * Returns all components, utilities, files, and npm packages needed\n */\nexport function resolveDependencies(\n selection: ComponentSelection,\n registry: ComponentRegistry\n): ResolvedComponents {\n const resolved = new Set<string>();\n const utilities = new Set<string>();\n const files = new Set<string>();\n const npmPackages = new Set<string>();\n\n // Handle different selection modes\n let requestedComponents: string[] = [];\n\n switch (selection.mode) {\n case 'none':\n return { components: [], utilities: [], files: [], npmPackages: [] };\n\n case 'all':\n requestedComponents = Object.keys(registry.components);\n break;\n\n case 'categories':\n if (selection.categories) {\n requestedComponents = Object.entries(registry.components)\n .filter(([, comp]) => selection.categories!.includes(comp.category))\n .map(([id]) => id);\n }\n break;\n\n case 'individual':\n requestedComponents = selection.components || [];\n break;\n }\n\n // Recursively resolve each component's dependencies\n function resolve(componentId: string): void {\n if (resolved.has(componentId)) return;\n\n const component = registry.components[componentId];\n if (!component) {\n console.warn(`Component not found: ${componentId}`);\n return;\n }\n\n // Resolve component dependencies first (recursive)\n for (const dep of component.dependencies.components) {\n resolve(dep);\n }\n\n // Collect utilities\n for (const util of component.dependencies.utilities) {\n utilities.add(util);\n }\n\n // Collect files\n for (const file of component.files) {\n files.add(file);\n }\n\n resolved.add(componentId);\n }\n\n // Resolve all requested components\n for (const componentId of requestedComponents) {\n resolve(componentId);\n }\n\n // Collect utility files and npm packages\n for (const utilId of utilities) {\n const utility = registry.utilities[utilId];\n if (utility) {\n for (const file of utility.files) {\n files.add(file);\n }\n for (const pkg of utility.npm) {\n npmPackages.add(pkg);\n }\n }\n }\n\n return {\n components: [...resolved],\n utilities: [...utilities],\n files: [...files],\n npmPackages: [...npmPackages],\n };\n}\n\n/**\n * Gets all components in a category\n */\nexport function getComponentsByCategory(\n categoryId: string,\n registry: ComponentRegistry\n): string[] {\n return Object.entries(registry.components)\n .filter(([, comp]) => comp.category === categoryId)\n .map(([id]) => id);\n}\n\n/**\n * Gets the dependency tree for a component (for visualization)\n */\nexport function getDependencyTree(\n componentId: string,\n registry: ComponentRegistry,\n visited = new Set<string>()\n): { id: string; name: string; deps: ReturnType<typeof getDependencyTree>[] } | null {\n if (visited.has(componentId)) return null;\n visited.add(componentId);\n\n const component = registry.components[componentId];\n if (!component) return null;\n\n const deps = component.dependencies.components\n .map((dep) => getDependencyTree(dep, registry, visited))\n .filter((d): d is NonNullable<typeof d> => d !== null);\n\n return {\n id: componentId,\n name: component.name,\n deps,\n };\n}\n\n/**\n * Validates that all components exist in the registry\n */\nexport function validateComponents(\n componentIds: string[],\n registry: ComponentRegistry\n): { valid: boolean; invalid: string[] } {\n const invalid = componentIds.filter((id) => !registry.components[id]);\n return {\n valid: invalid.length === 0,\n invalid,\n };\n}\n\n/**\n * Validates that all categories exist in the registry\n */\nexport function validateCategories(\n categoryIds: string[],\n registry: ComponentRegistry\n): { valid: boolean; invalid: string[] } {\n const invalid = categoryIds.filter((id) => !registry.categories[id]);\n return {\n valid: invalid.length === 0,\n invalid,\n };\n}\n\n/**\n * Gets summary stats for a component selection\n */\nexport function getSelectionStats(\n resolved: ResolvedComponents,\n registry: ComponentRegistry\n): { componentCount: number; fileCount: number; categories: string[] } {\n const categories = new Set<string>();\n\n for (const componentId of resolved.components) {\n const component = registry.components[componentId];\n if (component) {\n categories.add(component.category);\n }\n }\n\n return {\n componentCount: resolved.components.length,\n fileCount: resolved.files.length,\n categories: [...categories],\n };\n}\n","import gradient from 'gradient-string';\r\nimport figures from 'figures';\r\nimport pc from 'picocolors';\r\n\r\n// Velocity gradient: blue -> cyan -> purple (speed/tech theme)\r\nconst velocityGrad = gradient(['#3b82f6', '#06b6d4', '#8b5cf6']);\r\nconst successGrad = gradient(['#22c55e', '#10b981']);\r\n\r\n// ASCII Banner - Block letters style\r\nconst BANNER = `\r\n █ █ █▀▀ █ █▀█ █▀▀ █ ▀█▀ █ █\r\n ▀▄▀ ██▄ █▄▄ █▄█ █▄▄ █ █ ▀▄▀\r\n`;\r\n\r\nexport function showBanner(): void {\r\n console.log();\r\n console.log(velocityGrad.multiline(BANNER));\r\n console.log(pc.dim(' Astro + Tailwind v4 Starter Kit'));\r\n console.log();\r\n}\r\n\r\nexport const symbols = {\r\n rocket: '🚀',\r\n sparkles: '✨',\r\n package: '📦',\r\n check: figures.tick,\r\n pointer: figures.pointer,\r\n};\r\n\r\nexport function showSuccessBanner(): void {\r\n console.log();\r\n console.log(successGrad(' ✨ Project created successfully! ✨'));\r\n console.log();\r\n}\r\n\r\n/**\r\n * Apply velocity gradient to text\r\n */\r\nexport function velocityGradient(text: string): string {\r\n return velocityGrad(text);\r\n}\r\n\r\n/**\r\n * Apply success gradient to text\r\n */\r\nexport function successGradient(text: string): string {\r\n return successGrad(text);\r\n}\r\n","import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, writeFileSync, rmSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport * as p from '@clack/prompts';\nimport { execa, ExecaError } from 'execa';\nimport pc from 'picocolors';\nimport { downloadTemplate } from 'giget';\nimport type { ScaffoldOptions } from './types.js';\nimport type { ComponentSelection, ResolvedComponents } from './registry/types.js';\nimport { getI18nTemplatePath, getBaseTemplatePath } from './template.js';\nimport { getInstallCommand } from './utils/package-manager.js';\nimport { initGit } from './utils/git.js';\nimport { showSuccess, showWarning } from './prompts.js';\nimport { generatePages } from './features/pages.js';\nimport { fetchRegistry } from './registry/fetcher.js';\nimport { resolveDependencies } from './registry/resolver.js';\n\n// GitHub repository for the Velocity template\nconst TEMPLATE_REPO = 'github:southwellmedia/velocity';\n\n// Files/directories to remove after download\nconst CLEANUP_ITEMS = [\n 'pnpm-lock.yaml',\n 'package-lock.json',\n 'yarn.lock',\n 'bun.lockb',\n '.git',\n];\n\n// Demo-specific content to remove when --demo is false\n// Includes both base paths and i18n paths to handle all scenarios\n// Note: Hero is NOT included here - it's a core component useful for any page\n// Hero removal is handled by component selection logic (mode='none' or categories)\nconst DEMO_CONTENT = [\n // Landing page components (NOT hero - that's a core component)\n 'src/components/landing',\n // Landing-specific pages (base paths)\n 'src/pages/index.astro',\n 'src/pages/about.astro',\n 'src/pages/contact.astro',\n 'src/pages/components.astro',\n // Landing-specific pages (i18n paths)\n 'src/pages/[lang]/index.astro',\n 'src/pages/[lang]/[...about].astro',\n 'src/pages/[lang]/[...contact].astro',\n 'src/pages/[lang]/[...components].astro',\n // Landing layout (depends on Navbar from landing components)\n 'src/layouts/LandingLayout.astro',\n // Demo content\n 'src/content/blog',\n 'src/content/faqs',\n 'src/content/authors',\n 'src/content/pages',\n];\n\n// Optional component directories (for removal when mode='none')\n// Note: layout, seo, landing, blog are core template - not optional\nconst OPTIONAL_COMPONENT_DIRS = [\n 'src/components/ui',\n 'src/components/patterns',\n 'src/components/hero',\n];\n\n/**\n * Copies template files recursively\n */\nfunction copyTemplateFiles(src: string, dest: string): void {\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyTemplateFiles(srcPath, destPath);\n } else {\n copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * Removes files/directories from the target\n */\nfunction removeItems(targetDir: string, items: string[]): void {\n for (const item of items) {\n const itemPath = join(targetDir, item);\n if (existsSync(itemPath)) {\n try {\n rmSync(itemPath, { recursive: true, force: true });\n } catch {\n // Ignore errors - item may not exist or be locked\n }\n }\n }\n}\n\n/**\n * Keeps only specified files, removes everything else in optional component directories\n */\nfunction keepOnlyFiles(targetDir: string, filesToKeep: Set<string>): void {\n // Only filter optional component directories - core template dirs are untouched\n const componentDirs = [\n 'src/components/ui',\n 'src/components/patterns',\n 'src/components/hero',\n ];\n\n for (const dir of componentDirs) {\n const dirPath = join(targetDir, dir);\n if (!existsSync(dirPath)) continue;\n\n const entries = readdirSync(dirPath, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n const relativePath = `${dir}/${entry.name}`;\n if (!filesToKeep.has(relativePath)) {\n try {\n rmSync(join(dirPath, entry.name), { force: true });\n } catch {\n // Ignore errors\n }\n }\n }\n }\n\n // Remove empty directories\n try {\n const remaining = readdirSync(dirPath);\n if (remaining.length === 0) {\n rmSync(dirPath, { recursive: true, force: true });\n }\n } catch {\n // Ignore errors\n }\n }\n}\n\n/**\n * Updates the package.json with the new project name\n */\nfunction updatePackageJson(targetDir: string, projectName: string): void {\n const pkgPath = join(targetDir, 'package.json');\n\n if (!existsSync(pkgPath)) {\n throw new Error('package.json not found in template');\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n pkg.name = projectName;\n pkg.version = '0.1.0';\n delete pkg.repository;\n delete pkg.bugs;\n delete pkg.homepage;\n\n writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\n/**\n * Applies base template (minimal pages) when demo is not selected\n */\nfunction applyBaseTemplate(targetDir: string): void {\n const baseTemplate = getBaseTemplatePath();\n if (existsSync(baseTemplate)) {\n copyTemplateFiles(baseTemplate, targetDir);\n }\n}\n\n/**\n * Applies the i18n overlay to the project\n */\nfunction applyI18nOverlay(targetDir: string): void {\n const i18nTemplate = getI18nTemplatePath();\n copyTemplateFiles(i18nTemplate, targetDir);\n}\n\n/**\n * Removes the components route from routes.ts when demo content is not selected\n * This prevents the Components nav item from appearing when the page doesn't exist\n */\nfunction removeComponentsRoute(targetDir: string, isI18n: boolean): void {\n const routesPath = isI18n\n ? join(targetDir, 'src', 'i18n', 'routes.ts')\n : join(targetDir, 'src', 'config', 'routes.ts');\n\n if (!existsSync(routesPath)) return;\n\n let content = readFileSync(routesPath, 'utf-8');\n\n // Remove components route entry (matches the block with comment and route definition)\n // Pattern handles both i18n format (en: 'components', es: 'componentes'...) and base format\n content = content.replace(\n /\\n\\s*\\/\\/ Components showcase\\n\\s*components:\\s*\\{[^}]+\\},?\\n/g,\n '\\n'\n );\n\n writeFileSync(routesPath, content);\n}\n\n/**\n * Creates empty content directories with .gitkeep files\n */\nfunction createContentDirectories(targetDir: string): void {\n const contentDirs = [\n 'src/content/blog',\n ];\n\n for (const dir of contentDirs) {\n const dirPath = join(targetDir, dir);\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n writeFileSync(join(dirPath, '.gitkeep'), '');\n }\n }\n}\n\n/**\n * Applies selective component filtering based on registry resolution\n */\nasync function applyComponentSelection(\n targetDir: string,\n selection: ComponentSelection\n): Promise<void> {\n // Handle 'all' mode - keep everything\n if (selection.mode === 'all') {\n return;\n }\n\n // Handle 'none' mode - remove optional components only\n if (selection.mode === 'none') {\n removeItems(targetDir, OPTIONAL_COMPONENT_DIRS);\n return;\n }\n\n // For 'categories' and 'individual' modes, we need the registry\n let resolved: ResolvedComponents;\n try {\n const registry = await fetchRegistry();\n resolved = resolveDependencies(selection, registry);\n } catch {\n // If registry fetch fails, fall back to keeping all components\n console.warn('Could not fetch component registry, keeping all components');\n return;\n }\n\n // Create set of files to keep\n const filesToKeep = new Set(resolved.files);\n\n // Keep only the resolved files\n keepOnlyFiles(targetDir, filesToKeep);\n\n // Ensure utility files are present if needed\n if (resolved.utilities.includes('cn')) {\n const cnPath = join(targetDir, 'src/lib/cn.ts');\n const cnDir = dirname(cnPath);\n if (!existsSync(cnDir)) {\n mkdirSync(cnDir, { recursive: true });\n }\n }\n}\n\n/**\n * Main scaffold function\n *\n * IMPORTANT: Step order matters for option combinations\n * - i18n overlay is applied BEFORE demo removal\n * - This ensures demo=Yes + i18n=Yes gets full translated demo\n * - And demo=No + i18n=Yes gets i18n routing without demo pages\n */\nexport async function scaffold(options: ScaffoldOptions): Promise<void> {\n const { projectName, targetDir, demo, componentSelection, i18n, pages, pageLayout, packageManager } = options;\n const spinner = p.spinner();\n\n // Step 1: Download base template from GitHub\n spinner.start('Downloading template from GitHub...');\n\n try {\n await downloadTemplate(TEMPLATE_REPO, {\n dir: targetDir,\n force: true,\n });\n removeItems(targetDir, CLEANUP_ITEMS);\n spinner.stop('Template downloaded');\n } catch (error) {\n spinner.stop('Failed to download template');\n throw new Error(\n `Could not download template from GitHub. Please check your internet connection.\\n${error instanceof Error ? error.message : ''}`\n );\n }\n\n // Step 2: Apply component selection\n if (componentSelection.mode !== 'all') {\n spinner.start('Configuring components...');\n try {\n await applyComponentSelection(targetDir, componentSelection);\n spinner.stop('Components configured');\n } catch (error) {\n spinner.stop('Failed to configure components');\n throw error;\n }\n }\n\n // Step 3: Apply i18n overlay if requested (BEFORE demo removal)\n // This ensures demo=Yes + i18n=Yes gets translated demo pages\n if (i18n) {\n spinner.start('Adding i18n support...');\n try {\n applyI18nOverlay(targetDir);\n spinner.stop('i18n support added');\n } catch (error) {\n spinner.stop('Failed to add i18n support');\n throw error;\n }\n }\n\n // Step 4: Remove demo content LAST (handles both base and i18n paths)\n // This runs after i18n overlay so it can remove i18n demo pages if needed\n if (!demo) {\n spinner.start('Configuring minimal template...');\n removeItems(targetDir, DEMO_CONTENT);\n applyBaseTemplate(targetDir);\n createContentDirectories(targetDir);\n // Remove components route from navigation since components page doesn't exist\n removeComponentsRoute(targetDir, i18n);\n spinner.stop('Minimal template configured');\n }\n\n // Step 5: Generate starter pages if requested\n if (pages.length > 0) {\n spinner.start(`Generating ${pages.length} starter page${pages.length > 1 ? 's' : ''}...`);\n try {\n const generatedFiles = await generatePages(targetDir, pages, pageLayout, i18n);\n spinner.stop(`Generated ${generatedFiles.length} page file${generatedFiles.length > 1 ? 's' : ''}`);\n\n // Show i18n translation warning if pages were generated with i18n enabled\n if (i18n) {\n showWarning(`i18n pages created with English-only content.\n\nYou must manually:\n 1. Translate URL slugs in src/i18n/routes.ts\n 2. Add translations to src/i18n/translations/es.ts\n 3. Add translations to src/i18n/translations/fr.ts\n\nLook for [TODO: Translate] markers in the translation files.`);\n }\n } catch (error) {\n spinner.stop('Failed to generate pages');\n throw error;\n }\n }\n\n // Step 6: Update package.json\n spinner.start('Configuring project...');\n try {\n updatePackageJson(targetDir, projectName);\n spinner.stop('Project configured');\n } catch (error) {\n spinner.stop('Failed to configure project');\n throw error;\n }\n\n // Step 7: Initialize git\n spinner.start('Initializing git repository...');\n const gitInitialized = await initGit(targetDir);\n if (gitInitialized) {\n spinner.stop('Git repository initialized');\n } else {\n spinner.stop('Git not available, skipping');\n }\n\n // Step 8: Install dependencies with streaming output\n console.log();\n p.log.step(`Installing dependencies with ${packageManager}...`);\n console.log(pc.dim('─'.repeat(50)));\n\n try {\n const installCmd = getInstallCommand(packageManager);\n const [cmd, ...args] = installCmd.split(' ');\n\n await execa(cmd!, args, {\n cwd: targetDir,\n stdio: 'inherit', // Stream output to terminal\n shell: process.platform === 'win32', // Windows compatibility\n });\n\n console.log(pc.dim('─'.repeat(50)));\n showSuccess('Dependencies installed');\n } catch (error) {\n console.log(pc.dim('─'.repeat(50)));\n showWarning('Failed to install dependencies');\n\n // Show diagnostic info\n const execaError = error as ExecaError;\n if (execaError.message) {\n console.log(pc.dim(`\\nError: ${execaError.message}`));\n }\n\n console.log();\n console.log(pc.yellow('To install manually, run:'));\n console.log(` ${pc.cyan(getInstallCommand(packageManager))}`);\n }\n\n showSuccess(`Project \"${projectName}\" created successfully!`);\n}\n","import { existsSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolves the path to the base template (minimal pages)\n */\nexport function getBaseTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'base');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find base template. Package may be corrupted.');\n}\n\n/**\n * Resolves the path to the i18n overlay template\n */\nexport function getI18nTemplatePath(): string {\n const templatePath = resolve(__dirname, '..', 'templates', 'i18n');\n\n if (existsSync(templatePath)) {\n return templatePath;\n }\n\n throw new Error('Could not find i18n template. Package may be corrupted.');\n}\n","import { execa } from 'execa';\n\n/**\n * Initializes a git repository in the target directory\n */\nexport async function initGit(targetDir: string): Promise<boolean> {\n try {\n await execa('git', ['init'], { cwd: targetDir });\n await execa('git', ['add', '-A'], { cwd: targetDir });\n await execa('git', ['commit', '-m', 'Initial commit from create-velocity'], {\n cwd: targetDir,\n });\n return true;\n } catch {\n // Git may not be installed or configured\n return false;\n }\n}\n\n/**\n * Checks if git is available\n */\nexport async function isGitInstalled(): Promise<boolean> {\n try {\n await execa('git', ['--version']);\n return true;\n } catch {\n return false;\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { PageLayout } from '../types.js';\n\n/**\n * Converts a page slug to a display title\n * e.g., 'about-us' -> 'About Us'\n */\nfunction toTitle(slug: string): string {\n return slug\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Converts a page slug to a route ID (snake_case)\n * e.g., 'about-us' -> 'about_us'\n */\nfunction toRouteId(slug: string): string {\n return slug.replace(/-/g, '_');\n}\n\n/**\n * Calculates the next available nav order by finding the highest existing order\n */\nfunction getNextNavOrder(content: string): number {\n // Match all order values in nav configs\n const orderMatches = [...content.matchAll(/order:\\s*(\\d+)/g)];\n let maxOrder = 0;\n\n for (const match of orderMatches) {\n const orderStr = match[1];\n if (orderStr) {\n const order = parseInt(orderStr, 10);\n if (order > maxOrder) {\n maxOrder = order;\n }\n }\n }\n\n // Return the next order (10 more than current max for room to insert)\n return maxOrder + 10;\n}\n\n/**\n * Adds a new route entry to base routes.ts (non-i18n projects)\n * Includes nav config so the page appears in navigation\n */\nfunction addBaseRouteEntry(targetDir: string, pageName: string): void {\n const routesPath = join(targetDir, 'src', 'config', 'routes.ts');\n\n if (!existsSync(routesPath)) {\n return; // routes.ts doesn't exist, skip\n }\n\n const routeId = toRouteId(pageName);\n const title = toTitle(pageName);\n const content = readFileSync(routesPath, 'utf-8');\n\n // Check if route already exists\n if (content.includes(`${routeId}:`)) {\n return; // Route already defined\n }\n\n // Find the closing of routes object (before \"} as const satisfies\")\n const insertPoint = content.indexOf('} as const satisfies');\n if (insertPoint === -1) {\n return; // Can't find insertion point\n }\n\n // Calculate the next nav order\n const navOrder = getNextNavOrder(content);\n\n // Create new route entry with nav config\n const newRoute = `\n // Custom page: ${pageName}\n ${routeId}: {\n path: '/${pageName}',\n nav: { show: true, order: ${navOrder}, label: '${title}' },\n },\n`;\n\n const newContent = content.slice(0, insertPoint) + newRoute + content.slice(insertPoint);\n writeFileSync(routesPath, newContent);\n}\n\n/**\n * Adds a new route entry to i18n routes.ts\n * Creates the route with the same English slug for all locales (user customizes later)\n * Includes nav config so the page appears in navigation\n */\nfunction addI18nRouteEntry(targetDir: string, pageName: string): void {\n const routesPath = join(targetDir, 'src', 'i18n', 'routes.ts');\n\n if (!existsSync(routesPath)) {\n return; // routes.ts doesn't exist, skip\n }\n\n const routeId = toRouteId(pageName);\n const content = readFileSync(routesPath, 'utf-8');\n\n // Check if route already exists\n if (content.includes(`${routeId}:`)) {\n return; // Route already defined\n }\n\n // Find the closing of routes object (before \"} as const satisfies\")\n const insertPoint = content.indexOf('} as const satisfies');\n if (insertPoint === -1) {\n return; // Can't find insertion point\n }\n\n // Calculate the next nav order\n const navOrder = getNextNavOrder(content);\n\n // Create new route entry with nav config\n // Uses the route ID as the translation key (user should add translation)\n const title = toTitle(pageName);\n const newRoute = `\n // Custom page: ${pageName}\n ${routeId}: {\n en: '${pageName}', es: '${pageName}', fr: '${pageName}',\n nav: { show: true, order: ${navOrder}, label: 'nav.${routeId}' },\n },\n`;\n\n const newContent = content.slice(0, insertPoint) + newRoute + content.slice(insertPoint);\n writeFileSync(routesPath, newContent);\n\n // Also add translation keys to translation files\n addI18nTranslationKeys(targetDir, routeId, title);\n}\n\n/**\n * Adds translation keys for a new route to all i18n translation files\n * Non-English locales get [TODO: Translate] markers to remind users to translate\n */\nfunction addI18nTranslationKeys(targetDir: string, routeId: string, title: string): void {\n const locales = ['en', 'es', 'fr'];\n const defaultLocale = 'en';\n\n for (const locale of locales) {\n const translationPath = join(targetDir, 'src', 'i18n', 'translations', `${locale}.ts`);\n\n if (!existsSync(translationPath)) {\n continue;\n }\n\n let content = readFileSync(translationPath, 'utf-8');\n\n // Determine if this is the default locale (no TODO markers needed)\n const isDefaultLocale = locale === defaultLocale;\n const navLabel = isDefaultLocale ? title : `[TODO: Translate] ${title}`;\n const pageTitle = isDefaultLocale ? title : `[TODO: Translate] ${title}`;\n const pageDesc = isDefaultLocale\n ? `Add your ${title.toLowerCase()} page description here.`\n : `[TODO: Translate] Add your ${title.toLowerCase()} page description here.`;\n\n // Add nav translation if not exists\n if (!content.includes(`${routeId}:`)) {\n // Find the nav section and add the key\n const navSectionMatch = content.match(/nav:\\s*\\{([^}]+)\\}/);\n if (navSectionMatch) {\n const navSection = navSectionMatch[0];\n const insertPoint = navSection.lastIndexOf('}');\n const newNavSection =\n navSection.slice(0, insertPoint) +\n ` ${routeId}: '${navLabel}',\\n ` +\n navSection.slice(insertPoint);\n content = content.replace(navSection, newNavSection);\n }\n }\n\n // Add page-specific translations if not exists\n const pageKeyPattern = new RegExp(`^\\\\s*${routeId}:\\\\s*\\\\{`, 'm');\n if (!pageKeyPattern.test(content)) {\n // Find a good insertion point (before the closing export)\n const insertPoint = content.lastIndexOf('} as const');\n if (insertPoint !== -1) {\n const pageTranslations = `\n // ${title} page\n ${routeId}: {\n title: '${pageTitle}',\n description: '${pageDesc}',\n },\n\n`;\n content = content.slice(0, insertPoint) + pageTranslations + content.slice(insertPoint);\n }\n }\n\n writeFileSync(translationPath, content);\n }\n}\n\n/**\n * Generates the standard page template (non-i18n)\n */\nfunction generatePageTemplate(pageName: string, layout: PageLayout): string {\n const title = toTitle(pageName);\n const layoutName = layout === 'landing' ? 'LandingLayout' : 'PageLayout';\n\n return `---\nimport ${layoutName} from '@/layouts/${layoutName}.astro';\n---\n\n<${layoutName}\n title=\"${title}\"\n description=\"Add your description here\"\n>\n <!-- Hero Section -->\n <section class=\"py-20 bg-secondary\">\n <div class=\"container\">\n <h1 class=\"text-4xl font-bold text-foreground\">${title}</h1>\n <p class=\"mt-4 text-foreground-muted max-w-2xl\">\n Add your content here.\n </p>\n </div>\n </section>\n\n <!-- Content Section -->\n <section class=\"py-16\">\n <div class=\"container\">\n <!-- Your content -->\n </div>\n </section>\n</${layoutName}>\n`;\n}\n\n/**\n * Generates the i18n-aware page template for the DEFAULT locale\n * This template uses translations so the default locale page is consistent with other locales\n */\nfunction generateI18nDefaultLocaleTemplate(pageName: string, layout: PageLayout): string {\n const title = toTitle(pageName);\n const layoutName = layout === 'landing' ? 'LandingLayout' : 'PageLayout';\n const routeId = toRouteId(pageName);\n const titleKey = `${routeId}.title`;\n const descKey = `${routeId}.description`;\n\n return `---\nimport ${layoutName} from '@/layouts/${layoutName}.astro';\nimport { defaultLocale } from '@/i18n/config';\nimport { useTranslations } from '@/i18n/index';\n\nconst t = useTranslations(defaultLocale);\n---\n\n<${layoutName}\n title={t('${titleKey}') || '${title}'}\n description={t('${descKey}') || 'Add your description here'}\n lang={defaultLocale}\n routeId=\"${routeId}\"\n>\n <!-- Hero Section -->\n <section class=\"py-20 bg-secondary\">\n <div class=\"container\">\n <h1 class=\"text-4xl font-bold text-foreground\">\n {t('${titleKey}') || '${title}'}\n </h1>\n <p class=\"mt-4 text-foreground-muted max-w-2xl\">\n {t('${descKey}') || 'Add your content here.'}\n </p>\n </div>\n </section>\n\n <!-- Content Section -->\n <section class=\"py-16\">\n <div class=\"container\">\n <!-- Your content -->\n </div>\n </section>\n</${layoutName}>\n`;\n}\n\n/**\n * Generates the i18n-aware page template with translated URL support\n */\nfunction generateI18nPageTemplate(pageName: string, layout: PageLayout): string {\n const title = toTitle(pageName);\n const layoutName = layout === 'landing' ? 'LandingLayout' : 'PageLayout';\n const routeId = toRouteId(pageName);\n const titleKey = `${routeId}.title`;\n const descKey = `${routeId}.description`;\n\n return `---\nimport ${layoutName} from '@/layouts/${layoutName}.astro';\nimport { locales, isValidLocale, defaultLocale, type Locale } from '@/i18n/config';\nimport { useTranslations } from '@/i18n/index';\nimport { routes } from '@/i18n/routes';\n\nexport function getStaticPaths() {\n return locales\n .filter((lang) => lang !== defaultLocale)\n .map((lang) => ({\n params: {\n lang,\n ${routeId}: routes.${routeId}[lang],\n },\n }));\n}\n\nconst { lang } = Astro.params;\n\nif (!lang || !isValidLocale(lang)) {\n return Astro.redirect('/');\n}\n\nconst locale = lang as Locale;\nconst t = useTranslations(locale);\n---\n\n<${layoutName}\n title={t('${titleKey}') || '${title}'}\n description={t('${descKey}') || 'Add your description here'}\n lang={locale}\n routeId=\"${routeId}\"\n>\n <!-- Hero Section -->\n <section class=\"py-20 bg-secondary\">\n <div class=\"container\">\n <h1 class=\"text-4xl font-bold text-foreground\">\n {t('${titleKey}') || '${title}'}\n </h1>\n <p class=\"mt-4 text-foreground-muted max-w-2xl\">\n {t('${descKey}') || 'Add your content here.'}\n </p>\n </div>\n </section>\n\n <!-- Content Section -->\n <section class=\"py-16\">\n <div class=\"container\">\n <!-- Your content -->\n </div>\n </section>\n</${layoutName}>\n`;\n}\n\n/**\n * Generates pages in the target directory\n */\nexport async function generatePages(\n targetDir: string,\n pages: string[],\n layout: PageLayout,\n isI18n: boolean\n): Promise<string[]> {\n const generatedFiles: string[] = [];\n\n if (pages.length === 0) {\n return generatedFiles;\n }\n\n // Ensure pages directory exists\n const pagesDir = join(targetDir, 'src', 'pages');\n if (!existsSync(pagesDir)) {\n mkdirSync(pagesDir, { recursive: true });\n }\n\n // Generate standard pages (English / default locale)\n for (const pageName of pages) {\n const filePath = join(pagesDir, `${pageName}.astro`);\n // For i18n projects, use the i18n-aware template even for default locale pages\n // This ensures translations work consistently across all locales\n const template = isI18n\n ? generateI18nDefaultLocaleTemplate(pageName, layout)\n : generatePageTemplate(pageName, layout);\n writeFileSync(filePath, template);\n generatedFiles.push(`src/pages/${pageName}.astro`);\n\n // Add route entry to base routes.ts (for non-i18n nav)\n if (!isI18n) {\n addBaseRouteEntry(targetDir, pageName);\n }\n }\n\n // Generate i18n pages if enabled\n if (isI18n) {\n const langDir = join(pagesDir, '[lang]');\n if (!existsSync(langDir)) {\n mkdirSync(langDir, { recursive: true });\n }\n\n for (const pageName of pages) {\n const routeId = toRouteId(pageName);\n // Use rest parameter syntax for translated URL slugs\n const filePath = join(langDir, `[...${routeId}].astro`);\n const template = generateI18nPageTemplate(pageName, layout);\n writeFileSync(filePath, template);\n generatedFiles.push(`src/pages/[lang]/[...${routeId}].astro`);\n\n // Add route entry to i18n routes.ts\n addI18nRouteEntry(targetDir, pageName);\n }\n }\n\n return generatedFiles;\n}\n\n/**\n * List of page-related files that could be generated\n */\nexport const PAGES_FILES = [\n 'src/pages/{pageName}.astro',\n 'src/pages/[lang]/[...{routeId}].astro',\n];\n","import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\n/**\n * Recursively copies a directory\n */\nexport function copyDirectory(src: string, dest: string, overwrite = false): void {\n if (!existsSync(src)) {\n throw new Error(`Source directory does not exist: ${src}`);\n }\n\n if (!existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n const entries = readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n copyDirectory(srcPath, destPath, overwrite);\n } else {\n if (overwrite || !existsSync(destPath)) {\n const destDir = dirname(destPath);\n if (!existsSync(destDir)) {\n mkdirSync(destDir, { recursive: true });\n }\n copyFileSync(srcPath, destPath);\n }\n }\n }\n}\n\n/**\n * Checks if a directory is empty\n */\nexport function isEmptyDir(path: string): boolean {\n if (!existsSync(path)) return true;\n const files = readdirSync(path);\n return files.length === 0 || (files.length === 1 && files[0] === '.git');\n}\n\n/**\n * Reads a JSON file and parses it\n */\nexport function readJson<T = Record<string, unknown>>(path: string): T {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content) as T;\n}\n\n/**\n * Writes an object as JSON to a file\n */\nexport function writeJson(path: string, data: unknown): void {\n writeFileSync(path, JSON.stringify(data, null, 2) + '\\n');\n}\n\n/**\n * Checks if path exists and is a directory\n */\nexport function isDirectory(path: string): boolean {\n return existsSync(path) && statSync(path).isDirectory();\n}\n","import { run } from './cli.js';\n\nrun(process.argv.slice(2)).catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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","names":["resolve","existsSync","p","pc","pc","resolve","text","pc","existsSync","mkdirSync","readFileSync","writeFileSync","join","dirname","p","execa","pc","__dirname","existsSync","existsSync","mkdirSync","join","readFileSync","writeFileSync","dirname","spinner","pc","execa","existsSync","mkdirSync","readdirSync","copyFileSync","readFileSync","writeFileSync","join","dirname","existsSync","readdirSync","pc","projectName","targetDir","resolve","existsSync"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-velocity-astro",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Create Velocity - A CLI to scaffold production-ready Astro 6 + Tailwind v4 projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,11 +49,14 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@clack/prompts": "^0.8.2",
|
|
51
51
|
"execa": "^9.5.2",
|
|
52
|
+
"figures": "^6.1.0",
|
|
52
53
|
"giget": "^3.1.1",
|
|
54
|
+
"gradient-string": "^3.0.0",
|
|
53
55
|
"mri": "^1.2.0",
|
|
54
56
|
"picocolors": "^1.1.1"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
59
|
+
"@types/gradient-string": "^1.1.6",
|
|
57
60
|
"@types/mri": "^1.1.4",
|
|
58
61
|
"@types/node": "^22.10.0",
|
|
59
62
|
"tsup": "^8.3.5",
|
|
@@ -100,7 +100,7 @@ const t = useTranslations(locale);
|
|
|
100
100
|
// Get navigation items from i18n routes or custom nav
|
|
101
101
|
const defaultNav = getNavRoutes(locale);
|
|
102
102
|
const navItems: NavItem[] = nav || defaultNav.map(route => ({
|
|
103
|
-
label: route.label,
|
|
103
|
+
label: t(route.label as any) || route.label,
|
|
104
104
|
href: route.path,
|
|
105
105
|
}));
|
|
106
106
|
|
|
@@ -111,7 +111,7 @@ const isInvert = colorScheme === 'invert';
|
|
|
111
111
|
// Get navigation items from i18n routes or custom nav
|
|
112
112
|
const defaultNav = getNavRoutes(locale);
|
|
113
113
|
const navItems: NavItem[] = nav || [...extraNav, ...defaultNav.map(route => ({
|
|
114
|
-
label: route.label,
|
|
114
|
+
label: t(route.label as any) || route.label,
|
|
115
115
|
href: route.path,
|
|
116
116
|
}))];
|
|
117
117
|
|
|
@@ -241,29 +241,32 @@ export type NavRoute = {
|
|
|
241
241
|
routeId: RouteId;
|
|
242
242
|
label: string;
|
|
243
243
|
order: number;
|
|
244
|
+
path: string;
|
|
244
245
|
};
|
|
245
246
|
|
|
246
247
|
/**
|
|
247
248
|
* Get routes that should appear in navigation, sorted by order
|
|
248
249
|
*
|
|
249
|
-
* @
|
|
250
|
+
* @param locale - The locale to get paths for (defaults to defaultLocale)
|
|
251
|
+
* @returns Array of navigation routes with their translation keys and localized paths
|
|
250
252
|
*
|
|
251
253
|
* @example
|
|
252
|
-
* const navRoutes = getNavRoutes();
|
|
254
|
+
* const navRoutes = getNavRoutes('en');
|
|
253
255
|
* // → [
|
|
254
|
-
* // { routeId: 'components', label: 'nav.components', order: 1 },
|
|
255
|
-
* // { routeId: 'blog', label: 'nav.blog', order: 2 },
|
|
256
|
-
* // { routeId: 'about', label: 'nav.about', order: 3 },
|
|
257
|
-
* // { routeId: 'contact', label: 'nav.contact', order: 4 },
|
|
256
|
+
* // { routeId: 'components', label: 'nav.components', order: 1, path: '/components' },
|
|
257
|
+
* // { routeId: 'blog', label: 'nav.blog', order: 2, path: '/blog' },
|
|
258
|
+
* // { routeId: 'about', label: 'nav.about', order: 3, path: '/about' },
|
|
259
|
+
* // { routeId: 'contact', label: 'nav.contact', order: 4, path: '/contact' },
|
|
258
260
|
* // ]
|
|
259
261
|
*/
|
|
260
|
-
export function getNavRoutes(): NavRoute[] {
|
|
262
|
+
export function getNavRoutes(locale: Locale = defaultLocale): NavRoute[] {
|
|
261
263
|
return Object.entries(routes)
|
|
262
264
|
.filter(([_, route]) => route.nav?.show === true)
|
|
263
265
|
.map(([routeId, route]) => ({
|
|
264
266
|
routeId: routeId as RouteId,
|
|
265
267
|
label: route.nav!.label,
|
|
266
268
|
order: route.nav!.order,
|
|
269
|
+
path: getLocalizedPath(routeId as RouteId, locale),
|
|
267
270
|
}))
|
|
268
271
|
.sort((a, b) => a.order - b.order);
|
|
269
272
|
}
|