Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
* A glob string needs to be transferred from the CLI process to the child process of TSLint.
* This is the environment variable, which will be set if the `--extra-stylesheets` option is set.
*/
export const EXTRA_STYLESHEETS_GLOB_KEY = 'MD_EXTRA_STYLESHEETS_GLOB';
/**
* Message that is being sent to TSLint if there is something in the stylesheet that still use an
* outdated prefix.
*/
const failureMessage = 'Stylesheet uses outdated Material prefix.';
/**
* 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 SwitchStylesheetsWalker(sourceFile, this.getOptions()));
}
}
export class SwitchStylesheetsWalker extends ComponentWalker {
constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);
// This is a special feature. In some applications, developers will have global stylesheets
// that are not specified in any Angular component. Those stylesheets can be also migrated
// if the developer specifies the `--extra-stylesheets` option which accepts a glob for files.
if (process.env[EXTRA_STYLESHEETS_GLOB_KEY]) {
process.env[EXTRA_STYLESHEETS_GLOB_KEY].split(' ')
'When a dt-radio-button does not contain any content it must have an aria-label or an aria-labelledby attribute.',
);
}
}
/**
* The dtRadioButtonAltTextRule ensures that a radio button always has a text or an aria-label as alternative.
*
* The following example passes the lint checks:
* Aberfeldy
*
*
* For the following example the linter throws errors:
*
*/
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description:
'Ensures that a radio button always contains content or an aria-label as alternative.',
// tslint:disable-next-line:no-null-keyword
options: null,
optionsDescription: 'Not configurable.',
rationale:
'A radio button without content must have an aria-label or aria-labelledby attribute.',
ruleName: 'dt-radio-button-no-empty',
type: 'maintainability',
typescriptOnly: true,
};
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
/**
* The dtRadioButtonRequiresNameRule ensures that a radio button has a name when not part of a radio group.
*
* The following example passes the lint checks:
*
* Aberfeldy
* Dalmore
*
*
* Dalmore
*
* For the following example the linter throws errors:
* Radio button value
*/
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description:
'Ensures that a radio button has a name attribute when not part of a radiogroup.',
// tslint:disable-next-line:no-null-keyword
options: null,
optionsDescription: 'Not configurable.',
rationale:
'A radio button that is not part of a radio group must have a name attribute.',
ruleName: 'dt-radio-button-requires-name',
type: 'maintainability',
typescriptOnly: true,
};
apply(sourceFile: SourceFile): RuleFailure[] {
const result = this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
*
* No Coffee (Triggers an error)
* ThePerfectPour
* Affogato
* Americano
*
*
*
* For the following example the linter throws errors:
*
* ThePerfectPour
* Affogato
* // ...
*
*/
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description:
'Ensures that a label or text alternatives are given for a dt-select.',
// tslint:disable-next-line:no-null-keyword
options: null,
optionsDescription: 'Not configurable.',
rationale:
'A dt-select must have a label when used with the form field component or an aria-label or aria-labelledby attribute.',
ruleName: 'dt-select-requires-label',
type: 'maintainability',
typescriptOnly: true,
};
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
/**
* The dtShowMoreNoEmpty ensures that a dt-show-more always contains content.
*
* The following examples pass the check:
*
* Show more
* Show less
*
*
*
* For the following example the linter throws an error:
*
* Show less
*
*/
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description:
'Ensures that a dt-show-more always contains content or a text alternative.',
// tslint:disable-next-line:no-null-keyword
options: null,
optionsDescription: 'Not configurable.',
rationale:
'A dt-show-more must always contain content apart from the dt-show-less-label or a text alternative.',
ruleName: 'dt-show-more-no-empty',
type: 'maintainability',
typescriptOnly: true,
};
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
*
* ...
*
*
* ...
*
*
*
* For the following examples the linter throws errors:
*
*
* ...
*
*
*/
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description: 'Ensures that a dt-tab-group contains at least two tabs.',
// tslint:disable-next-line:no-null-keyword
options: null,
optionsDescription: 'Not configurable.',
rationale: 'A dt-tab-group must always contain at least two tabs.',
ruleName: 'dt-tab-group-requires-tabs',
type: 'maintainability',
typescriptOnly: true,
};
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithWalker(
new NgWalker(sourceFile, this.getOptions(), {
templateVisitorCtrl: DtTabGroupVisitor,
}),
* 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) {
/** Regular expression that matches [matRippleSpeedFactor]="$NOT_A_NUMBER" in templates. */
const speedFactorNotParseable = /\[matRippleSpeedFactor]="(?!\d+(?:\.\d+)?")(.*)"/g;
/** Failure message that will be shown if a speed factor is set to a readable number. */
const failureMessageReadableNumber =
'Detected deprecated [matRippleSpeedFactor] input binding with readable number.';
/** Failure message that will be shown if a speed factor is set to a non-parseable value. */
const failureMessageNonParseableValue =
'Detected deprecated [matRippleSpeedFactor] input binding with non-parseable value.';
/**
* Rule that walks through every inline or external template and updates the deprecated
* [matRippleSpeedFactor] to [matRippleAnimation].
*/
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(node: ts.StringLiteralLike) {
this._createReplacementsForContent(node, node.getText()).forEach(data => {
this.addFailureAtReplacement(data.failureMessage, data.replacement);
});
}
visitExternalTemplate(node: ExternalResource) {
this._createReplacementsForContent(node, node.getText()).forEach(data => {
this.addExternalFailureAtReplacement(node, data.failureMessage, data.replacement);
* 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 {CssSelectorUpgradeData} from '../../data/css-selectors';
import {findAllSubstringIndices} from '../../typescript/literal';
import {getUpgradeDataFromWalker} from '../../upgrade-data';
/**
* Rule that walks through every string literal that is wrapped inside of a call expression.
* All string literals which include an outdated CSS selector 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 {
/** Change data that upgrades to the specified target version. */
data = getUpgradeDataFromWalker(this, 'cssSelectors');
visitStringLiteral(node: ts.StringLiteral) {
if (node.parent && node.parent.kind !== ts.SyntaxKind.CallExpression) {
return;
}
const textContent = node.getText();
import {green, red} from 'chalk';
import {Replacement, RuleFailure, Rules} from 'tslint';
import * as ts from 'typescript';
import {AttributeSelectorUpgradeData} from '../../data';
import {ExternalResource} from '../../tslint/component-file';
import {ComponentWalker} from '../../tslint/component-walker';
import {findAllSubstringIndices} from '../../typescript/literal';
import {getUpgradeDataFromWalker} from '../../upgrade-data';
/**
* Rule that walks through every component template and switches outdated attribute
* selectors to the updated selector.
*/
export class Rule extends Rules.AbstractRule {
apply(sourceFile: ts.SourceFile): RuleFailure[] {
return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
}
}
export class Walker extends ComponentWalker {
/** Change data that upgrades to the specified target version. */
data: AttributeSelectorUpgradeData[] = getUpgradeDataFromWalker(this, 'attributeSelectors');
visitInlineTemplate(node: ts.StringLiteralLike) {
this._createReplacementsForContent(node, node.getText()).forEach(data => {
this.addFailureAtReplacement(data.failureMessage, data.replacement);
});
}