Skip to content

Commit e5ede4b

Browse files
committed
fix(migrations): Fix typo for strict-template migration
Fix typo for strict-template migration
1 parent 836094c commit e5ede4b

6 files changed

Lines changed: 155 additions & 72 deletions

File tree

packages/core/schematics/BUILD.bazel

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ bundle_entrypoints = [
126126
"packages/core/schematics/migrations/http-xhr-backend/index.js",
127127
],
128128
[
129-
"strict-templates",
130-
"packages/core/schematics/migrations/strict-template/index.js",
129+
"strict-templates-default",
130+
"packages/core/schematics/migrations/strict-templates-default/index.js",
131131
],
132132
[
133133
"can-match-snapshot-required",
@@ -152,7 +152,7 @@ rollup.rollup(
152152
"//packages/core/schematics/migrations/change-detection-eager",
153153
"//packages/core/schematics/migrations/http-xhr-backend",
154154
"//packages/core/schematics/migrations/incremental-hydration",
155-
"//packages/core/schematics/migrations/strict-template",
155+
"//packages/core/schematics/migrations/strict-templates-default",
156156
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
157157
"//packages/core/schematics/ng-generate/common-to-standalone-migration",
158158
"//packages/core/schematics/ng-generate/control-flow-migration",

packages/core/schematics/migrations.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
"description": "Adds 'withXhr' to 'provideHttpClient' function calls when the 'HttpXhrBackend' is used. For more information see: https://angular.dev/api/common/http/withXhr",
1111
"factory": "./bundles/http-xhr-backend.cjs#migrate"
1212
},
13-
"strict-template": {
13+
"strict-templates-default": {
1414
"version": "22.0.0",
15-
"description": "Adds 'strictTemplates: true' in tsconfig.json.",
16-
"factory": "./bundles/strict-templates.cjs#migrate"
15+
"description": "Adds 'strictTemplates: false' in tsconfig.json when not set.",
16+
"factory": "./bundles/strict-templates-default.cjs#migrate"
1717
},
1818
"can-match-snapshot-required": {
1919
"version": "22.0.0",

packages/core/schematics/migrations/strict-template/index.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

packages/core/schematics/migrations/strict-template/BUILD.bazel renamed to packages/core/schematics/migrations/strict-templates-default/BUILD.bazel

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ package(
88
)
99

1010
ts_project(
11-
name = "strict-template",
11+
name = "strict-templates-default",
1212
srcs = glob(
1313
["**/*.ts"],
1414
exclude = ["*.spec.ts"],
1515
),
1616
deps = [
17+
"//:node_modules/@angular-devkit/core",
1718
"//:node_modules/@angular-devkit/schematics",
19+
"//:node_modules/@schematics/angular",
1820
"//packages/core/schematics/utils",
1921
],
2022
)
@@ -24,9 +26,10 @@ ts_project(
2426
testonly = True,
2527
srcs = glob(["*.spec.ts"]),
2628
deps = [
27-
":strict-template",
29+
":strict-templates-default",
2830
"//:node_modules/@angular-devkit/core",
2931
"//:node_modules/@angular-devkit/schematics",
32+
"//:node_modules/@schematics/angular",
3033
"//packages/core/schematics/utils",
3134
],
3235
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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} from '@angular-devkit/schematics';
10+
import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
11+
import {JSONFile} from '@schematics/angular/utility/json-file';
12+
import ts from 'typescript';
13+
import {dirname, join} from 'node:path';
14+
15+
function getResolvedAngularCompilerOptions(tree: any, tsconfigPath: string): Record<string, any> {
16+
const sourceFile = ts.readJsonConfigFile(tsconfigPath, (path) => tree.readText(path));
17+
const config = ts.convertToObject(sourceFile, []);
18+
19+
let angularOptions = config.angularCompilerOptions || {};
20+
21+
// Manually resolve inheritance for Angular-specific options.
22+
// Since the TypeScript API doesn't perform a deep merge of custom/non-standard keys
23+
// during config parsing, we must traverse the inheritance chain manually
24+
if (config.extends) {
25+
// Management extends property...
26+
const parentPath = join(dirname(tsconfigPath), config.extends);
27+
28+
if (tree.exists(parentPath)) {
29+
const parentOptions = getResolvedAngularCompilerOptions(tree, parentPath);
30+
31+
// Merge: the options of the current file overwrite those of the parent
32+
angularOptions = {
33+
...parentOptions,
34+
...angularOptions,
35+
};
36+
}
37+
}
38+
39+
return angularOptions;
40+
}
41+
42+
/**
43+
* Migration that adds `strictTemplates: false` to `tsconfig.json` files.
44+
*/
45+
export function migrate(): Rule {
46+
return async (tree) => {
47+
const {buildPaths, testPaths} = await getProjectTsConfigPaths(tree);
48+
const allPaths = [...new Set([...buildPaths, ...testPaths])];
49+
50+
for (const tsconfigPath of allPaths) {
51+
const json = new JSONFile(tree, tsconfigPath);
52+
const compilerOptions = json.get(['compilerOptions']);
53+
54+
if (
55+
!compilerOptions ||
56+
typeof compilerOptions !== 'object' ||
57+
Object.keys(compilerOptions).length === 0
58+
) {
59+
continue;
60+
}
61+
62+
const angularOptions = getResolvedAngularCompilerOptions(tree, tsconfigPath);
63+
64+
if (angularOptions['strictTemplates'] !== undefined) {
65+
continue;
66+
}
67+
68+
if (json.get(['angularCompilerOptions', 'strictTemplates']) === undefined) {
69+
json.modify(['angularCompilerOptions', 'strictTemplates'], false);
70+
}
71+
}
72+
};
73+
}

packages/core/schematics/migrations/strict-template/strict-template.spec.ts renamed to packages/core/schematics/migrations/strict-templates-default/migration.spec.ts

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import {HostTree} from '@angular-devkit/schematics';
1010
import {UnitTestTree} from '@angular-devkit/schematics/testing/index.js';
1111
import {migrate} from './index';
1212

13-
describe('strict-template migration', () => {
13+
function parseConfig(tree: UnitTestTree, path: string) {
14+
return JSON.parse(tree.readContent(path).replace(/\/\/.*$/gm, ''));
15+
}
16+
17+
describe('strict-templates-default migration', () => {
1418
let tree: UnitTestTree;
1519

1620
beforeEach(() => {
@@ -45,7 +49,7 @@ describe('strict-template migration', () => {
4549

4650
await migrate()(tree, {} as any);
4751

48-
const tsconfig = JSON.parse(tree.readContent('/tsconfig.json'));
52+
const tsconfig = parseConfig(tree, '/tsconfig.json');
4953
expect(tsconfig.angularCompilerOptions).toBeUndefined();
5054
});
5155

@@ -54,7 +58,7 @@ describe('strict-template migration', () => {
5458

5559
await migrate()(tree, {} as any);
5660

57-
const tsconfig = JSON.parse(tree.readContent('/tsconfig.json'));
61+
const tsconfig = parseConfig(tree, '/tsconfig.json');
5862
expect(tsconfig.angularCompilerOptions).toBeUndefined();
5963
});
6064

@@ -70,7 +74,7 @@ describe('strict-template migration', () => {
7074

7175
await migrate()(tree, {} as any);
7276

73-
const tsconfig = JSON.parse(tree.readContent('/tsconfig.json'));
77+
const tsconfig = parseConfig(tree, '/tsconfig.json');
7478
expect(tsconfig.angularCompilerOptions.strictTemplates).toBe(false);
7579
});
7680

@@ -87,7 +91,7 @@ describe('strict-template migration', () => {
8791

8892
await migrate()(tree, {} as any);
8993

90-
const tsconfig = JSON.parse(tree.readContent('/tsconfig.json'));
94+
const tsconfig = parseConfig(tree, '/tsconfig.json');
9195
expect(tsconfig.angularCompilerOptions.strictTemplates).toBe(false);
9296
});
9397

@@ -103,7 +107,68 @@ describe('strict-template migration', () => {
103107

104108
await migrate()(tree, {} as any);
105109

106-
const tsconfig = JSON.parse(tree.readContent('/tsconfig.json'));
110+
const tsconfig = parseConfig(tree, '/tsconfig.json');
107111
expect(tsconfig.angularCompilerOptions.strictTemplates).toBe(true);
108112
});
113+
114+
it('should handle tsconfig with comments', async () => {
115+
tree.create(
116+
'/tsconfig.json',
117+
`{
118+
// This is a comment
119+
"compilerOptions": {
120+
"target": "es2020"
121+
}
122+
}`,
123+
);
124+
125+
const runMigration = migrate();
126+
await runMigration(tree, {} as any);
127+
128+
const tsconfig = parseConfig(tree, '/tsconfig.json');
129+
expect(tsconfig.compilerOptions.target).toBe('es2020');
130+
expect(tsconfig.angularCompilerOptions.strictTemplates).toBe(false);
131+
});
132+
133+
it('should not add strictTemplates to child tsconfig that inherits it from parent', async () => {
134+
tree.create(
135+
'/tsconfig.json',
136+
JSON.stringify({
137+
compilerOptions: {target: 'es2020'},
138+
angularCompilerOptions: {strictTemplates: true},
139+
include: ['src/**/*.d.ts'],
140+
}),
141+
);
142+
143+
tree.create(
144+
'/tsconfig.app.json',
145+
JSON.stringify({
146+
extends: './tsconfig.json',
147+
compilerOptions: {outDir: './out-tsc/app'},
148+
}),
149+
);
150+
151+
tree.overwrite(
152+
'/angular.json',
153+
JSON.stringify({
154+
version: 1,
155+
projects: {
156+
t: {
157+
root: '',
158+
architect: {
159+
build: {
160+
options: {tsConfig: './tsconfig.app.json'},
161+
},
162+
},
163+
},
164+
},
165+
}),
166+
);
167+
168+
await migrate()(tree, {} as any);
169+
170+
// The child MUST NOT receive strictTemplates because it inherits it
171+
const childTsconfig = parseConfig(tree, '/tsconfig.app.json');
172+
expect(childTsconfig.angularCompilerOptions).toBeUndefined();
173+
});
109174
});

0 commit comments

Comments
 (0)