Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions src/env/envManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import logger from '../utils/logger.js'
import { type StepResult } from '../types/index.js'

export class EnvironmentManager {
async setupEnvironment(projectName: string, apiKey: string): Promise<StepResult> {
async setupEnvironment(projectName: string, apiKey: string, options: { isCurrentDir?: boolean } = { isCurrentDir: false }): Promise<StepResult> {
try {
const projectPath = path.join(process.cwd(), projectName)
const projectPath = options.isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName)

// Ensure we're in the project directory
try {
Expand Down
34 changes: 27 additions & 7 deletions src/generators/project.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import execa from 'execa'
import fs, { createReadStream, createWriteStream } from 'fs'
import fs, { createReadStream, createWriteStream, Dirent } from 'fs'
import path from 'path'

import logger from '../utils/logger.js'
Expand All @@ -10,14 +10,34 @@ import telemetry from '../utils/telemetry.js'
export class ProjectGenerator {
async createProject(options: ProjectGenerationOptions): Promise<StepResult> {
try {
const projectPath = path.join(options.directory, options.name)
const projectPath = options.isCurrentDir ? process.cwd() : path.join(options.directory, options.name)

// Check if directory already exists
try {
await fs.promises.access(projectPath, fs.constants.F_OK)
throw new Error(`Directory "${options.name}" already exists`)
} catch (error) {
// Directory doesn't exist, which is what we want
if (!options.isCurrentDir) {
try {
await fs.promises.access(projectPath, fs.constants.F_OK)
throw new Error(`Directory "${options.name}" already exists`)
} catch (error) {
// Directory doesn't exist, which is what we want
}
} else {
const files = await fs.promises.readdir(projectPath, { withFileTypes: true });
const ignoredFiles = [
".git",
".DS_Store",
"node_modules",
".env",
"Thumbs.db",
];
const significantFiles = files.filter(
(file: Dirent) => file.isFile() && !ignoredFiles.includes(file.name)
).map(file => file.name);

if (significantFiles.length > 0) {
throw new Error(
"Current directory is not empty. Please use an empty directory or specify a different project name."
);
}
}

logger.debug(`Creating project from template at: ${projectPath}`)
Expand Down
67 changes: 48 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ function checkNodeVersion(): void {
}
}

// Helper function to resolve project name from "." to currect directory name
function resolveProjectName(projectName: string): { name: string, isCurrentDir: boolean } {
if (projectName === '.') {
return { name: path.basename(process.cwd()), isCurrentDir: true }
}
return { name: projectName, isCurrentDir: false }
}

const TOTAL_STEPS = 3
class CreateC1App {
private readonly spinner: SpinnerManager
Expand All @@ -79,7 +87,8 @@ class CreateC1App {
this.spinner = new SpinnerManager()
this.config = {
projectName: '',
template: 'app'
template: 'app',
isCurrentDir: false
}
}

Expand Down Expand Up @@ -367,21 +376,35 @@ class CreateC1App {

let projectName = options.projectName
let template = options.template
let isCurrentDir = false

// Project name
projectName ??= await input({
message: 'What is your project name?',
default: 'my-c1-app',
prefill: 'editable',
validate: (input: string) => {
const validation = Validator.validateProjectName(input)
if (!validation.isValid) {
return validation.errors[0]
}
return true
},
transformer: (input: string) => Validator.sanitizeProjectName(input)
})
if (projectName === '' || projectName === undefined) {
projectName = await input({
message: 'What is your project name?',
default: 'my-c1-app',
prefill: 'editable',
validate: (input: string) => {
const validation = Validator.validateProjectName(input)
if (!validation.isValid) {
return validation.errors[0]
}
return true
},
transformer: (input: string) => Validator.sanitizeProjectName(input)
})
} else {
const resolved = resolveProjectName(projectName)
projectName = resolved.name
isCurrentDir = resolved.isCurrentDir

const validation = Validator.validateProjectName(projectName)
if (!validation.isValid) {
logger.error(`Invalid project name "${projectName}": ${validation.errors[0]}`)
logger.info('Please enter a valid project name')
process.exit(1)
}
}

// Template selection
if (template === undefined) {
Expand All @@ -402,7 +425,8 @@ class CreateC1App {
// Update config with answers and CLI options
this.config = {
projectName,
template: template || 'template-c1-component-next'
template: template || 'template-c1-component-next',
isCurrentDir
}

// Track project configuration
Expand All @@ -426,7 +450,8 @@ class CreateC1App {
const result = await generator.createProject({
name: this.config.projectName,
template: this.config.template,
directory: process.cwd()
directory: process.cwd(),
isCurrentDir: this.config.isCurrentDir
})

if (result.success) {
Expand Down Expand Up @@ -460,7 +485,7 @@ class CreateC1App {
try {
const envManager = new EnvironmentManager()

const result = await envManager.setupEnvironment(this.config.projectName, apiKey)
const result = await envManager.setupEnvironment(this.config.projectName, apiKey, { isCurrentDir: this.config.isCurrentDir })

if (result.success) {
// Track successful environment setup
Expand Down Expand Up @@ -488,8 +513,11 @@ class CreateC1App {
logger.newLine()

logger.info('Your project is ready! Next steps:')
logger.info(` 1. cd ${this.config.projectName}`)
logger.info(' 2. npm run dev')
if (this.config.isCurrentDir) logger.info(' 1. npm run dev')
else {
logger.info(` 1. cd ${this.config.projectName}`)
logger.info(' 2. npm run dev')
}
logger.newLine()

logger.info('Happy coding! 🚀')
Expand Down Expand Up @@ -532,6 +560,7 @@ export { CreateC1App }
// Execute main function when run directly
// ESM equivalent of require.main === module
import { fileURLToPath } from 'url'
import path from 'path'
const isMainModule = process.argv[1] === fileURLToPath(import.meta.url)

if (isMainModule) {
Expand Down
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface CreateC1AppConfig {
projectName: string
template: string
isCurrentDir: boolean
}

export interface AuthCredentials {
Expand Down Expand Up @@ -49,6 +50,7 @@ export interface ProjectGenerationOptions {
name: string
template: string
directory: string
isCurrentDir: boolean
}

export interface EnvironmentConfig {
Expand Down