diff --git a/tools/cli/src/build.ts b/tools/cli/src/build.ts index 94337b55d..861f4b8bf 100644 --- a/tools/cli/src/build.ts +++ b/tools/cli/src/build.ts @@ -4,12 +4,14 @@ export class BuildCommand extends PackageCommand { static override paths = [['build'], ['b']]; async execute() { - const args = ['affine build', this.package]; + const args: string[] = []; if (this.deps) { args.push('--deps'); } + args.push(this.package, 'build'); + await this.cli.run(args); } } diff --git a/tools/cli/src/bundle.ts b/tools/cli/src/bundle.ts index 014ceb404..a44b5915f 100644 --- a/tools/cli/src/bundle.ts +++ b/tools/cli/src/bundle.ts @@ -25,7 +25,8 @@ export class BundleCommand extends PackageCommand { static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']]; // bundle is not able to run with deps - override deps = false; + override _deps = false; + override waitDeps = false; dev = Option.Boolean('--dev,-d', false, { description: 'Run in Development mode', diff --git a/tools/cli/src/command.ts b/tools/cli/src/command.ts index ab5b54da1..6b5326f00 100644 --- a/tools/cli/src/command.ts +++ b/tools/cli/src/command.ts @@ -38,10 +38,18 @@ export abstract class PackageCommand extends Command { ); } - deps = Option.Boolean('--deps', false, { + protected _deps = Option.Boolean('--deps', false, { description: 'Execute the same command in workspace dependencies, if defined.', }); + + get deps() { + return this._deps; + } + + waitDeps = Option.Boolean('--wait-deps', false, { + description: 'Wait for dependencies to be ready before running the command', + }); } export abstract class PackagesCommand extends Command { diff --git a/tools/cli/src/dev.ts b/tools/cli/src/dev.ts index efa3c3028..3c8cf2c40 100644 --- a/tools/cli/src/dev.ts +++ b/tools/cli/src/dev.ts @@ -4,12 +4,14 @@ export class DevCommand extends PackageCommand { static override paths = [['dev'], ['d']]; async execute() { - const args = [this.package, 'dev']; + const args = []; if (this.deps) { - args.push('--deps'); + args.push('--deps', '--wait-deps'); } + args.push(this.package, 'dev'); + await this.cli.run(args); } } diff --git a/tools/cli/src/run.ts b/tools/cli/src/run.ts index 5149d9e50..e55aca85f 100644 --- a/tools/cli/src/run.ts +++ b/tools/cli/src/run.ts @@ -1,12 +1,13 @@ import { Path } from '@affine-tools/utils/path'; import { execAsync } from '@affine-tools/utils/process'; -import type { PackageName } from '@affine-tools/utils/workspace'; +import type { Package, PackageName } from '@affine-tools/utils/workspace'; import { Option, PackageCommand } from './command'; interface RunScriptOptions { includeDependencies?: boolean; waitDependencies?: boolean; + ignoreIfNotFound?: boolean; } const currentDir = Path.dir(import.meta.url); @@ -68,68 +69,97 @@ export class RunCommand extends PackageCommand { async execute() { await this.run(this.package, this.args, { includeDependencies: this.deps, - waitDependencies: true, + waitDependencies: this.waitDeps, }); } async run(name: PackageName, args: string[], opts: RunScriptOptions = {}) { - opts = { includeDependencies: false, ...opts }; + opts = { + includeDependencies: false, + waitDependencies: true, + ignoreIfNotFound: false, + ...opts, + }; const pkg = this.workspace.getPackage(name); - const script = args[0]; - const pkgScript = pkg.scripts[script]; - - let isPackageJsonScript = false; - let isAFFiNEScript = false; + const scriptName = args[0]; + const pkgScript = pkg.scripts[scriptName]; if (pkgScript) { - isPackageJsonScript = true; - isAFFiNEScript = pkgScript.startsWith('affine '); + await this.runScript(pkg, scriptName, args.slice(1), opts); } else { - isAFFiNEScript = script.startsWith('affine '); - } - - if (isPackageJsonScript && opts.includeDependencies) { - this.logger.info( - `Running [${script}] script in dependencies of ${pkg.name}...` - ); - - await Promise.all( - pkg.deps.map(dep => { - this.logger.info(`Running [${script}] script in ${dep.name}...`); - return this.run(dep.name, args, opts); - }) - ); - } - - if (isPackageJsonScript) { - this.logger.info(`Running [${script}] script in ${pkg.name}...`); - } - - if (isAFFiNEScript) { - await this.cli.run([ - ...pkgScript.split(' ').slice(1), - ...args.slice(1), - '-p', - pkg.name, - ]); - } else { - const script = pkgScript ?? args[0]; - // very simple test for auto ts/mjs scripts - const isLoaderRequired = !ignoreLoaderScripts.some(ignore => - new RegExp(ignore).test(script) - ); - - await execAsync(name, ['yarn', ...args], { - cwd: pkg.path.value, - ...(isLoaderRequired - ? { - env: { - NODE_OPTIONS: `--import=${currentDir.join('../register.js').toFileUrl()}`, - }, - } - : {}), - }); + await this.runCommand(pkg, scriptName, args.slice(1)); } } + + async runScript( + pkg: Package, + scriptName: string, + args: string[], + opts: RunScriptOptions = {} + ) { + const script = pkg.scripts[scriptName]; + + if (!script) { + if (opts.ignoreIfNotFound) { + return; + } + + throw new Error(`Script ${scriptName} not found in ${pkg.name}`); + } + + const isAFFiNECommand = script.startsWith('affine '); + if (opts.includeDependencies) { + const depsRun = Promise.all( + pkg.deps.map(dep => { + return this.runScript( + pkg.workspace.getPackage(dep.name), + scriptName, + args, + { + ...opts, + ignoreIfNotFound: true, + } + ); + }) + ); + if (opts.waitDependencies) { + await depsRun; + } else { + depsRun.catch(e => { + this.logger.error(e); + }); + } + } + + args = [...script.split(' '), ...args]; + + if (isAFFiNECommand) { + args.shift(); + args.push('-p', pkg.name); + } else { + args.unshift(pkg.name); + } + + await this.cli.run(args); + } + + async runCommand(pkg: Package, scriptName: string, args: string[]) { + // very simple test for auto ts/mjs scripts + // TODO(@forehalo): bypass cross-env and fetch the next script after envs + const isLoaderRequired = !ignoreLoaderScripts.some(ignore => + new RegExp(ignore).test(scriptName) + ); + + await execAsync(pkg.name, ['yarn', scriptName, ...args], { + cwd: pkg.path.value, + ...(isLoaderRequired + ? { + env: { + NODE_OPTIONS: `--import=${currentDir.join('../register.js').toFileUrl()}`, + }, + } + : {}), + }); + } }