feat(angular): add an option to add strict type checking (#3465)
* feat(angular): add an option to add strict type checking Adding support for strict type checking to Angular application and library generate schematics. E.g. `nx generate application myapp --strict` `nx generate lib mylib --strict` Closes #3383. Performs the following configuration changes: - Enables strict mode in TypeScript, as well as other strictness flags recommended by the TypeScript team. Specifically, forceConsistentCasingInFileNames, noImplicitReturns, noFallthroughCasesInSwitch. - Turns on strict Angular compiler flags strictTemplates and strictInjectionParameters These match the flags used in the standard CLI strict mode. * cleanup(misc): updating import path Co-authored-by: Ashley Hunter <ashley.hunter@hotmail.co.uk>
This commit is contained in:
parent
86b4f4e7b8
commit
10911e25c2
@ -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`
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -19,4 +19,5 @@ export interface Schema {
|
||||
unitTestRunner: UnitTestRunner;
|
||||
e2eTestRunner: E2eTestRunner;
|
||||
backendProject?: string;
|
||||
strict?: boolean;
|
||||
}
|
||||
|
||||
@ -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": []
|
||||
|
||||
@ -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;
|
||||
});
|
||||
}
|
||||
@ -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
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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),
|
||||
]);
|
||||
};
|
||||
|
||||
@ -22,6 +22,7 @@ export interface Schema {
|
||||
lazy?: boolean;
|
||||
parentModule?: string;
|
||||
tags?: string;
|
||||
strict?: boolean;
|
||||
|
||||
linter: Linter;
|
||||
unitTestRunner: UnitTestRunner;
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user