mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
feat: add command (#337)
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import { cancel, isCancel, multiselect } from "@clack/prompts";
|
||||
import pc from "picocolors";
|
||||
import { DEFAULT_CONFIG } from "../constants";
|
||||
import type { Addons, Frontend } from "../types";
|
||||
import { type Addons, AddonsSchema, type Frontend } from "../types";
|
||||
import {
|
||||
getCompatibleAddons,
|
||||
validateAddonCompatibility,
|
||||
} from "../utils/addon-compatibility";
|
||||
|
||||
type AddonOption = {
|
||||
value: Addons;
|
||||
@@ -9,63 +13,73 @@ type AddonOption = {
|
||||
hint: string;
|
||||
};
|
||||
|
||||
function getAddonDisplay(
|
||||
addon: Addons,
|
||||
isRecommended = false,
|
||||
): { label: string; hint: string } {
|
||||
let label: string;
|
||||
let hint: string;
|
||||
|
||||
if (addon === "turborepo") {
|
||||
label = isRecommended ? "Turborepo (Recommended)" : "Turborepo";
|
||||
hint = "High-performance build system for JavaScript and TypeScript";
|
||||
} else if (addon === "pwa") {
|
||||
label = "PWA (Progressive Web App)";
|
||||
hint = "Make your app installable and work offline";
|
||||
} else if (addon === "tauri") {
|
||||
label = isRecommended ? "Tauri Desktop App" : "Tauri";
|
||||
hint = "Build native desktop apps from your web frontend";
|
||||
} else if (addon === "biome") {
|
||||
label = "Biome";
|
||||
hint = isRecommended
|
||||
? "Add Biome for linting and formatting"
|
||||
: "Fast formatter and linter for JavaScript, TypeScript, JSX";
|
||||
} else if (addon === "husky") {
|
||||
label = "Husky";
|
||||
hint = isRecommended
|
||||
? "Add Git hooks with Husky, lint-staged (requires Biome)"
|
||||
: "Git hooks made easy";
|
||||
} else if (addon === "starlight") {
|
||||
label = "Starlight";
|
||||
hint = isRecommended
|
||||
? "Add Astro Starlight documentation site"
|
||||
: "Documentation site with Astro";
|
||||
} else {
|
||||
label = addon;
|
||||
hint = `Add ${addon}`;
|
||||
}
|
||||
|
||||
return { label, hint };
|
||||
}
|
||||
|
||||
export async function getAddonsChoice(
|
||||
addons?: Addons[],
|
||||
frontends?: Frontend[],
|
||||
): Promise<Addons[]> {
|
||||
if (addons !== undefined) return addons;
|
||||
|
||||
const hasCompatiblePwaFrontend =
|
||||
frontends?.includes("react-router") ||
|
||||
frontends?.includes("tanstack-router") ||
|
||||
frontends?.includes("solid") ||
|
||||
frontends?.includes("next");
|
||||
const allAddons = AddonsSchema.options.filter((addon) => addon !== "none");
|
||||
|
||||
const hasCompatibleTauriFrontend =
|
||||
frontends?.includes("react-router") ||
|
||||
frontends?.includes("tanstack-router") ||
|
||||
frontends?.includes("nuxt") ||
|
||||
frontends?.includes("svelte") ||
|
||||
frontends?.includes("solid") ||
|
||||
frontends?.includes("next");
|
||||
const allPossibleOptions: AddonOption[] = [];
|
||||
|
||||
const allPossibleOptions: AddonOption[] = [
|
||||
{
|
||||
value: "turborepo",
|
||||
label: "Turborepo (Recommended)",
|
||||
hint: "Optimize builds for monorepos",
|
||||
},
|
||||
{
|
||||
value: "starlight",
|
||||
label: "Starlight",
|
||||
hint: "Add Astro Starlight documentation site",
|
||||
},
|
||||
{
|
||||
value: "biome",
|
||||
label: "Biome",
|
||||
hint: "Add Biome for linting and formatting",
|
||||
},
|
||||
{
|
||||
value: "husky",
|
||||
label: "Husky",
|
||||
hint: "Add Git hooks with Husky, lint-staged (requires Biome)",
|
||||
},
|
||||
{
|
||||
value: "pwa",
|
||||
label: "PWA (Progressive Web App)",
|
||||
hint: "Make your app installable and work offline",
|
||||
},
|
||||
{
|
||||
value: "tauri",
|
||||
label: "Tauri Desktop App",
|
||||
hint: "Build native desktop apps from your web frontend",
|
||||
},
|
||||
];
|
||||
for (const addon of allAddons) {
|
||||
const { isCompatible } = validateAddonCompatibility(addon, frontends || []);
|
||||
|
||||
const options = allPossibleOptions.filter((option) => {
|
||||
if (option.value === "pwa") return hasCompatiblePwaFrontend;
|
||||
if (option.value === "tauri") return hasCompatibleTauriFrontend;
|
||||
return true;
|
||||
if (isCompatible) {
|
||||
const { label, hint } = getAddonDisplay(addon, true);
|
||||
|
||||
allPossibleOptions.push({
|
||||
value: addon,
|
||||
label,
|
||||
hint,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const options = allPossibleOptions.sort((a, b) => {
|
||||
if (a.value === "turborepo") return -1;
|
||||
if (b.value === "turborepo") return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const initialValues = DEFAULT_CONFIG.addons.filter((addonValue) =>
|
||||
@@ -90,3 +104,45 @@ export async function getAddonsChoice(
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function getAddonsToAdd(
|
||||
frontend: Frontend[],
|
||||
existingAddons: Addons[] = [],
|
||||
): Promise<Addons[]> {
|
||||
const options: AddonOption[] = [];
|
||||
|
||||
const allAddons = AddonsSchema.options.filter((addon) => addon !== "none");
|
||||
|
||||
const compatibleAddons = getCompatibleAddons(
|
||||
allAddons,
|
||||
frontend,
|
||||
existingAddons,
|
||||
);
|
||||
|
||||
for (const addon of compatibleAddons) {
|
||||
const { label, hint } = getAddonDisplay(addon, false);
|
||||
|
||||
options.push({
|
||||
value: addon,
|
||||
label,
|
||||
hint,
|
||||
});
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const response = await multiselect<Addons>({
|
||||
message: "Select addons",
|
||||
options: options,
|
||||
required: true,
|
||||
});
|
||||
|
||||
if (isCancel(response)) {
|
||||
cancel(pc.red("Operation cancelled"));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user