Skip to content

Commit b40e074

Browse files
committed
feat(migrations): Disabling nullishCoalescingNotNullable & optionalChainNotNullable on ng update
Related to angular#67959 disabling two diagnostics errors by `ng update`: - nullishCoalescingNotNullable - optionalChainNotNullable
1 parent a89b565 commit b40e074

5 files changed

Lines changed: 231 additions & 0 deletions

File tree

packages/core/schematics/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ bundle_entrypoints = [
137137
"incremental-hydration",
138138
"packages/core/schematics/migrations/incremental-hydration/index.js",
139139
],
140+
[
141+
"strict-safe-navigation-narrow",
142+
"packages/core/schematics/migrations/strict-safe-navigation-narrow/index.js",
143+
],
140144
]
141145

142146
rollup.rollup(
@@ -152,6 +156,7 @@ rollup.rollup(
152156
"//packages/core/schematics/migrations/change-detection-eager",
153157
"//packages/core/schematics/migrations/http-xhr-backend",
154158
"//packages/core/schematics/migrations/incremental-hydration",
159+
"//packages/core/schematics/migrations/strict-safe-navigation-narrow",
155160
"//packages/core/schematics/migrations/strict-templates-default",
156161
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
157162
"//packages/core/schematics/ng-generate/common-to-standalone-migration",

packages/core/schematics/migrations.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
"version": "22.0.0",
2525
"description": "Adds withNoIncrementalHydration() opt out to provideClientHydration() when incremental hydration is not enabled to retain pre-v22 behavior-.",
2626
"factory": "./bundles/incremental-hydration.cjs#migrate"
27+
},
28+
"strict-safe-navigation-narrow": {
29+
"version": "22.0.0",
30+
"description": "Disables the 'nullishCoalescingNotNullable & optionalChainNotNullable extended diagnostics.",
31+
"factory": "./bundles/strict-safe-navigation-narrow.cjs#migrate"
2732
}
2833
}
2934
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
load("//tools:defaults.bzl", "jasmine_test", "ts_project")
2+
3+
package(
4+
default_visibility = [
5+
"//packages/core/schematics:__pkg__",
6+
"//packages/core/schematics/test:__pkg__",
7+
],
8+
)
9+
10+
ts_project(
11+
name = "strict-safe-navigation-narrow",
12+
srcs = glob(
13+
["**/*.ts"],
14+
exclude = ["*.spec.ts"],
15+
),
16+
deps = [
17+
"//:node_modules/@angular-devkit/core",
18+
"//:node_modules/@angular-devkit/schematics",
19+
"//:node_modules/@schematics/angular",
20+
"//packages/core/schematics/utils",
21+
],
22+
)
23+
24+
ts_project(
25+
name = "test_lib",
26+
testonly = True,
27+
srcs = glob(["*.spec.ts"]),
28+
deps = [
29+
":strict-safe-navigation-narrow",
30+
"//:node_modules/@angular-devkit/core",
31+
"//:node_modules/@angular-devkit/schematics",
32+
"//:node_modules/@schematics/angular",
33+
"//packages/core/schematics/utils",
34+
],
35+
)
36+
37+
jasmine_test(
38+
name = "test",
39+
data = [":test_lib"],
40+
)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
9+
import {Rule, Tree} from '@angular-devkit/schematics';
10+
import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
11+
import {JSONFile} from '@schematics/angular/utility/json-file';
12+
13+
export function migrate(): Rule {
14+
return async (tree: Tree) => {
15+
const {buildPaths, testPaths} = await getProjectTsConfigPaths(tree);
16+
const allPaths = [...new Set([...buildPaths, ...testPaths])];
17+
18+
for (const tsconfigPath of allPaths) {
19+
const json = new JSONFile(tree, tsconfigPath);
20+
const compilerOptions = json.get(['compilerOptions']);
21+
22+
if (
23+
!compilerOptions ||
24+
typeof compilerOptions !== 'object' ||
25+
Object.keys(compilerOptions).length === 0
26+
) {
27+
continue;
28+
}
29+
30+
json.modify(
31+
['angularCompilerOptions', 'extendedDiagnostics', 'checks', 'nullishCoalescingNotNullable'],
32+
'suppress',
33+
);
34+
json.modify(
35+
['angularCompilerOptions', 'extendedDiagnostics', 'checks', 'optionalChainNotNullable'],
36+
'suppress',
37+
);
38+
}
39+
};
40+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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+
9+
import {HostTree} from '@angular-devkit/schematics';
10+
import {UnitTestTree} from '@angular-devkit/schematics/testing/index.js';
11+
import {migrate} from './index';
12+
13+
function parseConfig(tree: UnitTestTree, path: string) {
14+
return JSON.parse(tree.readContent(path).replace(/\/\/.*$/gm, ''));
15+
}
16+
17+
describe('strict-safe-navigation-narrow migration', () => {
18+
let tree: UnitTestTree;
19+
20+
beforeEach(() => {
21+
tree = new UnitTestTree(new HostTree());
22+
tree.create(
23+
'/angular.json',
24+
JSON.stringify({
25+
version: 1,
26+
projects: {
27+
t: {
28+
root: '',
29+
architect: {
30+
build: {
31+
options: {
32+
tsConfig: './tsconfig.json',
33+
},
34+
},
35+
},
36+
},
37+
},
38+
}),
39+
);
40+
});
41+
42+
it('should not add options if compilerOptions is empty', async () => {
43+
tree.create(
44+
'/tsconfig.json',
45+
JSON.stringify({
46+
compilerOptions: {},
47+
}),
48+
);
49+
50+
const runMigration = migrate();
51+
await runMigration(tree, {} as any);
52+
53+
const tsconfig = parseConfig(tree, '/tsconfig.json');
54+
expect(tsconfig.angularCompilerOptions).toBeUndefined();
55+
});
56+
57+
it('should not add options if compilerOptions is missing', async () => {
58+
tree.create('/tsconfig.json', JSON.stringify({}));
59+
60+
const runMigration = migrate();
61+
await runMigration(tree, {} as any);
62+
63+
const tsconfig = parseConfig(tree, '/tsconfig.json');
64+
expect(tsconfig.angularCompilerOptions).toBeUndefined();
65+
});
66+
67+
it('should add suppress options if compilerOptions is not empty', async () => {
68+
tree.create(
69+
'/tsconfig.json',
70+
JSON.stringify({
71+
compilerOptions: {
72+
target: 'es2020',
73+
},
74+
}),
75+
);
76+
77+
const runMigration = migrate();
78+
await runMigration(tree, {} as any);
79+
80+
const tsconfig = parseConfig(tree, '/tsconfig.json');
81+
expect(
82+
tsconfig.angularCompilerOptions.extendedDiagnostics.checks.nullishCoalescingNotNullable,
83+
).toBe('suppress');
84+
expect(
85+
tsconfig.angularCompilerOptions.extendedDiagnostics.checks.optionalChainNotNullable,
86+
).toBe('suppress');
87+
});
88+
89+
it('should preserve existing checks', async () => {
90+
tree.create(
91+
'/tsconfig.json',
92+
JSON.stringify({
93+
compilerOptions: {
94+
target: 'es2020',
95+
},
96+
angularCompilerOptions: {
97+
extendedDiagnostics: {
98+
checks: {
99+
somethingElse: 'warning',
100+
},
101+
},
102+
},
103+
}),
104+
);
105+
106+
const runMigration = migrate();
107+
await runMigration(tree, {} as any);
108+
109+
const tsconfig = parseConfig(tree, '/tsconfig.json');
110+
expect(tsconfig.angularCompilerOptions.extendedDiagnostics.checks.somethingElse).toBe(
111+
'warning',
112+
);
113+
expect(
114+
tsconfig.angularCompilerOptions.extendedDiagnostics.checks.nullishCoalescingNotNullable,
115+
).toBe('suppress');
116+
expect(
117+
tsconfig.angularCompilerOptions.extendedDiagnostics.checks.optionalChainNotNullable,
118+
).toBe('suppress');
119+
});
120+
121+
it('should handle tsconfig with comments', async () => {
122+
tree.create(
123+
'/tsconfig.json',
124+
`{
125+
// This is a comment
126+
"compilerOptions": {
127+
"target": "es2020"
128+
}
129+
}`,
130+
);
131+
132+
const runMigration = migrate();
133+
await runMigration(tree, {} as any);
134+
135+
const tsconfig = parseConfig(tree, '/tsconfig.json');
136+
expect(tsconfig.compilerOptions.target).toBe('es2020');
137+
expect(
138+
tsconfig.angularCompilerOptions.extendedDiagnostics.checks.nullishCoalescingNotNullable,
139+
).toBe('suppress');
140+
});
141+
});

0 commit comments

Comments
 (0)