chore(cli): remove all explicit return types (#573)

This commit is contained in:
Aman Varshney
2025-09-11 10:00:59 +05:30
committed by GitHub
parent 2b97093a1d
commit 0bfb3cfda0
45 changed files with 113 additions and 157 deletions

View File

@@ -1,6 +1,5 @@
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { Addons, Frontend, ProjectConfig } from "./types";
import { getUserPkgManager } from "./utils/get-package-manager";
const __filename = fileURLToPath(import.meta.url);
@@ -26,7 +25,7 @@ export const DEFAULT_CONFIG_BASE = {
serverDeploy: "none",
} as const;
export function getDefaultConfig(): ProjectConfig {
export function getDefaultConfig() {
return {
...DEFAULT_CONFIG_BASE,
projectDir: path.resolve(process.cwd(), DEFAULT_CONFIG_BASE.projectName),
@@ -160,7 +159,7 @@ export const dependencyVersionMap = {
export type AvailableDependencies = keyof typeof dependencyVersionMap;
export const ADDON_COMPATIBILITY: Record<Addons, readonly Frontend[]> = {
export const ADDON_COMPATIBILITY = {
pwa: ["tanstack-router", "react-router", "solid", "next"],
tauri: ["tanstack-router", "react-router", "nuxt", "svelte", "solid", "next"],
biome: [],

View File

@@ -95,7 +95,7 @@ ${pc.cyan("Docs:")} ${pc.underline("https://turborepo.com/docs")}
}
}
function getWebAppDir(projectDir: string, frontends: Frontend[]): string {
function getWebAppDir(projectDir: string, frontends: Frontend[]) {
if (
frontends.some((f) =>
["react-router", "tanstack-router", "nuxt", "svelte", "solid"].includes(

View File

@@ -115,7 +115,7 @@ export async function setupAuth(config: ProjectConfig) {
}
}
export function generateAuthSecret(length = 32): string {
export function generateAuthSecret(length = 32) {
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";

View File

@@ -13,7 +13,6 @@ import type {
AddInput,
CreateInput,
DirectoryConflict,
InitResult,
ProjectConfig,
} from "../../types";
import { trackProjectCreation } from "../../utils/analytics";
@@ -40,7 +39,7 @@ import { installDependencies } from "./install-dependencies";
export async function createProjectHandler(
input: CreateInput & { projectName?: string },
): Promise<InitResult> {
) {
const startTime = Date.now();
const timeScaffolded = new Date().toISOString();
@@ -58,7 +57,7 @@ export async function createProjectHandler(
currentPathInput = input.projectName;
} else if (input.yes) {
const defaultConfig = getDefaultConfig();
let defaultName = defaultConfig.relativePath;
let defaultName: string = defaultConfig.relativePath;
let counter = 1;
while (
(await fs.pathExists(path.resolve(process.cwd(), defaultName))) &&
@@ -210,7 +209,7 @@ export async function createProjectHandler(
async function handleDirectoryConflictProgrammatically(
currentPathInput: string,
strategy: DirectoryConflict,
): Promise<{ finalPathInput: string; shouldClearDirectory: boolean }> {
) {
const currentPath = path.resolve(process.cwd(), currentPathInput);
if (!(await fs.pathExists(currentPath))) {

View File

@@ -24,7 +24,7 @@ export async function createReadme(projectDir: string, options: ProjectConfig) {
}
}
function generateReadmeContent(options: ProjectConfig): string {
function generateReadmeContent(options: ProjectConfig) {
const {
projectName,
packageManager,
@@ -163,7 +163,7 @@ function generateStackDescription(
backend: string,
api: API,
isConvex: boolean,
): string {
) {
const parts: string[] = [];
const hasTanstackRouter = frontend.includes("tanstack-router");
@@ -210,7 +210,7 @@ function generateRunningInstructions(
webPort: string,
hasNative: boolean,
isConvex: boolean,
): string {
) {
const instructions: string[] = [];
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
@@ -265,7 +265,7 @@ function generateProjectStructure(
isConvex: boolean,
api: API,
auth: Auth,
): string {
) {
const structure: string[] = [`${projectName}/`, "├── apps/"];
const hasFrontendNone = frontend.length === 0 || frontend.includes("none");
@@ -349,7 +349,7 @@ function generateFeaturesList(
frontend: Frontend[],
backend: string,
api: API,
): string {
) {
const isConvex = backend === "convex";
const isBackendNone = backend === "none";
const hasTanstackRouter = frontend.includes("tanstack-router");
@@ -493,7 +493,7 @@ function generateDatabaseSetup(
orm: ORM,
dbSetup: DatabaseSetup,
serverDeploy?: string,
): string {
) {
if (database === "none") {
return "";
}
@@ -591,7 +591,7 @@ function generateScriptsList(
hasNative: boolean,
addons: Addons[],
backend: string,
): string {
) {
const isConvex = backend === "convex";
const isBackendNone = backend === "none";
@@ -657,7 +657,7 @@ function generateDeploymentCommands(
packageManagerRunCmd: string,
webDeploy?: string,
serverDeploy?: string,
): string {
) {
const lines: string[] = [];
if (webDeploy === "alchemy" || serverDeploy === "alchemy") {

View File

@@ -1,11 +1,8 @@
import path from "node:path";
import fs from "fs-extra";
import type { ProjectConfig } from "../../types";
import { readBtsConfig } from "../../utils/bts-config";
export async function detectProjectConfig(
projectDir: string,
): Promise<Partial<ProjectConfig> | null> {
export async function detectProjectConfig(projectDir: string) {
try {
const btsConfig = await readBtsConfig(projectDir);
if (btsConfig) {

View File

@@ -203,7 +203,7 @@ export async function displayPostInstallInstructions(
consola.box(output);
}
function getNativeInstructions(isConvex: boolean): string {
function getNativeInstructions(isConvex: boolean) {
const envVar = isConvex ? "EXPO_PUBLIC_CONVEX_URL" : "EXPO_PUBLIC_SERVER_URL";
const exampleUrl = isConvex
? "https://<YOUR_CONVEX_URL>"
@@ -226,7 +226,7 @@ function getNativeInstructions(isConvex: boolean): string {
return instructions;
}
function getLintingInstructions(runCmd?: string): string {
function getLintingInstructions(runCmd?: string) {
return `${pc.bold("Linting and formatting:")}\n${pc.cyan(
"•",
)} Format and lint fix: ${`${runCmd} check`}\n`;
@@ -239,7 +239,7 @@ async function getDatabaseInstructions(
runtime?: Runtime,
dbSetup?: DatabaseSetup,
serverDeploy?: string,
): Promise<string> {
) {
const instructions: string[] = [];
if (dbSetup === "docker") {
@@ -384,7 +384,7 @@ async function getDatabaseInstructions(
: "";
}
function getTauriInstructions(runCmd?: string): string {
function getTauriInstructions(runCmd?: string) {
return `\n${pc.bold("Desktop app with Tauri:")}\n${pc.cyan(
"•",
)} Start desktop app: ${`cd apps/web && ${runCmd} desktop:dev`}\n${pc.cyan(
@@ -394,13 +394,13 @@ function getTauriInstructions(runCmd?: string): string {
)} Tauri requires Rust and platform-specific dependencies.\n See: ${"https://v2.tauri.app/start/prerequisites/"}`;
}
function getPwaInstructions(): string {
function getPwaInstructions() {
return `\n${pc.bold("PWA with React Router v7:")}\n${pc.yellow(
"NOTE:",
)} There is a known compatibility issue between VitePWA\n and React Router v7. See:\n https://github.com/vite-pwa/vite-plugin-pwa/issues/809`;
}
function getStarlightInstructions(runCmd?: string): string {
function getStarlightInstructions(runCmd?: string) {
return `\n${pc.bold("Documentation with Starlight:")}\n${pc.cyan(
"•",
)} Start docs site: ${`cd apps/docs && ${runCmd} dev`}\n${pc.cyan(
@@ -408,13 +408,13 @@ function getStarlightInstructions(runCmd?: string): string {
)} Build docs site: ${`cd apps/docs && ${runCmd} build`}`;
}
function getNoOrmWarning(): string {
function getNoOrmWarning() {
return `\n${pc.yellow(
"WARNING:",
)} Database selected without an ORM. Features requiring\n database access (e.g., examples, auth) need manual setup.`;
}
function getBunWebNativeWarning(): string {
function getBunWebNativeWarning() {
return `\n${pc.yellow(
"WARNING:",
)} 'bun' might cause issues with web + native apps in a monorepo.\n Use 'pnpm' if problems arise.`;
@@ -424,7 +424,7 @@ function getWranglerDeployInstructions(
runCmd?: string,
webDeploy?: string,
serverDeploy?: string,
): string {
) {
const instructions: string[] = [];
if (webDeploy === "wrangler") {
@@ -441,7 +441,7 @@ function getWranglerDeployInstructions(
return instructions.length ? `\n${instructions.join("\n")}` : "";
}
function getClerkInstructions(): string {
function getClerkInstructions() {
return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("•")} Follow the guide: ${pc.underline("https://docs.convex.dev/auth/clerk")}\n${pc.cyan("•")} Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n${pc.cyan("•")} Set CLERK_PUBLISHABLE_KEY in apps/*/.env`;
}
@@ -449,7 +449,7 @@ function getAlchemyDeployInstructions(
runCmd?: string,
webDeploy?: string,
serverDeploy?: string,
): string {
) {
const instructions: string[] = [];
if (webDeploy === "alchemy" && serverDeploy !== "alchemy") {

View File

@@ -34,7 +34,7 @@ async function writeEnvFile(
await addEnvVariablesToFile(envPath, variables);
}
function getDatabaseUrl(database: Database, projectName: string): string {
function getDatabaseUrl(database: Database, projectName: string) {
switch (database) {
case "postgres":
return `postgresql://postgres:password@localhost:5432/${projectName}`;

View File

@@ -31,9 +31,7 @@ async function checkAtlasCLI() {
}
}
async function initMongoDBAtlas(
serverDir: string,
): Promise<MongoDBConfig | null> {
async function initMongoDBAtlas(serverDir: string) {
try {
const hasAtlas = await checkAtlasCLI();

View File

@@ -37,7 +37,7 @@ async function writeSupabaseEnvFile(projectDir: string, databaseUrl: string) {
}
}
function extractDbUrl(output: string): string | null {
function extractDbUrl(output: string) {
const dbUrlMatch = output.match(/DB URL:\s*(postgresql:\/\/[^\s]+)/);
const url = dbUrlMatch?.[1];
if (url) {

View File

@@ -14,13 +14,6 @@ type TursoConfig = {
authToken: string;
};
type TursoGroup = {
name: string;
locations: string;
version: string;
status: string;
};
async function isTursoInstalled() {
return commandExists("turso");
}
@@ -71,7 +64,7 @@ async function installTursoCLI(isMac: boolean) {
}
}
async function getTursoGroups(): Promise<TursoGroup[]> {
async function getTursoGroups() {
const s = spinner();
try {
s.start("Fetching Turso groups...");
@@ -97,7 +90,7 @@ async function getTursoGroups(): Promise<TursoGroup[]> {
}
}
async function selectTursoGroup(): Promise<string | null> {
async function selectTursoGroup() {
const groups = await getTursoGroups();
if (groups.length === 0) {

View File

@@ -76,7 +76,7 @@ export async function setupSvelteAlchemyDeploy(
}
}
function updateAdapterInConfig(configObject: Node): void {
function updateAdapterInConfig(configObject: Node) {
if (!Node.isObjectLiteralExpression(configObject)) return;
const kitProperty = configObject.getProperty("kit");

View File

@@ -218,10 +218,7 @@ export function createBtsCli() {
* }
* ```
*/
export async function init(
projectName?: string,
options?: CreateInput,
): Promise<InitResult> {
export async function init(projectName?: string, options?: CreateInput) {
const opts = (options ?? {}) as CreateInput;
const programmaticOpts = { ...opts, verbose: true };
const prev = process.env.BTS_PROGRAMMATIC;

View File

@@ -75,7 +75,7 @@ const ADDON_GROUPS = {
export async function getAddonsChoice(
addons?: Addons[],
frontends?: Frontend[],
): Promise<Addons[]> {
) {
if (addons !== undefined) return addons;
const allAddons = AddonsSchema.options.filter((addon) => addon !== "none");
@@ -131,7 +131,7 @@ export async function getAddonsChoice(
export async function getAddonsToAdd(
frontend: Frontend[],
existingAddons: Addons[] = [],
): Promise<Addons[]> {
) {
const groupedOptions: Record<string, AddonOption[]> = {
Documentation: [],
Linting: [],

View File

@@ -7,7 +7,7 @@ export async function getApiChoice(
Api?: API | undefined,
frontend?: Frontend[],
backend?: Backend,
): Promise<API> {
) {
if (backend === "convex" || backend === "none") {
return "none";
}

View File

@@ -6,7 +6,7 @@ import { exitCancelled } from "../utils/errors";
export async function getBackendFrameworkChoice(
backendFramework?: Backend,
frontends?: Frontend[],
): Promise<Backend> {
) {
if (backendFramework !== undefined) return backendFramework;
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid");

View File

@@ -55,7 +55,7 @@ export async function gatherConfig(
projectName: string,
projectDir: string,
relativePath: string,
): Promise<ProjectConfig> {
) {
const result = await group<PromptGroupResults>(
{
frontend: () =>
@@ -75,10 +75,14 @@ export async function gatherConfig(
results.runtime,
),
api: ({ results }) =>
getApiChoice(flags.api, results.frontend, results.backend),
getApiChoice(
flags.api,
results.frontend,
results.backend,
) as Promise<API>,
auth: ({ results }) =>
getAuthChoice(
flags.auth as import("../types").Auth | undefined,
flags.auth,
results.database !== "none",
results.backend,
results.frontend,
@@ -91,7 +95,7 @@ export async function gatherConfig(
results.frontend,
results.backend,
results.api,
),
) as Promise<Examples[]>,
dbSetup: ({ results }) =>
getDBSetupChoice(
results.database ?? "none",

View File

@@ -8,7 +8,7 @@ export async function getDBSetupChoice(
_orm?: ORM,
backend?: Backend,
runtime?: Runtime,
): Promise<DatabaseSetup> {
) {
if (backend === "convex") {
return "none";
}

View File

@@ -7,7 +7,7 @@ export async function getDatabaseChoice(
database?: Database,
backend?: Backend,
runtime?: Runtime,
): Promise<Database> {
) {
if (backend === "convex" || backend === "none") {
return "none";
}

View File

@@ -13,7 +13,7 @@ export async function getExamplesChoice(
frontends?: Frontend[],
backend?: Backend,
api?: API,
): Promise<Examples[]> {
) {
if (examples !== undefined) return examples;
if (api === "none") {

View File

@@ -8,7 +8,7 @@ export async function getFrontendChoice(
frontendOptions?: Frontend[],
backend?: Backend,
auth?: string,
): Promise<Frontend[]> {
) {
if (frontendOptions !== undefined) return frontendOptions;
const frontendTypes = await multiselect({

View File

@@ -27,7 +27,7 @@ export async function getORMChoice(
database?: Database,
backend?: Backend,
runtime?: Runtime,
): Promise<ORM> {
) {
if (backend === "convex") {
return "none";
}

View File

@@ -3,9 +3,7 @@ import type { PackageManager } from "../types";
import { exitCancelled } from "../utils/errors";
import { getUserPkgManager } from "../utils/get-package-manager";
export async function getPackageManagerChoice(
packageManager?: PackageManager,
): Promise<PackageManager> {
export async function getPackageManagerChoice(packageManager?: PackageManager) {
if (packageManager !== undefined) return packageManager;
const detectedPackageManager = getUserPkgManager();

View File

@@ -7,13 +7,13 @@ import { DEFAULT_CONFIG } from "../constants";
import { ProjectNameSchema } from "../types";
import { exitCancelled } from "../utils/errors";
function isPathWithinCwd(targetPath: string): boolean {
function isPathWithinCwd(targetPath: string) {
const resolved = path.resolve(targetPath);
const rel = path.relative(process.cwd(), resolved);
return !rel.startsWith("..") && !path.isAbsolute(rel);
}
function validateDirectoryName(name: string): string | undefined {
function validateDirectoryName(name: string) {
if (name === ".") return undefined;
const result = ProjectNameSchema.safeParse(name);
@@ -23,7 +23,7 @@ function validateDirectoryName(name: string): string | undefined {
return undefined;
}
export async function getProjectName(initialName?: string): Promise<string> {
export async function getProjectName(initialName?: string) {
if (initialName) {
if (initialName === ".") {
return initialName;
@@ -41,7 +41,7 @@ export async function getProjectName(initialName?: string): Promise<string> {
let isValid = false;
let projectPath = "";
let defaultName = DEFAULT_CONFIG.projectName;
let defaultName: string = DEFAULT_CONFIG.projectName;
let counter = 1;
while (

View File

@@ -3,10 +3,7 @@ import { DEFAULT_CONFIG } from "../constants";
import type { Backend, Runtime } from "../types";
import { exitCancelled } from "../utils/errors";
export async function getRuntimeChoice(
runtime?: Runtime,
backend?: Backend,
): Promise<Runtime> {
export async function getRuntimeChoice(runtime?: Runtime, backend?: Backend) {
if (backend === "convex" || backend === "none") {
return "none";
}

View File

@@ -36,7 +36,7 @@ export async function getServerDeploymentChoice(
runtime?: Runtime,
backend?: Backend,
webDeploy?: WebDeploy,
): Promise<ServerDeploy> {
) {
if (deployment !== undefined) return deployment;
if (backend === "none" || backend === "convex") {
@@ -82,7 +82,7 @@ export async function getServerDeploymentToAdd(
runtime?: Runtime,
existingDeployment?: ServerDeploy,
backend?: Backend,
): Promise<ServerDeploy> {
) {
if (backend !== "hono") {
return "none";
}

View File

@@ -4,7 +4,7 @@ import type { Backend, Frontend, Runtime, WebDeploy } from "../types";
import { WEB_FRAMEWORKS } from "../utils/compatibility";
import { exitCancelled } from "../utils/errors";
function hasWebFrontend(frontends: Frontend[]): boolean {
function hasWebFrontend(frontends: Frontend[]) {
return frontends.some((f) => WEB_FRAMEWORKS.includes(f));
}
@@ -41,7 +41,7 @@ export async function getDeploymentChoice(
_runtime?: Runtime,
_backend?: Backend,
frontend: Frontend[] = [],
): Promise<WebDeploy> {
) {
if (deployment !== undefined) return deployment;
if (!hasWebFrontend(frontend)) {
return "none";
@@ -72,7 +72,7 @@ export async function getDeploymentChoice(
export async function getDeploymentToAdd(
frontend: Frontend[],
existingDeployment?: WebDeploy,
): Promise<WebDeploy> {
) {
if (!hasWebFrontend(frontend)) {
return "none";
}

View File

@@ -30,7 +30,7 @@ export function getCompatibleAddons(
allAddons: Addons[],
frontend: Frontend[],
existingAddons: Addons[] = [],
): Addons[] {
) {
return allAddons.filter((addon) => {
if (existingAddons.includes(addon)) return false;

View File

@@ -5,10 +5,7 @@ import consola from "consola";
let biome: Biome | null = null;
let projectKey: number | null = null;
async function initializeBiome(): Promise<{
biome: Biome;
projectKey: number;
}> {
async function initializeBiome() {
if (biome && projectKey !== null) return { biome, projectKey };
try {
@@ -39,19 +36,18 @@ async function initializeBiome(): Promise<{
});
return { biome, projectKey };
} catch (error) {
consola.error("Failed to initialize Biome:", error);
throw error;
} catch (_error) {
return null;
}
}
function isSupportedFile(filePath: string): boolean {
function isSupportedFile(filePath: string) {
const ext = path.extname(filePath).toLowerCase();
const supportedExtensions = [".js", ".jsx", ".ts", ".tsx", ".json", ".jsonc"];
return supportedExtensions.includes(ext);
}
function shouldSkipFile(filePath: string): boolean {
function shouldSkipFile(filePath: string) {
const basename = path.basename(filePath);
const skipPatterns = [
".hbs",
@@ -65,16 +61,16 @@ function shouldSkipFile(filePath: string): boolean {
return skipPatterns.some((pattern) => basename.includes(pattern));
}
export async function formatFileWithBiome(
filePath: string,
content: string,
): Promise<string | null> {
export async function formatFileWithBiome(filePath: string, content: string) {
if (!isSupportedFile(filePath) || shouldSkipFile(filePath)) {
return null;
}
try {
const { biome: biomeInstance, projectKey: key } = await initializeBiome();
const biomeResult = await initializeBiome();
if (!biomeResult) return null;
const { biome: biomeInstance, projectKey: key } = biomeResult;
const result = biomeInstance.formatContent(key, content, {
filePath: path.basename(filePath),
@@ -88,8 +84,7 @@ export async function formatFileWithBiome(
}
return result.content;
} catch (error) {
consola.warn(`Failed to format ${filePath} with Biome:`, error);
} catch (_error) {
return null;
}
}

View File

@@ -62,9 +62,7 @@ ${configContent}`;
await fs.writeFile(configPath, finalContent, "utf-8");
}
export async function readBtsConfig(
projectDir: string,
): Promise<BetterTStackConfig | null> {
export async function readBtsConfig(projectDir: string) {
try {
const configPath = path.join(projectDir, BTS_CONFIG_FILE);

View File

@@ -12,7 +12,7 @@ import { validateAddonCompatibility } from "./addon-compatibility";
import { WEB_FRAMEWORKS } from "./compatibility";
import { exitWithError } from "./errors";
export function isWebFrontend(value: Frontend): boolean {
export function isWebFrontend(value: Frontend) {
return WEB_FRAMEWORKS.includes(value);
}
@@ -138,7 +138,7 @@ export function isFrontendAllowedWithBackend(
return true;
}
export function allowedApisForFrontends(frontends: Frontend[] = []): API[] {
export function allowedApisForFrontends(frontends: Frontend[] = []) {
const includesNuxt = frontends.includes("nuxt");
const includesSvelte = frontends.includes("svelte");
const includesSolid = frontends.includes("solid");

View File

@@ -14,9 +14,7 @@ import type {
WebDeploy,
} from "../types";
export function processArrayOption<T>(
options: (T | "none")[] | undefined,
): T[] {
export function processArrayOption<T>(options: (T | "none")[] | undefined) {
if (!options || options.length === 0) return [];
if (options.includes("none" as T | "none")) return [];
return options.filter((item): item is T => item !== "none");
@@ -25,7 +23,7 @@ export function processArrayOption<T>(
export function deriveProjectName(
projectName?: string,
projectDirectory?: string,
): string {
) {
if (projectName) {
return projectName;
}
@@ -35,10 +33,7 @@ export function deriveProjectName(
return "";
}
export function processFlags(
options: CLIInput,
projectName?: string,
): Partial<ProjectConfig> {
export function processFlags(options: CLIInput, projectName?: string) {
const config: Partial<ProjectConfig> = {};
if (options.api) {
@@ -109,7 +104,7 @@ export function processFlags(
return config;
}
export function getProvidedFlags(options: CLIInput): Set<string> {
export function getProvidedFlags(options: CLIInput) {
return new Set(
Object.keys(options).filter(
(key) => options[key as keyof CLIInput] !== undefined,
@@ -120,7 +115,7 @@ export function getProvidedFlags(options: CLIInput): Set<string> {
export function validateNoneExclusivity<T>(
options: (T | "none")[] | undefined,
optionName: string,
): void {
) {
if (!options || options.length === 0) return;
if (options.includes("none" as T | "none") && options.length > 1) {
@@ -128,7 +123,7 @@ export function validateNoneExclusivity<T>(
}
}
export function validateArrayOptions(options: CLIInput): void {
export function validateArrayOptions(options: CLIInput) {
validateNoneExclusivity(options.frontend, "frontend options");
validateNoneExclusivity(options.addons, "addons");
validateNoneExclusivity(options.examples, "examples");

View File

@@ -20,7 +20,7 @@ import { exitWithError } from "./errors";
export function validateDatabaseOrmAuth(
cfg: Partial<ProjectConfig>,
flags?: Set<string>,
): void {
) {
const db = cfg.database;
const orm = cfg.orm;
const has = (k: string) => (flags ? flags.has(k) : true);
@@ -91,7 +91,7 @@ export function validateDatabaseOrmAuth(
export function validateDatabaseSetup(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
): void {
) {
const { dbSetup, database, runtime } = config;
if (
@@ -188,7 +188,7 @@ export function validateDatabaseSetup(
export function validateConvexConstraints(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
): void {
) {
const { backend } = config;
if (backend !== "convex") {
@@ -243,7 +243,7 @@ export function validateConvexConstraints(
export function validateBackendNoneConstraints(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
): void {
) {
const { backend } = config;
if (backend !== "none") {
@@ -299,7 +299,7 @@ export function validateBackendConstraints(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
options: CLIInput,
): void {
) {
const { backend } = config;
if (config.auth === "clerk" && backend !== "convex") {
@@ -353,7 +353,7 @@ export function validateBackendConstraints(
export function validateFrontendConstraints(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
): void {
) {
const { frontend } = config;
if (frontend && frontend.length > 0) {
@@ -375,7 +375,7 @@ export function validateFrontendConstraints(
export function validateApiConstraints(
config: Partial<ProjectConfig>,
options: CLIInput,
): void {
) {
if (config.api === "none") {
if (
options.examples &&
@@ -393,7 +393,7 @@ export function validateFullConfig(
config: Partial<ProjectConfig>,
providedFlags: Set<string>,
options: CLIInput,
): void {
) {
validateDatabaseOrmAuth(config, providedFlags);
validateDatabaseSetup(config, providedFlags);
@@ -430,7 +430,7 @@ export function validateFullConfig(
export function validateConfigForProgrammaticUse(
config: Partial<ProjectConfig>,
): void {
) {
try {
validateDatabaseOrmAuth(config);

View File

@@ -1,4 +1,5 @@
import os from "node:os";
import { $ } from "execa";
import pc from "picocolors";
import type { Database } from "../types";
import { commandExists } from "./command-exists";
@@ -9,7 +10,6 @@ export async function isDockerInstalled() {
export async function isDockerRunning() {
try {
const { $ } = await import("execa");
await $`docker info`;
return true;
} catch {
@@ -20,7 +20,7 @@ export async function isDockerRunning() {
export function getDockerInstallInstructions(
platform: string,
database: Database,
): string {
) {
const isMac = platform === "darwin";
const isWindows = platform === "win32";
const isLinux = platform === "linux";
@@ -50,11 +50,7 @@ export function getDockerInstallInstructions(
return `${pc.yellow("IMPORTANT:")} Docker required for ${databaseName}. Install for ${platformName}:\n${pc.blue(installUrl)}`;
}
export async function getDockerStatus(database: Database): Promise<{
installed: boolean;
running: boolean;
message?: string;
}> {
export async function getDockerStatus(database: Database) {
const platform = os.platform();
const installed = await isDockerInstalled();

View File

@@ -2,7 +2,7 @@ import { cancel } from "@clack/prompts";
import consola from "consola";
import pc from "picocolors";
function isProgrammatic(): boolean {
function isProgrammatic() {
return process.env.BTS_PROGRAMMATIC === "1";
}

View File

@@ -1,6 +1,6 @@
import type { ProjectConfig } from "../types";
export function generateReproducibleCommand(config: ProjectConfig): string {
export function generateReproducibleCommand(config: ProjectConfig) {
const flags: string[] = [];
if (config.frontend && config.frontend.length > 0) {

View File

@@ -11,7 +11,7 @@ import type { PackageManager } from "../types";
export function getPackageExecutionCommand(
packageManager: PackageManager | null | undefined,
commandWithArgs: string,
): string {
) {
switch (packageManager) {
case "pnpm":
return `pnpm dlx ${commandWithArgs}`;

View File

@@ -8,10 +8,7 @@ import { exitCancelled, handleError } from "./errors";
export async function handleDirectoryConflict(
currentPathInput: string,
silent = false,
): Promise<{
finalPathInput: string;
shouldClearDirectory: boolean;
}> {
) {
while (true) {
const resolvedPath = path.resolve(process.cwd(), currentPathInput);
const dirExists = await fs.pathExists(resolvedPath);
@@ -86,7 +83,7 @@ export async function handleDirectoryConflict(
export async function setupProjectDirectory(
finalPathInput: string,
shouldClearDirectory: boolean,
): Promise<{ finalResolvedPath: string; finalBaseName: string }> {
) {
let finalResolvedPath: string;
let finalBaseName: string;

View File

@@ -2,7 +2,7 @@ import path from "node:path";
import { ProjectNameSchema } from "../types";
import { exitWithError } from "./errors";
export function validateProjectName(name: string): void {
export function validateProjectName(name: string) {
const result = ProjectNameSchema.safeParse(name);
if (!result.success) {
exitWithError(
@@ -13,7 +13,7 @@ export function validateProjectName(name: string): void {
}
}
export function validateProjectNameThrow(name: string): void {
export function validateProjectNameThrow(name: string) {
const result = ProjectNameSchema.safeParse(name);
if (!result.success) {
throw new Error(`Invalid project name: ${result.error.issues[0]?.message}`);
@@ -24,7 +24,7 @@ export function extractAndValidateProjectName(
projectName?: string,
projectDirectory?: string,
throwOnError = false,
): string {
) {
const derivedName =
projectName ||
(projectDirectory

View File

@@ -41,9 +41,7 @@ type SponsorEntry = {
export const SPONSORS_JSON_URL =
"https://sponsors.better-t-stack.dev/sponsors.json";
export async function fetchSponsors(
url: string = SPONSORS_JSON_URL,
): Promise<SponsorEntry> {
export async function fetchSponsors(url: string = SPONSORS_JSON_URL) {
const s = spinner();
s.start("Fetching sponsors…");

View File

@@ -4,7 +4,7 @@
* - If BTS_TELEMETRY_DISABLED is present and "1", disables analytics.
* - Otherwise, BTS_TELEMETRY: "0" disables, "1" enables (default: enabled).
*/
export function isTelemetryEnabled(): boolean {
export function isTelemetryEnabled() {
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
const BTS_TELEMETRY = process.env.BTS_TELEMETRY;

View File

@@ -19,7 +19,7 @@ export const tsProject = new Project({
export function ensureArrayProperty(
obj: ObjectLiteralExpression,
name: string,
): ArrayLiteralExpression {
) {
return (obj
.getProperty(name)
?.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression) ??

View File

@@ -48,7 +48,7 @@ export function processAndValidateFlags(
options: CLIInput,
providedFlags: Set<string>,
projectName?: string,
): Partial<ProjectConfig> {
) {
if (options.yolo) {
const cfg = processFlags(options, projectName);
const validatedProjectName = extractAndValidateProjectName(
@@ -89,7 +89,7 @@ export function processAndValidateFlags(
export function processProvidedFlagsWithoutValidation(
options: CLIInput,
projectName?: string,
): Partial<ProjectConfig> {
) {
if (!options.yolo) {
const providedFlags = getProvidedFlags(options);
validateYesFlagCombination(options, providedFlags);