diff --git a/src/lib/schematics/update/material/data/css-names.ts b/src/lib/schematics/update/material/data/css-names.ts index 491f1f7f167e..ba5b274ffb9e 100644 --- a/src/lib/schematics/update/material/data/css-names.ts +++ b/src/lib/schematics/update/material/data/css-names.ts @@ -15,8 +15,8 @@ export interface MaterialCssNameData { replaceWith: string; /** Whitelist where this replacement is made. If omitted it is made in all files. */ whitelist?: { - /** Replace this name in CSS files. */ - css?: boolean, + /** Replace this name in stylesheet files. */ + stylesheet?: boolean, /** Replace this name in HTML files. */ html?: boolean, /** Replace this name in TypeScript strings. */ @@ -32,10 +32,6 @@ export const cssNames = transformChanges([ replace: 'mat-form-field-placeholder', replaceWith: 'mat-form-field-label' }, - { - replace: 'mat-form-field-placeholder-wrapper', - replaceWith: 'mat-form-field-label-wrapper' - }, { replace: 'mat-input-container', replaceWith: 'mat-form-field' @@ -96,13 +92,13 @@ export const cssNames = transformChanges([ }, { - pr: 'https://github.com/angular/material2/pull/10325', + pr: 'https://github.com/angular/material2/pull/10430', changes: [ { replace: '$mat-font-family', replaceWith: "Roboto, 'Helvetica Neue', sans-serif", whitelist: { - css: true + stylesheet: true } } ] diff --git a/src/lib/schematics/update/rules/checkIdentifierMiscRule.ts b/src/lib/schematics/update/rules/class-names/classNamesIdentifierMiscRule.ts similarity index 64% rename from src/lib/schematics/update/rules/checkIdentifierMiscRule.ts rename to src/lib/schematics/update/rules/class-names/classNamesIdentifierMiscRule.ts index eea5b20b6ce7..9278436f0bb6 100644 --- a/src/lib/schematics/update/rules/checkIdentifierMiscRule.ts +++ b/src/lib/schematics/update/rules/class-names/classNamesIdentifierMiscRule.ts @@ -7,21 +7,22 @@ */ import {bold, red} from 'chalk'; -import {ProgramAwareRuleWalker, RuleFailure, Rules} from 'tslint'; +import {RuleFailure, Rules, RuleWalker} from 'tslint'; import * as ts from 'typescript'; /** - * Rule that walks through every identifier that is part of Angular Material and replaces the - * outdated name with the new one. + * Rule that looks for class name identifiers that have been removed but cannot be + * automatically migrated. */ -export class Rule extends Rules.TypedRule { - applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] { - return this.applyWithWalker( - new CheckIdentifierMiscWalker(sourceFile, this.getOptions(), program)); +export class Rule extends Rules.AbstractRule { + + apply(sourceFile: ts.SourceFile): RuleFailure[] { + return this.applyWithWalker(new Walker(sourceFile, this.getOptions())); } } -export class CheckIdentifierMiscWalker extends ProgramAwareRuleWalker { +export class Walker extends RuleWalker { + visitIdentifier(identifier: ts.Identifier) { if (identifier.getText() === 'MatDrawerToggleResult') { this.addFailureAtNode( diff --git a/src/lib/schematics/update/rules/switchIdentifiersRule.ts b/src/lib/schematics/update/rules/class-names/classNamesIdentifierRule.ts similarity index 93% rename from src/lib/schematics/update/rules/switchIdentifiersRule.ts rename to src/lib/schematics/update/rules/class-names/classNamesIdentifierRule.ts index 215e920a2e42..60cfe99904c0 100644 --- a/src/lib/schematics/update/rules/switchIdentifiersRule.ts +++ b/src/lib/schematics/update/rules/class-names/classNamesIdentifierRule.ts @@ -9,16 +9,16 @@ import {green, red} from 'chalk'; import {RuleFailure, Rules, RuleWalker} from 'tslint'; import * as ts from 'typescript'; -import {classNames} from '../material/data/class-names'; +import {classNames} from '../../material/data/class-names'; import { isMaterialExportDeclaration, isMaterialImportDeclaration, -} from '../material/typescript-specifiers'; +} from '../../material/typescript-specifiers'; import { isExportSpecifierNode, isImportSpecifierNode, isNamespaceImportNode, -} from '../typescript/imports'; +} from '../../typescript/imports'; /** * Rule that walks through every identifier that is part of Angular Material and replaces the @@ -27,11 +27,11 @@ import { export class Rule extends Rules.AbstractRule { apply(sourceFile: ts.SourceFile): RuleFailure[] { - return this.applyWithWalker(new SwitchIdentifiersWalker(sourceFile, this.getOptions())); + return this.applyWithWalker(new Walker(sourceFile, this.getOptions())); } } -export class SwitchIdentifiersWalker extends RuleWalker { +export class Walker extends RuleWalker { /** * List of identifier names that have been imported from `@angular/material` or `@angular/cdk` diff --git a/src/lib/schematics/update/rules/css-names/cssNamesStringLiteralRule.ts b/src/lib/schematics/update/rules/css-names/cssNamesStringLiteralRule.ts new file mode 100644 index 000000000000..6d9eacbc13f4 --- /dev/null +++ b/src/lib/schematics/update/rules/css-names/cssNamesStringLiteralRule.ts @@ -0,0 +1,52 @@ +/** + * @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, RuleWalker} from 'tslint'; +import * as ts from 'typescript'; +import {cssNames, MaterialCssNameData} from '../../material/data/css-names'; +import {findAllSubstringIndices} from '../../typescript/literal'; + +/** + * Rule that walks through every string literal that is wrapped inside of a call expression. + * All string literals which include an outdated CSS class name will be migrated. + */ +export class Rule extends Rules.AbstractRule { + apply(sourceFile: ts.SourceFile): RuleFailure[] { + return this.applyWithWalker(new Walker(sourceFile, this.getOptions())); + } +} + +export class Walker extends RuleWalker { + + visitStringLiteral(node: ts.StringLiteral) { + if (node.parent && node.parent.kind !== ts.SyntaxKind.CallExpression) { + return; + } + + const textContent = node.getFullText(); + + cssNames.forEach(name => { + if (name.whitelist && !name.whitelist.strings) { + return; + } + + findAllSubstringIndices(textContent, name.replace) + .map(offset => node.getStart() + offset) + .map(start => new Replacement(start, name.replace.length, name.replaceWith)) + .forEach(replacement => this._addFailureWithReplacement(node, replacement, name)); + }); + } + + /** Adds a css name failure with the given replacement at the specified node. */ + private _addFailureWithReplacement(node: ts.Node, replacement: Replacement, + name: MaterialCssNameData) { + this.addFailureAtNode(node, `Found deprecated CSS class "${red(name.replace)}" which has ` + + `been renamed to "${green(name.replaceWith)}"`, replacement); + } +} diff --git a/src/lib/schematics/update/rules/css-names/cssNamesStylesheetRule.ts b/src/lib/schematics/update/rules/css-names/cssNamesStylesheetRule.ts new file mode 100644 index 000000000000..a92927b6317a --- /dev/null +++ b/src/lib/schematics/update/rules/css-names/cssNamesStylesheetRule.ts @@ -0,0 +1,79 @@ +/** + * @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 {cssNames} from '../../material/data/css-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 CSs stylesheet and updates outdated + * CSS classes. + */ +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 CSs classes 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}[] = []; + + cssNames.forEach(name => { + if (name.whitelist && !name.whitelist.stylesheet) { + return; + } + + const failureMessage = `Found deprecated CSS class "${red(name.replace)}" ` + + `which has been renamed to "${green(name.replaceWith)}"`; + + findAllSubstringIndices(stylesheetContent, name.replace) + .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/css-names/cssNamesTemplateRule.ts b/src/lib/schematics/update/rules/css-names/cssNamesTemplateRule.ts new file mode 100644 index 000000000000..6e9dee997749 --- /dev/null +++ b/src/lib/schematics/update/rules/css-names/cssNamesTemplateRule.ts @@ -0,0 +1,68 @@ +/** + * @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 {cssNames} from '../../material/data/css-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 HTML template and updates outdated + * CSS classes. + */ +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 css names 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}[] = []; + + cssNames.forEach(selector => { + if (selector.whitelist && !selector.whitelist.html) { + return; + } + + const failureMessage = `Found deprecated CSS class "${red(selector.replace)}"` + + ` which has been renamed to "${green(selector.replaceWith)}"`; + + findAllSubstringIndices(templateContent, selector.replace) + .map(offset => node.getStart() + offset) + .map(start => new Replacement(start, selector.replace.length, selector.replaceWith)) + .forEach(replacement => replacements.push({replacement, failureMessage})); + }); + + return replacements; + } +} diff --git a/src/lib/schematics/update/rules/switchStringLiteralCssNamesRule.ts b/src/lib/schematics/update/rules/switchStringLiteralCssNamesRule.ts deleted file mode 100644 index f0b966ce909a..000000000000 --- a/src/lib/schematics/update/rules/switchStringLiteralCssNamesRule.ts +++ /dev/null @@ -1,54 +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, RuleWalker} from 'tslint'; -import * as ts from 'typescript'; -import {cssNames} from '../material/data/css-names'; -import {findAllSubstringIndices} from '../typescript/literal'; - -/** - * Rule that walks through every string literal, which includes the outdated Material name and - * is part of a call expression. Those string literals will be changed to the new name. - */ -export class Rule extends Rules.AbstractRule { - apply(sourceFile: ts.SourceFile): RuleFailure[] { - return this.applyWithWalker( - new SwitchStringLiteralCssNamesWalker(sourceFile, this.getOptions())); - } -} - -export class SwitchStringLiteralCssNamesWalker extends RuleWalker { - visitStringLiteral(stringLiteral: ts.StringLiteral) { - if (stringLiteral.parent && stringLiteral.parent.kind !== ts.SyntaxKind.CallExpression) { - return; - } - - let stringLiteralText = stringLiteral.getFullText(); - - cssNames.forEach(name => { - if (!name.whitelist || name.whitelist.strings) { - this.createReplacementsForOffsets(stringLiteral, name, - findAllSubstringIndices(stringLiteralText, name.replace)).forEach(replacement => { - this.addFailureAtNode( - stringLiteral, - `Found deprecated CSS class "${red(name.replace)}" which has been renamed to` + - ` "${green(name.replaceWith)}"`, - replacement); - }); - } - }); - } - - 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/switchStylesheetCssNamesRule.ts b/src/lib/schematics/update/rules/switchStylesheetCssNamesRule.ts deleted file mode 100644 index 1ff4f664180e..000000000000 --- a/src/lib/schematics/update/rules/switchStylesheetCssNamesRule.ts +++ /dev/null @@ -1,88 +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 * as ts from 'typescript'; -import {cssNames} from '../material/data/css-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 - * stylesheets. - */ -export class Rule extends Rules.AbstractRule { - apply(sourceFile: ts.SourceFile): RuleFailure[] { - return this.applyWithWalker(new SwitchStylesheetCssNamesWalker(sourceFile, this.getOptions())); - } -} - -export class SwitchStylesheetCssNamesWalker 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}[] = []; - - cssNames.forEach(name => { - if (!name.whitelist || name.whitelist.css) { - const foundOffsets = findAllSubstringIndices(stylesheetContent, name.replace); - - this.createReplacementsForOffsets(node, name, foundOffsets).forEach(replacement => { - replacements.push({ - message: `Found CSS class "${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/switchTemplateCssNamesRule.ts b/src/lib/schematics/update/rules/switchTemplateCssNamesRule.ts deleted file mode 100644 index c9e2e8c7c85c..000000000000 --- a/src/lib/schematics/update/rules/switchTemplateCssNamesRule.ts +++ /dev/null @@ -1,76 +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 {cssNames} from '../material/data/css-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 SwitchTemplateCaaNamesWalker(sourceFile, this.getOptions())); - } -} - -export class SwitchTemplateCaaNamesWalker 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}[] = []; - - cssNames.forEach(name => { - if (!name.whitelist || name.whitelist.html) { - const foundOffsets = findAllSubstringIndices(templateContent, name.replace); - - this.createReplacementsForOffsets(node, name, foundOffsets).forEach(replacement => { - replacements.push({ - message: `Found deprecated CSS class "${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 1b75b9407c0b..41b8701fe7fe 100644 --- a/src/lib/schematics/update/test-cases/index.spec.ts +++ b/src/lib/schematics/update/test-cases/index.spec.ts @@ -16,6 +16,7 @@ describe('test cases', () => { */ const testCases = [ 'v5/attribute-selectors', + 'v5/css-names', 'v5/ts-class-names', ]; diff --git a/src/lib/schematics/update/test-cases/v5/css-names_expected_output.ts b/src/lib/schematics/update/test-cases/v5/css-names_expected_output.ts new file mode 100644 index 000000000000..924790c213fd --- /dev/null +++ b/src/lib/schematics/update/test-cases/v5/css-names_expected_output.ts @@ -0,0 +1,48 @@ +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; + +const a = By.css('.mat-form-field-label'); +const b = By.css('.mat-form-field-label-wrapper'); +const c = By.css('.mat-form-field'); +const d = By.css('.mat-form-field-flex'); +const e = By.css('.mat-form-field-hint-spacer'); + +@Component({ + template: ` + +
Content
+ + + ` +}) +class F {} + +@Component({ + styles: [` + .mat-form-field-subscript-wrapper { + flex-direction: row; + } + .mat-form-field .mat-form-field-label { + color: lightcoral; + } + `] +}) +class G {} + +@Component({ + // Considering this is SCSS that will be transformed by Webpack loaders. + styles: [` + body, html { + font-family: Roboto, 'Helvetica Neue', sans-serif; + } + `] +}) +class H {} diff --git a/src/lib/schematics/update/test-cases/v5/css-names_input.ts b/src/lib/schematics/update/test-cases/v5/css-names_input.ts new file mode 100644 index 000000000000..6fe3d21e4b74 --- /dev/null +++ b/src/lib/schematics/update/test-cases/v5/css-names_input.ts @@ -0,0 +1,48 @@ +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; + +const a = By.css('.mat-form-field-placeholder'); +const b = By.css('.mat-form-field-placeholder-wrapper'); +const c = By.css('.mat-input-container'); +const d = By.css('.mat-input-flex'); +const e = By.css('.mat-input-hint-spacer'); + +@Component({ + template: ` + +
Content
+ + + ` +}) +class F {} + +@Component({ + styles: [` + .mat-input-subscript-wrapper { + flex-direction: row; + } + .mat-input-container .mat-input-placeholder { + color: lightcoral; + } + `] +}) +class G {} + +@Component({ + // Considering this is SCSS that will be transformed by Webpack loaders. + styles: [` + body, html { + font-family: $mat-font-family; + } + `] +}) +class H {} diff --git a/src/lib/schematics/update/update.ts b/src/lib/schematics/update/update.ts index e15f91cfa1b7..c7c0e092880b 100644 --- a/src/lib/schematics/update/update.ts +++ b/src/lib/schematics/update/update.ts @@ -29,18 +29,16 @@ export default function(): Rule { rulesDirectory: [ path.join(__dirname, 'rules/'), path.join(__dirname, 'rules/attribute-selectors'), + path.join(__dirname, 'rules/class-names'), + path.join(__dirname, 'rules/css-names'), ], rules: { // Automatic fixes. - 'switch-identifiers': true, 'switch-property-names': true, - 'switch-string-literal-css-names': true, 'switch-string-literal-element-selectors': true, - 'switch-stylesheet-css-names': true, 'switch-stylesheet-element-selectors': true, 'switch-stylesheet-input-names': true, 'switch-stylesheet-output-names': true, - 'switch-template-css-names': true, 'switch-template-element-selectors': true, 'switch-template-export-as-names': true, 'switch-template-input-names': true, @@ -51,9 +49,17 @@ export default function(): Rule { 'attribute-selectors-stylesheet': true, 'attribute-selectors-template': true, + // Class name update rules + 'class-names-identifier': true, + 'class-names-identifier-misc': true, + + // CSS class name update rules + 'css-names-string-literal': true, + 'css-names-stylesheet': true, + 'css-names-template': 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,