@@ -14,7 +14,6 @@ import {
1414 logging ,
1515 normalize ,
1616 parseJson ,
17- parseJsonAst ,
1817 tags ,
1918} from '@angular-devkit/core' ;
2019import {
@@ -31,10 +30,7 @@ import {
3130 NodeDependencyType ,
3231 addPackageJsonDependency ,
3332} from '../../utility/dependencies' ;
34- import {
35- appendValueInAstArray ,
36- findPropertyInAstObject ,
37- } from '../../utility/json-utils' ;
33+ import { JSONFile } from '../../utility/json-file' ;
3834import { latestVersions } from '../../utility/latest-versions' ;
3935
4036const defaults = {
@@ -624,41 +620,35 @@ function extractDefaultProject(config: CliConfig): string | null {
624620}
625621
626622function updateSpecTsConfig ( config : CliConfig ) : Rule {
627- return ( host : Tree , context : SchematicContext ) => {
623+ return ( host ) => {
628624 const apps = config . apps || [ ] ;
629- apps . forEach ( ( app : AppConfig , idx : number ) => {
625+ apps . forEach ( ( app : AppConfig ) => {
630626 const testTsConfig = app . testTsconfig || defaults . testTsConfig ;
631627 const tsSpecConfigPath = join ( normalize ( app . root || '' ) , testTsConfig ) ;
632- const buffer = host . read ( tsSpecConfigPath ) ;
633628
634- if ( ! buffer ) {
629+ let tsConfigJson ;
630+ try {
631+ tsConfigJson = new JSONFile ( host , tsSpecConfigPath ) ;
632+ } catch {
635633 return ;
636634 }
637635
638-
639- const tsCfgAst = parseJsonAst ( buffer . toString ( ) , JsonParseMode . Loose ) ;
640- if ( tsCfgAst . kind != 'object' ) {
641- throw new SchematicsException ( 'Invalid tsconfig. Was expecting an object' ) ;
636+ const files = tsConfigJson . get ( [ 'files' ] ) ;
637+ if ( files === undefined ) {
638+ // Do nothing if the files array does not exist. This means exclude or include are
639+ // set and we shouldn't mess with that.
640+ return ;
642641 }
643642
644- const filesAstNode = findPropertyInAstObject ( tsCfgAst , 'files' ) ;
645- if ( filesAstNode && filesAstNode . kind != 'array' ) {
643+ if ( ! Array . isArray ( files ) ) {
646644 throw new SchematicsException ( 'Invalid tsconfig "files" property; expected an array.' ) ;
647645 }
648646
649- const recorder = host . beginUpdate ( tsSpecConfigPath ) ;
650-
651647 const polyfills = app . polyfills || defaults . polyfills ;
652- if ( ! filesAstNode ) {
653- // Do nothing if the files array does not exist. This means exclude or include are
654- // set and we shouldn't mess with that.
655- } else {
656- if ( filesAstNode . value . indexOf ( polyfills ) == - 1 ) {
657- appendValueInAstArray ( recorder , filesAstNode , polyfills ) ;
658- }
648+ if ( polyfills && ! files . includes ( polyfills ) ) {
649+ // Append polyfills file to the files array
650+ tsConfigJson . modify ( [ 'files' , - 1 ] , polyfills ) ;
659651 }
660-
661- host . commitUpdate ( recorder ) ;
662652 } ) ;
663653 } ;
664654}
@@ -682,111 +672,63 @@ function updatePackageJson(config: CliConfig) {
682672}
683673
684674function updateTsLintConfig ( ) : Rule {
685- return ( host : Tree , context : SchematicContext ) => {
675+ return ( host ) => {
686676 const tsLintPath = '/tslint.json' ;
687- const buffer = host . read ( tsLintPath ) ;
688- if ( ! buffer ) {
689- return host ;
690- }
691- const tsCfgAst = parseJsonAst ( buffer . toString ( ) , JsonParseMode . Loose ) ;
692-
693- if ( tsCfgAst . kind != 'object' ) {
694- return host ;
695- }
696-
697- const rulesNode = findPropertyInAstObject ( tsCfgAst , 'rules' ) ;
698- if ( ! rulesNode || rulesNode . kind != 'object' ) {
699- return host ;
700- }
701677
702- const importBlacklistNode = findPropertyInAstObject ( rulesNode , 'import-blacklist' ) ;
703- if ( ! importBlacklistNode || importBlacklistNode . kind != 'array' ) {
704- return host ;
678+ let tsLintJson ;
679+ try {
680+ tsLintJson = new JSONFile ( host , tsLintPath ) ;
681+ } catch {
682+ return ;
705683 }
706684
707- const recorder = host . beginUpdate ( tsLintPath ) ;
708- for ( let i = 0 ; i < importBlacklistNode . elements . length ; i ++ ) {
709- const element = importBlacklistNode . elements [ i ] ;
710- if ( element . kind == 'string' && element . value == 'rxjs' ) {
711- const { start, end } = element ;
712- // Remove this element.
713- if ( i == importBlacklistNode . elements . length - 1 ) {
714- // Last element.
715- if ( i > 0 ) {
716- // Not first, there's a comma to remove before.
717- const previous = importBlacklistNode . elements [ i - 1 ] ;
718- recorder . remove ( previous . end . offset , end . offset - previous . end . offset ) ;
719- } else {
720- // Only element, just remove the whole rule.
721- const { start, end } = importBlacklistNode ;
722- recorder . remove ( start . offset , end . offset - start . offset ) ;
723- recorder . insertLeft ( start . offset , '[]' ) ;
724- }
725- } else {
726- // Middle, just remove the whole node (up to next node start).
727- const next = importBlacklistNode . elements [ i + 1 ] ;
728- recorder . remove ( start . offset , next . start . offset - start . offset ) ;
729- }
730- }
685+ const rulePath = [ 'rules' , 'import-blacklist' ] ;
686+ const currentRuleItems = tsLintJson . get ( rulePath ) ;
687+ if ( ! currentRuleItems || ! Array . isArray ( currentRuleItems ) ) {
688+ return ;
731689 }
732690
733- host . commitUpdate ( recorder ) ;
734-
735- return host ;
691+ // Remove all occurences of rxjs
692+ const newRuleItems = currentRuleItems . filter ( value => value !== 'rxjs' ) ;
693+ tsLintJson . modify ( rulePath , newRuleItems ) ;
736694 } ;
737695}
738696
739697function updateRootTsConfig ( ) : Rule {
740698 return ( host : Tree , context : SchematicContext ) => {
741699 const tsConfigPath = '/tsconfig.json' ;
742- const buffer = host . read ( tsConfigPath ) ;
743- if ( ! buffer ) {
744- return ;
745- }
746-
747- const tsCfgAst = parseJsonAst ( buffer . toString ( ) , JsonParseMode . Loose ) ;
748- if ( tsCfgAst . kind !== 'object' ) {
749- throw new SchematicsException ( 'Invalid root tsconfig. Was expecting an object' ) ;
750- }
751-
752- const compilerOptionsAstNode = findPropertyInAstObject ( tsCfgAst , 'compilerOptions' ) ;
753- if ( ! compilerOptionsAstNode || compilerOptionsAstNode . kind != 'object' ) {
754- throw new SchematicsException (
755- 'Invalid root tsconfig "compilerOptions" property; expected an object.' ,
756- ) ;
757- }
758700
759- if (
760- findPropertyInAstObject ( compilerOptionsAstNode , 'baseUrl' ) &&
761- findPropertyInAstObject ( compilerOptionsAstNode , 'module' )
762- ) {
763- return host ;
701+ let tsConfigJson ;
702+ try {
703+ tsConfigJson = new JSONFile ( host , tsConfigPath ) ;
704+ } catch {
705+ return ;
764706 }
765707
766- const compilerOptions = compilerOptionsAstNode . value ;
767- const { baseUrl = './' , module = 'es2015' } = compilerOptions ;
768-
769- const validBaseUrl = [ './' , '' , '.' ] ;
770- if ( ! validBaseUrl . includes ( baseUrl as string ) ) {
771- const formattedBaseUrl = validBaseUrl . map ( x => `'${ x } '` ) . join ( ', ' ) ;
772- context . logger . warn ( tags . oneLine
773- `Root tsconfig option 'baseUrl' is not one of: ${ formattedBaseUrl } .
774- This might cause unexpected behaviour when generating libraries.` ,
775- ) ;
708+ const baseUrlPath = [ 'compilerOptions' , 'baseUrl' ] ;
709+ const baseUrl = tsConfigJson . get ( baseUrlPath ) ;
710+ if ( baseUrl === undefined || typeof baseUrl !== 'string' ) {
711+ tsConfigJson . modify ( baseUrlPath , './' ) ;
712+ } else {
713+ const validBaseUrl = [ './' , '' , '.' ] ;
714+ if ( ! validBaseUrl . includes ( baseUrl ) ) {
715+ const formattedBaseUrl = validBaseUrl . map ( x => `'${ x } '` ) . join ( ', ' ) ;
716+ context . logger . warn ( tags . oneLine
717+ `Root tsconfig option 'baseUrl' is not one of: ${ formattedBaseUrl } .
718+ This might cause unexpected behaviour when generating libraries.` ,
719+ ) ;
720+ }
776721 }
777722
778- if ( module !== 'es2015' ) {
723+ const modulePath = [ 'compilerOptions' , 'module' ] ;
724+ const module = tsConfigJson . get ( modulePath ) ;
725+ if ( module === undefined || typeof module !== 'string' ) {
726+ tsConfigJson . modify ( modulePath , 'es2015' ) ;
727+ } else if ( module . toLowerCase ( ) !== 'es2015' ) {
779728 context . logger . warn (
780729 `Root tsconfig option 'module' is not 'es2015'. This might cause unexpected behaviour.` ,
781730 ) ;
782731 }
783-
784- compilerOptions . module = module ;
785- compilerOptions . baseUrl = baseUrl ;
786-
787- host . overwrite ( tsConfigPath , JSON . stringify ( tsCfgAst . value , null , 2 ) ) ;
788-
789- return host ;
790732 } ;
791733}
792734
0 commit comments