Skip to content

fix(schematics): allow more tsconfig locations for ng update #11058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 30, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 80 additions & 37 deletions src/lib/schematics/update/update.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
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';

/** 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));
Expand All @@ -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(
Expand Down Expand Up @@ -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);
}