Skip to content
Merged
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
30 changes: 30 additions & 0 deletions packages/atxp/src/check-dependencies.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import { checkDependency } from './check-dependencies.js';

describe('checkDependency', () => {
it('should return true for available commands', async () => {
const nodeDependency = {
name: 'Node.js',
command: 'node',
args: ['--version'],
requiredFor: ['demo'],
installInstructions: 'Please install Node.js'
};

const result = await checkDependency(nodeDependency);
expect(result).toBe(true);
});

it('should return false for unavailable commands', async () => {
const fakeDependency = {
name: 'Fake Command',
command: 'nonexistent-command-12345',
args: ['--version'],
requiredFor: ['demo'],
installInstructions: 'This command does not exist'
};

const result = await checkDependency(fakeDependency);
expect(result).toBe(false);
});
});
75 changes: 75 additions & 0 deletions packages/atxp/src/check-dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { spawn } from 'child_process';
import chalk from 'chalk';

interface DependencyCheck {
name: string;
command: string;
args: string[];
requiredFor: string[];
installInstructions: string;
}

const DEPENDENCIES: DependencyCheck[] = [
{
name: 'Git',
command: 'git',
args: ['--version'],
requiredFor: ['demo', 'create'],
installInstructions: 'Please install Git from https://git-scm.com/downloads'
},
{
name: 'npm',
command: 'npm',
args: ['--version'],
requiredFor: ['demo'],
installInstructions: 'Please install Node.js (which includes npm) from https://nodejs.org/'
}
];

export async function checkDependency(dependency: DependencyCheck): Promise<boolean> {
return new Promise((resolve) => {
const process = spawn(dependency.command, dependency.args, {
stdio: 'ignore'
});

process.on('close', (code) => {
resolve(code === 0);
});

process.on('error', () => {
resolve(false);
});
});
}

export async function checkAllDependencies(command?: string): Promise<boolean> {
let allDependenciesOk = true;

for (const dependency of DEPENDENCIES) {
// If a specific command is provided, only check dependencies for that command
if (command && !dependency.requiredFor.includes(command)) {
continue;
}

const isAvailable = await checkDependency(dependency);

if (!isAvailable) {
console.error(chalk.red(`✗ ${dependency.name} is not installed or not available in PATH`));
console.error(chalk.yellow(` Required for: ${dependency.requiredFor.join(', ')}`));
console.error(chalk.white(` ${dependency.installInstructions}`));
console.error('');
allDependenciesOk = false;
}
}

return allDependenciesOk;
}

export function showDependencyError(command: string): void {
console.error(chalk.red(`Cannot run "${command}" command due to missing dependencies.`));
console.error(chalk.yellow('Please install the required dependencies and try again.'));
console.error('');
console.error(chalk.white('For help with installation, visit:'));
console.error(chalk.blue(' Git: https://git-scm.com/downloads'));
console.error(chalk.blue(' Node.js/npm: https://nodejs.org/'));
}
50 changes: 34 additions & 16 deletions packages/atxp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from 'os';
import { createProject } from './create-project.js';
import { runDemo } from './run-demo.js';
import { showHelp } from './help.js';
import { checkAllDependencies, showDependencyError } from './check-dependencies.js';

interface DemoOptions {
port: number;
Expand Down Expand Up @@ -54,20 +55,37 @@ const isCreateMode = process.env.npm_config_argv?.includes('create') ||
command === 'create';

// Handle different commands
if (isCreateMode) {
console.log('Creating new ATXP project...');
createProject();
} else if (command === 'demo') {
console.log('Starting ATXP demo...');
runDemo(demoOptions);
} else if (command === 'help' || command === '--help' || command === '-h') {
showHelp();
} else if (!command) {
// No command provided - show help instead of running demo
showHelp();
} else {
// Unknown command
console.log(`Unknown command: ${command}`);
console.log('Run "npx atxp help" for usage information.');
async function main() {
if (isCreateMode) {
console.log('Creating new ATXP project...');
const dependenciesOk = await checkAllDependencies('create');
if (!dependenciesOk) {
showDependencyError('create');
process.exit(1);
}
createProject();
} else if (command === 'demo') {
console.log('Starting ATXP demo...');
const dependenciesOk = await checkAllDependencies('demo');
if (!dependenciesOk) {
showDependencyError('demo');
process.exit(1);
}
runDemo(demoOptions);
} else if (command === 'help' || command === '--help' || command === '-h') {
showHelp();
} else if (!command) {
// No command provided - show help instead of running demo
showHelp();
} else {
// Unknown command
console.log(`Unknown command: ${command}`);
console.log('Run "npx atxp help" for usage information.');
process.exit(1);
}
}

main().catch((error) => {
console.error('An unexpected error occurred:', error.message);
process.exit(1);
}
});
1 change: 0 additions & 1 deletion packages/atxp/src/run-demo.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import chalk from 'chalk';
import { spawn } from 'child_process';
import fs from 'fs-extra';
import path from 'path';
import open from 'open';

interface DemoOptions {
Expand Down