diff --git a/src/lib/schematics/update/html/angular.ts b/src/lib/schematics/update/html/angular.ts
index c7ed1f5f801..6823f229674 100644
--- a/src/lib/schematics/update/html/angular.ts
+++ b/src/lib/schematics/update/html/angular.ts
@@ -10,10 +10,26 @@ import {findAttributeOnElementWithAttrs, findAttributeOnElementWithTag} from './
/** Finds the specified Angular @Input in the given elements with tag name. */
export function findInputsOnElementWithTag(html: string, inputName: string, tagNames: string[]) {
- // Add one column to the mapped offset because the first bracket for the @Input
- // is part of the attribute and therefore also part of the offset. We only want to return
- // the offset for the inner name of the input.
- return findAttributeOnElementWithTag(html, `[${inputName}]`, tagNames).map(offset => offset + 1);
+ return [
+ // Inputs can be also used without brackets (e.g. ``)
+ ...findAttributeOnElementWithTag(html, inputName, tagNames),
+ // Add one column to the mapped offset because the first bracket for the @Input
+ // is part of the attribute and therefore also part of the offset. We only want to return
+ // the offset for the inner name of the bracketed input.
+ ...findAttributeOnElementWithTag(html, `[${inputName}]`, tagNames).map(offset => offset + 1),
+ ];
+}
+
+/** Finds the specified Angular @Input in elements that have one of the specified attributes. */
+export function findInputsOnElementWithAttr(html: string, inputName: string, attrs: string[]) {
+ return [
+ // Inputs can be also used without brackets (e.g. ``)
+ ...findAttributeOnElementWithAttrs(html, inputName, attrs),
+ // Add one column to the mapped offset because the first bracket for the @Input
+ // is part of the attribute and therefore also part of the offset. We only want to return
+ // the offset for the inner name of the bracketed input.
+ ...findAttributeOnElementWithAttrs(html, `[${inputName}]`, attrs).map(offset => offset + 1),
+ ];
}
/** Finds the specified Angular @Output in the given elements with tag name. */
@@ -24,14 +40,6 @@ export function findOutputsOnElementWithTag(html: string, outputName: string, ta
return findAttributeOnElementWithTag(html, `(${outputName})`, tagNames).map(offset => offset + 1);
}
-/** Finds the specified Angular @Input in elements that have one of the specified attributes. */
-export function findInputsOnElementWithAttr(html: string, inputName: string, attrs: string[]) {
- // Add one column to the mapped offset because the first bracket for the @Input
- // is part of the attribute and therefore also part of the offset. We only want to return
- // the offset for the inner name of the input.
- return findAttributeOnElementWithAttrs(html, `[${inputName}]`, attrs).map(offset => offset + 1);
-}
-
/** Finds the specified Angular @Output in elements that have one of the specified attributes. */
export function findOutputsOnElementWithAttr(html: string, outputName: string, attrs: string[]) {
// Add one column to the mapped offset because the first bracket for the @Output
diff --git a/src/lib/schematics/update/material/data/input-names.ts b/src/lib/schematics/update/material/data/input-names.ts
index 1c6ef2419c7..c0a5f975c98 100644
--- a/src/lib/schematics/update/material/data/input-names.ts
+++ b/src/lib/schematics/update/material/data/input-names.ts
@@ -19,8 +19,12 @@ export interface MaterialInputNameData {
elements?: string[],
/** Limit to elements with any of these attributes. */
attributes?: string[],
- /** Whether to ignore CSS attribute selectors when doing this replacement. */
- css?: boolean,
+ /**
+ * Whether inputs in stylesheets should be updated or not. Note that inputs inside of
+ * stylesheets usually don't make sense, but if developers use an input as a plain one-time
+ * attribute, it can be targeted through CSS selectors.
+ */
+ stylesheet?: boolean,
};
}
diff --git a/src/lib/schematics/update/material/data/output-names.ts b/src/lib/schematics/update/material/data/output-names.ts
index 28aa78fd9a2..d639d43464e 100644
--- a/src/lib/schematics/update/material/data/output-names.ts
+++ b/src/lib/schematics/update/material/data/output-names.ts
@@ -19,8 +19,6 @@ export interface MaterialOutputNameData {
elements?: string[],
/** Limit to elements with any of these attributes. */
attributes?: string[],
- /** Whether to ignore CSS attribute selectors when doing this replacement. */
- css?: boolean,
};
}
diff --git a/src/lib/schematics/update/rules/input-names/inputNamesStylesheetRule.ts b/src/lib/schematics/update/rules/input-names/inputNamesStylesheetRule.ts
new file mode 100644
index 00000000000..9375833707e
--- /dev/null
+++ b/src/lib/schematics/update/rules/input-names/inputNamesStylesheetRule.ts
@@ -0,0 +1,86 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {green, red} from 'chalk';
+import {sync as globSync} from 'glob';
+import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
+import * as ts from 'typescript';
+import {inputNames} from '../../material/data/input-names';
+import {ExternalResource} from '../../tslint/component-file';
+import {ComponentWalker} from '../../tslint/component-walker';
+import {
+ addFailureAtReplacement,
+ createExternalReplacementFailure,
+} from '../../tslint/rule-failures';
+import {findAllSubstringIndices} from '../../typescript/literal';
+
+/**
+ * Rule that walks through every inline or external stylesheet and replaces outdated CSS selectors
+ * that query for an @Input() with the new input name.
+ *
+ * Note that inputs inside of stylesheets usually don't make sense, but if developers use an
+ * input as a plain one-time attribute, it can be targeted through CSS selectors.
+ *
+ * e.g. `` becomes `my-component[color]`
+ */
+export class Rule extends Rules.AbstractRule {
+ apply(sourceFile: ts.SourceFile): RuleFailure[] {
+ return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
+ }
+}
+
+export class Walker extends ComponentWalker {
+
+ constructor(sourceFile: ts.SourceFile, options: IOptions) {
+ // In some applications, developers will have global stylesheets that are not specified in any
+ // Angular component. Therefore we glob up all css and scss files outside of node_modules and
+ // dist and check them as well.
+ const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
+ super(sourceFile, options, extraFiles);
+ extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
+ }
+
+ visitInlineStylesheet(literal: ts.StringLiteral) {
+ this._createReplacementsForContent(literal, literal.getText())
+ .forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
+ }
+
+ visitExternalStylesheet(node: ExternalResource) {
+ this._createReplacementsForContent(node, node.getFullText())
+ .map(data => createExternalReplacementFailure(node, data.failureMessage,
+ this.getRuleName(), data.replacement))
+ .forEach(failure => this.addFailure(failure));
+ }
+
+ /**
+ * Searches for outdated attribute selectors in the specified content and creates replacements
+ * with the according messages that can be added to a rule failure.
+ */
+ private _createReplacementsForContent(node: ts.Node, stylesheetContent: string) {
+ const replacements: {failureMessage: string, replacement: Replacement}[] = [];
+
+ inputNames.forEach(name => {
+ if (name.whitelist && !name.whitelist.stylesheet) {
+ return;
+ }
+
+ const currentSelector = `[${name.replace}]`;
+ const updatedSelector = `[${name.replaceWith}]`;
+
+ const failureMessage = `Found deprecated @Input() CSS selector "${red(currentSelector)}" ` +
+ `which has been renamed to "${green(updatedSelector)}"`;
+
+ findAllSubstringIndices(stylesheetContent, currentSelector)
+ .map(offset => node.getStart() + offset)
+ .map(start => new Replacement(start, currentSelector.length, updatedSelector))
+ .forEach(replacement => replacements.push({replacement, failureMessage}));
+ });
+
+ return replacements;
+ }
+}
diff --git a/src/lib/schematics/update/rules/input-names/inputNamesTemplateRule.ts b/src/lib/schematics/update/rules/input-names/inputNamesTemplateRule.ts
new file mode 100644
index 00000000000..b214a310468
--- /dev/null
+++ b/src/lib/schematics/update/rules/input-names/inputNamesTemplateRule.ts
@@ -0,0 +1,76 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {green, red} from 'chalk';
+import {Replacement, RuleFailure, Rules} from 'tslint';
+import * as ts from 'typescript';
+import {findInputsOnElementWithAttr, findInputsOnElementWithTag} from '../../html/angular';
+import {inputNames} from '../../material/data/input-names';
+import {ExternalResource} from '../../tslint/component-file';
+import {ComponentWalker} from '../../tslint/component-walker';
+import {
+ addFailureAtReplacement,
+ createExternalReplacementFailure,
+} from '../../tslint/rule-failures';
+
+/**
+ * Rule that walks through every inline or external HTML template and switches changed input
+ * bindings to the proper new name.
+ */
+export class Rule extends Rules.AbstractRule {
+ apply(sourceFile: ts.SourceFile): RuleFailure[] {
+ return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
+ }
+}
+
+export class Walker extends ComponentWalker {
+
+ visitInlineTemplate(template: ts.StringLiteral) {
+ this._createReplacementsForContent(template, template.getText())
+ .forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
+ }
+
+ visitExternalTemplate(template: ExternalResource) {
+ this._createReplacementsForContent(template, template.getFullText())
+ .map(data => createExternalReplacementFailure(template, data.failureMessage,
+ this.getRuleName(), data.replacement))
+ .forEach(failure => this.addFailure(failure));
+ }
+
+ /**
+ * Searches for outdated input bindings in the specified content and creates
+ * replacements with the according messages that can be added to a rule failure.
+ */
+ private _createReplacementsForContent(node: ts.Node, templateContent: string) {
+ const replacements: {failureMessage: string, replacement: Replacement}[] = [];
+
+ inputNames.forEach(name => {
+ const whitelist = name.whitelist;
+ const relativeOffsets = [];
+ const failureMessage = `Found deprecated @Input() "${red(name.replace)}"` +
+ ` which has been renamed to "${green(name.replaceWith)}"`;
+
+ if (!whitelist || whitelist.attributes) {
+ relativeOffsets.push(
+ ...findInputsOnElementWithAttr(templateContent, name.replace, whitelist.attributes));
+ }
+
+ if (!whitelist || whitelist.elements) {
+ relativeOffsets.push(
+ ...findInputsOnElementWithTag(templateContent, name.replace, whitelist.elements));
+ }
+
+ relativeOffsets
+ .map(offset => node.getStart() + offset)
+ .map(start => new Replacement(start, name.replace.length, name.replaceWith))
+ .forEach(replacement => replacements.push({replacement, failureMessage}));
+ });
+
+ return replacements;
+ }
+}
diff --git a/src/lib/schematics/update/rules/output-names/outputNamesTemplateRule.ts b/src/lib/schematics/update/rules/output-names/outputNamesTemplateRule.ts
new file mode 100644
index 00000000000..9c146646ec2
--- /dev/null
+++ b/src/lib/schematics/update/rules/output-names/outputNamesTemplateRule.ts
@@ -0,0 +1,76 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {green, red} from 'chalk';
+import {Replacement, RuleFailure, Rules} from 'tslint';
+import * as ts from 'typescript';
+import {findOutputsOnElementWithAttr, findOutputsOnElementWithTag} from '../../html/angular';
+import {outputNames} from '../../material/data/output-names';
+import {ExternalResource} from '../../tslint/component-file';
+import {ComponentWalker} from '../../tslint/component-walker';
+import {
+ addFailureAtReplacement,
+ createExternalReplacementFailure,
+} from '../../tslint/rule-failures';
+
+/**
+ * Rule that walks through every inline or external HTML template and switches changed output
+ * bindings to the proper new output name.
+ */
+export class Rule extends Rules.AbstractRule {
+ apply(sourceFile: ts.SourceFile): RuleFailure[] {
+ return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
+ }
+}
+
+export class Walker extends ComponentWalker {
+
+ visitInlineTemplate(template: ts.StringLiteral) {
+ this._createReplacementsForContent(template, template.getText())
+ .forEach(data => addFailureAtReplacement(this, data.failureMessage, data.replacement));
+ }
+
+ visitExternalTemplate(template: ExternalResource) {
+ this._createReplacementsForContent(template, template.getFullText())
+ .map(data => createExternalReplacementFailure(template, data.failureMessage,
+ this.getRuleName(), data.replacement))
+ .forEach(failure => this.addFailure(failure));
+ }
+
+ /**
+ * Searches for outdated output bindings in the specified content and creates
+ * replacements with the according messages that can be added to a rule failure.
+ */
+ private _createReplacementsForContent(node: ts.Node, templateContent: string) {
+ const replacements: {failureMessage: string, replacement: Replacement}[] = [];
+
+ outputNames.forEach(name => {
+ const whitelist = name.whitelist;
+ const relativeOffsets = [];
+ const failureMessage = `Found deprecated @Output() "${red(name.replace)}"` +
+ ` which has been renamed to "${green(name.replaceWith)}"`;
+
+ if (!whitelist || whitelist.attributes) {
+ relativeOffsets.push(
+ ...findOutputsOnElementWithAttr(templateContent, name.replace, whitelist.attributes));
+ }
+
+ if (!whitelist || whitelist.elements) {
+ relativeOffsets.push(
+ ...findOutputsOnElementWithTag(templateContent, name.replace, whitelist.elements));
+ }
+
+ relativeOffsets
+ .map(offset => node.getStart() + offset)
+ .map(start => new Replacement(start, name.replace.length, name.replaceWith))
+ .forEach(replacement => replacements.push({replacement, failureMessage}));
+ });
+
+ return replacements;
+ }
+}
diff --git a/src/lib/schematics/update/rules/switchStylesheetInputNamesRule.ts b/src/lib/schematics/update/rules/switchStylesheetInputNamesRule.ts
deleted file mode 100644
index 03f3fb3dac9..00000000000
--- a/src/lib/schematics/update/rules/switchStylesheetInputNamesRule.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-import {green, red} from 'chalk';
-import {sync as globSync} from 'glob';
-import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
-import {inputNames} from '../material/data/input-names';
-import {ExternalResource} from '../tslint/component-file';
-import {ComponentWalker} from '../tslint/component-walker';
-import {findAllSubstringIndices} from '../typescript/literal';
-import * as ts from 'typescript';
-
-/**
- * Rule that walks through every component decorator and updates their inline or external
- * stylesheets.
- */
-export class Rule extends Rules.AbstractRule {
- apply(sourceFile: ts.SourceFile): RuleFailure[] {
- return this.applyWithWalker(
- new SwitchStylesheetInputNamesWalker(sourceFile, this.getOptions()));
- }
-}
-
-export class SwitchStylesheetInputNamesWalker extends ComponentWalker {
-
- constructor(sourceFile: ts.SourceFile, options: IOptions) {
- // In some applications, developers will have global stylesheets that are not specified in any
- // Angular component. Therefore we glob up all css and scss files outside of node_modules and
- // dist and check them as well.
- const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
- super(sourceFile, options, extraFiles);
- extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
- }
-
- visitInlineStylesheet(stylesheet: ts.StringLiteral) {
- this.replaceNamesInStylesheet(stylesheet, stylesheet.getText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(stylesheet.getSourceFile(), fix.start, fix.end,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- visitExternalStylesheet(stylesheet: ExternalResource) {
- this.replaceNamesInStylesheet(stylesheet, stylesheet.getFullText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(stylesheet, fix.start + 1, fix.end + 1,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- /**
- * Replaces the outdated name in the stylesheet with the new one and returns an updated
- * stylesheet.
- */
- private replaceNamesInStylesheet(node: ts.Node, stylesheetContent: string):
- {message: string, replacement: Replacement}[] {
- const replacements: {message: string, replacement: Replacement}[] = [];
-
- inputNames.forEach(name => {
- if (!name.whitelist || name.whitelist.css) {
- const bracketedName = {replace: `[${name.replace}]`, replaceWith: `[${name.replaceWith}]`};
- const foundOffsets = findAllSubstringIndices(stylesheetContent, bracketedName.replace);
-
- this.createReplacementsForOffsets(node, name, foundOffsets).forEach(replacement => {
- replacements.push({
- message: `Found deprecated @Input() "${red(name.replace)}" which has been renamed` +
- ` to "${green(name.replaceWith)}"`,
- replacement
- });
- });
- }
- });
-
- return replacements;
- }
-
- private createReplacementsForOffsets(node: ts.Node,
- update: {replace: string, replaceWith: string},
- offsets: number[]): Replacement[] {
- return offsets.map(offset => this.createReplacement(
- node.getStart() + offset, update.replace.length, update.replaceWith));
- }
-}
diff --git a/src/lib/schematics/update/rules/switchStylesheetOutputNamesRule.ts b/src/lib/schematics/update/rules/switchStylesheetOutputNamesRule.ts
deleted file mode 100644
index 868fc67cfd0..00000000000
--- a/src/lib/schematics/update/rules/switchStylesheetOutputNamesRule.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-import {green, red} from 'chalk';
-import {sync as globSync} from 'glob';
-import {IOptions, Replacement, RuleFailure, Rules} from 'tslint';
-import {outputNames} from '../material/data/output-names';
-import {ExternalResource} from '../tslint/component-file';
-import {ComponentWalker} from '../tslint/component-walker';
-import {findAllSubstringIndices} from '../typescript/literal';
-import * as ts from 'typescript';
-
-/**
- * Rule that walks through every component decorator and updates their inline or external
- * stylesheets.
- */
-export class Rule extends Rules.AbstractRule {
- apply(sourceFile: ts.SourceFile): RuleFailure[] {
- return this.applyWithWalker(
- new SwitchStylesheetOutputNamesWalker(sourceFile, this.getOptions()));
- }
-}
-
-export class SwitchStylesheetOutputNamesWalker extends ComponentWalker {
-
- constructor(sourceFile: ts.SourceFile, options: IOptions) {
- // In some applications, developers will have global stylesheets that are not specified in any
- // Angular component. Therefore we glob up all css and scss files outside of node_modules and
- // dist and check them as well.
- const extraFiles = globSync('!(node_modules|dist)/**/*.+(css|scss)');
- super(sourceFile, options, extraFiles);
- extraFiles.forEach(styleUrl => this._reportExternalStyle(styleUrl));
- }
-
- visitInlineStylesheet(stylesheet: ts.StringLiteral) {
- this.replaceNamesInStylesheet(stylesheet, stylesheet.getText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(stylesheet.getSourceFile(), fix.start, fix.end,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- visitExternalStylesheet(stylesheet: ExternalResource) {
- this.replaceNamesInStylesheet(stylesheet, stylesheet.getFullText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(stylesheet, fix.start + 1, fix.end + 1,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- /**
- * Replaces the outdated name in the stylesheet with the new one and returns an updated
- * stylesheet.
- */
- private replaceNamesInStylesheet(node: ts.Node, stylesheetContent: string):
- {message: string, replacement: Replacement}[] {
- const replacements: {message: string, replacement: Replacement}[] = [];
-
- outputNames.forEach(name => {
- if (!name.whitelist || name.whitelist.css) {
- const bracketedName = {replace: `[${name.replace}]`, replaceWith: `[${name.replaceWith}]`};
- const foundOffsets = findAllSubstringIndices(stylesheetContent, bracketedName.replace);
-
- this.createReplacementsForOffsets(node, name, foundOffsets).forEach(replacement => {
- replacements.push({
- message: `Found deprecated @Output() "${red(name.replace)}" which has been` +
- ` renamed to "${green(name.replaceWith)}"`,
- replacement
- });
- });
- }
- });
-
- return replacements;
- }
-
- private createReplacementsForOffsets(node: ts.Node,
- update: {replace: string, replaceWith: string},
- offsets: number[]): Replacement[] {
- return offsets.map(offset => this.createReplacement(
- node.getStart() + offset, update.replace.length, update.replaceWith));
- }
-}
diff --git a/src/lib/schematics/update/rules/switchTemplateInputNamesRule.ts b/src/lib/schematics/update/rules/switchTemplateInputNamesRule.ts
deleted file mode 100644
index c3e97c5b2bb..00000000000
--- a/src/lib/schematics/update/rules/switchTemplateInputNamesRule.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-import {green, red} from 'chalk';
-import {Replacement, RuleFailure, Rules} from 'tslint';
-import * as ts from 'typescript';
-import {findInputsOnElementWithAttr, findInputsOnElementWithTag} from '../html/angular';
-import {inputNames} from '../material/data/input-names';
-import {ExternalResource} from '../tslint/component-file';
-import {ComponentWalker} from '../tslint/component-walker';
-import {findAllSubstringIndices} from '../typescript/literal';
-
-/**
- * Rule that walks through every component decorator and updates their inline or external
- * templates.
- */
-export class Rule extends Rules.AbstractRule {
- apply(sourceFile: ts.SourceFile): RuleFailure[] {
- return this.applyWithWalker(new SwitchTemplateInputNamesWalker(sourceFile, this.getOptions()));
- }
-}
-
-export class SwitchTemplateInputNamesWalker extends ComponentWalker {
- visitInlineTemplate(template: ts.StringLiteral) {
- this.replaceNamesInTemplate(template, template.getText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(template.getSourceFile(), fix.start, fix.end,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- visitExternalTemplate(template: ExternalResource) {
- this.replaceNamesInTemplate(template, template.getFullText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(template, fix.start + 1, fix.end + 1,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- /**
- * Replaces the outdated name in the template with the new one and returns an updated template.
- */
- private replaceNamesInTemplate(node: ts.Node, templateContent: string):
- {message: string, replacement: Replacement}[] {
- const replacements: {message: string, replacement: Replacement}[] = [];
-
- inputNames.forEach(name => {
- let offsets: number[] = [];
- if (name.whitelist && name.whitelist.attributes && name.whitelist.attributes.length) {
- offsets = offsets.concat(findInputsOnElementWithAttr(
- templateContent, name.replace, name.whitelist.attributes));
- }
- if (name.whitelist && name.whitelist.elements && name.whitelist.elements.length) {
- offsets = offsets.concat(findInputsOnElementWithTag(
- templateContent, name.replace, name.whitelist.elements));
- }
- if (!name.whitelist) {
- offsets = offsets.concat(findAllSubstringIndices(templateContent, name.replace));
- }
- this.createReplacementsForOffsets(node, name, offsets).forEach(replacement => {
- replacements.push({
- message: `Found deprecated @Input() "${red(name.replace)}" which has been renamed to` +
- ` "${green(name.replaceWith)}"`,
- replacement
- });
- });
- });
-
- return replacements;
- }
-
- private createReplacementsForOffsets(node: ts.Node,
- update: {replace: string, replaceWith: string},
- offsets: number[]): Replacement[] {
- return offsets.map(offset => this.createReplacement(
- node.getStart() + offset, update.replace.length, update.replaceWith));
- }
-}
diff --git a/src/lib/schematics/update/rules/switchTemplateOutputNamesRule.ts b/src/lib/schematics/update/rules/switchTemplateOutputNamesRule.ts
deleted file mode 100644
index 7e77b9d4b7f..00000000000
--- a/src/lib/schematics/update/rules/switchTemplateOutputNamesRule.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * @license
- * Copyright Google LLC All Rights Reserved.
- *
- * Use of this source code is governed by an MIT-style license that can be
- * found in the LICENSE file at https://angular.io/license
- */
-
-import {green, red} from 'chalk';
-import {Replacement, RuleFailure, Rules} from 'tslint';
-import * as ts from 'typescript';
-import {findOutputsOnElementWithAttr, findOutputsOnElementWithTag} from '../html/angular';
-import {outputNames} from '../material/data/output-names';
-import {ExternalResource} from '../tslint/component-file';
-import {ComponentWalker} from '../tslint/component-walker';
-import {findAllSubstringIndices} from '../typescript/literal';
-
-/**
- * Rule that walks through every component decorator and updates their inline or external
- * templates.
- */
-export class Rule extends Rules.AbstractRule {
- apply(sourceFile: ts.SourceFile): RuleFailure[] {
- return this.applyWithWalker(new SwitchTemplateOutputNamesWalker(sourceFile, this.getOptions()));
- }
-}
-
-export class SwitchTemplateOutputNamesWalker extends ComponentWalker {
- visitInlineTemplate(template: ts.StringLiteral) {
- this.replaceNamesInTemplate(template, template.getText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(template.getSourceFile(), fix.start, fix.end,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- visitExternalTemplate(template: ExternalResource) {
- this.replaceNamesInTemplate(template, template.getFullText()).forEach(replacement => {
- const fix = replacement.replacement;
- const ruleFailure = new RuleFailure(template, fix.start + 1, fix.end + 1,
- replacement.message, this.getRuleName(), fix);
- this.addFailure(ruleFailure);
- });
- }
-
- /**
- * Replaces the outdated name in the template with the new one and returns an updated template.
- */
- private replaceNamesInTemplate(node: ts.Node, templateContent: string):
- {message: string, replacement: Replacement}[] {
- const replacements: {message: string, replacement: Replacement}[] = [];
-
- outputNames.forEach(name => {
- let offsets: number[] = [];
- if (name.whitelist && name.whitelist.attributes && name.whitelist.attributes.length) {
- offsets = offsets.concat(findOutputsOnElementWithAttr(
- templateContent, name.replace, name.whitelist.attributes));
- }
- if (name.whitelist && name.whitelist.elements && name.whitelist.elements.length) {
- offsets = offsets.concat(findOutputsOnElementWithTag(
- templateContent, name.replace, name.whitelist.elements));
- }
- if (!name.whitelist) {
- offsets = offsets.concat(findAllSubstringIndices(templateContent, name.replace));
- }
- this.createReplacementsForOffsets(node, name, offsets).forEach(replacement => {
- replacements.push({
- message: `Found deprecated @Output() "${red(name.replace)}" which has been renamed to` +
- ` "${green(name.replaceWith)}"`,
- replacement
- });
- });
- });
-
- return replacements;
- }
-
- private createReplacementsForOffsets(node: ts.Node,
- update: {replace: string, replaceWith: string},
- offsets: number[]): Replacement[] {
- return offsets.map(offset => this.createReplacement(
- node.getStart() + offset, update.replace.length, update.replaceWith));
- }
-}
diff --git a/src/lib/schematics/update/test-cases/index.spec.ts b/src/lib/schematics/update/test-cases/index.spec.ts
index 398c9ea95c1..59fe0ff15ad 100644
--- a/src/lib/schematics/update/test-cases/index.spec.ts
+++ b/src/lib/schematics/update/test-cases/index.spec.ts
@@ -16,9 +16,11 @@ describe('test cases', () => {
*/
const testCases = [
'v5/attribute-selectors',
+ 'v5/class-names',
'v5/css-names',
'v5/element-selectors',
- 'v5/ts-class-names',
+ 'v5/input-names',
+ 'v5/output-names',
];
// Iterates through every test case directory and generates a jasmine test block that will
diff --git a/src/lib/schematics/update/test-cases/v5/ts-class-names_expected_output.ts b/src/lib/schematics/update/test-cases/v5/class-names_expected_output.ts
similarity index 100%
rename from src/lib/schematics/update/test-cases/v5/ts-class-names_expected_output.ts
rename to src/lib/schematics/update/test-cases/v5/class-names_expected_output.ts
diff --git a/src/lib/schematics/update/test-cases/v5/ts-class-names_input.ts b/src/lib/schematics/update/test-cases/v5/class-names_input.ts
similarity index 100%
rename from src/lib/schematics/update/test-cases/v5/ts-class-names_input.ts
rename to src/lib/schematics/update/test-cases/v5/class-names_input.ts
diff --git a/src/lib/schematics/update/test-cases/v5/input-names_expected_output.ts b/src/lib/schematics/update/test-cases/v5/input-names_expected_output.ts
new file mode 100644
index 00000000000..636868b67a7
--- /dev/null
+++ b/src/lib/schematics/update/test-cases/v5/input-names_expected_output.ts
@@ -0,0 +1,62 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+ `
+})
+class A {}
+
+@Component({
+ template: `
+
+
+
+
+
+ `
+})
+class B {}
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class C {}
+
+@Component({
+ template: `
+
+
+
+
+ `
+})
+class D {}
+
+@Component({
+ template: `
+
+
+
+
+
+ `
+})
+class E {}
diff --git a/src/lib/schematics/update/test-cases/v5/input-names_input.ts b/src/lib/schematics/update/test-cases/v5/input-names_input.ts
new file mode 100644
index 00000000000..02e8721ec59
--- /dev/null
+++ b/src/lib/schematics/update/test-cases/v5/input-names_input.ts
@@ -0,0 +1,62 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+ `
+})
+class A {}
+
+@Component({
+ template: `
+
+
+
+
+
+ `
+})
+class B {}
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class C {}
+
+@Component({
+ template: `
+
+
+
+
+ `
+})
+class D {}
+
+@Component({
+ template: `
+
+
+
+
+
+ `
+})
+class E {}
diff --git a/src/lib/schematics/update/test-cases/v5/output-names_expected_output.ts b/src/lib/schematics/update/test-cases/v5/output-names_expected_output.ts
new file mode 100644
index 00000000000..fbe33bac905
--- /dev/null
+++ b/src/lib/schematics/update/test-cases/v5/output-names_expected_output.ts
@@ -0,0 +1,29 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class A {}
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class B {}
+
+@Component({
+ template: `
+
+
+
+
+ `
+})
+class C {}
diff --git a/src/lib/schematics/update/test-cases/v5/output-names_input.ts b/src/lib/schematics/update/test-cases/v5/output-names_input.ts
new file mode 100644
index 00000000000..4143ab9b957
--- /dev/null
+++ b/src/lib/schematics/update/test-cases/v5/output-names_input.ts
@@ -0,0 +1,29 @@
+import {Component} from '@angular/core';
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class A {}
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class B {}
+
+@Component({
+ template: `
+
+
+
+
+ `
+})
+class C {}
diff --git a/src/lib/schematics/update/update.ts b/src/lib/schematics/update/update.ts
index c4839ef36b2..f739d970804 100644
--- a/src/lib/schematics/update/update.ts
+++ b/src/lib/schematics/update/update.ts
@@ -31,15 +31,13 @@ export default function(): Rule {
path.join(__dirname, 'rules/attribute-selectors'),
path.join(__dirname, 'rules/class-names'),
path.join(__dirname, 'rules/css-names'),
+ path.join(__dirname, 'rules/input-names'),
+ path.join(__dirname, 'rules/output-names'),
],
rules: {
// Automatic fixes.
'switch-property-names': true,
- 'switch-stylesheet-input-names': true,
- 'switch-stylesheet-output-names': true,
'switch-template-export-as-names': true,
- 'switch-template-input-names': true,
- 'switch-template-output-names': true,
// Attribute selector update rules.
'attribute-selectors-string-literal': true,
@@ -60,6 +58,13 @@ export default function(): Rule {
'element-selectors-stylesheet': true,
'element-selectors-template': true,
+ // Input name update rules
+ 'input-names-stylesheet': true,
+ 'input-names-template': true,
+
+ // Output name update rules
+ 'output-names-template': true,
+
// Additional issues we can detect but not automatically fix.
'check-class-declaration-misc': true,
'check-import-misc': true,