Add the possibility to set a rule name in a conformanceRule's config.

Tsetse's error whitelisting scheme, when used with Bazel, relies on the rule name as the key to the whitelist object, but our current autogenerated rule names for ConformancePattern rules won't cut it: there could be two different BANNED_NAME rules enabled in the same codebase, who'd have colliding names with the current naming rules. With this change, the configuration of a rule lets you specify its rule name to avoid that collision.

PiperOrigin-RevId: 272206672
diff --git a/internal/tsetse/rule.ts b/internal/tsetse/rule.ts
index 96d888a..7cc07a8 100644
--- a/internal/tsetse/rule.ts
+++ b/internal/tsetse/rule.ts
@@ -6,6 +6,11 @@
  * files.
  */
 export abstract class AbstractRule {
+  /**
+   * A lower-dashed-case name for that rule. This is not used by Tsetse itself,
+   * but the integrators might (such as the TypeScript Bazel rules, for
+   * instance).
+   */
   abstract readonly ruleName: string;
   abstract readonly code: number;
 
diff --git a/internal/tsetse/rules/conformance_pattern_rule.ts b/internal/tsetse/rules/conformance_pattern_rule.ts
index 0cbfe71..feb72c2 100644
--- a/internal/tsetse/rules/conformance_pattern_rule.ts
+++ b/internal/tsetse/rules/conformance_pattern_rule.ts
@@ -40,7 +40,7 @@
       default:
         throw new Error('Config type not recognized, or not implemented yet.');
     }
-    this.ruleName = `conformance-pattern-${config.kind}`;
+    this.ruleName = config.name || `conformance-pattern-${config.kind}`;
   }
 
   register(checker: Checker) {
diff --git a/internal/tsetse/tests/ban_conformance_pattern/rule_creation_test.ts b/internal/tsetse/tests/ban_conformance_pattern/rule_creation_test.ts
new file mode 100644
index 0000000..46cc156
--- /dev/null
+++ b/internal/tsetse/tests/ban_conformance_pattern/rule_creation_test.ts
@@ -0,0 +1,28 @@
+import 'jasmine';
+import {ConformancePatternRule, PatternKind} from '../../rules/conformance_pattern_rule';
+import {customMatchers} from '../../util/testing/test_support';
+
+describe('ConformancePatternRule creation', () => {
+  describe('naming', () => {
+    const baseConfig = {
+      errorMessage: 'do not cite',
+      kind: PatternKind.BANNED_PROPERTY_WRITE,
+      values: ['HTMLQuoteElement.prototype.cite'],
+    };
+
+    it('generates a name by default', () => {
+      const rule = new ConformancePatternRule(baseConfig);
+      expect(rule.ruleName).toBe('conformance-pattern-banned-property-write');
+    });
+
+    it('accepts given names', () => {
+      const namedConfig = {name: 'myRuleName', ...baseConfig};
+      const rule = new ConformancePatternRule(namedConfig);
+      expect(rule.ruleName).toBe('myRuleName');
+    });
+  });
+});
+
+beforeEach(() => {
+  jasmine.addMatchers(customMatchers);
+});
diff --git a/internal/tsetse/util/pattern_config.ts b/internal/tsetse/util/pattern_config.ts
index 216ce13..cb35d41 100644
--- a/internal/tsetse/util/pattern_config.ts
+++ b/internal/tsetse/util/pattern_config.ts
@@ -31,6 +31,12 @@
 
   /** A list of whitelist blocks. */
   whitelistEntries?: WhitelistEntry[];
+
+  /**
+   * An optional name for that rule, which will be the rule's `ruleName`.
+   * Should be lower-dashed-case.
+   */
+  name?: string;
 }
 
 /**