diff --git a/enterprise/frontend/src/embedding-sdk/cli/constants/messages.ts b/enterprise/frontend/src/embedding-sdk/cli/constants/messages.ts index a55f63b38985fcfeb35bae236626af58943810ce..4dc83f4ffa9b06b1339ff19f37222ba880b150a9 100644 --- a/enterprise/frontend/src/embedding-sdk/cli/constants/messages.ts +++ b/enterprise/frontend/src/embedding-sdk/cli/constants/messages.ts @@ -74,3 +74,5 @@ export const SETUP_PRO_LICENSE_MESSAGE = ` export const SDK_LEARN_MORE_MESSAGE = `All done! 🚀 Learn more about the SDK here: ${green( SDK_NPM_LINK, )}`; + +export const CONTINUE_SETUP_ON_WARNING_MESSAGE = `Do you want to continue setup?`; diff --git a/enterprise/frontend/src/embedding-sdk/cli/steps/check-if-react-project.ts b/enterprise/frontend/src/embedding-sdk/cli/steps/check-if-react-project.ts index 4eb62f70a565382b3844fe9b6ff15c507c22e327..3ffc634ffa4241f32777a86885874a7f48e3b79a 100644 --- a/enterprise/frontend/src/embedding-sdk/cli/steps/check-if-react-project.ts +++ b/enterprise/frontend/src/embedding-sdk/cli/steps/check-if-react-project.ts @@ -6,12 +6,13 @@ import { PACKAGE_JSON_NOT_FOUND_MESSAGE, UNSUPPORTED_REACT_VERSION, } from "embedding-sdk/cli/constants/messages"; -import { - getPackageVersion, - hasPackageJson, -} from "embedding-sdk/cli/utils/get-package-version"; import type { CliStepMethod } from "../types/cli"; +import { + getPackageVersions, + hasPackageJson, +} from "../utils/get-package-version"; +import { showWarningAndAskToContinue } from "../utils/show-warning-prompt"; const isReactVersionSupported = (version: string) => semver.satisfies(semver.coerce(version)!, "18.x"); @@ -21,49 +22,40 @@ export const checkIfReactProject: CliStepMethod = async state => { if (!(await hasPackageJson())) { spinner.fail(); - return [ - { - type: "error", - message: PACKAGE_JSON_NOT_FOUND_MESSAGE, - }, - state, - ]; + return [{ type: "error", message: PACKAGE_JSON_NOT_FOUND_MESSAGE }, state]; } - const reactDep = await getPackageVersion("react"); - const reactDomDep = await getPackageVersion("react-dom"); + const dependencyVersions = await getPackageVersions("react", "react-dom"); + + const reactDep = dependencyVersions["react"]; + const reactDomDep = dependencyVersions["react-dom"]; const hasReactDependency = reactDep && reactDomDep; + const hasSupportedReactVersion = - isReactVersionSupported(reactDep) && isReactVersionSupported(reactDomDep); + hasReactDependency && + isReactVersionSupported(reactDep) && + isReactVersionSupported(reactDomDep); + + let warningMessage: string | null = null; if (!hasReactDependency) { - spinner.fail(); - return [ - { - type: "error", - message: MISSING_REACT_DEPENDENCY, - }, - state, - ]; + warningMessage = MISSING_REACT_DEPENDENCY; + } else if (!hasSupportedReactVersion) { + warningMessage = UNSUPPORTED_REACT_VERSION; } - if (!hasSupportedReactVersion) { + if (warningMessage) { spinner.fail(); - return [ - { - type: "error", - message: UNSUPPORTED_REACT_VERSION, - }, - state, - ]; + + const shouldContinue = await showWarningAndAskToContinue(warningMessage); + + if (!shouldContinue) { + return [{ type: "error", message: "Canceled." }, state]; + } + } else { + spinner.succeed(`React ${reactDep} and React DOM ${reactDomDep} found`); } - spinner.succeed(`React v${reactDep} and React DOM v${reactDomDep} found`); - return [ - { - type: "success", - }, - state, - ]; + return [{ type: "success" }, state]; }; diff --git a/enterprise/frontend/src/embedding-sdk/cli/steps/check-sdk-available.ts b/enterprise/frontend/src/embedding-sdk/cli/steps/check-sdk-available.ts index 3bfbd753a9728baac32caff385d4fb3cc6054620..90ac5ebd0514dc072bfc66ba842e946608f005cd 100644 --- a/enterprise/frontend/src/embedding-sdk/cli/steps/check-sdk-available.ts +++ b/enterprise/frontend/src/embedding-sdk/cli/steps/check-sdk-available.ts @@ -1,24 +1,20 @@ import ora from "ora"; -import { SDK_PACKAGE_NAME } from "embedding-sdk/cli/constants/config"; -import { installSdk } from "embedding-sdk/cli/steps/install-sdk"; -import { getPackageVersion } from "embedding-sdk/cli/utils/get-package-version"; - +import { SDK_PACKAGE_NAME } from "../constants/config"; +import { installSdk } from "../steps/install-sdk"; import type { CliStepMethod } from "../types/cli"; +import { getPackageVersions } from "../utils/get-package-version"; export const checkSdkAvailable: CliStepMethod = async state => { const spinner = ora("Checking if SDK is installed…").start(); - const sdkVersion = await getPackageVersion(SDK_PACKAGE_NAME); + + const projectDependencies = await getPackageVersions(SDK_PACKAGE_NAME); + const sdkVersion = projectDependencies?.[SDK_PACKAGE_NAME]; // skip install step if we already have the SDK installed if (sdkVersion) { spinner.succeed(`SDK v${sdkVersion} found`); - return [ - { - type: "success", - }, - state, - ]; + return [{ type: "success" }, state]; } spinner.fail("SDK not found"); diff --git a/enterprise/frontend/src/embedding-sdk/cli/utils/get-package-version.ts b/enterprise/frontend/src/embedding-sdk/cli/utils/get-package-version.ts index 6fbf46b7610dc5acece76786a4d3995169906838..8176324c4d9206e29553228b0c6b05fb9c02f520 100644 --- a/enterprise/frontend/src/embedding-sdk/cli/utils/get-package-version.ts +++ b/enterprise/frontend/src/embedding-sdk/cli/utils/get-package-version.ts @@ -11,28 +11,52 @@ export const hasPackageJson = async () => { } }; -export const getPackageVersion = async (packageName: string) => { +type DependencyMap = Record<string, string>; + +export const getPackageVersions = async (...packageNames: string[]) => { + const versions: Record<string, string> = {}; + + const projectDeps = await getProjectDependenciesFromPackageJson(); + + for (const name of packageNames) { + versions[name] = + (await getPackageVersionFromModule(name)) || projectDeps?.[name] || null; + } + + return versions; +}; + +export const readJson = async (path: string) => { + const packageJson = await fs.readFile(path, "utf8"); + + return JSON.parse(packageJson); +}; + +export const getProjectDependenciesFromPackageJson = + async (): Promise<DependencyMap | null> => { + try { + const packageJsonPath = path.join(process.cwd(), "package.json"); + const packageInfo = await readJson(packageJsonPath); + + return packageInfo?.dependencies || null; + } catch (error) { + return null; + } + }; + +export const getPackageVersionFromModule = async (packageName: string) => { try { - const packagePath = path.join( + const packageJsonPath = path.join( process.cwd(), "node_modules", packageName, "package.json", ); - const packageJson = await fs.readFile(packagePath, "utf8"); - const packageInfo = JSON.parse(packageJson); + const packageInfo = await readJson(packageJsonPath); + return packageInfo.version || null; } catch (error) { - if ((error as { code: string }).code === "ENOENT") { - // Package not found - return null; - } - console.error( - `Error checking package version: ${ - (error as { message: string }).message - }`, - ); return null; } }; diff --git a/enterprise/frontend/src/embedding-sdk/cli/utils/print.ts b/enterprise/frontend/src/embedding-sdk/cli/utils/print.ts index 2da4163327132008c420362238c2fa30c1699030..085cc6d09e106b8b647a5235a9ab1f3741a13e18 100644 --- a/enterprise/frontend/src/embedding-sdk/cli/utils/print.ts +++ b/enterprise/frontend/src/embedding-sdk/cli/utils/print.ts @@ -7,6 +7,7 @@ export const OUTPUT_STYLES = { version: chalk.hex("#509EE3"), link: chalk.underline.blueBright, error: chalk.red.bold, + warning: chalk.yellow.bold, success: chalk.green.bold, info: chalk.bold, }; @@ -37,6 +38,9 @@ export const printLink = (text: string) => _print(OUTPUT_STYLES.link, text); export const printError = (message: string) => console.error(OUTPUT_STYLES.error(message)); +export const printWarning = (message: string) => + console.warn(OUTPUT_STYLES.warning(message)); + export const printSuccess = (message: string) => _print(OUTPUT_STYLES.success, message); diff --git a/enterprise/frontend/src/embedding-sdk/cli/utils/show-warning-prompt.ts b/enterprise/frontend/src/embedding-sdk/cli/utils/show-warning-prompt.ts new file mode 100644 index 0000000000000000000000000000000000000000..884938f17234fe9ae94c0fcd747a6e825df4aa00 --- /dev/null +++ b/enterprise/frontend/src/embedding-sdk/cli/utils/show-warning-prompt.ts @@ -0,0 +1,23 @@ +import { select } from "@inquirer/prompts"; + +import { CONTINUE_SETUP_ON_WARNING_MESSAGE } from "../constants/messages"; + +import { printWarning } from "./print"; + +/** + * @returns {boolean} whether the user wants to continue setup or not + */ +export async function showWarningAndAskToContinue( + message: string, +): Promise<boolean> { + printWarning(message); + + return select({ + message: CONTINUE_SETUP_ON_WARNING_MESSAGE, + choices: [ + { name: "Continue", value: true }, + { name: "Exit setup", value: false }, + ], + default: true, + }); +}