diff --git a/docs/angular/api-angular/schematics/application.md b/docs/angular/api-angular/schematics/application.md index 57ad312d7d..21d84d5a9e 100644 --- a/docs/angular/api-angular/schematics/application.md +++ b/docs/angular/api-angular/schematics/application.md @@ -136,6 +136,14 @@ Type: `boolean` Skip creating spec files. +### strict + +Default: `false` + +Type: `boolean` + +Creates an application with stricter type checking and build optimization options. + ### style Default: `css` diff --git a/docs/angular/api-angular/schematics/library.md b/docs/angular/api-angular/schematics/library.md index eb001908ec..2bef93086b 100644 --- a/docs/angular/api-angular/schematics/library.md +++ b/docs/angular/api-angular/schematics/library.md @@ -142,6 +142,14 @@ Type: `boolean` Do not update tsconfig.json for development experience. +### strict + +Default: `false` + +Type: `boolean` + +Creates a library with stricter type checking and build optimization options. + ### style Default: `css` diff --git a/docs/react/api-angular/schematics/application.md b/docs/react/api-angular/schematics/application.md index 0dcfebbb28..a895bddf45 100644 --- a/docs/react/api-angular/schematics/application.md +++ b/docs/react/api-angular/schematics/application.md @@ -136,6 +136,14 @@ Type: `boolean` Skip creating spec files. +### strict + +Default: `false` + +Type: `boolean` + +Creates an application with stricter type checking and build optimization options. + ### style Default: `css` diff --git a/docs/react/api-angular/schematics/library.md b/docs/react/api-angular/schematics/library.md index 20a6919587..fb756b7a75 100644 --- a/docs/react/api-angular/schematics/library.md +++ b/docs/react/api-angular/schematics/library.md @@ -142,6 +142,14 @@ Type: `boolean` Do not update tsconfig.json for development experience. +### strict + +Default: `false` + +Type: `boolean` + +Creates a library with stricter type checking and build optimization options. + ### style Default: `css` diff --git a/packages/angular/src/schematics/application/application.spec.ts b/packages/angular/src/schematics/application/application.spec.ts index 8391de6821..d3dceb14dc 100644 --- a/packages/angular/src/schematics/application/application.spec.ts +++ b/packages/angular/src/schematics/application/application.spec.ts @@ -556,4 +556,43 @@ describe('app', () => { ); }); }); + + describe('--strict', () => { + it('should enable strict type checking', async () => { + const tree = await runSchematic( + 'app', + { name: 'my-app', strict: true }, + appTree + ); + + // define all the tsconfig files to update + const configFiles = [ + 'apps/my-app/tsconfig.json', + 'apps/my-app-e2e/tsconfig.e2e.json', + ]; + + for (const configFile of configFiles) { + const { compilerOptions, angularCompilerOptions } = JSON.parse( + tree.readContent(configFile) + ); + + // check that the TypeScript compiler options have been updated + expect(compilerOptions.forceConsistentCasingInFileNames).toBe(true); + expect(compilerOptions.strict).toBe(true); + expect(compilerOptions.noImplicitReturns).toBe(true); + expect(compilerOptions.noFallthroughCasesInSwitch).toBe(true); + + // check that the Angular Template options have been updated + expect(angularCompilerOptions.strictInjectionParameters).toBe(true); + expect(angularCompilerOptions.strictTemplates).toBe(true); + } + + // check to see if the workspace configuration has been updated to use strict + // mode by default in future applications + const workspaceJson = readJsonInTree(tree, 'workspace.json'); + expect(workspaceJson.schematics['@nrwl/angular:application'].strict).toBe( + true + ); + }); + }); }); diff --git a/packages/angular/src/schematics/application/application.ts b/packages/angular/src/schematics/application/application.ts index 1261cf6b29..81a5634369 100644 --- a/packages/angular/src/schematics/application/application.ts +++ b/packages/angular/src/schematics/application/application.ts @@ -680,6 +680,66 @@ function addProxyConfig(options: NormalizedSchema): Rule { }; } +function enableStrictTypeChecking(schema: Schema): Rule { + return (host) => { + const options = normalizeOptions(host, schema); + + // define all the tsconfig files to update + const configFiles = [ + `${options.appProjectRoot}/tsconfig.json`, + `${options.e2eProjectRoot}/tsconfig.e2e.json`, + ]; + + const rules: Rule[] = []; + + // iterate each config file, if it exists then update it + for (const configFile of configFiles) { + if (!host.exists(configFile)) { + continue; + } + + // Update the settings in the tsconfig.app.json to enable strict type checking. + // This matches the settings defined by the Angular CLI https://angular.io/guide/strict-mode + const rule = updateJsonInTree(configFile, (json) => { + // update the TypeScript settings + json.compilerOptions = { + ...(json.compilerOptions ?? {}), + forceConsistentCasingInFileNames: true, + strict: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, + }; + + // update Angular Template Settings + json.angularCompilerOptions = { + ...(json.angularCompilerOptions ?? {}), + strictInjectionParameters: true, + strictTemplates: true, + }; + + return json; + }); + + rules.push(rule); + } + + // set the default so future applications will default to strict mode + // unless the user has previously set this to false by default + const updateAngularWorkspace = updateWorkspace((workspace) => { + workspace.extensions.schematics = workspace.extensions.schematics || {}; + + workspace.extensions.schematics['@nrwl/angular:application'] = + workspace.extensions.schematics['@nrwl/angular:application'] || {}; + + workspace.extensions.schematics['@nrwl/angular:application'].strict = + workspace.extensions.schematics['@nrwl/angular:application'].strict ?? + options.strict; + }); + + return chain([...rules, updateAngularWorkspace]); + }; +} + export default function (schema: Schema): Rule { return (host: Tree, context: SchematicContext) => { const options = normalizeOptions(host, schema); @@ -762,6 +822,7 @@ export default function (schema: Schema): Rule { }) : noop(), options.backendProject ? addProxyConfig(options) : noop(), + options.strict ? enableStrictTypeChecking(options) : noop(), formatFiles(options), ])(host, context); }; diff --git a/packages/angular/src/schematics/application/schema.d.ts b/packages/angular/src/schematics/application/schema.d.ts index bab4a0ba2a..659d471e40 100644 --- a/packages/angular/src/schematics/application/schema.d.ts +++ b/packages/angular/src/schematics/application/schema.d.ts @@ -19,4 +19,5 @@ export interface Schema { unitTestRunner: UnitTestRunner; e2eTestRunner: E2eTestRunner; backendProject?: string; + strict?: boolean; } diff --git a/packages/angular/src/schematics/application/schema.json b/packages/angular/src/schematics/application/schema.json index 9936be5880..4322480d9f 100644 --- a/packages/angular/src/schematics/application/schema.json +++ b/packages/angular/src/schematics/application/schema.json @@ -120,6 +120,11 @@ "backendProject": { "type": "string", "description": "Backend project that provides data to this application. This sets up proxy.config.json." + }, + "strict": { + "type": "boolean", + "description": "Creates an application with stricter type checking and build optimization options.", + "default": false } }, "required": [] diff --git a/packages/angular/src/schematics/library/lib/enable-strict-type-checking.ts b/packages/angular/src/schematics/library/lib/enable-strict-type-checking.ts new file mode 100644 index 0000000000..72eedbef7e --- /dev/null +++ b/packages/angular/src/schematics/library/lib/enable-strict-type-checking.ts @@ -0,0 +1,50 @@ +import { NormalizedSchema } from './normalized-schema'; +import { chain, Rule } from '@angular-devkit/schematics'; +import { updateJsonInTree, updateWorkspace } from '@nrwl/workspace'; + +/** + * Enable Strict Mode in the library and spec TS Config + * */ +export function enableStrictTypeChecking(options: NormalizedSchema): Rule { + return () => chain([updateTsConfig(options), updateAngularWorkspace()]); +} + +function updateTsConfig(options: NormalizedSchema): Rule { + return () => { + // Update the settings in the tsconfig.app.json to enable strict type checking. + // This matches the settings defined by the Angular CLI https://angular.io/guide/strict-mode + return updateJsonInTree(`${options.projectRoot}/tsconfig.json`, (json) => { + // update the TypeScript settings + json.compilerOptions = { + ...(json.compilerOptions ?? {}), + forceConsistentCasingInFileNames: true, + strict: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, + }; + + // update Angular Template Settings + json.angularCompilerOptions = { + ...(json.angularCompilerOptions ?? {}), + strictInjectionParameters: true, + strictTemplates: true, + }; + + return json; + }); + }; +} + +function updateAngularWorkspace(): Rule { + // set the default so future libraries will default to strict mode + // unless the user has previously set this to false by default + return updateWorkspace((workspace) => { + workspace.extensions.schematics = workspace.extensions.schematics || {}; + + workspace.extensions.schematics['@nrwl/angular:library'] = + workspace.extensions.schematics['@nrwl/angular:library'] || {}; + + workspace.extensions.schematics['@nrwl/angular:library'].strict = + workspace.extensions.schematics['@nrwl/angular:library'].strict ?? true; + }); +} diff --git a/packages/angular/src/schematics/library/library.spec.ts b/packages/angular/src/schematics/library/library.spec.ts index 52c6c772fc..f774b85355 100644 --- a/packages/angular/src/schematics/library/library.spec.ts +++ b/packages/angular/src/schematics/library/library.spec.ts @@ -1149,4 +1149,41 @@ describe('lib', () => { expect.assertions(1); }); }); + + describe('--strict', () => { + it('should enable strict type checking', async () => { + const tree = await runSchematic( + 'lib', + { + name: 'myLib', + framework: 'angular', + publishable: true, + importPath: '@myorg/lib', + strict: true, + }, + appTree + ); + + const { compilerOptions, angularCompilerOptions } = JSON.parse( + tree.readContent('libs/my-lib/tsconfig.json') + ); + + // check that the TypeScript compiler options have been updated + expect(compilerOptions.forceConsistentCasingInFileNames).toBe(true); + expect(compilerOptions.strict).toBe(true); + expect(compilerOptions.noImplicitReturns).toBe(true); + expect(compilerOptions.noFallthroughCasesInSwitch).toBe(true); + + // check that the Angular Template options have been updated + expect(angularCompilerOptions.strictInjectionParameters).toBe(true); + expect(angularCompilerOptions.strictTemplates).toBe(true); + + // check to see if the workspace configuration has been updated to use strict + // mode by default in future applications + const workspaceJson = readJsonInTree(tree, 'workspace.json'); + expect(workspaceJson.schematics['@nrwl/angular:library'].strict).toBe( + true + ); + }); + }); }); diff --git a/packages/angular/src/schematics/library/library.ts b/packages/angular/src/schematics/library/library.ts index 146f2d856e..09dee1d544 100644 --- a/packages/angular/src/schematics/library/library.ts +++ b/packages/angular/src/schematics/library/library.ts @@ -21,6 +21,7 @@ import { updateLibPackageNpmScope } from './lib/update-lib-package-npm-scope'; import { updateProject } from './lib/update-project'; import { updateTsConfig } from './lib/update-tsconfig'; import { Schema } from './schema'; +import { enableStrictTypeChecking } from './lib/enable-strict-type-checking'; export default function (schema: Schema): Rule { return (host: Tree): Rule => { @@ -79,6 +80,7 @@ export default function (schema: Schema): Rule { ? updateLibPackageNpmScope(options) : noop(), addModule(options), + options.strict ? enableStrictTypeChecking(options) : noop(), formatFiles(options), ]); }; diff --git a/packages/angular/src/schematics/library/schema.d.ts b/packages/angular/src/schematics/library/schema.d.ts index 986c27e4a1..b778f7adc5 100644 --- a/packages/angular/src/schematics/library/schema.d.ts +++ b/packages/angular/src/schematics/library/schema.d.ts @@ -22,6 +22,7 @@ export interface Schema { lazy?: boolean; parentModule?: string; tags?: string; + strict?: boolean; linter: Linter; unitTestRunner: UnitTestRunner; diff --git a/packages/angular/src/schematics/library/schema.json b/packages/angular/src/schematics/library/schema.json index ed3e96c3ed..b1123d71ee 100644 --- a/packages/angular/src/schematics/library/schema.json +++ b/packages/angular/src/schematics/library/schema.json @@ -114,6 +114,11 @@ "type": "string", "description": "The library name used to import it, like @myorg/my-awesome-lib. Must be a valid npm name." }, + "strict": { + "type": "boolean", + "description": "Creates a library with stricter type checking and build optimization options.", + "default": false + }, "linter": { "description": "The tool to use for running lint checks.", "type": "string",