From 7bbc040aeea301aba03b803a12464fc84db7811f Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Mon, 30 Apr 2018 13:01:23 -0700 Subject: [PATCH] fix(schematics): allow more tsconfig locations for ng update (#11058) * fix(schematics): allow more tsconfig locations for ng update * Delete old temp files if they're present * Do all the tsconfigs --- src/lib/schematics/update/update.ts | 117 +++++++++++++++++++--------- 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/src/lib/schematics/update/update.ts b/src/lib/schematics/update/update.ts index bcd983da40a..cc33a62f0b7 100644 --- a/src/lib/schematics/update/update.ts +++ b/src/lib/schematics/update/update.ts @@ -1,10 +1,12 @@ -import {chain, FileEntry, Rule, SchematicContext, Tree} from '@angular-devkit/schematics'; +import {FileEntry, Rule, SchematicContext, Tree} from '@angular-devkit/schematics'; import { NodePackageInstallTask, RunSchematicTask, TslintFixTask } from '@angular-devkit/schematics/tasks'; import * as path from 'path'; +import {existsSync, readFileSync} from 'fs'; +import {getProjectFromWorkspace, getWorkspace} from '../utils/devkit-utils/config'; const schematicsSrcPath = 'node_modules/@angular/material/schematics'; const schematicsTmpPath = 'node_modules/_tmp_angular_material_schematics'; @@ -12,6 +14,10 @@ const schematicsTmpPath = 'node_modules/_tmp_angular_material_schematics'; /** Entry point for `ng update` from Angular CLI. */ export default function(): Rule { return (tree: Tree, context: SchematicContext) => { + // If this script failed in an earlier run, clear out the temporary files from that failed + // run before doing anything else. + tree.getDir(schematicsTmpPath).visit((_, entry) => tree.delete(entry.path)); + // Copy the update schematics to a temporary directory. const updateSrcs: FileEntry[] = []; tree.getDir(schematicsSrcPath).visit((_, entry) => updateSrcs.push(entry)); @@ -25,48 +31,52 @@ export default function(): Rule { packageName: '@angular/cdk@">=5 <6" @angular/material@">=5 <6"' })); - // Run the update tslint rules. - const updateTask = context.addTask(new TslintFixTask({ - rulesDirectory: path.join(schematicsTmpPath, 'update/rules'), - rules: { - // Automatic fixes. - "switch-identifiers": true, - "switch-property-names": true, - "switch-string-literal-attribute-selectors": true, - "switch-string-literal-css-names": true, - "switch-string-literal-element-selectors": true, - "switch-stylesheet-attribute-selectors": true, - "switch-stylesheet-css-names": true, - "switch-stylesheet-element-selectors": true, - "switch-stylesheet-input-names": true, - "switch-stylesheet-output-names": true, - "switch-template-attribute-selectors": true, - "switch-template-css-names": true, - "switch-template-element-selectors": true, - "switch-template-export-as-names": true, - "switch-template-input-names": true, - "switch-template-output-names": true, + const allTsConfigPaths = getTsConfigPaths(tree); + const allUpdateTasks = []; + for (const tsconfig of allTsConfigPaths) { + // Run the update tslint rules. + allUpdateTasks.push(context.addTask(new TslintFixTask({ + rulesDirectory: path.join(schematicsTmpPath, 'update/rules'), + rules: { + // Automatic fixes. + "switch-identifiers": true, + "switch-property-names": true, + "switch-string-literal-attribute-selectors": true, + "switch-string-literal-css-names": true, + "switch-string-literal-element-selectors": true, + "switch-stylesheet-attribute-selectors": true, + "switch-stylesheet-css-names": true, + "switch-stylesheet-element-selectors": true, + "switch-stylesheet-input-names": true, + "switch-stylesheet-output-names": true, + "switch-template-attribute-selectors": true, + "switch-template-css-names": true, + "switch-template-element-selectors": true, + "switch-template-export-as-names": true, + "switch-template-input-names": true, + "switch-template-output-names": true, - // Additional issues we can detect but not automatically fix. - "check-class-declaration-misc": true, - "check-identifier-misc": true, - "check-import-misc": true, - "check-inheritance": true, - "check-method-calls": true, - "check-property-access-misc": true, - "check-template-misc": true - } - }, { - silent: false, - ignoreErrors: true, - tsConfigPath: './src/tsconfig.json', - }), [downgradeTask]); + // Additional issues we can detect but not automatically fix. + "check-class-declaration-misc": true, + "check-identifier-misc": true, + "check-import-misc": true, + "check-inheritance": true, + "check-method-calls": true, + "check-property-access-misc": true, + "check-template-misc": true + } + }, { + silent: false, + ignoreErrors: true, + tsConfigPath: tsconfig, + }), [downgradeTask])); + } // Upgrade @angular/material back to 6.x. const upgradeTask = context.addTask(new NodePackageInstallTask({ // TODO(mmalerba): Change "next" to ">=6 <7". packageName: '@angular/cdk@next @angular/material@next' - }), [updateTask]); + }), allUpdateTasks); // Delete the temporary schematics directory. context.addTask( @@ -94,3 +104,36 @@ export function postPostUpdate(): Rule { '\nComplete! Please check the output above for any issues that were detected but could not' + ' be automatically fixed.'); } + +/** Gets the first tsconfig path from possibile locations based on the history of the CLI. */ +function getTsConfigPaths(tree: Tree): string[] { + // Start with some tsconfig paths that are generally used. + const tsconfigPaths = [ + './tsconfig.json', + './src/tsconfig.json', + './src/tsconfig.app.json', + ]; + + // Add any tsconfig directly referenced in a build or test task of the angular.json workspace. + const workspace = getWorkspace(tree); + for (const project of Object.values(workspace.projects)) { + if (project && project.architect) { + for (const taskName of ['build', 'test']) { + const task = project.architect[taskName]; + if (task && task.options && task.options.tsConfig) { + const tsConfigOption = project.architect.tsConfig; + if (typeof tsConfigOption === 'string') { + tsconfigPaths.push(tsConfigOption); + } else if (Array.isArray(tsConfigOption)) { + tsconfigPaths.push(...tsConfigOption); + } + } + } + } + } + + // Filter out tsconfig files that don't exist and remove any duplicates. + return tsconfigPaths + .filter(p => existsSync(p)) + .filter((value, index, self) => self.indexOf(value) === index); +}