diff --git a/packages/@ionic/cli/src/definitions.ts b/packages/@ionic/cli/src/definitions.ts index 4f17d688e9..23f20a77e8 100644 --- a/packages/@ionic/cli/src/definitions.ts +++ b/packages/@ionic/cli/src/definitions.ts @@ -481,7 +481,7 @@ export interface ITelemetry { sendCommand(command: string, args: string[]): Promise; } -export type NpmClient = 'yarn' | 'npm' | 'pnpm'; +export type NpmClient = 'yarn' | 'yarn-berry' | 'npm' | 'pnpm'; export type FeatureId = 'ssl-commands'; diff --git a/packages/@ionic/cli/src/lib/build.ts b/packages/@ionic/cli/src/lib/build.ts index 6889c8caf7..57647ca004 100644 --- a/packages/@ionic/cli/src/lib/build.ts +++ b/packages/@ionic/cli/src/lib/build.ts @@ -48,6 +48,7 @@ export abstract class BuildRunner> implements Runner npm: NpmBuildCLI, pnpm: PnpmBuildCLI, yarn: YarnBuildCLI, + 'yarn-berry': YarnBuildCLI, }; const client = this.e.config.get('npmClient'); diff --git a/packages/@ionic/cli/src/lib/utils/__tests__/npm.ts b/packages/@ionic/cli/src/lib/utils/__tests__/npm.ts index b031a91c93..f4693a0513 100644 --- a/packages/@ionic/cli/src/lib/utils/__tests__/npm.ts +++ b/packages/@ionic/cli/src/lib/utils/__tests__/npm.ts @@ -159,6 +159,83 @@ describe('@ionic/cli', () => { }); + describe('yarn-berry', () => { + + jest.resetModules(); + const { pkgManagerArgs } = require('../npm'); + + it('should be pkg install with default args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'install' }); + expect(result).toEqual(['yarn', 'install']); + }); + + it('should be pkg install args for local package', async () => { + const result = await pkgManagerArgs('yarn', { command: 'install', pkg: 'foo' }); + expect(result).toEqual(['yarn', 'add', '--exact', 'foo']); + }); + + it('should be pkg install args for local package install', async () => { + const result = await pkgManagerArgs('yarn', { command: 'install', pkg: 'foo', saveDev: true }); + expect(result).toEqual(['yarn', 'add', '--dev', '--exact', 'foo']); + }); + + it('should be pkg install args for local package uninstall', async () => { + const result = await pkgManagerArgs('yarn', { command: 'uninstall', pkg: 'foo', saveDev: true }); + expect(result).toEqual(['yarn', 'remove', '--dev', 'foo']); + }); + + it('should be pkg install args for global package install', async () => { + const result = await pkgManagerArgs('yarn', { command: 'install', pkg: 'foo', global: true }); + expect(result).toEqual(['yarn', 'global', 'add', 'foo']); + }); + + it('should be pkg install args for global package install with bad options', async () => { + const result = await pkgManagerArgs('yarn', { command: 'install', pkg: 'foo', global: true, saveDev: true }); + expect(result).toEqual(['yarn', 'global', 'add', 'foo']); + }); + + it('should be dedupe args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'dedupe' }); + expect(result).toEqual([]); // yarn doesn't support dedupe + }); + + it('should be rebuild args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'rebuild' }); + expect(result).toEqual(['yarn', 'install', '--force']); + }); + + it('should be run args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'run' }); + expect(result).toEqual(['yarn', 'run']); + }); + + it('should be run args with script', async () => { + const result = await pkgManagerArgs('yarn', { command: 'run', script: 'test' }); + expect(result).toEqual(['yarn', 'run', 'test']); + }); + + it('should be run args with script and script args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'run', script: 'test', scriptArgs: ['-s'] }); + expect(result).toEqual(['yarn', 'run', 'test', '-s']); + }); + + it('should be info args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'info' }); + expect(result).toEqual(['yarn', 'info']); + }); + + it('should be pkg info args', async () => { + const result = await pkgManagerArgs('yarn', { command: 'info', pkg: '@ionic/cli' }); + expect(result).toEqual(['yarn', 'info', '@ionic/cli']); + }); + + it('should be pkg info args with json flag', async () => { + const result = await pkgManagerArgs('yarn', { command: 'info', pkg: '@ionic/cli', json: true }); + expect(result).toEqual(['yarn', 'info', '@ionic/cli', '--json']); + }); + + }); + describe('pnpm', () => { jest.resetModules(); diff --git a/packages/@ionic/cli/src/lib/utils/npm.ts b/packages/@ionic/cli/src/lib/utils/npm.ts index c717b1924d..0b1a55b888 100644 --- a/packages/@ionic/cli/src/lib/utils/npm.ts +++ b/packages/@ionic/cli/src/lib/utils/npm.ts @@ -76,19 +76,30 @@ export async function pkgManagerArgs(npmClient: NpmClient, options: PkgManagerOp } } + let installerExec: string = ''; const installerArgs: string[] = []; switch (npmClient) { case 'npm': + installerExec = 'npm'; vocab = { run: 'run', install: 'i', bareInstall: 'i', uninstall: 'uninstall', dedupe: 'dedupe', rebuild: 'rebuild', global: '-g', save: '--save', saveDev: '-D', saveExact: '-E', nonInteractive: '', lockFileOnly: '--package-lock-only' }; break; case 'yarn': + installerExec = 'yarn'; vocab = { run: 'run', install: 'add', bareInstall: 'install', uninstall: 'remove', dedupe: '', rebuild: 'install', global: '', save: '', saveDev: '--dev', saveExact: '--exact', nonInteractive: '--non-interactive', lockFileOnly: '' }; if (options.global) { // yarn installs packages globally under the 'global' prefix, instead of having a flag installerArgs.push('global'); } break; + case 'yarn-berry': + installerExec = 'yarn'; + vocab = { run: 'run', install: 'add', bareInstall: 'install', uninstall: 'remove', dedupe: '', rebuild: 'install', global: '', save: '', saveDev: '--dev', saveExact: '--exact', nonInteractive: '', lockFileOnly: '' }; + if (options.global) { // yarn installs packages globally under the 'global' prefix, instead of having a flag + installerArgs.push('global'); + } + break; case 'pnpm': + installerExec = 'pnpm'; vocab = { run: 'run', install: 'add', bareInstall: 'install', uninstall: 'remove', dedupe: '', rebuild: 'rebuild', global: '--global', save: '', saveDev: '--save-dev', saveExact: '--save-exact', nonInteractive: '', lockFileOnly: '--lockfile-only' }; break; default: @@ -171,7 +182,7 @@ export async function pkgManagerArgs(npmClient: NpmClient, options: PkgManagerOp installerArgs.push('--json'); } - return [npmClient, ...installerArgs]; + return [installerExec, ...installerArgs]; } /**