From 1e6a4f8e65e2f621f77dab4db392b6680a11aa55 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Fri, 17 Feb 2023 20:44:10 +0000 Subject: [PATCH] feat(angular): prompt users for standalone components in application (#14987) --- .../angular/generators/application.json | 2 +- e2e/angular-core/src/angular-linting.test.ts | 12 +++-- e2e/angular-extensions/src/misc.test.ts | 6 +-- packages/angular/ng-package.json | 3 +- packages/angular/package.json | 3 +- .../application/application.spec.ts | 50 ++++++++++++++++++- .../src/generators/application/application.ts | 15 +++++- .../src/generators/application/schema.json | 2 +- packages/angular/src/generators/host/host.ts | 1 + .../angular/src/generators/remote/remote.ts | 1 + 10 files changed, 83 insertions(+), 12 deletions(-) diff --git a/docs/generated/packages/angular/generators/application.json b/docs/generated/packages/angular/generators/application.json index 63896891c6c7f..deee6493f34fe 100644 --- a/docs/generated/packages/angular/generators/application.json +++ b/docs/generated/packages/angular/generators/application.json @@ -148,7 +148,7 @@ "standalone": { "description": "Generate an application that is setup to use standalone components. _Note: This is only supported in Angular versions >= 14.1.0_", "type": "boolean", - "default": false + "x-priority": "important" }, "rootProject": { "description": "Create an application at the root of the workspace.", diff --git a/e2e/angular-core/src/angular-linting.test.ts b/e2e/angular-core/src/angular-linting.test.ts index 8d4f1034d7737..4e91baf76a568 100644 --- a/e2e/angular-core/src/angular-linting.test.ts +++ b/e2e/angular-core/src/angular-linting.test.ts @@ -14,18 +14,24 @@ describe('Angular Package', () => { it('should support eslint and pass linting on the standard generated code', async () => { const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --linter=eslint`); + runCLI( + `generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive` + ); expect(runCLI(`lint ${myapp}`)).toContain('All files pass linting.'); const mylib = uniq('mylib'); - runCLI(`generate @nrwl/angular:lib ${mylib} --linter=eslint`); + runCLI( + `generate @nrwl/angular:lib ${mylib} --linter=eslint --no-interactive` + ); expect(runCLI(`lint ${mylib}`)).toContain('All files pass linting.'); }); it('should support eslint and successfully lint external HTML files and inline templates', async () => { const myapp = uniq('myapp'); - runCLI(`generate @nrwl/angular:app ${myapp} --linter=eslint`); + runCLI( + `generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive` + ); const templateWhichFailsBananaInBoxLintCheck = `
`; const wrappedAsInlineTemplate = ` diff --git a/e2e/angular-extensions/src/misc.test.ts b/e2e/angular-extensions/src/misc.test.ts index 6aa2599cdbf1a..e02c618b8edcc 100644 --- a/e2e/angular-extensions/src/misc.test.ts +++ b/e2e/angular-extensions/src/misc.test.ts @@ -20,7 +20,7 @@ describe('Move Angular Project', () => { app1 = uniq('app1'); app2 = uniq('app2'); newPath = `subfolder/${app2}`; - runCLI(`generate @nrwl/angular:app ${app1}`); + runCLI(`generate @nrwl/angular:app ${app1} --no-interactive`); }); afterAll(() => cleanupProject()); @@ -99,13 +99,13 @@ describe('Move Angular Project', () => { it('should work for libraries', () => { const lib1 = uniq('mylib'); const lib2 = uniq('mylib'); - runCLI(`generate @nrwl/angular:lib ${lib1}`); + runCLI(`generate @nrwl/angular:lib ${lib1} --no-interactive`); /** * Create a library which imports the module from the other lib */ - runCLI(`generate @nrwl/angular:lib ${lib2}`); + runCLI(`generate @nrwl/angular:lib ${lib2} --no-interactive`); updateFile( `libs/${lib2}/src/lib/${lib2}.module.ts`, diff --git a/packages/angular/ng-package.json b/packages/angular/ng-package.json index 1437718a040a8..bb8fbc5f547e6 100644 --- a/packages/angular/ng-package.json +++ b/packages/angular/ng-package.json @@ -22,7 +22,8 @@ "semver", "webpack", "http-server", - "magic-string" + "magic-string", + "enquirer" ], "keepLifecycleScripts": true } diff --git a/packages/angular/package.json b/packages/angular/package.json index 11bb92bf7965a..7976ee6249efb 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -54,7 +54,8 @@ "ts-node": "10.9.1", "tsconfig-paths": "^4.1.2", "webpack": "^5.75.0", - "webpack-merge": "5.7.3" + "webpack-merge": "5.7.3", + "enquirer": "^2.3.6" }, "peerDependencies": { "@angular-devkit/build-angular": ">= 14.0.0 < 16.0.0", diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts index c2a1f2a3873b8..1cd1107b167c6 100644 --- a/packages/angular/src/generators/application/application.spec.ts +++ b/packages/angular/src/generators/application/application.spec.ts @@ -20,17 +20,23 @@ import { } from '../../utils/versions'; import { applicationGenerator } from './application'; import type { Schema } from './schema'; - +import * as enquirer from 'enquirer'; // need to mock cypress otherwise it'll use the nx installed version from package.json // which is v9 while we are testing for the new v10 version jest.mock('@nrwl/cypress/src/utils/cypress-version'); +jest.mock('enquirer'); describe('app', () => { let appTree: Tree; let mockedInstalledCypressVersion: jest.Mock< ReturnType > = installedCypressVersion as never; + beforeEach(() => { mockedInstalledCypressVersion.mockReturnValue(10); + // @ts-ignore + enquirer.prompt = jest + .fn() + .mockReturnValue(Promise.resolve({ 'standalone-components': true })); appTree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); }); @@ -819,6 +825,48 @@ describe('app', () => { appTree.read('apps/standalone/src/app/nx-welcome.component.ts', 'utf-8') ).toContain('standalone: true'); }); + + it('should prompt for standalone components and not use them when the user selects false', async () => { + // ARRANGE + process.env.NX_INTERACTIVE = 'true'; + // @ts-ignore + enquirer.prompt = jest + .fn() + .mockReturnValue(Promise.resolve({ 'standalone-components': false })); + + // ACT + await generateApp(appTree, 'nostandalone'); + + // ASSERT + expect( + appTree.exists('apps/nostandalone/src/app/app.module.ts') + ).toBeTruthy(); + expect(enquirer.prompt).toHaveBeenCalled(); + + // CLEANUP + process.env.NX_INTERACTIVE = undefined; + }); + + it('should prompt for standalone components and use them when the user selects true', async () => { + // ARRANGE + process.env.NX_INTERACTIVE = 'true'; + // @ts-ignore + enquirer.prompt = jest + .fn() + .mockReturnValue(Promise.resolve({ 'standalone-components': true })); + + // ACT + await generateApp(appTree, 'nostandalone'); + + // ASSERT + expect( + appTree.exists('apps/nostandalone/src/app/app.module.ts') + ).not.toBeTruthy(); + expect(enquirer.prompt).toHaveBeenCalled(); + + // CLEANUP + process.env.NX_INTERACTIVE = undefined; + }); }); it('should generate correct main.ts', async () => { diff --git a/packages/angular/src/generators/application/application.ts b/packages/angular/src/generators/application/application.ts index 1b25e792ffa6c..d167e40741b22 100644 --- a/packages/angular/src/generators/application/application.ts +++ b/packages/angular/src/generators/application/application.ts @@ -34,7 +34,8 @@ import { updateNxComponentTemplate, } from './lib'; import type { Schema } from './schema'; -import { lt } from 'semver'; +import { gte, lt } from 'semver'; +import { prompt } from 'enquirer'; export async function applicationGenerator( tree: Tree, @@ -47,6 +48,18 @@ export async function applicationGenerator( You can resolve this error by removing the "standalone" option or by migrating to Angular 14.1.0.`); } + if ( + gte(installedAngularVersionInfo.version, '14.1.0') && + schema.standalone === undefined && + process.env.NX_INTERACTIVE === 'true' + ) { + schema.standalone = await prompt({ + name: 'standalone-components', + message: 'Would you like to use Standalone Components?', + type: 'confirm', + }).then((a) => a['standalone-components']); + } + const generatorDirectory = getGeneratorDirectoryForInstalledAngularVersion(tree); if (generatorDirectory) { diff --git a/packages/angular/src/generators/application/schema.json b/packages/angular/src/generators/application/schema.json index 26bf421988762..75ea15600632d 100644 --- a/packages/angular/src/generators/application/schema.json +++ b/packages/angular/src/generators/application/schema.json @@ -151,7 +151,7 @@ "standalone": { "description": "Generate an application that is setup to use standalone components. _Note: This is only supported in Angular versions >= 14.1.0_", "type": "boolean", - "default": false + "x-priority": "important" }, "rootProject": { "description": "Create an application at the root of the workspace.", diff --git a/packages/angular/src/generators/host/host.ts b/packages/angular/src/generators/host/host.ts index 4de32f3f3414c..020339ce4fc03 100644 --- a/packages/angular/src/generators/host/host.ts +++ b/packages/angular/src/generators/host/host.ts @@ -37,6 +37,7 @@ export async function host(tree: Tree, options: Schema) { const appInstallTask = await applicationGenerator(tree, { ...options, + standalone: options.standalone ?? false, routing: true, port: 4200, skipFormat: true, diff --git a/packages/angular/src/generators/remote/remote.ts b/packages/angular/src/generators/remote/remote.ts index e9eb917548d7c..e219187ecf37e 100644 --- a/packages/angular/src/generators/remote/remote.ts +++ b/packages/angular/src/generators/remote/remote.ts @@ -29,6 +29,7 @@ export async function remote(tree: Tree, options: Schema) { const appInstallTask = await applicationGenerator(tree, { ...options, + standalone: options.standalone ?? false, routing: true, port, });