diff --git a/packages/eslint-plugin-template/docs/rules/no-negated-async.md b/packages/eslint-plugin-template/docs/rules/no-negated-async.md
index bc6f78b23..b36daced0 100644
--- a/packages/eslint-plugin-template/docs/rules/no-negated-async.md
+++ b/packages/eslint-plugin-template/docs/rules/no-negated-async.md
@@ -23,6 +23,12 @@ Ensures that async pipe results are not negated
+## Rationale
+
+Angular's async pipes emit null initially, prior to the observable emitting any values, or the promise resolving. This can cause negations, like \*ngIf="!(myConditional | async)" to thrash the layout and cause expensive side-effects like firing off XHR requests for a component which should not be shown.
+
+
+
## Rule Options
The rule does not have any configuration options.
diff --git a/packages/eslint-plugin-template/src/rules/no-negated-async.ts b/packages/eslint-plugin-template/src/rules/no-negated-async.ts
index 1769d2a23..00b977bd8 100644
--- a/packages/eslint-plugin-template/src/rules/no-negated-async.ts
+++ b/packages/eslint-plugin-template/src/rules/no-negated-async.ts
@@ -65,6 +65,10 @@ export default createESLintRule({
},
});
+export const RULE_DOCS_EXTENSION = {
+ rationale: `Angular's async pipes emit null initially, prior to the observable emitting any values, or the promise resolving. This can cause negations, like *ngIf="!(myConditional | async)" to thrash the layout and cause expensive side-effects like firing off XHR requests for a component which should not be shown.`,
+};
+
function getSuggestionsSchema() {
return [
{ messageId: 'suggestFalseComparison', textToInsert: ' === false' },
diff --git a/tools/scripts/generate-rule-docs.ts b/tools/scripts/generate-rule-docs.ts
index 8ffc56727..066b48544 100644
--- a/tools/scripts/generate-rule-docs.ts
+++ b/tools/scripts/generate-rule-docs.ts
@@ -33,6 +33,7 @@ const testDirs = readdirSync(testDirsDir);
meta: { deprecated, replacedBy, type, fixable, schema, hasSuggestions },
defaultOptions,
},
+ docsExtension,
ruleFilePath,
testCasesFilePath,
} = ruleData;
@@ -125,7 +126,18 @@ ${
hasSuggestions
? '- 💡 Provides suggestions on how to fix issues (https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions)'
: ''
-}
+}${
+ docsExtension?.rationale
+ ? `
+
+
+
+## Rationale
+
+${docsExtension.rationale}
+`
+ : ''
+ }
@@ -211,6 +223,10 @@ interface RuleData {
ruleConfig: TSESLint.RuleModule & {
defaultOptions?: Record[];
};
+ // Rules can optionally export extended documentation content (outside of ESLint's concept of "docs")
+ docsExtension?: {
+ rationale?: string;
+ };
valid: ExtractedTestCase[];
invalid: ExtractedTestCase[];
}
@@ -230,10 +246,15 @@ async function generateAllRuleData(): Promise {
// For rule sources we just import/execute the rule source file
for (const ruleFile of ruleFiles) {
const ruleFilePath = join(rulesDir, ruleFile.replace('.ts', ''));
- const { default: ruleConfig, RULE_NAME } = await import(ruleFilePath);
+ const {
+ default: ruleConfig,
+ RULE_NAME,
+ RULE_DOCS_EXTENSION,
+ } = await import(ruleFilePath);
ruleData[RULE_NAME] = {
ruleConfig,
ruleFilePath: ruleFilePath + '.ts',
+ docsExtension: RULE_DOCS_EXTENSION,
} as RuleData;
}