diff --git a/package.json b/package.json index c5512aa346..afaf000b10 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "cross-spawn": "^7.0.3", "cross-zip": "^4.0.0", "debug": "^4.3.1", + "detect-package-manager": "^3.0.2", "express": "^4.17.1", "express-ws": "^5.0.2", "fast-glob": "^3.2.7", @@ -78,8 +79,7 @@ "which": "^2.0.2", "xterm": "^4.9.0", "xterm-addon-fit": "^0.5.0", - "xterm-addon-search": "^0.8.0", - "yarn-or-npm": "^3.0.1" + "xterm-addon-search": "^0.8.0" }, "devDependencies": { "@electron/fuses": ">=1.0.0", diff --git a/packages/api/cli/src/util/check-system.ts b/packages/api/cli/src/util/check-system.ts index 5ba4ce6e1b..a07993e579 100644 --- a/packages/api/cli/src/util/check-system.ts +++ b/packages/api/cli/src/util/check-system.ts @@ -57,7 +57,7 @@ function warnIfPackageManagerIsntAKnownGoodVersion(packageManager: string, versi async function checkPackageManagerVersion() { const version = await forgeUtils.yarnOrNpmSpawn(['--version']); const versionString = version.toString().trim(); - if (forgeUtils.hasYarn()) { + if (await forgeUtils.hasYarn()) { warnIfPackageManagerIsntAKnownGoodVersion('Yarn', versionString, YARN_ALLOWLISTED_VERSIONS); return `yarn@${versionString}`; } else { diff --git a/packages/api/core/package.json b/packages/api/core/package.json index dac732dc25..d040c95235 100644 --- a/packages/api/core/package.json +++ b/packages/api/core/package.json @@ -44,6 +44,7 @@ "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.3.1", + "detect-package-manager": "^3.0.2", "fast-glob": "^3.2.7", "filenamify": "^4.1.0", "find-up": "^5.0.0", @@ -59,8 +60,7 @@ "semver": "^7.2.1", "source-map-support": "^0.5.13", "sudo-prompt": "^9.1.1", - "username": "^5.1.0", - "yarn-or-npm": "^3.0.1" + "username": "^5.1.0" }, "engines": { "node": ">= 16.4.0" diff --git a/packages/api/core/spec/fast/util/install-dependencies.spec.ts b/packages/api/core/spec/fast/util/install-dependencies.spec.ts index d7553bdb1b..2afa34d731 100644 --- a/packages/api/core/spec/fast/util/install-dependencies.spec.ts +++ b/packages/api/core/spec/fast/util/install-dependencies.spec.ts @@ -34,7 +34,7 @@ describe('installDependencies', () => { { pm: 'yarn', install: 'add', flags: { exact: '--exact', dev: '--dev' } }, ])('$pm', ({ pm, install, flags }) => { beforeEach(() => { - vi.mocked(hasYarn).mockReturnValue(pm === 'yarn'); + vi.mocked(hasYarn).mockResolvedValue(pm === 'yarn'); }); it('should install deps', async () => { diff --git a/packages/api/core/src/api/import.ts b/packages/api/core/src/api/import.ts index ca0c5e7c19..ed764e6404 100644 --- a/packages/api/core/src/api/import.ts +++ b/packages/api/core/src/api/import.ts @@ -193,7 +193,7 @@ export default autoTrace( { title: 'Installing dependencies', task: async (_, task) => { - const packageManager = safeYarnOrNpm(); + const packageManager = await safeYarnOrNpm(); await writeChanges(); d('deleting old dependencies forcefully'); diff --git a/packages/api/core/src/api/init-scripts/init-link.ts b/packages/api/core/src/api/init-scripts/init-link.ts index af9151bb51..93ebde4a7e 100644 --- a/packages/api/core/src/api/init-scripts/init-link.ts +++ b/packages/api/core/src/api/init-scripts/init-link.ts @@ -22,7 +22,7 @@ export async function initLink(dir: string, task?: ForgeListrTask) { if (shouldLink) { d('Linking forge dependencies'); const packageJson = await readRawPackageJson(dir); - const packageManager = safeYarnOrNpm(); + const packageManager = await safeYarnOrNpm(); const linkFolder = path.resolve(__dirname, '..', '..', '..', '..', '..', '..', '.links'); for (const packageName of Object.keys(packageJson.devDependencies)) { if (packageName.startsWith('@electron-forge/')) { diff --git a/packages/api/core/src/api/init-scripts/init-npm.ts b/packages/api/core/src/api/init-scripts/init-npm.ts index d9ec16e2f3..ecc63e8546 100644 --- a/packages/api/core/src/api/init-scripts/init-npm.ts +++ b/packages/api/core/src/api/init-scripts/init-npm.ts @@ -29,7 +29,7 @@ export const exactDevDeps = ['electron']; export const initNPM = async (dir: string, task: ForgeListrTask): Promise => { d('installing dependencies'); - const packageManager = safeYarnOrNpm(); + const packageManager = await safeYarnOrNpm(); task.output = `${packageManager} install ${deps.join(' ')}`; await installDepList(dir, deps); diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 4e444ac3c5..d3c92f1f35 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -56,7 +56,7 @@ async function validateTemplate(template: string, templateModule: ForgeTemplate) export default async ({ dir = process.cwd(), interactive = false, copyCIFiles = false, force = false, template = 'base' }: InitOptions): Promise => { d(`Initializing in: ${dir}`); - const packageManager = safeYarnOrNpm(); + const packageManager = await safeYarnOrNpm(); const runner = new Listr<{ templateModule: ForgeTemplate; diff --git a/packages/api/core/src/util/install-dependencies.ts b/packages/api/core/src/util/install-dependencies.ts index b561f4d719..ca616b10e0 100644 --- a/packages/api/core/src/util/install-dependencies.ts +++ b/packages/api/core/src/util/install-dependencies.ts @@ -15,13 +15,13 @@ export enum DepVersionRestriction { } export default async (dir: string, deps: string[], depType = DepType.PROD, versionRestriction = DepVersionRestriction.RANGE): Promise => { - d('installing', JSON.stringify(deps), 'in:', dir, `depType=${depType},versionRestriction=${versionRestriction},withYarn=${hasYarn()}`); + d('installing', JSON.stringify(deps), 'in:', dir, `depType=${depType},versionRestriction=${versionRestriction},withYarn=${await hasYarn()}`); if (deps.length === 0) { d('nothing to install, stopping immediately'); return Promise.resolve(); } let cmd = ['install'].concat(deps); - if (hasYarn()) { + if (await hasYarn()) { cmd = ['add'].concat(deps); if (depType === DepType.DEV) cmd.push('--dev'); if (versionRestriction === DepVersionRestriction.EXACT) cmd.push('--exact'); diff --git a/packages/utils/core-utils/package.json b/packages/utils/core-utils/package.json index 82ab581b1e..961c4042e6 100644 --- a/packages/utils/core-utils/package.json +++ b/packages/utils/core-utils/package.json @@ -13,11 +13,11 @@ "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.3.1", + "detect-package-manager": "^3.0.2", "find-up": "^5.0.0", "fs-extra": "^10.0.0", "log-symbols": "^4.0.0", - "semver": "^7.2.1", - "yarn-or-npm": "^3.0.1" + "semver": "^7.2.1" }, "engines": { "node": ">= 16.4.0" diff --git a/packages/utils/core-utils/spec/yarn-or-npm.spec.ts b/packages/utils/core-utils/spec/yarn-or-npm.spec.ts index 1d4abc3eed..010bc21dfd 100644 --- a/packages/utils/core-utils/spec/yarn-or-npm.spec.ts +++ b/packages/utils/core-utils/spec/yarn-or-npm.spec.ts @@ -1,5 +1,5 @@ +import { detect } from 'detect-package-manager'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import systemYarnOrNpm from 'yarn-or-npm'; import { safeYarnOrNpm } from '../src/yarn-or-npm'; @@ -19,24 +19,26 @@ describe('yarn-or-npm', () => { } }); - it('should by default equal the system yarn-or-npm value', () => { - expect(safeYarnOrNpm()).toEqual(systemYarnOrNpm()); + it('should by default equal the system yarn-or-npm value', async () => { + const pm = await detect(); + expect(safeYarnOrNpm()).resolves.toEqual(pm); }); it('should return yarn if NODE_INSTALLER=yarn', () => { process.env.NODE_INSTALLER = 'yarn'; - expect(safeYarnOrNpm()).toEqual('yarn'); + expect(safeYarnOrNpm()).resolves.toEqual('yarn'); }); it('should return npm if NODE_INSTALLER=npm', () => { process.env.NODE_INSTALLER = 'npm'; - expect(safeYarnOrNpm()).toEqual('npm'); + expect(safeYarnOrNpm()).resolves.toEqual('npm'); }); - it('should return system value if NODE_INSTALLER is an unrecognized installer', () => { + it('should return system value if NODE_INSTALLER is an unrecognized installer', async () => { process.env.NODE_INSTALLER = 'magical_unicorn'; console.warn = vi.fn(); - expect(safeYarnOrNpm()).toEqual(systemYarnOrNpm()); + const pm = await detect(); + await expect(safeYarnOrNpm()).resolves.toEqual(pm); expect(console.warn).toHaveBeenCalledWith('⚠', expect.stringContaining('Unknown NODE_INSTALLER')); }); }); diff --git a/packages/utils/core-utils/src/electron-version.ts b/packages/utils/core-utils/src/electron-version.ts index 871b7fa1ab..cc117795f3 100644 --- a/packages/utils/core-utils/src/electron-version.ts +++ b/packages/utils/core-utils/src/electron-version.ts @@ -5,8 +5,6 @@ import findUp from 'find-up'; import fs from 'fs-extra'; import semver from 'semver'; -import { safeYarnOrNpm } from './yarn-or-npm'; - const d = debug('electron-forge:electron-version'); const electronPackageNames = ['electron-nightly', 'electron']; @@ -44,7 +42,7 @@ async function determineNodeModulesPath(dir: string, packageName: string): Promi export class PackageNotFoundError extends Error { constructor(packageName: string, dir: string) { - super(`Cannot find the package "${packageName}". Perhaps you need to run "${safeYarnOrNpm()} install" in "${dir}"?`); + super(`Cannot find the package "${packageName}". Perhaps you need to run install it in "${dir}"?`); } } diff --git a/packages/utils/core-utils/src/yarn-or-npm.ts b/packages/utils/core-utils/src/yarn-or-npm.ts index a2ddb4d259..ad8055e455 100644 --- a/packages/utils/core-utils/src/yarn-or-npm.ts +++ b/packages/utils/core-utils/src/yarn-or-npm.ts @@ -1,10 +1,10 @@ import { CrossSpawnArgs, CrossSpawnOptions, spawn } from '@malept/cross-spawn-promise'; import chalk from 'chalk'; +import { detect } from 'detect-package-manager'; import logSymbols from 'log-symbols'; -import yarnOrNpm from 'yarn-or-npm'; -export const safeYarnOrNpm = () => { - const system = yarnOrNpm(); +export const safeYarnOrNpm = async () => { + const system = await detect(); switch (process.env.NODE_INSTALLER) { case 'yarn': case 'npm': @@ -17,6 +17,6 @@ export const safeYarnOrNpm = () => { } }; -export const yarnOrNpmSpawn = (args?: CrossSpawnArgs, opts?: CrossSpawnOptions): Promise => spawn(safeYarnOrNpm(), args, opts); +export const yarnOrNpmSpawn = async (args?: CrossSpawnArgs, opts?: CrossSpawnOptions): Promise => spawn(await safeYarnOrNpm(), args, opts); -export const hasYarn = (): boolean => safeYarnOrNpm() === 'yarn'; +export const hasYarn = async () => (await safeYarnOrNpm()) === 'yarn'; diff --git a/typings/yarn-or-npm/index.d.ts b/typings/yarn-or-npm/index.d.ts deleted file mode 100644 index f80008235e..0000000000 --- a/typings/yarn-or-npm/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'yarn-or-npm' { - const yon: () => 'yarn' | 'npm'; - export default yon; -} diff --git a/yarn.lock b/yarn.lock index 0892d27524..ddc330ea4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5032,7 +5032,7 @@ cross-spawn-windows-exe@^1.1.0: is-wsl "^2.2.0" which "^2.0.2" -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -5319,6 +5319,13 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== +detect-package-manager@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/detect-package-manager/-/detect-package-manager-3.0.2.tgz#ca34261ab84198072580e93ae86582c575428da9" + integrity sha512-8JFjJHutStYrfWwzfretQoyNGoZVW1Fsrp4JO9spa7h/fBfwgTMEIy4/LBzRDGsxwVPHU0q+T9YvwLDJoOApLQ== + dependencies: + execa "^5.1.1" + dezalgo@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" @@ -14213,14 +14220,6 @@ yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yarn-or-npm@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/yarn-or-npm/-/yarn-or-npm-3.0.1.tgz#6336eea4dff7e23e226acc98c1a8ada17a1b8666" - integrity sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ== - dependencies: - cross-spawn "^6.0.5" - pkg-dir "^4.2.0" - yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"