6
6
* found in the LICENSE file at https://angular.io/license
7
7
*/
8
8
import { JsonAstObject , join , logging , normalize } from '@angular-devkit/core' ;
9
- import { Rule , Tree , UpdateRecorder } from '@angular-devkit/schematics' ;
9
+ import { Rule , Tree } from '@angular-devkit/schematics' ;
10
10
import { dirname , relative } from 'path' ;
11
- import {
12
- findPropertyInAstObject ,
13
- insertPropertyInAstObjectInOrder ,
14
- removePropertyInAstObject ,
15
- } from '../../utility/json-utils' ;
11
+ import { JSONFile } from '../../utility/json-file' ;
12
+ import { findPropertyInAstObject } from '../../utility/json-utils' ;
16
13
import { Builders } from '../../utility/workspace-models' ;
17
14
import {
18
15
forwardSlashPath ,
19
16
getAllOptions ,
20
17
getTargets ,
21
18
getWorkspace ,
22
- readJsonFileAsAstObject ,
23
19
} from './utils' ;
24
20
25
21
/**
@@ -29,9 +25,8 @@ import {
29
25
* - Sets module compiler option to esnext or commonjs
30
26
*/
31
27
export function updateApplicationTsConfigs ( ) : Rule {
32
- return ( tree , context ) => {
28
+ return ( tree , { logger } ) => {
33
29
const workspace = getWorkspace ( tree ) ;
34
- const logger = context . logger ;
35
30
36
31
// Add `module` option in the workspace tsconfig
37
32
updateModuleCompilerOption ( tree , '/tsconfig.json' ) ;
@@ -47,8 +42,6 @@ export function updateApplicationTsConfigs(): Rule {
47
42
for ( const { target, project } of getTargets ( workspace , 'test' , Builders . Karma ) ) {
48
43
updateTsConfig ( tree , target , project , Builders . Karma , logger ) ;
49
44
}
50
-
51
- return tree ;
52
45
} ;
53
46
}
54
47
@@ -61,58 +54,48 @@ function updateTsConfig(
61
54
) {
62
55
const options = getAllOptions ( builderConfig ) ;
63
56
for ( const option of options ) {
64
- let recorder : UpdateRecorder ;
65
57
const tsConfigOption = findPropertyInAstObject ( option , 'tsConfig' ) ;
66
58
67
59
if ( ! tsConfigOption || tsConfigOption . kind !== 'string' ) {
68
60
continue ;
69
61
}
70
62
71
63
const tsConfigPath = tsConfigOption . value ;
72
- let tsConfigAst = readJsonFileAsAstObject ( tree , tsConfigPath ) ;
73
- if ( ! tsConfigAst ) {
64
+
65
+ // Update 'module' compilerOption
66
+ updateModuleCompilerOption ( tree , tsConfigPath , builderName ) ;
67
+
68
+ let tsConfigJson ;
69
+ try {
70
+ tsConfigJson = new JSONFile ( tree , tsConfigPath ) ;
71
+ } catch {
74
72
logger . warn ( `Cannot find file: ${ tsConfigPath } ` ) ;
75
73
continue ;
76
74
}
77
75
78
76
// Remove 'enableIvy: true' since this is the default in version 9.
79
- const angularCompilerOptions = findPropertyInAstObject ( tsConfigAst , 'angularCompilerOptions' ) ;
80
- if ( angularCompilerOptions && angularCompilerOptions . kind === 'object' ) {
81
- const enableIvy = findPropertyInAstObject ( angularCompilerOptions , 'enableIvy' ) ;
82
- if ( enableIvy && enableIvy . kind === 'true' ) {
83
- recorder = tree . beginUpdate ( tsConfigPath ) ;
84
- if ( angularCompilerOptions . properties . length === 1 ) {
85
- // remove entire 'angularCompilerOptions'
86
- removePropertyInAstObject ( recorder , tsConfigAst , 'angularCompilerOptions' ) ;
87
- } else {
88
- removePropertyInAstObject ( recorder , angularCompilerOptions , 'enableIvy' ) ;
89
- }
90
- tree . commitUpdate ( recorder ) ;
77
+ if ( tsConfigJson . get ( [ 'angularCompilerOptions' , 'enableIvy' ] ) === true ) {
78
+ const angularCompilerOptions = tsConfigJson . get ( [ 'angularCompilerOptions' ] ) ;
79
+ const keys = Object . keys ( angularCompilerOptions as object ) ;
80
+
81
+ if ( keys . length === 1 ) {
82
+ // remove entire 'angularCompilerOptions'
83
+ tsConfigJson . remove ( [ 'angularCompilerOptions' ] ) ;
84
+ } else {
85
+ // leave other options
86
+ tsConfigJson . remove ( [ 'angularCompilerOptions' , 'enableIvy' ] ) ;
91
87
}
92
88
}
93
89
94
- // Update 'module' compilerOption
95
- updateModuleCompilerOption ( tree , tsConfigPath , builderName ) ;
96
-
97
90
// Add stricter file inclusions to avoid unused file warning during compilation
98
91
if ( builderName !== Builders . Karma ) {
99
- // Note: we need to re-read the tsconfig after very commit because
100
- // otherwise the updates will be out of sync since we are ammending the same node.
101
-
102
- // we are already checking that tsconfig exists above!
103
- // tslint:disable-next-line: no-non-null-assertion
104
- tsConfigAst = readJsonFileAsAstObject ( tree , tsConfigPath ) ! ;
105
- const include = findPropertyInAstObject ( tsConfigAst , 'include' ) ;
106
-
107
- if ( include && include . kind === 'array' ) {
108
- const tsInclude = include . elements . find ( ( { value } ) => typeof value === 'string' && value . endsWith ( '**/*.ts' ) ) ;
109
- if ( tsInclude ) {
110
- const { start, end } = tsInclude ;
111
- recorder = tree . beginUpdate ( tsConfigPath ) ;
112
- recorder . remove ( start . offset , end . offset - start . offset ) ;
92
+
93
+ const include = tsConfigJson . get ( [ 'include' ] ) ;
94
+ if ( include && Array . isArray ( include ) ) {
95
+ const tsInclude = include . findIndex ( ( value ) => typeof value === 'string' && value . endsWith ( '**/*.ts' ) ) ;
96
+ if ( tsInclude !== - 1 ) {
113
97
// Replace ts includes with d.ts
114
- recorder . insertLeft ( start . offset , tsInclude . text . replace ( '.ts' , '.d.ts' ) ) ;
115
- tree . commitUpdate ( recorder ) ;
98
+ tsConfigJson . modify ( [ 'include' , tsInclude ] , include [ tsInclude ] . replace ( '.ts' , '.d.ts' ) ) ;
116
99
}
117
100
} else {
118
101
// Includes are not present, add includes to dts files
@@ -123,13 +106,11 @@ function updateTsConfig(
123
106
? join ( normalize ( srcRootAst . value ) , '**/*.d.ts' )
124
107
: '**/*.d.ts' ;
125
108
126
- recorder = tree . beginUpdate ( tsConfigPath ) ;
127
- insertPropertyInAstObjectInOrder ( recorder , tsConfigAst , 'include' , [ include ] , 2 ) ;
128
- tree . commitUpdate ( recorder ) ;
109
+ tsConfigJson . modify ( [ 'include' ] , [ include ] ) ;
129
110
}
130
111
131
- const files = findPropertyInAstObject ( tsConfigAst , 'files' ) ;
132
- if ( ! files ) {
112
+ const files = tsConfigJson . get ( [ 'files' ] ) ;
113
+ if ( files === undefined ) {
133
114
const newFiles : string [ ] = [ ] ;
134
115
const tsConfigDir = dirname ( forwardSlashPath ( tsConfigPath ) ) ;
135
116
@@ -146,53 +127,37 @@ function updateTsConfig(
146
127
}
147
128
148
129
if ( newFiles . length ) {
149
- recorder = tree . beginUpdate ( tsConfigPath ) ;
150
- // tslint:disable-next-line: no-non-null-assertion
151
- tsConfigAst = readJsonFileAsAstObject ( tree , tsConfigPath ) ! ;
152
- insertPropertyInAstObjectInOrder ( recorder , tsConfigAst , 'files' , newFiles , 2 ) ;
153
- tree . commitUpdate ( recorder ) ;
130
+ tsConfigJson . modify ( [ 'files' ] , newFiles ) ;
154
131
}
155
132
156
- recorder = tree . beginUpdate ( tsConfigPath ) ;
157
- // tslint:disable-next-line: no-non-null-assertion
158
- tsConfigAst = readJsonFileAsAstObject ( tree , tsConfigPath ) ! ;
159
- removePropertyInAstObject ( recorder , tsConfigAst , 'exclude' ) ;
160
- tree . commitUpdate ( recorder ) ;
133
+ tsConfigJson . remove ( [ 'exclude' ] ) ;
161
134
}
162
135
}
163
136
}
164
137
}
165
138
166
139
function updateModuleCompilerOption ( tree : Tree , tsConfigPath : string , builderName ?: Builders ) {
167
- const tsConfigAst = readJsonFileAsAstObject ( tree , tsConfigPath ) ;
168
-
169
- if ( ! tsConfigAst ) {
140
+ let tsConfigJson ;
141
+ try {
142
+ tsConfigJson = new JSONFile ( tree , tsConfigPath ) ;
143
+ } catch {
170
144
return ;
171
145
}
172
146
173
- const compilerOptions = findPropertyInAstObject ( tsConfigAst , 'compilerOptions' ) ;
174
- if ( ! compilerOptions || compilerOptions . kind !== 'object' ) {
147
+ const compilerOptions = tsConfigJson . get ( [ 'compilerOptions' ] ) ;
148
+ if ( ! compilerOptions || typeof compilerOptions !== 'object' ) {
175
149
return ;
176
150
}
177
151
178
- const configExtends = findPropertyInAstObject ( tsConfigAst , 'extends' ) ;
179
- const isExtendedConfig = configExtends && configExtends . kind === 'string' ;
180
- const recorder = tree . beginUpdate ( tsConfigPath ) ;
152
+ const configExtends = tsConfigJson . get ( [ 'extends' ] ) ;
153
+ const isExtended = configExtends && typeof configExtends === 'string' ;
181
154
182
155
// Server tsconfig should have a module of commonjs
183
156
const moduleType = builderName === Builders . Server ? 'commonjs' : 'esnext' ;
184
- if ( isExtendedConfig && builderName !== Builders . Server ) {
185
- removePropertyInAstObject ( recorder , compilerOptions , 'module' ) ;
157
+
158
+ if ( isExtended && builderName !== Builders . Server ) {
159
+ tsConfigJson . remove ( [ 'compilerOptions' , 'module' ] ) ;
186
160
} else {
187
- const scriptModule = findPropertyInAstObject ( compilerOptions , 'module' ) ;
188
- if ( ! scriptModule ) {
189
- insertPropertyInAstObjectInOrder ( recorder , compilerOptions , 'module' , moduleType , 4 ) ;
190
- } else if ( scriptModule . value !== moduleType ) {
191
- const { start, end } = scriptModule ;
192
- recorder . remove ( start . offset , end . offset - start . offset ) ;
193
- recorder . insertLeft ( start . offset , `"${ moduleType } "` ) ;
194
- }
161
+ tsConfigJson . modify ( [ 'compilerOptions' , 'module' ] , moduleType ) ;
195
162
}
196
-
197
- tree . commitUpdate ( recorder ) ;
198
163
}
0 commit comments