66 * found in the LICENSE file at https://angular.io/license
77 */
88import { 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' ;
1010import { 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' ;
1613import { Builders } from '../../utility/workspace-models' ;
1714import {
1815 forwardSlashPath ,
1916 getAllOptions ,
2017 getTargets ,
2118 getWorkspace ,
22- readJsonFileAsAstObject ,
2319} from './utils' ;
2420
2521/**
@@ -29,9 +25,8 @@ import {
2925 * - Sets module compiler option to esnext or commonjs
3026 */
3127export function updateApplicationTsConfigs ( ) : Rule {
32- return ( tree , context ) => {
28+ return ( tree , { logger } ) => {
3329 const workspace = getWorkspace ( tree ) ;
34- const logger = context . logger ;
3530
3631 // Add `module` option in the workspace tsconfig
3732 updateModuleCompilerOption ( tree , '/tsconfig.json' ) ;
@@ -47,8 +42,6 @@ export function updateApplicationTsConfigs(): Rule {
4742 for ( const { target, project } of getTargets ( workspace , 'test' , Builders . Karma ) ) {
4843 updateTsConfig ( tree , target , project , Builders . Karma , logger ) ;
4944 }
50-
51- return tree ;
5245 } ;
5346}
5447
@@ -61,58 +54,48 @@ function updateTsConfig(
6154) {
6255 const options = getAllOptions ( builderConfig ) ;
6356 for ( const option of options ) {
64- let recorder : UpdateRecorder ;
6557 const tsConfigOption = findPropertyInAstObject ( option , 'tsConfig' ) ;
6658
6759 if ( ! tsConfigOption || tsConfigOption . kind !== 'string' ) {
6860 continue ;
6961 }
7062
7163 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 {
7472 logger . warn ( `Cannot find file: ${ tsConfigPath } ` ) ;
7573 continue ;
7674 }
7775
7876 // 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' ] ) ;
9187 }
9288 }
9389
94- // Update 'module' compilerOption
95- updateModuleCompilerOption ( tree , tsConfigPath , builderName ) ;
96-
9790 // Add stricter file inclusions to avoid unused file warning during compilation
9891 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 ) {
11397 // 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' ) ) ;
11699 }
117100 } else {
118101 // Includes are not present, add includes to dts files
@@ -123,13 +106,11 @@ function updateTsConfig(
123106 ? join ( normalize ( srcRootAst . value ) , '**/*.d.ts' )
124107 : '**/*.d.ts' ;
125108
126- recorder = tree . beginUpdate ( tsConfigPath ) ;
127- insertPropertyInAstObjectInOrder ( recorder , tsConfigAst , 'include' , [ include ] , 2 ) ;
128- tree . commitUpdate ( recorder ) ;
109+ tsConfigJson . modify ( [ 'include' ] , [ include ] ) ;
129110 }
130111
131- const files = findPropertyInAstObject ( tsConfigAst , 'files' ) ;
132- if ( ! files ) {
112+ const files = tsConfigJson . get ( [ 'files' ] ) ;
113+ if ( files === undefined ) {
133114 const newFiles : string [ ] = [ ] ;
134115 const tsConfigDir = dirname ( forwardSlashPath ( tsConfigPath ) ) ;
135116
@@ -146,53 +127,37 @@ function updateTsConfig(
146127 }
147128
148129 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 ) ;
154131 }
155132
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' ] ) ;
161134 }
162135 }
163136 }
164137}
165138
166139function 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 {
170144 return ;
171145 }
172146
173- const compilerOptions = findPropertyInAstObject ( tsConfigAst , 'compilerOptions' ) ;
174- if ( ! compilerOptions || compilerOptions . kind !== 'object' ) {
147+ const compilerOptions = tsConfigJson . get ( [ 'compilerOptions' ] ) ;
148+ if ( ! compilerOptions || typeof compilerOptions !== 'object' ) {
175149 return ;
176150 }
177151
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' ;
181154
182155 // Server tsconfig should have a module of commonjs
183156 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' ] ) ;
186160 } 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 ) ;
195162 }
196-
197- tree . commitUpdate ( recorder ) ;
198163}
0 commit comments