@ttsc/lint 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -817,7 +817,7 @@ Source: [`eslint-plugin-unicorn`](https://github.com/sindresorhus/eslint-plugin-
817
817
  - [`unicorn/custom-error-definition`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-custom-error-definition.ts): require user-defined `Error` subclasses to set `name`, call `super(message)`, and assign their stack correctly.
818
818
  - [`unicorn/empty-brace-spaces`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-empty-brace-spaces.ts): reject whitespace inside empty `{}` braces.
819
819
  - [`unicorn/error-message`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-error-message.ts): require a non-empty `message` argument when constructing a built-in `Error`.
820
- - [`unicorn/escape-case`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-escape-case.ts): require consistent case for escape sequences (`\xA9` over `\xa9`, `µ` over `µ`).
820
+ - [`unicorn/escape-case`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-escape-case.ts): require consistent case for escape sequences (`\xA9` over `\xa9`, `\u00B5` over `\u00b5`).
821
821
  - [`unicorn/expiring-todo-comments`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-expiring-todo-comments.ts): require every `TODO`/`FIXME`/`XXX` comment to declare an expiration date or package version.
822
822
  - [`unicorn/explicit-length-check`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-explicit-length-check.ts): require explicit comparison of `.length` / `.size` instead of relying on truthy coercion.
823
823
  - [`unicorn/filename-case`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-filename-case.ts): enforce a single case style (kebab/camel/snake/pascal) for source filenames.
@@ -839,7 +839,7 @@ Source: [`eslint-plugin-unicorn`](https://github.com/sindresorhus/eslint-plugin-
839
839
  - [`unicorn/no-document-cookie`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-document-cookie.ts): reject direct reads or assignments to `document.cookie`; use the Cookie Store API or a wrapper.
840
840
  - [`unicorn/no-empty-file`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-empty-file.ts): reject source files whose only content is whitespace and/or comments.
841
841
  - [`unicorn/no-for-loop`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-for-loop.ts): prefer `for...of` over index-based `for` loops over arrays.
842
- - [`unicorn/no-hex-escape`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-hex-escape.ts): prefer Unicode escape (`©`) over hexadecimal escape (`\xA9`).
842
+ - [`unicorn/no-hex-escape`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-hex-escape.ts): prefer Unicode escape (`\u00A9`) over hexadecimal escape (`\xA9`).
843
843
  - [`unicorn/no-immediate-mutation`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-immediate-mutation.ts): reject mutating a value on the same expression that produces it (`[...x].push(y)`); separate the construction and the mutation.
844
844
  - [`unicorn/no-instanceof-builtins`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-instanceof-builtins.ts): reject `instanceof Array`, `instanceof Error`, `instanceof Map`, etc.. They fail across realms and for subclasses.
845
845
  - [`unicorn/no-invalid-fetch-options`](https://github.com/samchon/ttsc/blob/master/tests/test-lint/src/cases/unicorn-no-invalid-fetch-options.ts): reject GET / HEAD `fetch()` calls that also set a request `body`, which throws at runtime.
@@ -1132,6 +1132,8 @@ export default {
1132
1132
 
1133
1133
  Contributor rules emit autofixes the same way built-ins do, call `ctx.ReportFix(node, message, edits...)` or `ctx.ReportRangeFix(pos, end, message, edits...)`. The `rule/astutil` package re-exports the byte-range helpers built-ins use (`NodeText`, `KeywordStart`, `FindKeyword`, `TokenRange`). See the [contributor autofix path](https://ttsc.dev/docs/development/walkthroughs/lint#the-contributor-autofix-path) section for the full contract and an example.
1134
1134
 
1135
+ Contributor rules run on declaration files (`.d.ts`) by default. The engine skips its own value-level rules there — executable grammar cannot appear in a declaration file — but it cannot infer a third-party rule's shape, so contributors keep the conservative default. A rule that only inspects executable code can implement the optional `rule.DeclarationFileRule` marker (`VisitsDeclarationFiles() bool { return false }`) to get the same skip and save the dispatch on declaration-heavy projects.
1136
+
1135
1137
  ## Sponsors
1136
1138
 
1137
1139
  [![Sponsors](https://raw.githubusercontent.com/samchon/sponsor-images/refs/heads/master/public/circle.svg)](https://github.com/sponsors/samchon)
@@ -230,9 +230,9 @@ export interface ITtscLintTestingLibraryRules {
230
230
  */
231
231
  "testing-library/prefer-presence-queries"?: TtscLintRuleSetting;
232
232
  /**
233
- * Prefer `queryBy*` inside `waitForElementToBeRemoved`.
233
+ * Prefer `queryBy*` inside disappearance waits.
234
234
  *
235
- * The helper retries the callback against the disappearing element, but
235
+ * `waitFor` retries the callback against the disappearing element, but
236
236
  * `getBy*` throws on the very state being waited for, which produces a noisy
237
237
  * error in the trace each retry.
238
238
  *
@@ -94,8 +94,8 @@ export interface ITtscLintUnicornRules {
94
94
  */
95
95
  "unicorn/error-message"?: TtscLintRuleSetting;
96
96
  /**
97
- * Require consistent case for escape sequences (`\xA9` over `\xa9`, `µ` over
98
- * `µ`).
97
+ * Require consistent case for escape sequences (`\xA9` over `\xa9`, `\u00B5`
98
+ * over `\u00b5`).
99
99
  *
100
100
  * @reference https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/escape-case.md
101
101
  */
@@ -243,7 +243,7 @@ export interface ITtscLintUnicornRules {
243
243
  */
244
244
  "unicorn/no-for-loop"?: TtscLintRuleSetting;
245
245
  /**
246
- * Prefer Unicode escape (`©`) over hexadecimal escape (`\xA9`).
246
+ * Prefer Unicode escape (`\u00A9`) over hexadecimal escape (`\xA9`).
247
247
  *
248
248
  * @reference https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-hex-escape.md
249
249
  */
@@ -75,6 +75,18 @@ func (a contributorAdapter) NeedsTypeChecker() bool {
75
75
  return true
76
76
  }
77
77
 
78
+ // VisitsDeclarationFiles keeps contributor rules running on declaration
79
+ // files unless the contributor opts out through the public
80
+ // `rule.DeclarationFileRule` marker. Same conservative-default reasoning
81
+ // as NeedsTypeChecker: the host cannot infer a third-party rule's grammar
82
+ // shape, and a wrong skip silently loses findings.
83
+ func (a contributorAdapter) VisitsDeclarationFiles() bool {
84
+ if dr, ok := a.inner.(rule.DeclarationFileRule); ok {
85
+ return dr.VisitsDeclarationFiles()
86
+ }
87
+ return true
88
+ }
89
+
78
90
  // formatContributorAdapter is the FormatRule-tagged variant of
79
91
  // contributorAdapter. Wrapping the lint-only adapter (rather than
80
92
  // duplicating its method set) keeps the marker addition trivial and
@@ -0,0 +1,173 @@
1
+ // Declaration-file dispatch policy.
2
+ //
3
+ // The engine skips rules on `.d.ts` (and other declaration) sources unless
4
+ // the rule is known to produce legitimate findings there. Declaration files
5
+ // carry no executable code, so most value-level rules can never fire on one;
6
+ // walking them anyway is pure dispatch overhead on declaration-heavy
7
+ // projects (see issue #177).
8
+ //
9
+ // Three ways a rule participates in declaration files:
10
+ //
11
+ // - FormatRule markers: every format rule visits declaration files —
12
+ // `ttsc format` / `ttsc fix` must keep formatting hand-written `.d.ts`
13
+ // on the same boundary as other sources.
14
+ // - declarationFileRule: the optional interface a rule (built-in or
15
+ // contributor adapter) implements to answer for itself.
16
+ // - declarationFileRuleNames: the curated allowlist below for built-in
17
+ // rules, kept in one place so the whole audit stays reviewable.
18
+ //
19
+ // Audit principle for the allowlist: a rule is listed when its grammar
20
+ // shape occurs in declaration files under normal usage — type syntax,
21
+ // signatures, import/export forms, enums and their constant initializers,
22
+ // comments/JSDoc, identifier naming, or per-file metrics. Rules that need
23
+ // executable statements, expressions outside ambient-legal constant
24
+ // expressions, or runtime semantics (promises, DOM, JSX, test frameworks)
25
+ // are deliberately absent. When in doubt the rule is listed: a wrongly
26
+ // listed rule only costs dispatch time, while a wrongly skipped rule
27
+ // silently loses findings.
28
+ package linthost
29
+
30
+ // declarationFileRule marks rules that want to fire on declaration-file
31
+ // (`.d.ts`, `.d.mts`, `.d.cts`) inputs. Rules that neither implement this
32
+ // interface (returning true) nor appear in declarationFileRuleNames nor
33
+ // carry the FormatRule marker are skipped on every
34
+ // `file.IsDeclarationFile == true` source.
35
+ type declarationFileRule interface {
36
+ VisitsDeclarationFiles() bool
37
+ }
38
+
39
+ // ruleVisitsDeclarationFiles reports whether the engine dispatches `r` on
40
+ // declaration-file sources.
41
+ func ruleVisitsDeclarationFiles(r Rule) bool {
42
+ if isFormatRule(r) {
43
+ return true
44
+ }
45
+ if dr, ok := r.(declarationFileRule); ok {
46
+ return dr.VisitsDeclarationFiles()
47
+ }
48
+ return declarationFileRuleNames[r.Name()]
49
+ }
50
+
51
+ // declarationFileRuleNames is the audited allowlist of built-in rules whose
52
+ // grammar shapes occur in declaration files. Grouped by namespace; each
53
+ // group states the shape that justifies it. A name listed here must exist
54
+ // in the registry — the registry-parity test pins that.
55
+ var declarationFileRuleNames = map[string]bool{
56
+ // JSDoc lives on declarations; declaration files are its prime habitat.
57
+ "jsdoc/check-tag-names": true,
58
+ "jsdoc/check-values": true,
59
+ "jsdoc/empty-tags": true,
60
+ "jsdoc/no-types": true,
61
+ "jsdoc/reject-any-type": true,
62
+ "jsdoc/reject-function-type": true,
63
+ "jsdoc/require-description": true,
64
+ "jsdoc/require-param-description": true,
65
+ "jsdoc/require-param-name": true,
66
+ "jsdoc/require-property-description": true,
67
+ "jsdoc/require-property-name": true,
68
+ "jsdoc/require-returns-description": true,
69
+ "jsdoc/tsdoc-syntax": true,
70
+
71
+ // Import-graph boundaries: declaration files import and re-export, and
72
+ // an architectural boundary holds for hand-written `.d.ts` too.
73
+ "boundaries/dependencies": true,
74
+ "boundaries/element-types": true,
75
+ "boundaries/entry-point": true,
76
+ "boundaries/external": true,
77
+ "boundaries/no-private": true,
78
+ "boundaries/no-unknown": true,
79
+
80
+ // Core rules over shapes a declaration file contains: identifier
81
+ // naming, import/export forms, accessor and class-member signatures,
82
+ // per-file metrics, user-configured selectors, and the constant
83
+ // expressions enum initializers allow (bitwise flags, numeric
84
+ // literals).
85
+ "camelcase": true,
86
+ "grouped-accessor-pairs": true,
87
+ "id-length": true,
88
+ "max-classes-per-file": true,
89
+ "max-lines": true,
90
+ "max-params": true,
91
+ "no-bitwise": true,
92
+ "no-dupe-class-members": true,
93
+ "no-duplicate-imports": true,
94
+ "no-empty-named-blocks": true,
95
+ "no-irregular-whitespace": true,
96
+ "no-loss-of-precision": true,
97
+ "no-magic-numbers": true,
98
+ "no-mixed-operators": true,
99
+ "no-redeclare": true,
100
+ "no-restricted-imports": true,
101
+ "no-restricted-syntax": true,
102
+ "no-shadow": true,
103
+ "no-shadow-restricted-names": true,
104
+ "no-useless-computed-key": true,
105
+ "no-useless-rename": true,
106
+ "sort-imports": true,
107
+
108
+ // typescript/* rules over type syntax, signatures, enums, import/export
109
+ // type forms, comments, and declaration merging.
110
+ "typescript/adjacent-overload-signatures": true,
111
+ "typescript/array-type": true,
112
+ "typescript/ban-ts-comment": true,
113
+ "typescript/ban-tslint-comment": true,
114
+ "typescript/class-literal-property-style": true,
115
+ "typescript/consistent-indexed-object-style": true,
116
+ "typescript/consistent-type-definitions": true,
117
+ "typescript/consistent-type-exports": true,
118
+ "typescript/consistent-type-imports": true,
119
+ "typescript/explicit-function-return-type": true,
120
+ "typescript/explicit-member-accessibility": true,
121
+ "typescript/method-signature-style": true,
122
+ "typescript/no-deprecated": true,
123
+ "typescript/no-duplicate-enum-values": true,
124
+ "typescript/no-empty-interface": true,
125
+ "typescript/no-empty-object-type": true,
126
+ "typescript/no-explicit-any": true,
127
+ "typescript/no-extraneous-class": true,
128
+ "typescript/no-import-type-side-effects": true,
129
+ "typescript/no-invalid-void-type": true,
130
+ "typescript/no-magic-numbers": true,
131
+ "typescript/no-misused-new": true,
132
+ "typescript/no-mixed-enums": true,
133
+ "typescript/no-redundant-type-constituents": true,
134
+ "typescript/no-require-imports": true,
135
+ "typescript/no-restricted-types": true,
136
+ "typescript/no-unnecessary-qualifier": true,
137
+ "typescript/no-unnecessary-template-expression": true,
138
+ "typescript/no-unnecessary-type-arguments": true,
139
+ "typescript/no-unnecessary-type-constraint": true,
140
+ "typescript/no-unsafe-declaration-merging": true,
141
+ "typescript/no-unsafe-function-type": true,
142
+ "typescript/no-wrapper-object-types": true,
143
+ "typescript/prefer-enum-initializers": true,
144
+ "typescript/prefer-function-type": true,
145
+ "typescript/prefer-literal-enum-member": true,
146
+ "typescript/prefer-namespace-keyword": true,
147
+ "typescript/prefer-return-this-type": true,
148
+ "typescript/related-getter-setter-pairs": true,
149
+ "typescript/sort-type-constituents": true,
150
+ "typescript/triple-slash-reference": true,
151
+
152
+ // functional/* rules that police type shapes (not statements).
153
+ "functional/no-mixed-types": true,
154
+ "functional/no-return-void": true,
155
+ "functional/prefer-immutable-types": true,
156
+ "functional/prefer-property-signatures": true,
157
+ "functional/prefer-readonly-type": true,
158
+ "functional/readonly-type": true,
159
+ "functional/type-declaration-immutability": true,
160
+
161
+ // unicorn/* rules over file names, comments, identifier naming, and
162
+ // the numeric literals that appear in enum initializers and literal
163
+ // types.
164
+ "unicorn/empty-brace-spaces": true,
165
+ "unicorn/expiring-todo-comments": true,
166
+ "unicorn/filename-case": true,
167
+ "unicorn/no-abusive-eslint-disable": true,
168
+ "unicorn/no-empty-file": true,
169
+ "unicorn/no-keyword-prefix": true,
170
+ "unicorn/number-literal-case": true,
171
+ "unicorn/numeric-separators-style": true,
172
+ "unicorn/prevent-abbreviations": true,
173
+ }
@@ -534,6 +534,12 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
534
534
  // Context for every (node, rule) pair, which on a large program meant
535
535
  // millions of short-lived heap allocations and the GC pressure they
536
536
  // carry. Rules never mutate their Context, so reuse is safe.
537
+ //
538
+ // Declaration files only bind rules that opt into them (see
539
+ // declaration_rules.go): value-level rules can never fire on a `.d.ts`,
540
+ // so dispatching to them is pure overhead on declaration-heavy trees.
541
+ declarationFile := file.IsDeclarationFile
542
+ bound := 0
537
543
  byKind := make([][]boundRule, len(e.rules))
538
544
  ctxByRule := make(map[string]*Context, len(e.enabled))
539
545
  for kind, rules := range e.rules {
@@ -541,6 +547,9 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
541
547
  continue
542
548
  }
543
549
  for _, rule := range rules {
550
+ if declarationFile && !ruleVisitsDeclarationFiles(rule) {
551
+ continue
552
+ }
544
553
  name := rule.Name()
545
554
  ctx, built := ctxByRule[name]
546
555
  if !built {
@@ -563,6 +572,7 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
563
572
  continue
564
573
  }
565
574
  byKind[kind] = append(byKind[kind], boundRule{rule: rule, ctx: ctx})
575
+ bound++
566
576
  }
567
577
  }
568
578
 
@@ -572,23 +582,30 @@ func (e *Engine) runFile(file *shimast.SourceFile, checker *shimchecker.Checker)
572
582
  // the heap on every invocation; converting to a method value with a
573
583
  // cached function field removes that allocation from the hot path —
574
584
  // ~38 % of pre-Opt-4 CPU was in the inner ForEachChild closure.
575
- w := &lintFileWalker{byKind: byKind, collect: collect}
576
- w.childCB = w.visitChild
577
-
578
- // SourceFile dispatches into its statement list directly; we walk
579
- // statements explicitly so the file node itself can be inspected by
580
- // rules (e.g., `ban-ts-comment` reads CommentDirectives off the
581
- // SourceFile).
582
- if k := int(shimast.KindSourceFile); k >= 0 && k < len(byKind) {
583
- for _, bound := range byKind[k] {
584
- runRuleCheck(bound.rule, bound.ctx, file.AsNode(), collect)
585
+ //
586
+ // With no bound rules at all (every active rule was filtered out, e.g.
587
+ // a declaration file where nothing opted in) the walk cannot produce a
588
+ // finding, so it is skipped entirely; inline directives are still
589
+ // parsed below so unknown-directive warnings stay file-complete.
590
+ if bound != 0 {
591
+ w := &lintFileWalker{byKind: byKind, collect: collect}
592
+ w.childCB = w.visitChild
593
+
594
+ // SourceFile dispatches into its statement list directly; we walk
595
+ // statements explicitly so the file node itself can be inspected by
596
+ // rules (e.g., `ban-ts-comment` reads CommentDirectives off the
597
+ // SourceFile).
598
+ if k := int(shimast.KindSourceFile); k >= 0 && k < len(byKind) {
599
+ for _, bound := range byKind[k] {
600
+ runRuleCheck(bound.rule, bound.ctx, file.AsNode(), collect)
601
+ }
585
602
  }
586
- }
587
603
 
588
- statements := file.Statements
589
- if statements != nil {
590
- for _, stmt := range statements.Nodes {
591
- w.walk(stmt)
604
+ statements := file.Statements
605
+ if statements != nil {
606
+ for _, stmt := range statements.Nodes {
607
+ w.walk(stmt)
608
+ }
592
609
  }
593
610
  }
594
611
  directives := parseLintInlineDirectives(file)
package/linthost/lsp.go CHANGED
@@ -502,8 +502,11 @@ func lspFormatBuffer(content string, opts *lspCommandOptions) (*lspWorkspaceEdit
502
502
 
503
503
  text := content
504
504
  converged := false
505
+ // The tsgo parser asserts on normalized (forward-slash) absolute paths;
506
+ // `target` comes from filepath.Abs and carries backslashes on Windows.
507
+ parseName := filepath.ToSlash(target)
505
508
  for pass := 0; pass < maxFormatPasses; pass++ {
506
- file := shimparser.ParseSourceFile(shimast.SourceFileParseOptions{FileName: target}, text, scriptKind)
509
+ file := shimparser.ParseSourceFile(shimast.SourceFileParseOptions{FileName: parseName}, text, scriptKind)
507
510
  if file == nil {
508
511
  // Match the disk path: a buffer we can't parse is a benign no-op, not a
509
512
  // hard error — don't fight the editor's own diagnostics on a dirty buffer.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/lint",
3
- "version": "0.15.1",
3
+ "version": "0.15.3",
4
4
  "description": "Reference ttsc plugin: ESLint-style lint rules hosted in the same Program/Checker as the type-check pass.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -33,10 +33,10 @@
33
33
  "src"
34
34
  ],
35
35
  "devDependencies": {
36
- "@typescript/native-preview": "7.0.0-dev.20260421.2",
36
+ "@typescript/native-preview": "7.0.0-dev.20260612.1",
37
37
  "@types/node": "^25.3.0",
38
38
  "rimraf": "^6.1.2",
39
- "ttsc": "0.15.1"
39
+ "ttsc": "0.15.3"
40
40
  },
41
41
  "repository": {
42
42
  "type": "git",
package/rule/rule.go CHANGED
@@ -97,6 +97,21 @@ type FormatRule interface {
97
97
  IsFormat() bool
98
98
  }
99
99
 
100
+ // DeclarationFileRule is an optional marker contributors implement to
101
+ // control whether their rule runs on declaration-file inputs (`.d.ts`,
102
+ // `.d.mts`, `.d.cts`). The engine skips most built-in rules on declaration
103
+ // files because value-level grammar cannot appear there; contributor rules
104
+ // keep the conservative default — they DO run on declaration files — since
105
+ // the host cannot infer a third-party rule's shape (mirror of the implicit
106
+ // checker default). A contributor whose rule inspects executable code only
107
+ // can implement this with `return false` to skip declaration files and
108
+ // save the dispatch on declaration-heavy projects; returning `true` is
109
+ // equivalent to not implementing the interface at all.
110
+ type DeclarationFileRule interface {
111
+ Rule
112
+ VisitsDeclarationFiles() bool
113
+ }
114
+
100
115
  // Reporter is the engine-supplied callback that records a finding. The
101
116
  // host implements this and passes it to `NewContext` when invoking a
102
117
  // contributor rule.
@@ -257,9 +257,9 @@ export interface ITtscLintTestingLibraryRules {
257
257
  "testing-library/prefer-presence-queries"?: TtscLintRuleSetting;
258
258
 
259
259
  /**
260
- * Prefer `queryBy*` inside `waitForElementToBeRemoved`.
260
+ * Prefer `queryBy*` inside disappearance waits.
261
261
  *
262
- * The helper retries the callback against the disappearing element, but
262
+ * `waitFor` retries the callback against the disappearing element, but
263
263
  * `getBy*` throws on the very state being waited for, which produces a noisy
264
264
  * error in the trace each retry.
265
265
  *
@@ -107,8 +107,8 @@ export interface ITtscLintUnicornRules {
107
107
  "unicorn/error-message"?: TtscLintRuleSetting;
108
108
 
109
109
  /**
110
- * Require consistent case for escape sequences (`\xA9` over `\xa9`, `µ` over
111
- * `µ`).
110
+ * Require consistent case for escape sequences (`\xA9` over `\xa9`, `\u00B5`
111
+ * over `\u00b5`).
112
112
  *
113
113
  * @reference https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/escape-case.md
114
114
  */
@@ -278,7 +278,7 @@ export interface ITtscLintUnicornRules {
278
278
  "unicorn/no-for-loop"?: TtscLintRuleSetting;
279
279
 
280
280
  /**
281
- * Prefer Unicode escape (`©`) over hexadecimal escape (`\xA9`).
281
+ * Prefer Unicode escape (`\u00A9`) over hexadecimal escape (`\xA9`).
282
282
  *
283
283
  * @reference https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-hex-escape.md
284
284
  */