Skip to content
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

fix(compiler-cli): improve the missingControlFlowDirective message #46846

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -15,14 +15,18 @@ import {NgTemplateDiagnostic} from '../../../api';
import {TemplateCheckFactory, TemplateCheckWithVisitor, TemplateContext} from '../../api';

/**
* The list of known control flow directives present in the `CommonModule`.
* The list of known control flow directives present in the `CommonModule`,
* and their corresponding imports.
*
* Note: there is no `ngSwitch` here since it's typically used as a regular
* binding (e.g. `[ngSwitch]`), however the `ngSwitchCase` and `ngSwitchDefault`
* are used as structural directives and a warning would be generated. Once the
* `CommonModule` is included, the `ngSwitch` would also be covered.
*/
const KNOWN_CONTROL_FLOW_DIRECTIVES = new Set(['ngIf', 'ngFor', 'ngSwitchCase', 'ngSwitchDefault']);
export const KNOWN_CONTROL_FLOW_DIRECTIVES = new Map([
['ngIf', 'NgIf'], ['ngFor', 'NgForOf'], ['ngSwitchCase', 'NgSwitchCase'],
['ngSwitchDefault', 'NgSwitchDefault']
]);

/**
* Ensures that there are no known control flow directives (such as *ngIf and *ngFor)
Expand Down Expand Up @@ -64,9 +68,14 @@ class MissingControlFlowDirectiveCheck extends
}

const sourceSpan = controlFlowAttr.keySpan || controlFlowAttr.sourceSpan;
const errorMessage = `The \`*${controlFlowAttr.name}\` directive was used in the template, ` +
`but the \`CommonModule\` was not imported. Please make sure that the \`CommonModule\` ` +
`is included into the \`@Component.imports\` array of this component.`;
const correspondingImport = KNOWN_CONTROL_FLOW_DIRECTIVES.get(controlFlowAttr.name);
const errorMessage =
`The \`*${controlFlowAttr.name}\` directive was used in the template, ` +
`but neither the \`${
correspondingImport}\` directive nor the \`CommonModule\` was imported. ` +
`Please make sure that either the \`${
correspondingImport}\` directive or the \`CommonModule\` ` +
`is included in the \`@Component.imports\` array of this component.`;
const diagnostic = ctx.makeTemplateDiagnostic(sourceSpan, errorMessage);
return [diagnostic];
}
Expand Down
Expand Up @@ -13,14 +13,12 @@ import {absoluteFrom, getSourceFileOrError} from '../../../../../file_system';
import {runInEachFileSystem} from '../../../../../file_system/testing';
import {getSourceCodeForDiagnostic} from '../../../../../testing';
import {getClass, setup} from '../../../../testing';
import {factory as missingControlFlowDirectiveCheck} from '../../../checks/missing_control_flow_directive';
import {factory as missingControlFlowDirectiveCheck, KNOWN_CONTROL_FLOW_DIRECTIVES} from '../../../checks/missing_control_flow_directive';
import {ExtendedTemplateCheckerImpl} from '../../../src/extended_template_checker';

const KNOWN_CONTROL_FLOW_DIRECTIVES = ['ngIf', 'ngFor', 'ngSwitchCase', 'ngSwitchDefault'];

runInEachFileSystem(() => {
describe('MissingControlFlowDirectiveCheck', () => {
KNOWN_CONTROL_FLOW_DIRECTIVES.forEach(directive => {
KNOWN_CONTROL_FLOW_DIRECTIVES.forEach((correspondingImport, directive) => {
['div', 'ng-template', 'ng-container', 'ng-content'].forEach(element => {
it(`should produce a warning when the '${directive}' directive is not imported ` +
`(when used on the '${element}' element)`,
Expand All @@ -47,6 +45,14 @@ runInEachFileSystem(() => {
expect(diags.length).toBe(1);
expect(diags[0].category).toBe(ts.DiagnosticCategory.Warning);
expect(diags[0].code).toBe(ngErrorCode(ErrorCode.MISSING_CONTROL_FLOW_DIRECTIVE));
expect(diags[0].messageText)
.toBe(
`The \`*${directive}\` directive was used in the template, ` +
`but neither the \`${
correspondingImport}\` directive nor the \`CommonModule\` was imported. ` +
`Please make sure that either the \`${
correspondingImport}\` directive or the \`CommonModule\` ` +
`is included in the \`@Component.imports\` array of this component.`);
expect(getSourceCodeForDiagnostic(diags[0])).toBe(directive);
});

Expand Down