@schematics/angular 21.0.0-next.4 → 21.0.0-next.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/ai-config/index.js +32 -15
  2. package/ai-config/schema.d.ts +1 -0
  3. package/ai-config/schema.js +1 -0
  4. package/ai-config/schema.json +5 -1
  5. package/application/files/module-files/src/app/app-module.ts.template +2 -3
  6. package/application/files/module-files/src/app/app__suffix__.spec.ts.template +4 -6
  7. package/application/files/standalone-files/src/app/app.config.ts.template +3 -3
  8. package/application/files/standalone-files/src/app/app__suffix__.spec.ts.template +4 -6
  9. package/application/schema.json +1 -1
  10. package/component/files/__name@dasherize@if-flat__/__name@dasherize__.__type@dasherize__.spec.ts.template +1 -1
  11. package/component/index.js +3 -0
  12. package/migrations/migration-collection.json +5 -0
  13. package/migrations/update-typescript-lib/migration.d.ts +9 -0
  14. package/migrations/update-typescript-lib/migration.js +79 -0
  15. package/migrations/use-application-builder/migration.js +1 -0
  16. package/ng-new/schema.d.ts +1 -0
  17. package/ng-new/schema.js +1 -0
  18. package/ng-new/schema.json +1 -1
  19. package/package.json +4 -4
  20. package/ssr/files/application-builder/server.ts.template +2 -2
  21. package/ssr/files/server-builder/server.ts.template +0 -2
  22. package/utility/latest-versions/package.json +1 -1
  23. package/utility/latest-versions.js +3 -3
  24. package/utility/project-targets.d.ts +1 -0
  25. package/utility/project-targets.js +10 -0
  26. package/workspace/files/__dot__gitignore.template +1 -0
  27. package/workspace/files/package.json.template +1 -0
  28. package/workspace/index.js +34 -9
  29. package/workspace/schema.json +4 -1
@@ -11,6 +11,10 @@ exports.default = default_1;
11
11
  const schematics_1 = require("@angular-devkit/schematics");
12
12
  const schema_1 = require("./schema");
13
13
  const AI_TOOLS = {
14
+ agents: {
15
+ rulesName: 'AGENTS.md',
16
+ directory: '.',
17
+ },
14
18
  gemini: {
15
19
  rulesName: 'GEMINI.md',
16
20
  directory: '.gemini',
@@ -39,19 +43,32 @@ const AI_TOOLS = {
39
43
  },
40
44
  };
41
45
  function default_1({ tool }) {
42
- if (!tool) {
43
- return (0, schematics_1.noop)();
44
- }
45
- const rules = tool
46
- .filter((tool) => tool !== schema_1.Tool.None)
47
- .map((selectedTool) => AI_TOOLS[selectedTool])
48
- .map(({ rulesName, directory, frontmatter }) => (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
49
- (0, schematics_1.applyTemplates)({
50
- ...schematics_1.strings,
51
- rulesName,
52
- frontmatter,
53
- }),
54
- (0, schematics_1.move)(directory),
55
- ])));
56
- return (0, schematics_1.chain)(rules);
46
+ return (tree, context) => {
47
+ if (!tool) {
48
+ return (0, schematics_1.noop)();
49
+ }
50
+ const rules = tool
51
+ .filter((tool) => tool !== schema_1.Tool.None)
52
+ .map((selectedTool) => {
53
+ const { rulesName, directory, frontmatter } = AI_TOOLS[selectedTool];
54
+ const path = `${directory}/${rulesName}`;
55
+ if (tree.exists(path)) {
56
+ const toolName = schematics_1.strings.classify(selectedTool);
57
+ context.logger.warn(`Skipping configuration file for '${toolName}' at '${path}' because it already exists.\n` +
58
+ 'This is to prevent overwriting a potentially customized file. ' +
59
+ 'If you want to regenerate it with Angular recommended defaults, please delete the existing file and re-run the command.\n' +
60
+ 'You can review the latest recommendations at https://angular.dev/ai/develop-with-ai.');
61
+ return (0, schematics_1.noop)();
62
+ }
63
+ return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
64
+ (0, schematics_1.applyTemplates)({
65
+ ...schematics_1.strings,
66
+ rulesName,
67
+ frontmatter,
68
+ }),
69
+ (0, schematics_1.move)(directory),
70
+ ]));
71
+ });
72
+ return (0, schematics_1.chain)(rules);
73
+ };
57
74
  }
@@ -11,6 +11,7 @@ export type Schema = {
11
11
  tool?: Tool[];
12
12
  };
13
13
  export declare enum Tool {
14
+ Agents = "agents",
14
15
  Claude = "claude",
15
16
  Copilot = "copilot",
16
17
  Cursor = "cursor",
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.Tool = void 0;
6
6
  var Tool;
7
7
  (function (Tool) {
8
+ Tool["Agents"] = "agents";
8
9
  Tool["Claude"] = "claude";
9
10
  Tool["Copilot"] = "copilot";
10
11
  Tool["Cursor"] = "cursor";
@@ -18,6 +18,10 @@
18
18
  "value": "none",
19
19
  "label": "None"
20
20
  },
21
+ {
22
+ "value": "agents",
23
+ "label": "Agents.md [ https://agents.md/ ]"
24
+ },
21
25
  {
22
26
  "value": "claude",
23
27
  "label": "Claude [ https://docs.anthropic.com/en/docs/claude-code/memory ]"
@@ -47,7 +51,7 @@
47
51
  "description": "Specifies which AI tools to generate configuration files for. These file are used to improve the outputs of AI tools by following the best practices.",
48
52
  "items": {
49
53
  "type": "string",
50
- "enum": ["none", "gemini", "copilot", "claude", "cursor", "jetbrains", "windsurf"]
54
+ "enum": ["none", "gemini", "copilot", "claude", "cursor", "jetbrains", "windsurf", "agents"]
51
55
  }
52
56
  }
53
57
  }
@@ -1,4 +1,4 @@
1
- import { NgModule, provideBrowserGlobalErrorListeners<% if(zoneless) { %>, provideZonelessChangeDetection<% } %> } from '@angular/core';
1
+ import { NgModule, provideBrowserGlobalErrorListeners } from '@angular/core';
2
2
  import { BrowserModule } from '@angular/platform-browser';
3
3
  <% if (routing) { %>
4
4
  import { AppRoutingModule } from './app-routing-module';<% } %>
@@ -13,8 +13,7 @@ import { App } from './app';
13
13
  AppRoutingModule<% } %>
14
14
  ],
15
15
  providers: [
16
- provideBrowserGlobalErrorListeners()<% if (zoneless) { %>,
17
- provideZonelessChangeDetection()<% } %>
16
+ provideBrowserGlobalErrorListeners()
18
17
  ],
19
18
  bootstrap: [App]
20
19
  })
@@ -1,5 +1,4 @@
1
- <% if(zoneless) { %>import { provideZonelessChangeDetection } from '@angular/core';
2
- <% } %>import { TestBed } from '@angular/core/testing';<% if (routing) { %>
1
+ import { TestBed } from '@angular/core/testing';<% if (routing) { %>
3
2
  import { RouterModule } from '@angular/router';<% } %>
4
3
  import { App } from './app';
5
4
 
@@ -11,8 +10,7 @@ describe('App', () => {
11
10
  ],<% } %>
12
11
  declarations: [
13
12
  App
14
- ],<% if(zoneless) { %>
15
- providers: [provideZonelessChangeDetection()]<% } %>
13
+ ],
16
14
  }).compileComponents();
17
15
  });
18
16
 
@@ -22,9 +20,9 @@ describe('App', () => {
22
20
  expect(app).toBeTruthy();
23
21
  });
24
22
 
25
- it('should render title', () => {
23
+ it('should render title', <% if(zoneless) { %> async <% } %>() => {
26
24
  const fixture = TestBed.createComponent(App);
27
- fixture.detectChanges();
25
+ <%= zoneless ? 'await fixture.whenStable();' : 'fixture.detectChanges();' %>
28
26
  const compiled = fixture.nativeElement as HTMLElement;
29
27
  expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');
30
28
  });
@@ -1,12 +1,12 @@
1
- import { ApplicationConfig, provideBrowserGlobalErrorListeners, <% if(!zoneless) { %>provideZoneChangeDetection<% } else { %>provideZonelessChangeDetection<% } %> } from '@angular/core';<% if (routing) { %>
1
+ import { ApplicationConfig, provideBrowserGlobalErrorListeners<% if(!zoneless) { %>, provideZoneChangeDetection<% } %> } from '@angular/core';<% if (routing) { %>
2
2
  import { provideRouter } from '@angular/router';
3
3
 
4
4
  import { routes } from './app.routes';<% } %>
5
5
 
6
6
  export const appConfig: ApplicationConfig = {
7
7
  providers: [
8
- provideBrowserGlobalErrorListeners(),
9
- <% if(zoneless) { %>provideZonelessChangeDetection()<% } else { %>provideZoneChangeDetection({ eventCoalescing: true })<% } %>,
8
+ provideBrowserGlobalErrorListeners(),<% if(!zoneless) { %>
9
+ provideZoneChangeDetection({ eventCoalescing: true }),<% } %>
10
10
  <% if (routing) {%>provideRouter(routes)<% } %>
11
11
  ]
12
12
  };
@@ -1,12 +1,10 @@
1
- <% if(zoneless) { %>import { provideZonelessChangeDetection } from '@angular/core';
2
- <% } %>import { TestBed } from '@angular/core/testing';
1
+ import { TestBed } from '@angular/core/testing';
3
2
  import { App } from './app';
4
3
 
5
4
  describe('App', () => {
6
5
  beforeEach(async () => {
7
6
  await TestBed.configureTestingModule({
8
- imports: [App],<% if(zoneless) { %>
9
- providers: [provideZonelessChangeDetection()]<% } %>
7
+ imports: [App],
10
8
  }).compileComponents();
11
9
  });
12
10
 
@@ -16,9 +14,9 @@ describe('App', () => {
16
14
  expect(app).toBeTruthy();
17
15
  });
18
16
 
19
- it('should render title', () => {
17
+ it('should render title', <% if(zoneless) { %> async <% } %>() => {
20
18
  const fixture = TestBed.createComponent(App);
21
- fixture.detectChanges();
19
+ <%= zoneless ? 'await fixture.whenStable();' : 'fixture.detectChanges();' %>
22
20
  const compiled = fixture.nativeElement as HTMLElement;
23
21
  expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');
24
22
  });
@@ -126,7 +126,7 @@
126
126
  "description": "Generate an application that does not use `zone.js`.",
127
127
  "x-prompt": "Do you want to create a 'zoneless' application without zone.js?",
128
128
  "type": "boolean",
129
- "default": false
129
+ "default": true
130
130
  },
131
131
  "fileNameStyleGuide": {
132
132
  "type": "string",
@@ -14,7 +14,7 @@ describe('<%= classifiedName %>', () => {
14
14
 
15
15
  fixture = TestBed.createComponent(<%= classifiedName %>);
16
16
  component = fixture.componentInstance;
17
- fixture.detectChanges();
17
+ <%= zoneless ? 'await fixture.whenStable();' : 'fixture.detectChanges();' %>
18
18
  });
19
19
 
20
20
  it('should create', () => {
@@ -12,6 +12,7 @@ const add_declaration_to_ng_module_1 = require("../utility/add-declaration-to-ng
12
12
  const find_module_1 = require("../utility/find-module");
13
13
  const parse_name_1 = require("../utility/parse-name");
14
14
  const project_1 = require("../utility/project");
15
+ const project_targets_1 = require("../utility/project-targets");
15
16
  const validation_1 = require("../utility/validation");
16
17
  const workspace_1 = require("../utility/workspace");
17
18
  const schema_1 = require("./schema");
@@ -40,6 +41,7 @@ exports.default = (0, project_1.createProjectSchematic)((options, { project, tre
40
41
  const classifiedName = schematics_1.strings.classify(options.name) +
41
42
  (options.addTypeToClassName && options.type ? schematics_1.strings.classify(options.type) : '');
42
43
  (0, validation_1.validateClassName)(classifiedName);
44
+ const zoneless = (0, project_targets_1.isZonelessApp)(project);
43
45
  const skipStyleFile = options.inlineStyle || options.style === schema_1.Style.None;
44
46
  const templateSource = (0, schematics_1.apply)((0, schematics_1.url)('./files'), [
45
47
  options.skipTests ? (0, schematics_1.filter)((path) => !path.endsWith('.spec.ts.template')) : (0, schematics_1.noop)(),
@@ -52,6 +54,7 @@ exports.default = (0, project_1.createProjectSchematic)((options, { project, tre
52
54
  ...options,
53
55
  // Add a new variable for the classified name, conditionally including the type
54
56
  classifiedName,
57
+ zoneless,
55
58
  }),
56
59
  !options.type
57
60
  ? (0, schematics_1.forEach)(((file) => {
@@ -13,6 +13,11 @@
13
13
  "version": "21.0.0",
14
14
  "factory": "./karma/migration",
15
15
  "description": "Remove any karma configuration files that only contain the default content. The default configuration is automatically available without a specific project file."
16
+ },
17
+ "update-typescript-lib": {
18
+ "version": "21.0.0",
19
+ "factory": "./update-typescript-lib/migration",
20
+ "description": "Updates the 'lib' property in tsconfig files to use 'es2022' or a more modern version."
16
21
  }
17
22
  }
18
23
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import { Rule } from '@angular-devkit/schematics';
9
+ export default function (): Rule;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.default = default_1;
11
+ const json_file_1 = require("../../utility/json-file");
12
+ const workspace_1 = require("../../utility/workspace");
13
+ function default_1() {
14
+ return async (host, context) => {
15
+ // Workspace level tsconfig
16
+ if (host.exists('tsconfig.json')) {
17
+ updateLib(host, 'tsconfig.json');
18
+ }
19
+ const workspace = await (0, workspace_1.getWorkspace)(host);
20
+ // Find all tsconfig which are references used by builders
21
+ for (const [, project] of workspace.projects) {
22
+ for (const [targetName, target] of project.targets) {
23
+ if (!target.options) {
24
+ continue;
25
+ }
26
+ // Update all other known CLI builders that use a tsconfig
27
+ const tsConfigs = [target.options, ...Object.values(target.configurations || {})]
28
+ .filter((opt) => typeof opt?.tsConfig === 'string')
29
+ .map((opt) => opt.tsConfig);
30
+ const uniqueTsConfigs = new Set(tsConfigs);
31
+ for (const tsConfig of uniqueTsConfigs) {
32
+ if (host.exists(tsConfig)) {
33
+ updateLib(host, tsConfig);
34
+ }
35
+ else {
36
+ context.logger.warn(`'${tsConfig}' referenced in the '${targetName}' target does not exist.`);
37
+ }
38
+ }
39
+ }
40
+ }
41
+ };
42
+ }
43
+ function updateLib(host, tsConfigPath) {
44
+ const json = new json_file_1.JSONFile(host, tsConfigPath);
45
+ const jsonPath = ['compilerOptions', 'lib'];
46
+ const lib = json.get(jsonPath);
47
+ if (!lib || !Array.isArray(lib)) {
48
+ return;
49
+ }
50
+ const esLibs = lib.filter((l) => typeof l === 'string' && l.toLowerCase().startsWith('es'));
51
+ const hasDom = lib.some((l) => typeof l === 'string' && l.toLowerCase() === 'dom');
52
+ if (esLibs.length === 0) {
53
+ return;
54
+ }
55
+ const esLibToVersion = new Map();
56
+ for (const l of esLibs) {
57
+ const version = l.toLowerCase().match(/^es(next|(\d+))$/)?.[1];
58
+ if (version) {
59
+ esLibToVersion.set(l, version === 'next' ? Infinity : Number(version));
60
+ }
61
+ }
62
+ if (esLibToVersion.size === 0) {
63
+ return;
64
+ }
65
+ const latestEsLib = [...esLibToVersion.entries()].sort(([, v1], [, v2]) => v2 - v1)[0];
66
+ const latestVersion = latestEsLib[1];
67
+ if (hasDom) {
68
+ if (latestVersion <= 2022) {
69
+ json.remove(jsonPath);
70
+ }
71
+ return;
72
+ }
73
+ // No 'dom' with 'es' libs, so update 'es' lib.
74
+ if (latestVersion < 2022) {
75
+ const newLibs = lib.filter((l) => !esLibToVersion.has(l));
76
+ newLibs.push('es2022');
77
+ json.modify(jsonPath, newLibs);
78
+ }
79
+ }
@@ -270,6 +270,7 @@ function default_1() {
270
270
  rootJson.modify(['compilerOptions', 'esModuleInterop'], true);
271
271
  rootJson.modify(['compilerOptions', 'downlevelIteration'], undefined);
272
272
  rootJson.modify(['compilerOptions', 'allowSyntheticDefaultImports'], undefined);
273
+ rootJson.modify(['compilerOptions', 'moduleResolution'], 'bundler');
273
274
  }),
274
275
  ]);
275
276
  }
@@ -124,6 +124,7 @@ export type Schema = {
124
124
  zoneless?: boolean;
125
125
  };
126
126
  export declare enum AiConfig {
127
+ Agents = "agents",
127
128
  Claude = "claude",
128
129
  Copilot = "copilot",
129
130
  Cursor = "cursor",
package/ng-new/schema.js CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.ViewEncapsulation = exports.Style = exports.PackageManager = exports.FileNameStyleGuide = exports.AiConfig = void 0;
6
6
  var AiConfig;
7
7
  (function (AiConfig) {
8
+ AiConfig["Agents"] = "agents";
8
9
  AiConfig["Claude"] = "claude";
9
10
  AiConfig["Copilot"] = "copilot";
10
11
  AiConfig["Cursor"] = "cursor";
@@ -149,7 +149,7 @@
149
149
  "description": "Specifies which AI tools to generate configuration files for. These file are used to improve the outputs of AI tools by following the best practices.",
150
150
  "items": {
151
151
  "type": "string",
152
- "enum": ["none", "gemini", "copilot", "claude", "cursor", "jetbrains", "windsurf"]
152
+ "enum": ["none", "gemini", "copilot", "claude", "cursor", "jetbrains", "windsurf", "agents"]
153
153
  }
154
154
  },
155
155
  "fileNameStyleGuide": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematics/angular",
3
- "version": "21.0.0-next.4",
3
+ "version": "21.0.0-next.6",
4
4
  "description": "Schematics specific to Angular",
5
5
  "homepage": "https://github.com/angular/angular-cli",
6
6
  "keywords": [
@@ -22,15 +22,15 @@
22
22
  },
23
23
  "schematics": "./collection.json",
24
24
  "dependencies": {
25
- "@angular-devkit/core": "21.0.0-next.4",
26
- "@angular-devkit/schematics": "21.0.0-next.4",
25
+ "@angular-devkit/core": "21.0.0-next.6",
26
+ "@angular-devkit/schematics": "21.0.0-next.6",
27
27
  "jsonc-parser": "3.3.1"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
31
31
  "url": "https://github.com/angular/angular-cli.git"
32
32
  },
33
- "packageManager": "pnpm@10.17.0",
33
+ "packageManager": "pnpm@10.17.1",
34
34
  "engines": {
35
35
  "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
36
36
  "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
@@ -48,10 +48,10 @@ app.use((req, res, next) => {
48
48
  });
49
49
 
50
50
  /**
51
- * Start the server if this module is the main entry point.
51
+ * Start the server if this module is the main entry point, or it is ran via PM2.
52
52
  * The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
53
53
  */
54
- if (isMainModule(import.meta.url)) {
54
+ if (isMainModule(import.meta.url) || process.env['pm_id']) {
55
55
  const port = process.env['PORT'] || 4000;
56
56
  app.listen(port, (error) => {
57
57
  if (error) {
@@ -1,5 +1,3 @@
1
- import 'zone.js/node';
2
-
3
1
  import { APP_BASE_HREF } from '@angular/common';
4
2
  import { CommonEngine } from '@angular/ssr/node';
5
3
  import express from 'express';
@@ -8,7 +8,7 @@
8
8
  "@types/node": "^20.17.19",
9
9
  "browser-sync": "^3.0.0",
10
10
  "express": "^5.1.0",
11
- "jasmine-core": "~5.10.0",
11
+ "jasmine-core": "~5.11.0",
12
12
  "jasmine-spec-reporter": "~7.0.0",
13
13
  "karma-chrome-launcher": "~3.2.0",
14
14
  "karma-coverage": "~2.2.0",
@@ -16,7 +16,7 @@ exports.latestVersions = {
16
16
  // As Angular CLI works with same minor versions of Angular Framework, a tilde match for the current
17
17
  Angular: '^21.0.0-next.0',
18
18
  NgPackagr: '^21.0.0-next.0',
19
- DevkitBuildAngular: '^21.0.0-next.4',
20
- AngularBuild: '^21.0.0-next.4',
21
- AngularSSR: '^21.0.0-next.4',
19
+ DevkitBuildAngular: '^21.0.0-next.6',
20
+ AngularBuild: '^21.0.0-next.6',
21
+ AngularSSR: '^21.0.0-next.6',
22
22
  };
@@ -9,3 +9,4 @@ import { SchematicsException } from '@angular-devkit/schematics';
9
9
  import { ProjectDefinition } from './workspace';
10
10
  export declare function targetBuildNotFoundError(): SchematicsException;
11
11
  export declare function isUsingApplicationBuilder(project: ProjectDefinition): boolean;
12
+ export declare function isZonelessApp(project: ProjectDefinition): boolean;
@@ -9,6 +9,7 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.targetBuildNotFoundError = targetBuildNotFoundError;
11
11
  exports.isUsingApplicationBuilder = isUsingApplicationBuilder;
12
+ exports.isZonelessApp = isZonelessApp;
12
13
  const schematics_1 = require("@angular-devkit/schematics");
13
14
  const workspace_models_1 = require("./workspace-models");
14
15
  function targetBuildNotFoundError() {
@@ -19,3 +20,12 @@ function isUsingApplicationBuilder(project) {
19
20
  const isUsingApplicationBuilder = buildBuilder === workspace_models_1.Builders.Application || buildBuilder === workspace_models_1.Builders.BuildApplication;
20
21
  return isUsingApplicationBuilder;
21
22
  }
23
+ function isZonelessApp(project) {
24
+ const buildTarget = project.targets.get('build');
25
+ if (!buildTarget?.options?.polyfills) {
26
+ return true;
27
+ }
28
+ const polyfills = buildTarget.options.polyfills;
29
+ const polyfillsList = Array.isArray(polyfills) ? polyfills : [polyfills];
30
+ return !polyfillsList.includes('zone.js');
31
+ }
@@ -36,6 +36,7 @@ yarn-error.log
36
36
  /libpeerconnection.log
37
37
  testem.log
38
38
  /typings
39
+ __screenshots__/
39
40
 
40
41
  # System files
41
42
  .DS_Store
@@ -21,6 +21,7 @@
21
21
  ]
22
22
  },
23
23
  "private": true,
24
+ <% if (packageManagerWithVersion) { %>"packageManager": "<%= packageManagerWithVersion %>",<% } %>
24
25
  "dependencies": {
25
26
  "@angular/common": "<%= latestVersions.Angular %>",
26
27
  "@angular/compiler": "<%= latestVersions.Angular %>",
@@ -9,15 +9,40 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.default = default_1;
11
11
  const schematics_1 = require("@angular-devkit/schematics");
12
+ const node_child_process_1 = require("node:child_process");
12
13
  const latest_versions_1 = require("../utility/latest-versions");
13
14
  function default_1(options) {
14
- return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
15
- options.minimal ? (0, schematics_1.filter)((path) => !path.endsWith('editorconfig.template')) : (0, schematics_1.noop)(),
16
- (0, schematics_1.applyTemplates)({
17
- utils: schematics_1.strings,
18
- ...options,
19
- 'dot': '.',
20
- latestVersions: latest_versions_1.latestVersions,
21
- }),
22
- ]));
15
+ return () => {
16
+ const packageManager = options.packageManager;
17
+ let packageManagerWithVersion;
18
+ if (packageManager) {
19
+ let packageManagerVersion;
20
+ try {
21
+ packageManagerVersion = (0, node_child_process_1.execSync)(`${packageManager} --version`, {
22
+ encoding: 'utf8',
23
+ stdio: 'pipe',
24
+ env: {
25
+ ...process.env,
26
+ // NPM updater notifier will prevents the child process from closing until it timeout after 3 minutes.
27
+ NO_UPDATE_NOTIFIER: '1',
28
+ NPM_CONFIG_UPDATE_NOTIFIER: 'false',
29
+ },
30
+ }).trim();
31
+ }
32
+ catch { }
33
+ if (packageManagerVersion) {
34
+ packageManagerWithVersion = `${packageManager}@${packageManagerVersion}`;
35
+ }
36
+ }
37
+ return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./files'), [
38
+ options.minimal ? (0, schematics_1.filter)((path) => !path.endsWith('editorconfig.template')) : (0, schematics_1.noop)(),
39
+ (0, schematics_1.applyTemplates)({
40
+ utils: schematics_1.strings,
41
+ ...options,
42
+ 'dot': '.',
43
+ latestVersions: latest_versions_1.latestVersions,
44
+ packageManagerWithVersion,
45
+ }),
46
+ ]));
47
+ };
23
48
  }
@@ -40,7 +40,10 @@
40
40
  "packageManager": {
41
41
  "description": "The package manager to use for installing dependencies.",
42
42
  "type": "string",
43
- "enum": ["npm", "yarn", "pnpm", "bun"]
43
+ "enum": ["npm", "yarn", "pnpm", "bun"],
44
+ "$default": {
45
+ "$source": "packageManager"
46
+ }
44
47
  }
45
48
  },
46
49
  "required": ["name", "version"]