Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions cli/src/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { intro, isCancel, outro, select, text } from "@clack/prompts"
import color from "picocolors"
import { getUserPkgManager } from "@/utils/get-user-pkg-manager.js"
import path from "path"

export interface CliResults {
projectName: string
Expand All @@ -13,6 +14,19 @@ export interface CliResults {
export type Dialect = CliResults["dialect"]
export type Orm = CliResults["orm"]

// NPM package name validation regex
const VALID_PACKAGE_NAME = /^(?:(?:@(?:[a-z0-9-~][a-z0-9-.~]*)?\/)?[a-z0-9-._~]*[a-z0-9-~]|[a-z0-9-~])$/

// Function to sanitize package name
const sanitizePackageName = (name: string): string => {
return name
.toLowerCase()
.replace(/[^a-z0-9-~]/g, '-')
.replace(/^[._]/, '')
.replace(/^-+|-+$/g, '')
|| 'jstack-app'
}

export async function runCli(): Promise<CliResults | undefined> {
console.clear()

Expand All @@ -31,6 +45,19 @@ export async function runCli(): Promise<CliResults | undefined> {
validate: (value) => {
if (!value) return "Please enter a project name"
if (value.length > 50) return "Project name must be less than 50 characters"

// Handle "." input by using current directory name
if (value === ".") {
const currentDir = path.basename(process.cwd())
value = currentDir
}

// Validate against npm package name rules
if (!VALID_PACKAGE_NAME.test(value)) {
const sanitized = sanitizePackageName(value)
return `Invalid package name. Try: ${sanitized}`
}

return
},
}))
Expand Down