Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ jobs:
matrix:
os: [ubuntu-latest]
node: [22]
subset: [yarn, pnpm]
subset: [yarn, pnpm, deno]
shard: [0, 1, 2]
runs-on: ${{ matrix.os }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
matrix:
os: [ubuntu-latest]
node: [22]
subset: [yarn, pnpm]
subset: [yarn, pnpm, deno]
shard: [0, 1, 2]
runs-on: ${{ matrix.os }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions packages/angular/cli/lib/config/workspace-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"packageManager": {
"description": "Specify which package manager tool to use.",
"type": "string",
"enum": ["npm", "cnpm", "yarn", "pnpm", "bun"]
"enum": ["npm", "cnpm", "yarn", "pnpm", "bun", "deno"]
},
"warnings": {
"description": "Control CLI specific console warnings",
Expand Down Expand Up @@ -101,7 +101,7 @@
"packageManager": {
"description": "Specify which package manager tool to use.",
"type": "string",
"enum": ["npm", "cnpm", "yarn", "pnpm", "bun"]
"enum": ["npm", "cnpm", "yarn", "pnpm", "bun", "deno"]
},
"warnings": {
"description": "Control CLI specific console warnings",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"description": "The preferred package manager configuration files to use for registry settings.",
"type": "string",
"default": "npm",
"enum": ["npm", "yarn", "cnpm", "pnpm", "bun"]
"enum": ["npm", "yarn", "cnpm", "pnpm", "bun", "deno"]
}
},
"required": []
Expand Down
42 changes: 37 additions & 5 deletions packages/angular/cli/src/utilities/package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,14 @@ export class PackageManagerUtils {
prefix: '--cwd',
noLockfile: '',
};
case PackageManager.Deno:
return {
saveDev: '--dev',
install: 'add',
installAll: 'install',
prefix: '--root',
noLockfile: '--no-lock',
};
default:
return {
saveDev: '--save-dev',
Expand Down Expand Up @@ -194,7 +202,8 @@ export class PackageManagerUtils {
@memoize
private getVersion(name: PackageManager): string | undefined {
try {
return execSync(`${name} --version`, {
const versionArg = name !== PackageManager.Deno ? '--version' : '-v';
const version = execSync(`${name} ${versionArg}`, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
env: {
Expand All @@ -204,6 +213,13 @@ export class PackageManagerUtils {
NPM_CONFIG_UPDATE_NOTIFIER: 'false',
},
}).trim();

if (name === PackageManager.Deno) {
// Deno CLI outputs "deno 2.4.4"
return version.replace('deno ', '');
}

return version;
} catch {
return undefined;
}
Expand All @@ -220,14 +236,21 @@ export class PackageManagerUtils {
const hasYarnLock = this.hasLockfile(PackageManager.Yarn);
const hasPnpmLock = this.hasLockfile(PackageManager.Pnpm);
const hasBunLock = this.hasLockfile(PackageManager.Bun);
const hasDenoLock = this.hasLockfile(PackageManager.Deno);

// PERF NOTE: `this.getVersion` spawns the package a the child_process which can take around ~300ms at times.
// Therefore, we should only call this method when needed. IE: don't call `this.getVersion(PackageManager.Pnpm)` unless truly needed.
// The result of this method is not stored in a variable because it's memoized.

if (hasNpmLock) {
// Has NPM lock file.
if (!hasYarnLock && !hasPnpmLock && !hasBunLock && this.getVersion(PackageManager.Npm)) {
if (
!hasYarnLock &&
!hasPnpmLock &&
!hasBunLock &&
!hasDenoLock &&
this.getVersion(PackageManager.Npm)
) {
// Only NPM lock file and NPM binary is available.
return PackageManager.Npm;
}
Expand All @@ -242,6 +265,9 @@ export class PackageManagerUtils {
} else if (hasBunLock && this.getVersion(PackageManager.Bun)) {
// Bun lock file and Bun binary is available.
return PackageManager.Bun;
} else if (hasDenoLock && this.getVersion(PackageManager.Deno)) {
// Deno lock file and Deno binary is available.
return PackageManager.Deno;
}
}

Expand All @@ -250,13 +276,16 @@ export class PackageManagerUtils {
const hasYarn = !!this.getVersion(PackageManager.Yarn);
const hasPnpm = !!this.getVersion(PackageManager.Pnpm);
const hasBun = !!this.getVersion(PackageManager.Bun);
const hasDeno = !!this.getVersion(PackageManager.Deno);

if (hasYarn && !hasPnpm && !hasBun) {
if (hasYarn && !hasPnpm && !hasBun && !hasDeno) {
return PackageManager.Yarn;
} else if (hasPnpm && !hasYarn && !hasBun) {
} else if (hasPnpm && !hasYarn && !hasBun && !hasDeno) {
return PackageManager.Pnpm;
} else if (hasBun && !hasYarn && !hasPnpm) {
} else if (hasBun && !hasYarn && !hasPnpm && !hasDeno) {
return PackageManager.Bun;
} else if (hasDeno && !hasYarn && !hasPnpm && !hasBun) {
return PackageManager.Deno;
}
}

Expand All @@ -277,6 +306,9 @@ export class PackageManagerUtils {
case PackageManager.Bun:
lockfileName = 'bun.lockb';
break;
case PackageManager.Deno:
lockfileName = 'deno.lock';
break;
case PackageManager.Npm:
default:
lockfileName = 'package-lock.json';
Expand Down
6 changes: 6 additions & 0 deletions packages/angular/create/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ pnpm create @angular [project-name] [...options]
```
bun create @angular [project-name] [...options]
```

### deno

```
deno init --npm @angular [project-name] [...options]
```
2 changes: 1 addition & 1 deletion packages/angular/create/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const hasPackageManagerArg = args.some((a) => a.startsWith('--package-manager'))
if (!hasPackageManagerArg) {
// Ex: yarn/1.22.18 npm/? node/v16.15.1 linux x64
const packageManager = process.env['npm_config_user_agent']?.split('/')[0];
if (packageManager && ['npm', 'pnpm', 'yarn', 'cnpm', 'bun'].includes(packageManager)) {
if (packageManager && ['npm', 'pnpm', 'yarn', 'cnpm', 'bun', 'deno'].includes(packageManager)) {
args.push('--package-manager', packageManager);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ const packageManagers: { [name: string]: PackageManagerProfile } = {
installPackage: 'add',
},
},
'deno': {
commands: {
installAll: 'install',
installPackage: 'add',
},
},
'pnpm': {
commands: {
installAll: 'install',
Expand Down
2 changes: 1 addition & 1 deletion packages/angular_devkit/schematics_cli/blank/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"packageManager": {
"description": "The package manager used to install dependencies.",
"type": "string",
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun"],
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun", "deno"],
"default": "npm"
},
"author": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"packageManager": {
"description": "The package manager used to install dependencies.",
"type": "string",
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun"],
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun", "deno"],
"default": "npm"
}
},
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/ng-new/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
"packageManager": {
"description": "The package manager used to install dependencies.",
"type": "string",
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun"]
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun", "deno"]
},
"standalone": {
"description": "Creates an application based upon the standalone API, without NgModules.",
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/workspace/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"packageManager": {
"description": "The package manager to use for installing dependencies.",
"type": "string",
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun"]
"enum": ["npm", "yarn", "pnpm", "cnpm", "bun", "deno"]
}
},
"required": ["name", "version"]
Expand Down
5 changes: 3 additions & 2 deletions tests/legacy-cli/e2e.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def e2e_suites(name, runner, data):

_e2e_suite(name, runner, "npm", data, toolchain_name, toolchain)
_e2e_suite(name, runner, "bun", data, toolchain_name, toolchain)
_e2e_suite(name, runner, "deno", data, toolchain_name, toolchain)
_e2e_suite(name, runner, "pnpm", data, toolchain_name, toolchain)
_e2e_suite(name, runner, "yarn", data, toolchain_name, toolchain)
_e2e_suite(name, runner, "esbuild", data, toolchain_name, toolchain)
Expand Down Expand Up @@ -140,7 +141,7 @@ def _e2e_tests(name, runner, toolchain, **kwargs):

def _e2e_suite(name, runner, type, data, toolchain_name = "", toolchain = None):
"""
Setup a predefined test suite (yarn|pnpm|bun|esbuild|saucelabs|npm).
Setup a predefined test suite (yarn|pnpm|bun|deno|esbuild|saucelabs|npm).
"""
args = []
tests = None
Expand All @@ -149,7 +150,7 @@ def _e2e_suite(name, runner, type, data, toolchain_name = "", toolchain = None):
if toolchain_name:
toolchain_name = "_" + toolchain_name

if type == "yarn" or type == "bun" or type == "pnpm":
if type == "yarn" or type == "bun" or type == "deno" or type == "pnpm":
args.append("--package-manager=%s" % type)
args.append("--esbuild")
tests = PACKAGE_MANAGER_SUBSET_TESTS
Expand Down
1 change: 1 addition & 0 deletions tests/legacy-cli/e2e/setup/100-global-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const PACKAGE_MANAGER_VERSION = {
'yarn': '1.22.22',
'pnpm': '9.3.0',
'bun': '1.1.13',
'deno': '2.4.4',
};

export default async function () {
Expand Down
6 changes: 5 additions & 1 deletion tests/legacy-cli/e2e/tests/misc/create-angular.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { equal } from 'node:assert';
import { join, resolve } from 'node:path';
import { expectFileToExist, readFile, rimraf } from '../../utils/fs';
import { getActivePackageManager } from '../../utils/packages';
import { silentBun, silentNpm, silentPnpm, silentYarn } from '../../utils/process';
import { silentBun, silentDeno, silentNpm, silentPnpm, silentYarn } from '../../utils/process';

export default async function () {
const currentDirectory = process.cwd();
Expand All @@ -25,6 +25,10 @@ export default async function () {
case 'bun':
await silentBun('create', '@angular', projectName, '--style=scss');

break;
case 'deno':
await silentDeno('init', '--npm', '@angular', projectName, '--style=scss');

break;
case 'pnpm':
await silentPnpm('create', '@angular', projectName, '--style=scss');
Expand Down
12 changes: 10 additions & 2 deletions tests/legacy-cli/e2e/utils/packages.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { getGlobalVariable } from './env';
import { ProcessOutput, silentBun, silentNpm, silentPnpm, silentYarn } from './process';
import { ProcessOutput, silentBun, silentDeno, silentNpm, silentPnpm, silentYarn } from './process';

export interface PkgInfo {
readonly name: string;
readonly version: string;
readonly path: string;
}

export function getActivePackageManager(): 'npm' | 'yarn' | 'bun' | 'pnpm' {
export function getActivePackageManager(): 'npm' | 'yarn' | 'bun' | 'deno' | 'pnpm' {
return getGlobalVariable('package-manager');
}

Expand All @@ -29,6 +29,9 @@ export async function installWorkspacePackages(options?: { force?: boolean }): P
case 'bun':
await silentBun('install');
break;
case 'deno':
await silentDeno('install');
break;
}
}

Expand All @@ -41,6 +44,8 @@ export function installPackage(specifier: string, registry?: string): Promise<Pr
return silentYarn('add', specifier, ...registryOption);
case 'bun':
return silentBun('add', specifier, ...registryOption);
case 'deno':
return silentDeno('add', specifier, ...registryOption);
case 'pnpm':
return silentPnpm('add', specifier, ...registryOption);
}
Expand All @@ -58,6 +63,9 @@ export async function uninstallPackage(name: string): Promise<void> {
case 'bun':
await silentBun('remove', name);
break;
case 'deno':
await silentDeno('remove', name);
break;
case 'pnpm':
await silentPnpm('remove', name);
break;
Expand Down
4 changes: 4 additions & 0 deletions tests/legacy-cli/e2e/utils/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ export function silentBun(...args: string[]) {
return _exec({ silent: true }, 'bun', args);
}

export function silentDeno(...args: string[]) {
return _exec({ silent: true }, 'deno', args);
}

export function globalNpm(args: string[], env?: NodeJS.ProcessEnv) {
if (!process.env.LEGACY_CLI_RUNNER) {
throw new Error(
Expand Down
Loading