|
1 | 1 | // oxlint-disable-next-line import/order -- must appear first |
2 | 2 | import { getEnv } from '@epic-web/workshop-utils/init-env' |
3 | 3 |
|
4 | | -import { spawn, type ChildProcess, execSync } from 'node:child_process' |
| 4 | +import { spawn, type ChildProcess } from 'node:child_process' |
5 | 5 | import crypto from 'node:crypto' |
6 | 6 | import fs from 'node:fs' |
7 | 7 | import http from 'node:http' |
8 | 8 | import os from 'node:os' |
9 | 9 | import path from 'node:path' |
10 | | -import { fileURLToPath, pathToFileURL } from 'node:url' |
| 10 | +import { pathToFileURL } from 'node:url' |
11 | 11 | import chalk from 'chalk' |
12 | 12 | import closeWithGrace from 'close-with-grace' |
13 | 13 | import getPort from 'get-port' |
14 | 14 | import open from 'open' |
| 15 | +import { |
| 16 | + buildWorkshopAppNotFoundMessage, |
| 17 | + resolveWorkshopAppLocation, |
| 18 | +} from './workshop-app-location.ts' |
15 | 19 |
|
16 | 20 | export type StartOptions = { |
17 | 21 | appLocation?: string |
@@ -111,29 +115,12 @@ export function displayHelp() { |
111 | 115 | */ |
112 | 116 | export async function start(options: StartOptions = {}): Promise<StartResult> { |
113 | 117 | try { |
114 | | - // Find workshop-app directory using new resolution order |
115 | | - const appDir = await findWorkshopAppDir(options.appLocation) |
| 118 | + const resolution = await resolveWorkshopAppLocation({ |
| 119 | + appLocation: options.appLocation, |
| 120 | + }) |
| 121 | + const appDir = resolution.appDir |
116 | 122 | if (!appDir) { |
117 | | - const errorMessage = |
118 | | - 'Could not locate workshop-app directory. Please ensure the workshop app is installed or specify its location using:\n - Environment variable: EPICSHOP_APP_LOCATION\n - Command line flag: --app-location\n - Global installation: npm install -g @epic-web/workshop-app' |
119 | | - |
120 | | - if (!options.silent) { |
121 | | - console.error(chalk.red('❌ Could not locate workshop-app directory')) |
122 | | - console.error( |
123 | | - chalk.yellow( |
124 | | - 'Please ensure the workshop app is installed or specify its location using:', |
125 | | - ), |
126 | | - ) |
127 | | - console.error( |
128 | | - chalk.yellow(' - Environment variable: EPICSHOP_APP_LOCATION'), |
129 | | - ) |
130 | | - console.error(chalk.yellow(' - Command line flag: --app-location')) |
131 | | - console.error( |
132 | | - chalk.yellow( |
133 | | - ' - Global installation: npm install -g @epic-web/workshop-app', |
134 | | - ), |
135 | | - ) |
136 | | - } |
| 123 | + const errorMessage = buildWorkshopAppNotFoundMessage(resolution) |
137 | 124 |
|
138 | 125 | return { |
139 | 126 | success: false, |
@@ -642,110 +629,6 @@ async function killChild(child: ChildProcess | null): Promise<void> { |
642 | 629 | }) |
643 | 630 | } |
644 | 631 |
|
645 | | -async function findWorkshopAppDir( |
646 | | - appLocation?: string, |
647 | | -): Promise<string | null> { |
648 | | - // 1. Check process.env.EPICSHOP_APP_LOCATION |
649 | | - if (process.env.EPICSHOP_APP_LOCATION) { |
650 | | - const envDir = path.resolve(process.env.EPICSHOP_APP_LOCATION) |
651 | | - try { |
652 | | - await fs.promises.access(path.join(envDir, 'package.json')) |
653 | | - return envDir |
654 | | - } catch { |
655 | | - // Continue to next step |
656 | | - } |
657 | | - } |
658 | | - |
659 | | - // 2. Check command line flag --app-location |
660 | | - if (appLocation) { |
661 | | - const flagDir = path.resolve(appLocation) |
662 | | - try { |
663 | | - await fs.promises.access(path.join(flagDir, 'package.json')) |
664 | | - return flagDir |
665 | | - } catch { |
666 | | - // Continue to next step |
667 | | - } |
668 | | - } |
669 | | - |
670 | | - // 3. Node's resolution process |
671 | | - try { |
672 | | - const workshopAppPath = import.meta |
673 | | - .resolve('@epic-web/workshop-app/package.json') |
674 | | - const packagePath = fileURLToPath(workshopAppPath) |
675 | | - return path.dirname(packagePath) |
676 | | - } catch { |
677 | | - // Continue to next step |
678 | | - } |
679 | | - |
680 | | - // 4. Global installation lookup |
681 | | - try { |
682 | | - const globalDir = await findGlobalWorkshopApp() |
683 | | - if (globalDir) { |
684 | | - return globalDir |
685 | | - } |
686 | | - } catch { |
687 | | - // Continue to next step |
688 | | - } |
689 | | - |
690 | | - // Fallback for development (when running from a monorepo) |
691 | | - try { |
692 | | - const cliPkgPath = import.meta.resolve('epicshop/package.json') |
693 | | - const cliPkgDir = path.dirname(fileURLToPath(cliPkgPath)) |
694 | | - const relativePath = path.resolve(cliPkgDir, '..', '..', 'workshop-app') |
695 | | - try { |
696 | | - await fs.promises.access(path.join(relativePath, 'package.json')) |
697 | | - return relativePath |
698 | | - } catch { |
699 | | - // Continue to final return |
700 | | - } |
701 | | - } catch { |
702 | | - // Continue to final return |
703 | | - } |
704 | | - |
705 | | - return null |
706 | | -} |
707 | | - |
708 | | -async function findGlobalWorkshopApp(): Promise<string | null> { |
709 | | - // Try to find globally installed workshop app |
710 | | - try { |
711 | | - const npmRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim() |
712 | | - const globalAppPath = path.join(npmRoot, '@epic-web/workshop-app') |
713 | | - try { |
714 | | - await fs.promises.access(path.join(globalAppPath, 'package.json')) |
715 | | - return globalAppPath |
716 | | - } catch { |
717 | | - // Continue to common global locations |
718 | | - } |
719 | | - } catch { |
720 | | - // If npm root -g fails, try common global locations |
721 | | - } |
722 | | - |
723 | | - // Try common global locations |
724 | | - const commonGlobalPaths = [ |
725 | | - path.join( |
726 | | - os.homedir(), |
727 | | - '.npm-global/lib/node_modules/@epic-web/workshop-app', |
728 | | - ), |
729 | | - path.join( |
730 | | - os.homedir(), |
731 | | - '.npm-packages/lib/node_modules/@epic-web/workshop-app', |
732 | | - ), |
733 | | - '/usr/local/lib/node_modules/@epic-web/workshop-app', |
734 | | - '/usr/lib/node_modules/@epic-web/workshop-app', |
735 | | - ] |
736 | | - |
737 | | - for (const globalPath of commonGlobalPaths) { |
738 | | - try { |
739 | | - await fs.promises.access(path.join(globalPath, 'package.json')) |
740 | | - return globalPath |
741 | | - } catch { |
742 | | - // Continue to next path |
743 | | - } |
744 | | - } |
745 | | - |
746 | | - return null |
747 | | -} |
748 | | - |
749 | 632 | async function appIsPublished(appDir: string): Promise<boolean> { |
750 | 633 | if (process.env.EPICSHOP_IS_PUBLISHED) { |
751 | 634 | return ( |
|
0 commit comments