@ordino.ai/cli
Version:
ordino.ai global command line interface
321 lines (289 loc) ⢠11.7 kB
text/typescript
import { execSync } from "child_process";
import { printMessage } from "./printMessage.util";
import { getVersionRequirements, getVersionRequirementsAsStrings } from "../config/version-requirements";
import fs from "fs";
import path from "path";
interface VersionInfo {
major: number;
minor: number;
patch: number;
}
interface NodeVersionCheckResult {
compatible: boolean;
version: VersionInfo;
error?: string;
}
interface NpmVersionCheckResult {
compatible: boolean;
version: VersionInfo;
error?: string;
}
interface BrowserInfo {
name: string;
installLocation: string;
}
function parseVersion(versionString: string): VersionInfo {
const match = versionString.match(/^v?(\d+)\.(\d+)\.(\d+)/);
if (!match) {
throw new Error(`Invalid version format: ${versionString}`);
}
return {
major: parseInt(match[1], 10),
minor: parseInt(match[2], 10),
patch: parseInt(match[3], 10)
};
}
function compareVersions(required: VersionInfo, actual: VersionInfo): boolean {
if (actual.major > required.major) return true;
if (actual.major < required.major) return false;
if (actual.minor > required.minor) return true;
if (actual.minor < required.minor) return false;
return actual.patch >= required.patch;
}
function getNodeVersion(): VersionInfo {
try {
const nodeVersion = execSync("node --version", { encoding: "utf8" }).trim();
return parseVersion(nodeVersion);
} catch (error) {
throw new Error("Failed to get Node.js version. Please ensure Node.js is installed and accessible.");
}
}
function getNpmVersion(): VersionInfo {
try {
const npmVersion = execSync("npm --version", { encoding: "utf8" }).trim();
return parseVersion(npmVersion);
} catch (error) {
throw new Error("Failed to get npm version. Please ensure npm is installed and accessible.");
}
}
export function checkNodeVersion(): NodeVersionCheckResult {
const requiredVersions = getVersionRequirements();
const result: NodeVersionCheckResult = {
compatible: false,
version: { major: 0, minor: 0, patch: 0 }
};
try {
result.version = getNodeVersion();
result.compatible = compareVersions(requiredVersions.node, result.version);
} catch (error) {
result.error = error instanceof Error ? error.message : "Unknown error checking Node.js version";
}
return result;
}
export function checkNpmVersion(): NpmVersionCheckResult {
const requiredVersions = getVersionRequirements();
const result: NpmVersionCheckResult = {
compatible: false,
version: { major: 0, minor: 0, patch: 0 }
};
try {
result.version = getNpmVersion();
result.compatible = compareVersions(requiredVersions.npm, result.version);
} catch (error) {
result.error = error instanceof Error ? error.message : "Unknown error checking npm version";
}
return result;
}
export function checkNodeVersionOnly(): boolean {
const nodeCheck = checkNodeVersion();
const requiredVersionsStrings = getVersionRequirementsAsStrings();
printMessage("\nš Checking Node.js version...", "36", true);
printMessage(`Current: ${nodeCheck.version.major}.${nodeCheck.version.minor}.${nodeCheck.version.patch}`,
nodeCheck.compatible ? "32" : "31", false);
printMessage(`Required: ${requiredVersionsStrings.node}`, "33", false);
if (nodeCheck.error) {
printMessage(`ā Error checking Node.js version: ${nodeCheck.error}`, "31", true);
return false;
}
if (nodeCheck.compatible) {
printMessage("ā
Node.js version is compatible!", "32", true);
return true;
} else {
printMessage("ā Node.js version is not compatible:", "31", true);
printMessage(" ⢠Download from: https://nodejs.org/", "36", false);
printMessage(" ⢠Or use Node Version Manager (nvm):", "36", false);
printMessage(" - Windows: nvm install latest", "36", false);
printMessage(" - macOS/Linux: nvm install node", "36", false);
printMessage(" ⢠Or use package manager:", "36", false);
printMessage(" - Windows (Chocolatey): choco install nodejs", "36", false);
printMessage(" - macOS (Homebrew): brew install node", "36", false);
printMessage(" - Linux (apt): sudo apt update && sudo apt install nodejs", "36", false);
return false;
}
}
export function checkNpmVersionOnly(): boolean {
const npmCheck = checkNpmVersion();
const requiredVersionsStrings = getVersionRequirementsAsStrings();
printMessage("\nš Checking npm version...", "36", true);
printMessage(`Current: ${npmCheck.version.major}.${npmCheck.version.minor}.${npmCheck.version.patch}`,
npmCheck.compatible ? "32" : "31", false);
printMessage(`Required: ${requiredVersionsStrings.npm}`, "33", false);
if (npmCheck.error) {
printMessage(`ā Error checking npm version: ${npmCheck.error}`, "31", true);
return false;
}
if (npmCheck.compatible) {
printMessage("ā
npm version is compatible!", "32", true);
return true;
} else {
printMessage("ā npm version is not compatible:", "31", true);
printMessage(" ⢠Update npm globally: npm install -g npm@latest", "36", false);
printMessage(" ⢠Or use Node Version Manager (nvm):", "36", false);
printMessage(" - nvm install-latest-npm", "36", false);
printMessage(" ⢠Or reinstall Node.js (includes latest npm):", "36", false);
printMessage(" - Download from: https://nodejs.org/", "36", false);
return false;
}
}
export function displayVersionCheck(): boolean {
const nodeCompatible = checkNodeVersionOnly();
const npmCompatible = checkNpmVersionOnly();
return nodeCompatible && npmCompatible;
}
function checkConfigFile(): boolean {
const currentDir = process.cwd();
const configPath = path.join(currentDir, "ordino.config.ts");
const configExists = fs.existsSync(configPath);
printMessage(`ordino.config.ts: ${configExists ? "ā
Found" : "ā Not found"}`,
configExists ? "32" : "31", false);
return configExists;
}
function checkInitializeFile(): boolean {
const currentDir = process.cwd();
const initializePath = path.join(currentDir, "ordino.initialize.js");
const initializeExists = fs.existsSync(initializePath);
printMessage(`ordino.initialize.js: ${initializeExists ? "ā
Found" : "ā Not found"}`,
initializeExists ? "32" : "31", false);
return initializeExists;
}
function parsePlaywrightDryRunOutput(output: string): BrowserInfo[] {
const browsers: BrowserInfo[] = [];
const lines = output.split('\n');
let currentBrowser: Partial<BrowserInfo> = {};
for (const line of lines) {
const trimmedLine = line.trim();
const browserMatch = trimmedLine.match(/^browser:\s+(\S+)/);
if (browserMatch) {
if (currentBrowser.name && currentBrowser.installLocation) {
browsers.push(currentBrowser as BrowserInfo);
}
currentBrowser = {
name: browserMatch[1]
};
continue;
}
const locationMatch = trimmedLine.match(/^Install location:\s+(.+)/);
if (locationMatch && currentBrowser.name) {
currentBrowser.installLocation = locationMatch[1].trim();
}
}
if (currentBrowser.name && currentBrowser.installLocation) {
browsers.push(currentBrowser as BrowserInfo);
}
return browsers;
}
function extractBrowserVersionFromPath(installLocation: string): string | null {
const match = installLocation.match(/[\\\/]([^\\\/]+)-(\d+)$/);
if (match) {
return match[2];
}
return null;
}
export function checkPlaywrightBrowsers(cwd?: string): boolean {
try {
const playwrightVersion = execSync("npx playwright --version", {
encoding: "utf8",
stdio: "pipe",
timeout: 10000,
cwd: cwd
}).trim();
let dryRunOutput = execSync("npx playwright install --dry-run", {
encoding: "utf8",
stdio: "pipe",
timeout: 15000,
cwd: cwd
});
const browsers = parsePlaywrightDryRunOutput(dryRunOutput);
const platform = process.platform;
let playwrightDir = '';
if (platform === 'win32') {
const userHome = process.env.USERPROFILE || '';
playwrightDir = path.join(userHome, 'AppData', 'Local', 'ms-playwright');
} else if (platform === 'darwin') {
const userHome = process.env.HOME || '';
playwrightDir = path.join(userHome, 'Library', 'Caches', 'ms-playwright');
} else if (platform === 'linux') {
const userHome = process.env.HOME || '';
playwrightDir = path.join(userHome, '.cache', 'ms-playwright');
} else {
printMessage(`Playwright browser binaries: ā Not installed (${playwrightVersion}) - Unsupported platform`, "31", false);
return false;
}
if (!fs.existsSync(playwrightDir)) {
printMessage(`Playwright browser binaries: ā Not installed (${playwrightVersion})`, "31", false);
printMessage(" ⢠Run: npx playwright install", "36", false);
return false;
}
const chromiumRelatedBrowsers = browsers.filter(browser =>
browser.name === 'chromium' ||
browser.name === 'chrome' ||
browser.name === 'msedge' ||
browser.name.includes('chromium')
);
if (chromiumRelatedBrowsers.length === 0) {
printMessage(`Playwright browser binaries: ā No chromium-related browsers found in dry-run (${playwrightVersion})`, "31", false);
printMessage(" ⢠Run: npx playwright install chromium", "36", false);
return false;
}
const missingBrowsers: string[] = [];
const availableBrowsers: string[] = [];
chromiumRelatedBrowsers.forEach(browser => {
if (fs.existsSync(browser.installLocation)) {
const version = extractBrowserVersionFromPath(browser.installLocation);
const browserVersion = version ? `${browser.name}-${version}` : browser.name;
availableBrowsers.push(browserVersion);
} else {
missingBrowsers.push(browser.name);
}
});
if (missingBrowsers.length > 0) {
printMessage(`Playwright browser binaries: ā Some chromium-related binaries missing (${playwrightVersion})`, "31", false);
printMessage(` ⢠Missing: ${missingBrowsers.join(', ')}`, "31", false);
if (availableBrowsers.length > 0) {
printMessage(` ⢠Available: ${availableBrowsers.join(', ')}`, "36", false);
}
printMessage(" ⢠Run: npx playwright install", "36", false);
return false;
}
printMessage(`Playwright browser binaries: ā
All chromium-related browsers installed (${playwrightVersion})`, "32", false);
availableBrowsers.forEach(browserVersion => {
printMessage(` ⢠Found: ${browserVersion}`, "36", false);
});
return true;
} catch (error) {
printMessage("Playwright browser binaries: ā Not installed", "31", false);
printMessage(" ⢠Run: npx playwright install", "36", false);
return false;
}
}
export function checkCypressFiles(): boolean {
printMessage("\nš Checking Cypress configuration files...", "36", true);
const configExists = checkConfigFile();
const initializeExists = checkInitializeFile();
if (configExists && initializeExists) {
printMessage("ā
All Cypress configuration files are present!", "32", true);
return true;
}
return false;
}
export function checkPlaywrightFiles(): boolean {
printMessage("\nš Checking Playwright configuration files...", "36", true);
const configExists = checkConfigFile();
const initializeExists = checkInitializeFile();
const browsersInstalled = checkPlaywrightBrowsers();
if (configExists && initializeExists && browsersInstalled) {
printMessage("ā
All Playwright configuration files and browsers are present!", "32", true);
return true;
}
return false;
}