Skip to content

Commit 85ded36

Browse files
committed
Improve strict null checks compliance
1 parent a6249b8 commit 85ded36

File tree

10 files changed

+60
-30
lines changed

10 files changed

+60
-30
lines changed

src/lib/schematics/install/fonts/head-element.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export function appendElementToHead(host: Tree, project: WorkspaceProject, eleme
3333
throw `Could not find '<head>' element in HTML file: ${indexPath}`;
3434
}
3535

36+
// We always have access to the source code location here because the `getHeadTagElement`
37+
// function explicitly has the `sourceCodeLocationInfo` option enabled.
3638
const endTagOffset = headTag.sourceCodeLocation!.endTag.startOffset;
3739
const indentationOffset = getChildElementIndentation(headTag);
3840
const insertion = `${' '.repeat(indentationOffset)}${elementHtml}`;

src/lib/schematics/install/fonts/project-index-html.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88

99
import {SchematicsException} from '@angular-devkit/schematics';
1010
import {WorkspaceProject} from '@schematics/angular/utility/config';
11+
import {getArchitectOptions} from '../../utils/architect-options';
1112

1213
/** Looks for the index HTML file in the given project and returns its path. */
1314
export function getIndexHtmlPath(project: WorkspaceProject): string {
14-
const buildTarget = project.architect!.build.options;
15+
const buildOptions = getArchitectOptions(project, 'build');
1516

16-
if (buildTarget.index && buildTarget.index.endsWith('index.html')) {
17-
return buildTarget.index;
17+
if (!buildOptions.index) {
18+
throw new SchematicsException('No project "index.html" file could be found.');
1819
}
1920

20-
throw new SchematicsException('No project "index.html" file could be found.');
21+
return buildOptions.index;
2122
}

src/lib/schematics/install/gestures/hammerjs-import.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {Rule, Tree} from '@angular-devkit/schematics';
1010
import {getWorkspace} from '@schematics/angular/utility/config';
1111
import {getProjectFromWorkspace} from '../../utils/get-project';
1212
import {Schema} from '../schema';
13-
import {getProjectMainFile} from './project-main-file';
13+
import {getProjectMainFile} from '../../utils/project-main-file';
1414

1515
const hammerjsImportStatement = `import 'hammerjs';`;
1616

src/lib/schematics/install/theming/theming.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ function insertCustomTheme(project: WorkspaceProject, projectName: string, host:
5959
const customThemePath = normalize(join(project.sourceRoot, 'custom-theme.scss'));
6060

6161
host.create(customThemePath, themeContent);
62-
addStyleToTarget(project.architect!['build'], host, customThemePath, workspace);
63-
return;
62+
63+
// Architect is always defined because we initially asserted if the default builder
64+
// configuration is set up or not.
65+
return addStyleToTarget(project.architect!['build'], host, customThemePath, workspace);
6466
}
6567

6668
const insertion = new InsertChange(stylesPath, 0, themeContent);
@@ -77,12 +79,10 @@ function insertPrebuiltTheme(project: WorkspaceProject, host: Tree, theme: strin
7779
// Path needs to be always relative to the `package.json` or workspace root.
7880
const themePath = `./node_modules/@angular/material/prebuilt-themes/${theme}.css`;
7981

80-
if (project.architect) {
81-
addStyleToTarget(project.architect['build'], host, themePath, workspace);
82-
addStyleToTarget(project.architect['test'], host, themePath, workspace);
83-
} else {
84-
throw new SchematicsException(`${projectName} does not have an architect configuration`);
85-
}
82+
// Architect is always defined because we initially asserted if the default builder
83+
// configuration is set up or not.
84+
addStyleToTarget(project.architect!['build'], host, themePath, workspace);
85+
addStyleToTarget(project.architect!['test'], host, themePath, workspace);
8686
}
8787

8888
/** Adds a style entry to the given target. */

src/lib/schematics/update/rules/signature-check/constructorSignatureCheckRule.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export class Walker extends ProgramAwareRuleWalker {
4040
return signature.getParameters()
4141
.map(param => param.declarations[0] as ts.ParameterDeclaration)
4242
.map(node => node.type)
43-
.map(node => this.getTypeChecker().getTypeFromTypeNode(node));
43+
// TODO(devversion): handle non resolvable constructor types
44+
.map(typeNode => this.getTypeChecker().getTypeFromTypeNode(typeNode!));
4445
}
4546

4647
private checkExpressionSignature(node: ts.CallExpression | ts.NewExpression) {
@@ -50,7 +51,7 @@ export class Walker extends ProgramAwareRuleWalker {
5051

5152
// TODO(devversion): Consider handling pass-through classes better.
5253
// TODO(devversion): e.g. `export class CustomCalendar extends MatCalendar {}`
53-
if (!classType || !constructorChecks.includes(className)) {
54+
if (!classType || !constructorChecks.includes(className) || !node.arguments) {
5455
return;
5556
}
5657

@@ -62,6 +63,8 @@ export class Walker extends ProgramAwareRuleWalker {
6263
// TODO(devversion): we should check if the type is assignable to the signature
6364
// TODO(devversion): blocked on https://github.com/Microsoft/TypeScript/issues/9879
6465
const doesMatchSignature = classSignatures.some(signature => {
66+
// TODO(devversion): better handling if signature item type is unresolved but assignable
67+
// to everything.
6568
return signature.every((type, index) => callExpressionSignature[index] === type) &&
6669
signature.length === callExpressionSignature.length;
6770
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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.io/license
7+
*/
8+
9+
import {WorkspaceProject} from '@schematics/angular/utility/config';
10+
11+
/** Resolves the architect options for the build target of the given project. */
12+
export function getArchitectOptions(project: WorkspaceProject, buildTarget: string) {
13+
if (project.architect &&
14+
project.architect[buildTarget] &&
15+
project.architect[buildTarget].options) {
16+
17+
return project.architect[buildTarget].options;
18+
}
19+
20+
throw new Error(`Cannot determine architect configuration for target: ${buildTarget}.`);
21+
}

src/lib/schematics/utils/ast.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
*/
88

99
import {SchematicsException, Tree} from '@angular-devkit/schematics';
10+
import {Schema as ComponentOptions} from '@schematics/angular/component/schema';
1011
import {addImportToModule} from '@schematics/angular/utility/ast-utils';
1112
import {InsertChange} from '@schematics/angular/utility/change';
1213
import {getWorkspace, WorkspaceProject} from '@schematics/angular/utility/config';
1314
import {findModuleFromOptions as internalFindModule} from '@schematics/angular/utility/find-module';
1415
import {getAppModulePath} from '@schematics/angular/utility/ng-ast-utils';
15-
import {Schema as ComponentOptions} from '@schematics/angular/component/schema';
1616
import * as ts from 'typescript';
17+
import {getProjectMainFile} from './project-main-file';
1718

1819

1920
/** Reads file given path and returns TypeScript source file. */
@@ -29,8 +30,7 @@ export function getSourceFile(host: Tree, path: string): ts.SourceFile {
2930
/** Import and add module to root app module. */
3031
export function addModuleImportToRootModule(host: Tree, moduleName: string, src: string,
3132
project: WorkspaceProject) {
32-
33-
const modulePath = getAppModulePath(host, project.architect!.build.options.main);
33+
const modulePath = getAppModulePath(host, getProjectMainFile(project));
3434
addModuleImportToModule(host, modulePath, moduleName, src);
3535
}
3636

src/lib/schematics/utils/parse5-element.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ export function getChildElementIndentation(element: DefaultTreeElement) {
1313
const childElement = element.childNodes
1414
.find(node => node['tagName']) as DefaultTreeElement | null;
1515

16+
if ((childElement && !childElement.sourceCodeLocation) || !element.sourceCodeLocation) {
17+
throw new Error('Cannot determine child element indentation because the specified Parse5 ' +
18+
'element does not have any source code location metadata.');
19+
}
20+
1621
const startColumns = childElement ?
1722
// In case there are child elements inside of the element, we assume that their
1823
// indentation is also applicable for other child elements.

src/lib/schematics/install/gestures/project-main-file.ts renamed to src/lib/schematics/utils/project-main-file.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88

99
import {SchematicsException} from '@angular-devkit/schematics';
1010
import {WorkspaceProject} from '@schematics/angular/utility/config';
11+
import {getArchitectOptions} from './architect-options';
1112

1213
/** Looks for the main TypeScript file in the given project and returns its path. */
1314
export function getProjectMainFile(project: WorkspaceProject): string {
14-
const buildTarget = project.architect!.build.options;
15+
const buildOptions = getArchitectOptions(project, 'build');
1516

16-
if (buildTarget.main) {
17-
return buildTarget.main;
17+
if (!buildOptions.main) {
18+
throw new SchematicsException(`Could not find the project main file inside of the ` +
19+
`workspace config (${project.sourceRoot})`);
1820
}
1921

20-
throw new SchematicsException(
21-
'Could not find the project main file inside of the workspace config.');
22+
return buildOptions.main;
2223
}

src/lib/schematics/utils/project-style-file.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {normalize} from '@angular-devkit/core';
1010
import {WorkspaceProject} from '@schematics/angular/utility/config';
11+
import {getArchitectOptions} from './architect-options';
1112

1213
/** Regular expression that matches all possible Angular CLI default style files. */
1314
const defaultStyleFileRegex = /styles\.(c|le|sc)ss/;
@@ -20,14 +21,10 @@ const validStyleFileRegex = /\.(c|le|sc)ss/;
2021
* extension is specified, any style file with a valid extension will be returned.
2122
*/
2223
export function getProjectStyleFile(project: WorkspaceProject, extension?: string): string | null {
23-
if (!project.architect || !project.architect['build']) {
24-
return null;
25-
}
26-
27-
const target = project.architect['build'];
24+
const buildOptions = getArchitectOptions(project, 'build');
2825

29-
if (target.options && target.options.styles && target.options.styles.length) {
30-
const styles = target.options.styles.map(s => typeof s === 'string' ? s : s.input);
26+
if (buildOptions.styles && buildOptions.styles.length) {
27+
const styles = buildOptions.styles.map(s => typeof s === 'string' ? s : s.input);
3128

3229
// Look for the default style file that is generated for new projects by the Angular CLI. This
3330
// default style file is usually called `styles.ext` unless it has been changed explicitly.

0 commit comments

Comments
 (0)